From cb428520e6f5cb7f5e56f4ba06f54b1ce7b47c23 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Thu, 29 Dec 2005 14:51:59 +0100 Subject: [PATCH] cDevice::GrabImage() now returns a pointer to the image in memory; cDevice::GrabImageFile() grabs the image to a file --- HISTORY | 5 +++ device.c | 33 ++++++++++++-- device.h | 18 +++++--- dvbdevice.c | 123 ++++++++++++++++++++++++---------------------------- dvbdevice.h | 4 +- svdrp.c | 4 +- 6 files changed, 106 insertions(+), 81 deletions(-) diff --git a/HISTORY b/HISTORY index 00065c62..a486602f 100644 --- a/HISTORY +++ b/HISTORY @@ -4012,3 +4012,8 @@ Video Disk Recorder Revision History extension (".jpg", ".jpeg" or ".pnm") of the given file name. The explicit 'jpeg' or 'pnm' parameter is still accepted for backward compatibility, but has no meaning any more. +- The function cDevice::GrabImage() no longer writes the grabbed image to a + file, but rather returns a pointer to the image in memory. The wrapper + function cDevice::GrabImageFile() can be used to write the grabbed image + directly to a file. Plugins that used the old version of cDevice::GrabImage() + need to be adapted to the new interface. diff --git a/device.c b/device.c index 1b4cec45..fb5360c8 100644 --- a/device.c +++ b/device.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: device.c 1.112 2005/11/26 12:56:09 kls Exp $ + * $Id: device.c 1.113 2005/12/29 14:51:41 kls Exp $ */ #include "device.h" @@ -322,9 +322,36 @@ void cDevice::Shutdown(void) } } -bool cDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY) +uchar *cDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY) { - return false; + return NULL; +} + +bool cDevice::GrabImageFile(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY) +{ + int result = 0; + FILE *f = fopen(FileName, "wb"); + if (f) { + int ImageSize; + uchar *Image = GrabImage(ImageSize, Jpeg, Quality, SizeX, SizeY); + if (Image) { + if (fwrite(Image, ImageSize, 1, f) == 1) + isyslog("grabbed image to %s", FileName); + else { + LOG_ERROR_STR(FileName); + result |= 1; + } + free(Image); + } + else + result |= 1; + fclose(f); + } + else { + LOG_ERROR_STR(FileName); + result |= 1; + } + return result == 0; } void cDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat) diff --git a/device.h b/device.h index 43d386bf..88607319 100644 --- a/device.h +++ b/device.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: device.h 1.66 2005/11/05 15:25:41 kls Exp $ + * $Id: device.h 1.67 2005/12/29 14:51:59 kls Exp $ */ #ifndef __DEVICE_H @@ -305,11 +305,9 @@ public: // Image Grab facilities public: - virtual bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); - ///< Capture a single frame as an image. - ///< Grabs the currently visible screen image into the given file, with the - ///< given parameters. - ///< \param FileName The name of the file to write. Should include the proper extension. + virtual uchar *GrabImage(int &Size, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); + ///< Grabs the currently visible screen image. + ///< \param Size The size of the returned data block. ///< \param Jpeg If true will write a JPEG file. Otherwise a PNM file will be written. ///< \param Quality The compression factor for JPEG. 1 will create a very blocky ///< and small image, 70..80 will yield reasonable quality images while keeping the @@ -317,7 +315,13 @@ public: ///< but very high quality image. ///< \param SizeX The number of horizontal pixels in the frame (default is the current screen width). ///< \param SizeY The number of vertical pixels in the frame (default is the current screen height). - ///< \return True if all went well. */ + ///< \return A pointer to the grabbed image data, or NULL in case of an error. + ///< The caller takes ownership of the returned memory and must free() it once it isn't needed any more. + bool GrabImageFile(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); + ///< Calls GrabImage() and stores the resulting image in a file with the given name. + ///< \return True if all went well. + ///< The caller is responsible for making sure that the given file name + ///< doesn't lead to overwriting any important other file. // Video format facilities diff --git a/dvbdevice.c b/dvbdevice.c index 533a65ff..17b18cd1 100644 --- a/dvbdevice.c +++ b/dvbdevice.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbdevice.c 1.142 2005/12/29 11:24:02 kls Exp $ + * $Id: dvbdevice.c 1.143 2005/12/29 13:49:09 kls Exp $ */ #include "dvbdevice.h" @@ -480,95 +480,84 @@ cSpuDecoder *cDvbDevice::GetSpuDecoder(void) return spuDecoder; } -bool cDvbDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY) +uchar *cDvbDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY) { if (devVideoIndex < 0) - return false; + return NULL; char buffer[PATH_MAX]; snprintf(buffer, sizeof(buffer), "%s%d", DEV_VIDEO, devVideoIndex); int videoDev = open(buffer, O_RDWR); - if (videoDev < 0) - LOG_ERROR_STR(buffer); if (videoDev >= 0) { - int result = 0; + uchar *result = NULL; struct video_mbuf mbuf; - result |= ioctl(videoDev, VIDIOCGMBUF, &mbuf); - if (result == 0) { + if (ioctl(videoDev, VIDIOCGMBUF, &mbuf) == 0) { int msize = mbuf.size; unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0); if (mem && mem != (unsigned char *)-1) { // set up the size and RGB struct video_capability vc; - result |= ioctl(videoDev, VIDIOCGCAP, &vc); - struct video_mmap vm; - vm.frame = 0; - if ((SizeX > 0) && (SizeX <= vc.maxwidth) && - (SizeY > 0) && (SizeY <= vc.maxheight)) { - vm.width = SizeX; - vm.height = SizeY; - } - else { - vm.width = vc.maxwidth; - vm.height = vc.maxheight; - } - vm.format = VIDEO_PALETTE_RGB24; - result |= ioctl(videoDev, VIDIOCMCAPTURE, &vm); - result |= ioctl(videoDev, VIDIOCSYNC, &vm.frame); - // make RGB out of BGR: - int memsize = vm.width * vm.height; - unsigned char *mem1 = mem; - for (int i = 0; i < memsize; i++) { - unsigned char tmp = mem1[2]; - mem1[2] = mem1[0]; - mem1[0] = tmp; - mem1 += 3; - } - - if (Quality < 0) - Quality = 100; - - isyslog("grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height); - FILE *f = fopen(FileName, "wb"); - if (f) { - if (Jpeg) { - // write JPEG file: - int JpegImageSize; - uchar *JpegImage = RgbToJpeg(mem, vm.width, vm.height, JpegImageSize, Quality); - if (JpegImage) { - if (fwrite(JpegImage, JpegImageSize, 1, f) != 1) { - LOG_ERROR_STR(FileName); - result |= 1; - } - delete JpegImage; - } - else { - esyslog("ERROR: failed to convert image to JPEG"); - result |= 1; - } + if (ioctl(videoDev, VIDIOCGCAP, &vc) == 0) { + struct video_mmap vm; + vm.frame = 0; + if ((SizeX > 0) && (SizeX <= vc.maxwidth) && + (SizeY > 0) && (SizeY <= vc.maxheight)) { + vm.width = SizeX; + vm.height = SizeY; } else { - // write PNM file: - if (fprintf(f, "P6\n%d\n%d\n255\n", vm.width, vm.height) < 0 || - fwrite(mem, vm.width * vm.height * 3, 1, f) != 1) { - LOG_ERROR_STR(FileName); - result |= 1; + vm.width = vc.maxwidth; + vm.height = vc.maxheight; + } + vm.format = VIDEO_PALETTE_RGB24; + if (ioctl(videoDev, VIDIOCMCAPTURE, &vm) == 0 && ioctl(videoDev, VIDIOCSYNC, &vm.frame) == 0) { + // make RGB out of BGR: + int memsize = vm.width * vm.height; + unsigned char *mem1 = mem; + for (int i = 0; i < memsize; i++) { + unsigned char tmp = mem1[2]; + mem1[2] = mem1[0]; + mem1[0] = tmp; + mem1 += 3; + } + + if (Quality < 0) + Quality = 100; + + isyslog("grabbing to %s %d %d %d", Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height); + if (Jpeg) { + // convert to JPEG: + result = RgbToJpeg(mem, vm.width, vm.height, Size, Quality); + if (!result) + esyslog("ERROR: failed to convert image to JPEG"); + } + else { + // convert to PNM: + char buf[32]; + snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n", vm.width, vm.height); + int l = strlen(buf); + int bytes = memsize * 3; + Size = l + bytes; + result = MALLOC(uchar, Size); + if (result) { + memcpy(result, buf, l); + memcpy(result + l, mem, bytes); + } + else + esyslog("ERROR: failed to convert image to PNM"); } } - fclose(f); - } - else { - LOG_ERROR_STR(FileName); - result |= 1; } munmap(mem, msize); } else - result |= 1; + esyslog("ERROR: failed to memmap video device"); } close(videoDev); - return result == 0; + return result; } - return false; + else + LOG_ERROR_STR(buffer); + return NULL; } void cDvbDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat) diff --git a/dvbdevice.h b/dvbdevice.h index ed0cef8a..cc9d126a 100644 --- a/dvbdevice.h +++ b/dvbdevice.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbdevice.h 1.36 2005/11/11 14:51:38 kls Exp $ + * $Id: dvbdevice.h 1.37 2005/12/29 13:33:12 kls Exp $ */ #ifndef __DVBDEVICE_H @@ -85,7 +85,7 @@ private: static int devVideoOffset; int devVideoIndex; public: - virtual bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); + virtual uchar *GrabImage(int &Size, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); // Video format facilities diff --git a/svdrp.c b/svdrp.c index c6b557b9..91b39518 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.85 2005/12/29 12:17:27 kls Exp $ + * $Id: svdrp.c 1.86 2005/12/29 13:33:43 kls Exp $ */ #include "svdrp.h" @@ -711,7 +711,7 @@ void cSVDRP::CmdGRAB(const char *Option) Reply(501, "Unexpected parameter \"%s\"", p); return; } - if (cDevice::PrimaryDevice()->GrabImage(FileName, Jpeg, Quality, SizeX, SizeY)) + if (cDevice::PrimaryDevice()->GrabImageFile(FileName, Jpeg, Quality, SizeX, SizeY)) Reply(250, "Grabbed image %s", Option); else Reply(451, "Grab image failed");