From 6d7a1f124f38a4358f517437757f6f0c3fe21d8b Mon Sep 17 00:00:00 2001 From: deva Date: Sun, 19 Jun 2005 20:04:43 +0000 Subject: ImgEncoder now uses the file class for output, through jpeg_mem_dest. --- src/img_encoder.cc | 247 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 185 insertions(+), 62 deletions(-) (limited to 'src/img_encoder.cc') diff --git a/src/img_encoder.cc b/src/img_encoder.cc index c5cc58b..2412520 100644 --- a/src/img_encoder.cc +++ b/src/img_encoder.cc @@ -39,6 +39,9 @@ /* * $Log$ + * Revision 1.10 2005/06/19 20:04:43 deva + * ImgEncoder now uses the file class for output, through jpeg_mem_dest. + * * Revision 1.9 2005/05/26 12:48:36 deva * *** empty log message *** * @@ -62,91 +65,211 @@ #include #include -ImgEncoder::ImgEncoder() +ImgEncoder::ImgEncoder(const char* cpr, Info *i) { + info = i; + + // Create path and filename + char fname[256]; + string *server_root; + char birthmonth[3]; + char date[32]; + + // Get server root + server_root = config->readString("server_root"); + + // Copy the bytes representing the birth month from the cpr + // [dd][mm][yy]-[nn][nn] + strncpy(birthmonth, &cpr[2], 2); + birthmonth[2] = 0; + + // Create date (today) in [yyyy][mm][dd] + struct tm *ltime; + time_t t = time(NULL); + ltime = localtime(&t); + sprintf(date, "%.4d%.2d%.2d", + ltime->tm_year + 1900, + ltime->tm_mon, + ltime->tm_mday); + + sprintf(fname, "%s/%s/%s/%s-%s-", server_root->c_str(), birthmonth, cpr, cpr, date); + + file = new File(fname, "jpg", info); } + ImgEncoder::~ImgEncoder() { + delete file; } -void ImgEncoder::encode(Frame *dvframe, - char *filename, - int quality) + +void ImgEncoder::encode(Frame *dvframe, int quality) { - // Append suffix.. - char fname[256]; - sprintf(fname, "%s.jpg", filename); - unsigned char rgb[720*576*4]; getRGB(dvframe, rgb); - writeJPEGFile(fname, quality, (JSAMPLE*)rgb, 720, 576); + writeJPEGFile(quality, (JSAMPLE*)rgb, 720, 576); } -/////////////////////////////////////////////////////////////////////////////////////////// - -void ImgEncoder::writeJPEGFile(char *filename, - int quality, - JSAMPLE * image_buffer, // Points to large array of R,G,B-order data - int image_width, // Number of columns in image - int image_height // Number of rows in image -) + +#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently ?? size */ + +/* Expanded data destination object for stdio output */ +typedef struct { + struct jpeg_destination_mgr pub; /* public fields */ + + JOCTET * outbuff; /* target buffer */ + size_t * size; +} mem_destination_mgr; + +typedef mem_destination_mgr * mem_dest_ptr; + +/* + * Initialize destination --- called by jpeg_start_compress + * before any data is actually written. + */ +void init_destination (j_compress_ptr cinfo) { - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; - - FILE * outfile; // target file - JSAMPROW row_pointer[1]; // pointer to JSAMPLE row[s] - int row_stride; // physical row width in image buffer - - // Step 1: allocate and initialize JPEG compression object - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_compress(&cinfo); - - // Step 2: specify data destination (eg, a file) - if ((outfile = fopen(filename, "wb")) == NULL) { - fprintf(stderr, "can't open %s\n", filename); - exit(1); - } - jpeg_stdio_dest(&cinfo, outfile); + mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; + + *dest->size = 0; + dest->pub.next_output_byte = dest->outbuff; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + +/* + * Terminate destination --- called by jpeg_finish_compress + * after all data has been written. Usually needs to flush buffer. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ +void term_destination (j_compress_ptr cinfo) +{ + mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + + /* Write any data remaining in the buffer */ + if (datacount > 0) { + dest->outbuff+=datacount; + *dest->size+=datacount; + } +} + +/* + * Empty the output buffer --- called whenever buffer fills up. + * + * In typical applications, this should write the entire output buffer + * (ignoring the current state of next_output_byte & free_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been dumped. + * + * In applications that need to be able to suspend compression due to output + * overrun, a FALSE return indicates that the buffer cannot be emptied now. + * In this situation, the compressor will return to its caller (possibly with + * an indication that it has not accepted all the supplied scanlines). The + * application should resume compression after it has made more room in the + * output buffer. Note that there are substantial restrictions on the use of + * suspension --- see the documentation. + * + * When suspending, the compressor will back up to a convenient restart point + * (typically the start of the current MCU). next_output_byte & free_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point will be regenerated after resumption, so do not + * write it out when emptying the buffer externally. + */ +boolean empty_output_buffer (j_compress_ptr cinfo) +{ + mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; + + dest->outbuff+=OUTPUT_BUF_SIZE; + *dest->size+=OUTPUT_BUF_SIZE; + + dest->pub.next_output_byte = dest->outbuff; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + + return TRUE; +} + +/* + * Prepare for output to a memory buffer. + . The caller must have already allocated the buffer, and is responsible + * for closing it after finishing compression. + */ +void jpeg_mem_dest (j_compress_ptr cinfo, char * outbuff, size_t * size) +{ + mem_dest_ptr dest; + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_stdio_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(mem_destination_mgr)); + } + + dest = (mem_dest_ptr) cinfo->dest; + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; + dest->outbuff = (JOCTET *)outbuff; + dest->size = (size_t *)size; +} + +void ImgEncoder::writeJPEGFile(int quality, JSAMPLE * image_buffer, int image_width, int image_height) +{ + size_t buffersize = (image_width * image_height * 3) + JPEG_HEADER_PAD; + char *jpeg_output_buffer = new char [buffersize]; + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; - // Step 3: set parameters for compression - cinfo.image_width = image_width; // image width and height, in pixels - cinfo.image_height = image_height; - cinfo.input_components = 3; // # of color components per pixel + JSAMPROW row_pointer[1]; // pointer to JSAMPLE row[s] + int row_stride; // physical row width in image buffer - //typedef enum { - // JCS_UNKNOWN, // error/unspecified - // JCS_GRAYSCALE, // monochrome - // JCS_RGB, // red/green/blue - // JCS_YCbCr, // Y/Cb/Cr (also known as YUV) - // JCS_CMYK, // C/M/Y/K - // JCS_YCCK // Y/Cb/Cr/K - //} J_COLOR_SPACE; + // Step 1: allocate and initialize JPEG compression object + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); - cinfo.in_color_space = JCS_RGB; // colorspace of input image + // Step 2: specify data destination (eg, a file) + //jpeg_stdio_dest(&cinfo, file->getFP()); + jpeg_mem_dest(&cinfo, jpeg_output_buffer, &buffersize); - jpeg_set_defaults(&cinfo); + // Step 3: set parameters for compression + cinfo.image_width = image_width; // image width and height, in pixels + cinfo.image_height = image_height; + cinfo.input_components = 3; // # of color components per pixel + + cinfo.in_color_space = JCS_RGB; // colorspace of input image - jpeg_set_quality(&cinfo, quality, TRUE); // limit to baseline-JPEG values + jpeg_set_defaults(&cinfo); - // Step 4: Start compressor - jpeg_start_compress(&cinfo, TRUE); + jpeg_set_quality(&cinfo, quality, TRUE); // limit to baseline-JPEG values - // Step 5: while (scan lines remain to be written) - row_stride = image_width * 3; // JSAMPLEs per row in image_buffer + // Step 4: Start compressor + jpeg_start_compress(&cinfo, TRUE); - while (cinfo.next_scanline < cinfo.image_height) { - row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; - (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); - } + // Step 5: while (scan lines remain to be written) + row_stride = image_width * 3; // JSAMPLEs per row in image_buffer - // Step 6: Finish compression - jpeg_finish_compress(&cinfo); - fclose(outfile); + while (cinfo.next_scanline < cinfo.image_height) { + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } - // Step 7: release JPEG compression object - jpeg_destroy_compress(&cinfo); + // Step 6: Finish compression + jpeg_finish_compress(&cinfo); + + // Step 7: release JPEG compression object + jpeg_destroy_compress(&cinfo); + + info->info("JPEG buffersize: %d", buffersize); + file->Write(jpeg_output_buffer, buffersize); + delete jpeg_output_buffer; } void ImgEncoder::getRGB(Frame *frame, unsigned char *rgb) -- cgit v1.2.3