diff --git a/HISTORY b/HISTORY index a5c28232..1e02a787 100644 --- a/HISTORY +++ b/HISTORY @@ -3963,7 +3963,7 @@ Video Disk Recorder Revision History commands may now be executed at any time, and the message will be displayed (no more "pending message"). -2005-12-28: Version 1.3.38 +2005-12-29: Version 1.3.38 - Fixed handling second audio and Dolby Digital PIDs for encrypted channels (was broken in version 1.3.37). @@ -4006,3 +4006,5 @@ Video Disk Recorder Revision History timer" menu for that timer. - Removing deleted recordings is now done in a separate thread. - Dropped the unused "stop recording on primary interface" stuff. +- Converting a grabbed image to JPEG is now done with the new function + RgbToJpeg() (see tools.h). diff --git a/dvbdevice.c b/dvbdevice.c index 8ef90a80..533a65ff 100644 --- a/dvbdevice.c +++ b/dvbdevice.c @@ -4,18 +4,11 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbdevice.c 1.141 2005/12/28 12:28:05 kls Exp $ + * $Id: dvbdevice.c 1.142 2005/12/29 11:24:02 kls Exp $ */ #include "dvbdevice.h" #include -extern "C" { -#ifdef boolean -#define HAVE_BOOLEAN -#endif -#include -#undef boolean -} #include #include #include @@ -539,27 +532,19 @@ bool cDvbDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int Siz if (f) { if (Jpeg) { // write JPEG file: - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_compress(&cinfo); - jpeg_stdio_dest(&cinfo, f); - cinfo.image_width = vm.width; - cinfo.image_height = vm.height; - cinfo.input_components = 3; - cinfo.in_color_space = JCS_RGB; - - jpeg_set_defaults(&cinfo); - jpeg_set_quality(&cinfo, Quality, true); - jpeg_start_compress(&cinfo, true); - - int rs = vm.width * 3; - JSAMPROW rp[vm.height]; - for (int k = 0; k < vm.height; k++) - rp[k] = &mem[rs * k]; - jpeg_write_scanlines(&cinfo, rp, vm.height); - jpeg_finish_compress(&cinfo); - jpeg_destroy_compress(&cinfo); + 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; + } } else { // write PNM file: diff --git a/tools.c b/tools.c index 5937d857..1f474c8b 100644 --- a/tools.c +++ b/tools.c @@ -4,13 +4,20 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.105 2005/12/18 10:33:04 kls Exp $ + * $Id: tools.c 1.106 2005/12/29 11:20:28 kls Exp $ */ #include "tools.h" #include #include #include +extern "C" { +#ifdef boolean +#define HAVE_BOOLEAN +#endif +#include +#undef boolean +} #include #include #include @@ -651,6 +658,93 @@ cString TimeString(time_t t) return buf; } +// --- RgbToJpeg ------------------------------------------------------------- + +#define JPEGCOMPRESSMEM 500000 + +struct tJpegCompressData { + int size; + uchar *mem; + }; + +static void JpegCompressInitDestination(j_compress_ptr cinfo) +{ + tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data; + if (jcd) { + cinfo->dest->free_in_buffer = jcd->size = JPEGCOMPRESSMEM; + cinfo->dest->next_output_byte = jcd->mem = MALLOC(uchar, jcd->size); + } +} + +static boolean JpegCompressEmptyOutputBuffer(j_compress_ptr cinfo) +{ + tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data; + if (jcd) { + int Used = jcd->size; + jcd->size += JPEGCOMPRESSMEM; + jcd->mem = (uchar *)realloc(jcd->mem, jcd->size); + if (jcd->mem) { + cinfo->dest->next_output_byte = jcd->mem + Used; + cinfo->dest->free_in_buffer = jcd->size - Used; + return TRUE; + } + } + return FALSE; +} + +static void JpegCompressTermDestination(j_compress_ptr cinfo) +{ + tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data; + if (jcd) { + int Used = cinfo->dest->next_output_byte - jcd->mem; + if (Used < jcd->size) { + jcd->size = Used; + jcd->mem = (uchar *)realloc(jcd->mem, jcd->size); + } + } +} + +uchar *RgbToJpeg(uchar *Mem, int Width, int Height, int &Size, int Quality) +{ + if (Quality < 0) + Quality = 0; + else if (Quality > 100) + Quality = 100; + + jpeg_destination_mgr jdm; + + jdm.init_destination = JpegCompressInitDestination; + jdm.empty_output_buffer = JpegCompressEmptyOutputBuffer; + jdm.term_destination = JpegCompressTermDestination; + + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + cinfo.dest = &jdm; + tJpegCompressData jcd; + cinfo.client_data = &jcd; + cinfo.image_width = Width; + cinfo.image_height = Height; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, Quality, true); + jpeg_start_compress(&cinfo, true); + + int rs = Width * 3; + JSAMPROW rp[Height]; + for (int k = 0; k < Height; k++) + rp[k] = &Mem[rs * k]; + jpeg_write_scanlines(&cinfo, rp, Height); + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + Size = jcd.size; + return jcd.mem; +} + // --- cReadLine ------------------------------------------------------------- cReadLine::cReadLine(void) diff --git a/tools.h b/tools.h index 64c18238..9829209e 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.85 2005/12/17 11:09:37 kls Exp $ + * $Id: tools.h 1.86 2005/12/29 11:09:43 kls Exp $ */ #ifndef __TOOLS_H @@ -121,6 +121,15 @@ cString DayDateTime(time_t t = 0); cString TimeToString(time_t t); cString DateString(time_t t); cString TimeString(time_t t); +uchar *RgbToJpeg(uchar *Mem, int Width, int Height, int &Size, int Quality = 100); + ///< Converts the given Memory to a JPEG image and returns a pointer + ///< to the resulting image. Mem must point to a data block of exactly + ///< (Width * Height) triplets of RGB image data bytes. Upon return, Size + ///< will hold the number of bytes of the resulting JPEG data. + ///< Quality can be in the range 0..100 and controls the quality of the + ///< resulting image, where 100 is "best". The caller takes ownership of + ///< the result and has to delete it once it is no longer needed. + ///< The result may be NULL in case of an error. class cTimeMs { private: