int LoadJPGBuff( void *src_buffer, int src_size, unsigned char **pic, int *width, int *height ) { struct jpeg_decompress_struct cinfo; struct my_jpeg_error_mgr jerr; JSAMPARRAY buffer; int row_stride, size; cinfo.err = jpeg_std_error( &jerr.pub ); jerr.pub.error_exit = my_jpeg_error_exit; if ( setjmp( jerr.setjmp_buffer ) ) { *pic = (unsigned char*)errormsg; jpeg_destroy_decompress( &cinfo ); return -1; } jpeg_create_decompress( &cinfo ); jpeg_buffer_src( &cinfo, src_buffer, src_size ); jpeg_read_header( &cinfo, TRUE ); jpeg_start_decompress( &cinfo ); row_stride = cinfo.output_width * cinfo.output_components; size = cinfo.output_width * cinfo.output_height * 4; *width = cinfo.output_width; *height = cinfo.output_height; *pic = (unsigned char*)( malloc( size + 1 ) ); memset( *pic, 0, size + 1 ); buffer = ( *cinfo.mem->alloc_sarray )( ( j_common_ptr ) & cinfo, JPOOL_IMAGE, row_stride, 1 ); while ( cinfo.output_scanline < cinfo.output_height ) { jpeg_read_scanlines( &cinfo, buffer, 1 ); if ( cinfo.out_color_components == 4 ) { j_putRGBAScanline( buffer[0], cinfo.output_width, *pic, cinfo.output_scanline - 1 ); } else if ( cinfo.out_color_components == 3 ) { j_putRGBScanline( buffer[0], cinfo.output_width, *pic, cinfo.output_scanline - 1 ); } else if ( cinfo.out_color_components == 1 ) { j_putGrayScanlineToRGB( buffer[0], cinfo.output_width, *pic, cinfo.output_scanline - 1 ); } } jpeg_finish_decompress( &cinfo ); jpeg_destroy_decompress( &cinfo ); return 0; }
bool JpegDecoder::readHeader() { volatile bool result = false; close(); JpegState* state = new JpegState; m_state = state; state->cinfo.err = jpeg_std_error(&state->jerr.pub); state->jerr.pub.error_exit = error_exit; if( setjmp( state->jerr.setjmp_buffer ) == 0 ) { jpeg_create_decompress( &state->cinfo ); if( !m_buf.empty() ) { jpeg_buffer_src(&state->cinfo, &state->source); state->source.pub.next_input_byte = m_buf.ptr(); state->source.pub.bytes_in_buffer = m_buf.cols*m_buf.rows*m_buf.elemSize(); } else { m_f = fopen( m_filename.c_str(), "rb" ); if( m_f ) jpeg_stdio_src( &state->cinfo, m_f ); } if (state->cinfo.src != 0) { jpeg_read_header( &state->cinfo, TRUE ); state->cinfo.scale_num=1; state->cinfo.scale_denom = m_scale_denom; m_scale_denom=1; // trick! to know which decoder used scale_denom see imread_ jpeg_calc_output_dimensions(&state->cinfo); m_width = state->cinfo.output_width; m_height = state->cinfo.output_height; m_type = state->cinfo.num_components > 1 ? CV_8UC3 : CV_8UC1; result = true; } } m_orientation = getOrientation(); if( !result ) close(); return result; }
static Image* LoadJPGBuff_( const void *src_buffer, int src_size ){ struct jpeg_decompress_struct cinfo; struct my_jpeg_error_mgr jerr; cinfo.err = jpeg_std_error( &jerr.pub ); jerr.pub.error_exit = my_jpeg_error_exit; if ( setjmp( jerr.setjmp_buffer ) ) { //< TODO: use c++ exceptions instead of setjmp/longjmp to handle errors globalErrorStream() << "WARNING: JPEG library error: " << errormsg << "\n"; jpeg_destroy_decompress( &cinfo ); return 0; } jpeg_create_decompress( &cinfo ); jpeg_buffer_src( &cinfo, const_cast<void*>( src_buffer ), src_size ); jpeg_read_header( &cinfo, TRUE ); jpeg_start_decompress( &cinfo ); int row_stride = cinfo.output_width * cinfo.output_components; RGBAImage* image = new RGBAImage( cinfo.output_width, cinfo.output_height ); JSAMPARRAY buffer = ( *cinfo.mem->alloc_sarray )( ( j_common_ptr ) & cinfo, JPOOL_IMAGE, row_stride, 1 ); while ( cinfo.output_scanline < cinfo.output_height ) { jpeg_read_scanlines( &cinfo, buffer, 1 ); if ( cinfo.out_color_components == 4 ) { j_putRGBAScanline( buffer[0], cinfo.output_width, image->getRGBAPixels(), cinfo.output_scanline - 1 ); } else if ( cinfo.out_color_components == 3 ) { j_putRGBScanline( buffer[0], cinfo.output_width, image->getRGBAPixels(), cinfo.output_scanline - 1 ); } else if ( cinfo.out_color_components == 1 ) { j_putGrayScanlineToRGB( buffer[0], cinfo.output_width, image->getRGBAPixels(), cinfo.output_scanline - 1 ); } } jpeg_finish_decompress( &cinfo ); jpeg_destroy_decompress( &cinfo ); return image; }
bool JpegDecoder::readHeader() { bool result = false; close(); JpegState* state = new JpegState; m_state = state; state->cinfo.err = jpeg_std_error(&state->jerr.pub); state->jerr.pub.error_exit = error_exit; if( setjmp( state->jerr.setjmp_buffer ) == 0 ) { jpeg_create_decompress( &state->cinfo ); if( !m_buf.empty() ) { jpeg_buffer_src(&state->cinfo, &state->source); state->source.pub.next_input_byte = m_buf.data; state->source.pub.bytes_in_buffer = m_buf.cols*m_buf.rows*m_buf.elemSize(); } else { m_f = fopen( m_filename.c_str(), "rb" ); if( m_f ) jpeg_stdio_src( &state->cinfo, m_f ); } if (state->cinfo.src != 0) { jpeg_read_header( &state->cinfo, TRUE ); m_width = state->cinfo.image_width; m_height = state->cinfo.image_height; m_type = state->cinfo.num_components > 1 ? CV_8UC3 : CV_8UC1; result = true; } } if( !result ) close(); return result; }
jpeghdr_t *decode_jpeg_raw_hdr(unsigned char *jpeg_data, int len) { struct jpeg_decompress_struct dinfo; jpeg_create_decompress(&dinfo); jpeg_buffer_src(&dinfo, jpeg_data, len); jpeg_read_header(&dinfo, TRUE); jpeghdr_t *j = (jpeghdr_t*) malloc(sizeof(jpeghdr_t)); j->jpeg_color_space= dinfo.jpeg_color_space; j->width = dinfo.image_width; j->height= dinfo.image_height; j->num_components = dinfo.num_components; j->ccir601 = dinfo.CCIR601_sampling; j->version[0] = dinfo.JFIF_major_version; j->version[1] = dinfo.JFIF_minor_version; jpeg_destroy_decompress(&dinfo); return j; }
/* * jpeg_data: Buffer with jpeg data to decode * len: Length of buffer * itype: 0: Not interlaced * 1: Interlaced, Top field first * 2: Interlaced, Bottom field first * ctype Chroma format for decompression. * Currently only Y4M_CHROMA_{420JPEG,422} are available * returns: * -1 on fatal error * 0 on success * 1 if jpeg lib threw a "corrupt jpeg data" warning. * in this case, "a damaged output image is likely." * */ int decode_jpeg_raw (unsigned char *jpeg_data, int len, int itype, int ctype, unsigned int width, unsigned int height, unsigned char *raw0, unsigned char *raw1, unsigned char *raw2) { int numfields, hsf[3], field, yl, yc; int i, xsl, xsc, xs, hdown; unsigned int x, y = 0, vsf[3], xd; JSAMPROW row0[16] = { buf0[0], buf0[1], buf0[2], buf0[3], buf0[4], buf0[5], buf0[6], buf0[7], buf0[8], buf0[9], buf0[10], buf0[11], buf0[12], buf0[13], buf0[14], buf0[15]}; JSAMPROW row1[8] = { buf1[0], buf1[1], buf1[2], buf1[3], buf1[4], buf1[5], buf1[6], buf1[7]}; JSAMPROW row2[16] = { buf2[0], buf2[1], buf2[2], buf2[3], buf2[4], buf2[5], buf2[6], buf2[7]}; JSAMPROW row1_444[16], row2_444[16]; JSAMPARRAY scanarray[3] = { row0, row1, row2}; struct jpeg_decompress_struct dinfo; struct my_error_mgr jerr; /* We set up the normal JPEG error routines, then override error_exit. */ dinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; /* Also hook the emit_message routine to note corrupt-data warnings. */ jerr.original_emit_message = jerr.pub.emit_message; jerr.pub.emit_message = my_emit_message; jerr.warning_seen = 0; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp (jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. */ jpeg_destroy_decompress (&dinfo); return -1; } jpeg_create_decompress (&dinfo); jpeg_buffer_src (&dinfo, jpeg_data, len); /* * Read header, make some checks and try to figure out what the * user really wants. */ jpeg_read_header (&dinfo, TRUE); dinfo.raw_data_out = TRUE; #if JPEG_LIB_VERSION >= 70 dinfo.do_fancy_upsampling = FALSE; #endif dinfo.out_color_space = JCS_YCbCr; dinfo.dct_method = JDCT_IFAST; guarantee_huff_tables(&dinfo); jpeg_start_decompress (&dinfo); if (dinfo.output_components != 3) { MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Output components of JPEG image" " = %d, must be 3", dinfo.output_components); goto ERR_EXIT; } for (i = 0; i < 3; i++) { hsf[i] = dinfo.comp_info[i].h_samp_factor; vsf[i] = dinfo.comp_info[i].v_samp_factor; } if ((hsf[0] != 2 && hsf[0] != 1) || hsf[1] != 1 || hsf[2] != 1 || (vsf[0] != 1 && vsf[0] != 2) || vsf[1] != 1 || vsf[2] != 1) { MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Unsupported sampling factors," " hsf=(%d, %d, %d) vsf=(%d, %d, %d) !", hsf[0], hsf[1], hsf[2], vsf[0], vsf[1], vsf[2]); goto ERR_EXIT; } if (hsf[0] == 1) { if (height % 8 != 0) { MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: YUV 4:4:4 sampling, but image" " height %d not dividable by 8 !", height); goto ERR_EXIT; } for (y = 0; y < 16; y++) { // Allocate a special buffer for the extra sampling depth. row1_444[y] = (unsigned char *)malloc(dinfo.output_width * sizeof(char)); row2_444[y] = (unsigned char *)malloc(dinfo.output_width * sizeof(char)); } scanarray[1] = row1_444; scanarray[2] = row2_444; } /* Height match image height or be exact twice the image height. */ if (dinfo.output_height == height) { numfields = 1; } else if (2 * dinfo.output_height == height) { numfields = 2; } else { MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Read JPEG: requested height = %d, " "height of image = %d", height, dinfo.output_height); goto ERR_EXIT; } /* Width is more flexible */ if (dinfo.output_width > MAX_LUMA_WIDTH) { MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Image width of %d exceeds max", dinfo.output_width); goto ERR_EXIT; } if (width < 2 * dinfo.output_width / 3) { /* Downsample 2:1 */ hdown = 1; if (2 * width < dinfo.output_width) xsl = (dinfo.output_width - 2 * width) / 2; else xsl = 0; } else if (width == 2 * dinfo.output_width / 3) { /* Special case of 3:2 downsampling */ hdown = 2; xsl = 0; } else { /* No downsampling */ hdown = 0; if (width < dinfo.output_width) xsl = (dinfo.output_width - width) / 2; else xsl = 0; } /* Make xsl even, calculate xsc */ xsl = xsl & ~1; xsc = xsl / 2; yl = yc = 0; for (field = 0; field < numfields; field++) { if (field > 0) { jpeg_read_header (&dinfo, TRUE); dinfo.raw_data_out = TRUE; #if JPEG_LIB_VERSION >= 70 dinfo.do_fancy_upsampling = FALSE; #endif dinfo.out_color_space = JCS_YCbCr; dinfo.dct_method = JDCT_IFAST; jpeg_start_decompress (&dinfo); } if (numfields == 2) { switch (itype) { case Y4M_ILACE_TOP_FIRST: yl = yc = field; break; case Y4M_ILACE_BOTTOM_FIRST: yl = yc = (1 - field); break; default: MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Input is interlaced but" " no interlacing set"); goto ERR_EXIT; } } else { yl = yc = 0; } while (dinfo.output_scanline < dinfo.output_height) { /* Read raw data */ jpeg_read_raw_data (&dinfo, scanarray, 8 * vsf[0]); for (y = 0; y < 8 * vsf[0]; yl += numfields, y++) { xd = yl * width; xs = xsl; if (hdown == 0) { for (x = 0; x < width; x++) raw0[xd++] = row0[y][xs++]; } else if (hdown == 1) { for (x = 0; x < width; x++, xs += 2) raw0[xd++] = (row0[y][xs] + row0[y][xs + 1]) >> 1; } else { for (x = 0; x < width / 2; x++, xd += 2, xs += 3) { raw0[xd] = (2 * row0[y][xs] + row0[y][xs + 1]) / 3; raw0[xd + 1] = (2 * row0[y][xs + 2] + row0[y][xs + 1]) / 3; } } } /* Horizontal downsampling of chroma */ for (y = 0; y < 8; y++) { xs = xsc; if (hsf[0] == 1) for (x = 0; x < width / 2; x++, xs++) { row1[y][xs] = (row1_444[y][2*x] + row1_444[y][2*x + 1]) >> 1; row2[y][xs] = (row2_444[y][2*x] + row2_444[y][2*x + 1]) >> 1; } xs = xsc; if (hdown == 0) { for (x = 0; x < width / 2; x++, xs++) { chr1[y][x] = row1[y][xs]; chr2[y][x] = row2[y][xs]; } } else if (hdown == 1) { for (x = 0; x < width / 2; x++, xs += 2) { chr1[y][x] = (row1[y][xs] + row1[y][xs + 1]) >> 1; chr2[y][x] = (row2[y][xs] + row2[y][xs + 1]) >> 1; } } else { for (x = 0; x < width / 2; x += 2, xs += 3) { chr1[y][x] = (2 * row1[y][xs] + row1[y][xs + 1]) / 3; chr1[y][x + 1] = (2 * row1[y][xs + 2] + row1[y][xs + 1]) / 3; chr2[y][x] = (2 * row2[y][xs] + row2[y][xs + 1]) / 3; chr2[y][x + 1] = (2 * row2[y][xs + 2] + row2[y][xs + 1]) / 3; } } } /* Vertical resampling of chroma */ switch (ctype) { case Y4M_CHROMA_422: if (vsf[0] == 1) { /* Just copy */ for (y = 0; y < 8 /*&& yc < height */; y++, yc += numfields) { xd = yc * width / 2; for (x = 0; x < width / 2; x++, xd++) { raw1[xd] = chr1[y][x]; raw2[xd] = chr2[y][x]; } } } else { /* upsample */ for (y = 0; y < 8 /*&& yc < height */; y++) { xd = yc * width / 2; for (x = 0; x < width / 2; x++, xd++) { raw1[xd] = chr1[y][x]; raw2[xd] = chr2[y][x]; } yc += numfields; xd = yc * width / 2; for (x = 0; x < width / 2; x++, xd++) { raw1[xd] = chr1[y][x]; raw2[xd] = chr2[y][x]; } yc += numfields; } } break; default: /* * Should be case Y4M_CHROMA_420JPEG: but use default: for compatibility. Some * pass things like '420' in with the expectation that anything other than * Y4M_CHROMA_422 will default to 420JPEG. */ if (vsf[0] == 1) { /* Really downsample */ for (y = 0; y < 8 /*&& yc < height/2*/; y += 2, yc += numfields) { xd = yc * width / 2; for (x = 0; x < width / 2; x++, xd++) { assert(xd < (width * height / 4)); raw1[xd] = (chr1[y][x] + chr1[y + 1][x]) >> 1; raw2[xd] = (chr2[y][x] + chr2[y + 1][x]) >> 1; } } } else { /* Just copy */ for (y = 0; y < 8 /* && yc < height / 2 */; y++, yc += numfields) { xd = yc * width / 2; for (x = 0; x < width / 2; x++, xd++) { raw1[xd] = chr1[y][x]; raw2[xd] = chr2[y][x]; } } } break; }
int read_JPEG_buffer(struct jpeg_decompress_struct *cinfo, //header unsigned char*jpgbuffer, //src buffer, stores mjpeg long buffersize, //src buffer size unsigned char* destbuffer, //destination buffer, rgb long destbuffersize,//buffer size struct img_info* image_info , //image info int format) { int row_stride; /* physical row width in output buffer */ if (DEBUG)printf("come in\n"); /* Step 2: specify data source (eg, a file) */ if (DEBUG)printf("----------------jpeg_buffer_src--------------\n"); jpeg_buffer_src(cinfo, jpgbuffer,buffersize); if (DEBUG)printf("----------------after jpeg_buffer_src--------------\n"); /* Step 3: read file parameters with jpeg_read_header() */ if (DEBUG)printf("read header...\n"); int headerret= jpeg_read_header(cinfo, TRUE); if (DEBUG)printf("jpeg_read_header %d %d\n",headerret,JPEG_HEADER_OK); if (DEBUG)printf("read header end...\n"); /* We can ignore the return value from jpeg_read_header since * (a) suspension is not possible with the stdio data source, and * (b) we passed TRUE to reject a tables-only JPEG file as an error. * See libjpeg.doc for more info. */ //debug info: output header information /* if(DEBUG)printf("JPEG PARAMETERS:\n"); if(DEBUG)printf("Width Height %d %d\n",cinfo->image_width, cinfo->image_height); if(DEBUG)printf("COLOR SPACE %d %d\n",cinfo->jpeg_color_space,JCS_YCbCr); if(DEBUG)printf("OUT COLOR SPCAE: %d\n",cinfo->out_color_space); if(DEBUG)printf("QUANTIZE COLORS: %d\n",cinfo->quantize_colors); */ if (format==1) cinfo->out_color_space=JCS_YCbCr; if (image_info!=NULL) { image_info->width=cinfo->image_width; image_info->height=cinfo->image_height; if (DEBUG)printf("Width Height %d %d\n",cinfo->image_width, cinfo->image_height); } if (fatal_error) { if (DEBUG)printf("fatal error %d\n",fatal_error); return -1; } //for mjpeg pictures, huffman table must be added. //extracted from libquicktime if (DEBUG)printf("guarantee_huff_tables\n"); guarantee_huff_tables(cinfo); /* Step 4: set parameters for decompression */ /* In this example, we don't need to change any of the defaults set by * jpeg_read_header(), so we do nothing here. */ /* Step 5: Start decompressor */ (void) jpeg_start_decompress(cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ /* We may need to do some setup of our own at this point before reading * the data. After jpeg_start_decompress() we have the correct scaled * output image dimensions available, as well as the output colormap * if we asked for color quantization. * In this example, we need to make an output work buffer of the right size. */ /* JSAMPLEs per row in output buffer */ row_stride = cinfo->output_width * cinfo->output_components; //debug info: output_components must be 3, yuv or rgb // if(DEBUG)printf("row_stride: %d output component:%d \n", // row_stride,cinfo->output_components); /* Make a one-row-high sample array that will go away when done with image */ //buffer = (*cinfo->mem->alloc_sarray) // ((j_common_ptr) cinfo, JPOOL_IMAGE, row_stride, 1); //output rgb buffer long offset=0; //long offset=200; //unsigned char* filebuf=malloc(row_stride*cinfo->output_height+offset); //sif(DEBUG)printf(filebuf,"%d %d %d\ntype rgb, offset 0, width 1, height 2\n",offset,cinfo->output_width,cinfo->output_height); long start=0; /* Step 6: while (scan lines remain to be read) */ /* jpeg_read_scanlines(...); */ /* Here we use the library's state variable cinfo.output_scanline as the * loop counter, so that we don't have to keep track ourselves. */ int read_line=0; while (cinfo->output_scanline < cinfo->output_height) { /* jpeg_read_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could ask for * more than one scanline at a time if that's more convenient. */ read_line=jpeg_read_scanlines(cinfo, buffer,1);// cinfo.image_height); //debug info //if(DEBUG)printf("output_scan line %d height %d read lines: %d\n", // cinfo->output_scanline, // cinfo->output_height,read_line); /* Assume put_scanline_someplace wants a pointer and sample count. */ //put_scanline_someplace(buffer[0], row_stride); memcpy(destbuffer+offset+start,buffer[0],row_stride); start+=row_stride; if (start>destbuffersize) { if (DEBUG)fprintf(stderr,"destination buffer overflow while decompressing jpeg files.\n"); exit(-1); } } //debug //msave("1.tmp",filebuf,start); /* Step 7: Finish decompression */ (void) jpeg_finish_decompress(cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ /* And we're done! */ return 1; }
int decode_jpeg_raw(unsigned char *jpeg_data, int len, int itype, int ctype, int width, int height, unsigned char *raw0, unsigned char *raw1, unsigned char *raw2) { int numfields, hsf[3], vsf[3], field, yl, yc, x, y = 0, i, xsl, xsc, xs, xd, hdown; JSAMPROW row0[16] = { buf0[0], buf0[1], buf0[2], buf0[3], buf0[4], buf0[5], buf0[6], buf0[7], buf0[8], buf0[9], buf0[10], buf0[11], buf0[12], buf0[13], buf0[14], buf0[15] }; JSAMPROW row1[8] = { buf1[0], buf1[1], buf1[2], buf1[3], buf1[4], buf1[5], buf1[6], buf1[7] }; JSAMPROW row2[16] = { buf2[0], buf2[1], buf2[2], buf2[3], buf2[4], buf2[5], buf2[6], buf2[7] }; JSAMPROW row1_444[16], row2_444[16]; JSAMPARRAY scanarray[3] = { row0, row1, row2 }; struct jpeg_decompress_struct dinfo; struct my_error_mgr jerr; /* We set up the normal JPEG error routines, then override error_exit. */ dinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp(jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. */ jpeg_destroy_decompress(&dinfo); return -1; } jpeg_create_decompress(&dinfo); jpeg_buffer_src(&dinfo, jpeg_data, len); /* Read header, make some checks and try to figure out what the user really wants */ jpeg_read_header(&dinfo, TRUE); dinfo.raw_data_out = TRUE; dinfo.out_color_space = JCS_YCbCr; // dinfo.dct_method = (_dct_method == 0 ? JDCT_DEFAULT : JDCT_FLOAT); dinfo.dct_method = JDCT_DEFAULT; guarantee_huff_tables(&dinfo); jpeg_start_decompress(&dinfo); if (dinfo.output_components != 3) { veejay_msg(0,"Output components of JPEG image = %d, must be 3", dinfo.output_components); goto ERR_EXIT; } for (i = 0; i < 3; i++) { hsf[i] = dinfo.comp_info[i].h_samp_factor; vsf[i] = dinfo.comp_info[i].v_samp_factor; } if ((hsf[0] != 2 && hsf[0] != 1) || hsf[1] != 1 || hsf[2] != 1 || (vsf[0] != 1 && vsf[0] != 2) || vsf[1] != 1 || vsf[2] != 1) { veejay_msg (0,"Unsupported sampling factors, hsf=(%d, %d, %d) vsf=(%d, %d, %d) !", hsf[0], hsf[1], hsf[2], vsf[0], vsf[1], vsf[2]); goto ERR_EXIT; } if (hsf[0] == 1) { if (height % 8 != 0) { veejay_msg (0,"YUV 4:4:4 sampling, but image height %d not dividable by 8 !\n", height); goto ERR_EXIT; } mjpeg_info ("YUV 4:4:4 sampling encountered ! Allocating special row buffer\n"); for (y = 0; y < 16; y++) // allocate a special buffer for the extra sampling depth { //mjpeg_info("YUV 4:4:4 %d.\n",y); row1_444[y] = (unsigned char *) malloc(dinfo.output_width * sizeof(char)); row2_444[y] = (unsigned char *) malloc(dinfo.output_width * sizeof(char)); } //mjpeg_info("YUV 4:4:4 sampling encountered ! Allocating done.\n"); scanarray[1] = row1_444; scanarray[2] = row2_444; } /* Height match image height or be exact twice the image height */ if (dinfo.output_height == height) { numfields = 1; } else if (2 * dinfo.output_height == height) { numfields = 2; } else { veejay_msg (0,"Read JPEG: requested height = %d, height of image = %d", height, dinfo.output_height); goto ERR_EXIT; } /* Width is more flexible */ if (dinfo.output_width > MAX_LUMA_WIDTH) { veejay_msg(0,"Image width of %d exceeds max", dinfo.output_width); goto ERR_EXIT; } if (width < 2 * dinfo.output_width / 3) { /* Downclip 2:1 */ hdown = 1; if (2 * width < dinfo.output_width) xsl = (dinfo.output_width - 2 * width) / 2; else xsl = 0; } else if (width == 2 * dinfo.output_width / 3) { /* special case of 3:2 downsampling */ hdown = 2; xsl = 0; } else { /* No downsampling */ hdown = 0; if (width < dinfo.output_width) xsl = (dinfo.output_width - width) / 2; else xsl = 0; } /* Make xsl even, calculate xsc */ xsl = xsl & ~1; xsc = xsl / 2; yl = yc = 0; for (field = 0; field < numfields; field++) { if (field > 0) { jpeg_read_header(&dinfo, TRUE); dinfo.raw_data_out = TRUE; dinfo.out_color_space = JCS_YCbCr; dinfo.dct_method = JDCT_FLOAT; //JDCT_DEFAULT; jpeg_start_decompress(&dinfo); } if (numfields == 2) { switch (itype) { case LAV_INTER_TOP_FIRST: yl = yc = field; break; case LAV_INTER_BOTTOM_FIRST: yl = yc = (1 - field); break; default: veejay_msg(0,"Input is interlaced but no interlacing set"); goto ERR_EXIT; } } else yl = yc = 0; while (dinfo.output_scanline < dinfo.output_height) { /* read raw data */ jpeg_read_raw_data(&dinfo, scanarray, 8 * vsf[0]); for (y = 0; y < 8 * vsf[0]; yl += numfields, y++) { xd = yl * width; xs = xsl; if (hdown == 0) for (x = 0; x < width; x++) raw0[xd++] = row0[y][xs++]; else if (hdown == 1) for (x = 0; x < width; x++, xs += 2) raw0[xd++] = (row0[y][xs] + row0[y][xs + 1]) >> 1; else for (x = 0; x < width / 2; x++, xd += 2, xs += 3) { raw0[xd] = (2 * row0[y][xs] + row0[y][xs + 1]) / 3; raw0[xd + 1] = (2 * row0[y][xs + 2] + row0[y][xs + 1]) / 3; } } /* Horizontal downsampling of chroma */ for (y = 0; y < 8; y++) { xs = xsc; if (hsf[0] == 1) for (x = 0; x < width / 2; x++, xs++) { row1[y][xs] = (row1_444[y][2 * x] + row1_444[y][2 * x + 1]) >> 1; row2[y][xs] = (row2_444[y][2 * x] + row2_444[y][2 * x + 1]) >> 1; } xs = xsc; if (hdown == 0) for (x = 0; x < width / 2; x++, xs++) { chr1[y][x] = row1[y][xs]; chr2[y][x] = row2[y][xs]; } else if (hdown == 1) for (x = 0; x < width / 2; x++, xs += 2) { chr1[y][x] = (row1[y][xs] + row1[y][xs + 1]) >> 1; chr2[y][x] = (row2[y][xs] + row2[y][xs + 1]) >> 1; } else for (x = 0; x < width / 2; x += 2, xs += 3) { chr1[y][x] = (2 * row1[y][xs] + row1[y][xs + 1]) / 3; chr1[y][x + 1] = (2 * row1[y][xs + 2] + row1[y][xs + 1]) / 3; chr2[y][x] = (2 * row2[y][xs] + row2[y][xs + 1]) / 3; chr2[y][x + 1] = (2 * row2[y][xs + 2] + row2[y][xs + 1]) / 3; } } /* Vertical downsampling of chroma */ if (vsf[0] == 1) { for (y = 0; y < 8 /*&& yc < height/2 */ ; y += 2, yc += numfields) { xd = yc * width / 2; for (x = 0; x < width / 2; x++, xd++) { assert(xd < (width * height / 4)); raw1[xd] = (chr1[y][x] + chr1[y + 1][x]) >> 1; raw2[xd] = (chr2[y][x] + chr2[y + 1][x]) >> 1; } } } else { /* Just copy */ for (y = 0; y < 8 /*&& yc < height/2 */ ;
static int jpeg_image_control(ErlDrvData handle, unsigned int command, char* buf, int count, char** res, int res_size) { JSAMPROW row; ErlDrvBinary* bin = 0; switch (command) { case 0: { /* Read */ struct jpeg_decompress_struct cinfo; int row_stride; /* physical row width in output buffer */ unsigned char* rbuf; struct my_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp(jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ char buffer[JMSG_LENGTH_MAX]; /* Create the message */ (cinfo.err->format_message)((j_common_ptr) &cinfo, buffer); jpeg_destroy_decompress(&cinfo); bin = driver_alloc_binary(4+strlen(buffer)); rbuf = bin->orig_bytes; ((unsigned *)rbuf)[0] = 0; rbuf += 4; memcpy(rbuf, buffer, strlen(buffer)); *res = (void *) bin; return 0; } jpeg_create_decompress(&cinfo); jpeg_buffer_src(&cinfo, buf, count); (void) jpeg_read_header(&cinfo, TRUE); (void) jpeg_start_decompress(&cinfo); row_stride = cinfo.output_width * cinfo.output_components; res_size = row_stride * cinfo.output_height; bin = driver_alloc_binary(res_size+12); rbuf = bin->orig_bytes; ((unsigned *)rbuf)[0] = cinfo.output_width; ((unsigned *)rbuf)[1] = cinfo.output_height; ((unsigned *)rbuf)[2] = cinfo.output_components; rbuf += 12; while (cinfo.output_scanline < cinfo.output_height) { row = (JSAMPROW) rbuf; (void) jpeg_read_scanlines(&cinfo, &row, 1); rbuf += row_stride; } (void) jpeg_finish_decompress(&cinfo); *res = (void *) bin; return 0; } case 1: { /* Write */ struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; int row_stride; /* physical row width */ bin = driver_alloc_binary(count); cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_buffer_dest(&cinfo, bin); cinfo.image_width = ((unsigned *)buf)[0]; cinfo.image_height = ((unsigned *)buf)[1]; cinfo.input_components = ((unsigned *)buf)[2]; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); buf += 12; count -= 12; jpeg_start_compress(&cinfo, TRUE); row_stride = cinfo.input_components * cinfo.image_width; while (cinfo.next_scanline < cinfo.image_height) { row = (JSAMPROW) buf; (void) jpeg_write_scanlines(&cinfo, &row, 1); buf += row_stride; } jpeg_finish_compress(&cinfo); bin = jpeg_buffer_dest_get_bin(&cinfo); jpeg_destroy_compress(&cinfo); *res = (void *) bin; return 0; } default: return -1; /* Error return, throws exception in erlang */ } }