/* * 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; }
static GstFlowReturn gst_jpeg_dec_handle_frame (GstVideoDecoder * bdec, GstVideoCodecFrame * frame) { GstFlowReturn ret = GST_FLOW_OK; GstJpegDec *dec = (GstJpegDec *) bdec; GstVideoFrame vframe; gint width, height; gint r_h, r_v; guint code, hdr_ok; gboolean need_unmap = TRUE; GstVideoCodecState *state = NULL; dec->current_frame = frame; gst_buffer_map (frame->input_buffer, &dec->current_frame_map, GST_MAP_READ); gst_jpeg_dec_fill_input_buffer (&dec->cinfo); if (setjmp (dec->jerr.setjmp_buffer)) { code = dec->jerr.pub.msg_code; if (code == JERR_INPUT_EOF) { GST_DEBUG ("jpeg input EOF error, we probably need more data"); goto need_more_data; } goto decode_error; } /* read header */ hdr_ok = jpeg_read_header (&dec->cinfo, TRUE); if (G_UNLIKELY (hdr_ok != JPEG_HEADER_OK)) { GST_WARNING_OBJECT (dec, "reading the header failed, %d", hdr_ok); } GST_LOG_OBJECT (dec, "num_components=%d", dec->cinfo.num_components); GST_LOG_OBJECT (dec, "jpeg_color_space=%d", dec->cinfo.jpeg_color_space); if (!dec->cinfo.num_components || !dec->cinfo.comp_info) goto components_not_supported; r_h = dec->cinfo.comp_info[0].h_samp_factor; r_v = dec->cinfo.comp_info[0].v_samp_factor; GST_LOG_OBJECT (dec, "r_h = %d, r_v = %d", r_h, r_v); if (dec->cinfo.num_components > 3) goto components_not_supported; /* verify color space expectation to avoid going *boom* or bogus output */ if (dec->cinfo.jpeg_color_space != JCS_YCbCr && dec->cinfo.jpeg_color_space != JCS_GRAYSCALE && dec->cinfo.jpeg_color_space != JCS_RGB) goto unsupported_colorspace; #ifndef GST_DISABLE_GST_DEBUG { gint i; for (i = 0; i < dec->cinfo.num_components; ++i) { GST_LOG_OBJECT (dec, "[%d] h_samp_factor=%d, v_samp_factor=%d, cid=%d", i, dec->cinfo.comp_info[i].h_samp_factor, dec->cinfo.comp_info[i].v_samp_factor, dec->cinfo.comp_info[i].component_id); } } #endif /* prepare for raw output */ dec->cinfo.do_fancy_upsampling = FALSE; dec->cinfo.do_block_smoothing = FALSE; dec->cinfo.out_color_space = dec->cinfo.jpeg_color_space; dec->cinfo.dct_method = dec->idct_method; dec->cinfo.raw_data_out = TRUE; GST_LOG_OBJECT (dec, "starting decompress"); guarantee_huff_tables (&dec->cinfo); if (!jpeg_start_decompress (&dec->cinfo)) { GST_WARNING_OBJECT (dec, "failed to start decompression cycle"); } /* sanity checks to get safe and reasonable output */ switch (dec->cinfo.jpeg_color_space) { case JCS_GRAYSCALE: if (dec->cinfo.num_components != 1) goto invalid_yuvrgbgrayscale; break; case JCS_RGB: if (dec->cinfo.num_components != 3 || dec->cinfo.max_v_samp_factor > 1 || dec->cinfo.max_h_samp_factor > 1) goto invalid_yuvrgbgrayscale; break; case JCS_YCbCr: if (dec->cinfo.num_components != 3 || r_v > 2 || r_v < dec->cinfo.comp_info[0].v_samp_factor || r_v < dec->cinfo.comp_info[1].v_samp_factor || r_h < dec->cinfo.comp_info[0].h_samp_factor || r_h < dec->cinfo.comp_info[1].h_samp_factor) goto invalid_yuvrgbgrayscale; break; default: g_assert_not_reached (); break; } width = dec->cinfo.output_width; height = dec->cinfo.output_height; if (G_UNLIKELY (width < MIN_WIDTH || width > MAX_WIDTH || height < MIN_HEIGHT || height > MAX_HEIGHT)) goto wrong_size; gst_jpeg_dec_negotiate (dec, width, height, dec->cinfo.jpeg_color_space); state = gst_video_decoder_get_output_state (bdec); ret = gst_video_decoder_alloc_output_frame (bdec, frame); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto alloc_failed; if (!gst_video_frame_map (&vframe, &state->info, frame->output_buffer, GST_MAP_READWRITE)) goto alloc_failed; GST_LOG_OBJECT (dec, "width %d, height %d", width, height); if (dec->cinfo.jpeg_color_space == JCS_RGB) { gst_jpeg_dec_decode_rgb (dec, &vframe); } else if (dec->cinfo.jpeg_color_space == JCS_GRAYSCALE) { gst_jpeg_dec_decode_grayscale (dec, &vframe); } else { GST_LOG_OBJECT (dec, "decompressing (reqired scanline buffer height = %u)", dec->cinfo.rec_outbuf_height); /* For some widths jpeglib requires more horizontal padding than I420 * provides. In those cases we need to decode into separate buffers and then * copy over the data into our final picture buffer, otherwise jpeglib might * write over the end of a line into the beginning of the next line, * resulting in blocky artifacts on the left side of the picture. */ if (G_UNLIKELY (width % (dec->cinfo.max_h_samp_factor * DCTSIZE) != 0 || dec->cinfo.comp_info[0].h_samp_factor != 2 || dec->cinfo.comp_info[1].h_samp_factor != 1 || dec->cinfo.comp_info[2].h_samp_factor != 1)) { GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, dec, "indirect decoding using extra buffer copy"); gst_jpeg_dec_decode_indirect (dec, &vframe, r_v, r_h, dec->cinfo.num_components); } else { ret = gst_jpeg_dec_decode_direct (dec, &vframe); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto decode_direct_failed; } } gst_video_frame_unmap (&vframe); GST_LOG_OBJECT (dec, "decompressing finished"); jpeg_finish_decompress (&dec->cinfo); /* reset error count on successful decode */ dec->error_count = 0; gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map); ret = gst_video_decoder_finish_frame (bdec, frame); need_unmap = FALSE; done: exit: if (G_UNLIKELY (ret == GST_FLOW_ERROR)) { jpeg_abort_decompress (&dec->cinfo); ret = gst_jpeg_dec_post_error_or_warning (dec); } if (need_unmap) gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map); if (state) gst_video_codec_state_unref (state); return ret; /* special cases */ need_more_data: { GST_LOG_OBJECT (dec, "we need more data"); ret = GST_FLOW_OK; goto exit; } /* ERRORS */ wrong_size: { gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__, "Picture is too small or too big (%ux%u)", width, height); ret = GST_FLOW_ERROR; goto done; } decode_error: { gchar err_msg[JMSG_LENGTH_MAX]; dec->jerr.pub.format_message ((j_common_ptr) (&dec->cinfo), err_msg); gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__, "Decode error #%u: %s", code, err_msg); gst_buffer_unmap (frame->input_buffer, &dec->current_frame_map); gst_video_decoder_drop_frame (bdec, frame); need_unmap = FALSE; ret = GST_FLOW_ERROR; goto done; } decode_direct_failed: { /* already posted an error message */ jpeg_abort_decompress (&dec->cinfo); goto done; } alloc_failed: { const gchar *reason; reason = gst_flow_get_name (ret); GST_DEBUG_OBJECT (dec, "failed to alloc buffer, reason %s", reason); /* Reset for next time */ jpeg_abort_decompress (&dec->cinfo); if (ret != GST_FLOW_EOS && ret != GST_FLOW_FLUSHING && ret != GST_FLOW_NOT_LINKED) { gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__, "Buffer allocation failed, reason: %s", reason); } goto exit; } components_not_supported: { gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__, "number of components not supported: %d (max 3)", dec->cinfo.num_components); ret = GST_FLOW_ERROR; goto done; } unsupported_colorspace: { gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__, "Picture has unknown or unsupported colourspace"); ret = GST_FLOW_ERROR; goto done; } invalid_yuvrgbgrayscale: { gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__, "Picture is corrupt or unhandled YUV/RGB/grayscale layout"); ret = GST_FLOW_ERROR; goto done; } }
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 */ ;
/** * jpgutl_decode_jpeg * Purpose: Decompress the jpeg data_in into the img_out buffer. * * Parameters: * jpeg_data_in The jpeg data sent in * jpeg_data_len The length of the jpeg data * width The width of the image * height The height of the image * img_out Pointer to the image output * * Return Values * Success 0, Failure -1 */ int jpgutl_decode_jpeg (unsigned char *jpeg_data_in, int jpeg_data_len, unsigned int width, unsigned int height, unsigned char *volatile img_out) { JSAMPARRAY line; /* Array of decomp data lines */ unsigned char *wline; /* Will point to line[0] */ unsigned int i; unsigned char *img_y, *img_cb, *img_cr; unsigned char offset_y; struct jpeg_decompress_struct dinfo; struct jpgutl_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 = jpgutl_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 = jpgutl_emit_message; jerr.warning_seen = 0; jpeg_create_decompress (&dinfo); /* Establish the setjmp return context for jpgutl_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; } jpgutl_buffer_src (&dinfo, jpeg_data_in, jpeg_data_len); jpeg_read_header (&dinfo, TRUE); //420 sampling is the default for YCbCr so no need to override. dinfo.out_color_space = JCS_YCbCr; dinfo.dct_method = JDCT_DEFAULT; guarantee_huff_tables(&dinfo); /* Required by older versions of the jpeg libs */ jpeg_start_decompress (&dinfo); if ((dinfo.output_width == 0) || (dinfo.output_height == 0)) { MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO,_("Invalid JPEG image dimensions")); jpeg_destroy_decompress(&dinfo); return -1; } if ((dinfo.output_width != width) || (dinfo.output_height != height)) { MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO ,_("JPEG image size %dx%d, JPEG was %dx%d") ,width, height, dinfo.output_width, dinfo.output_height); jpeg_destroy_decompress(&dinfo); return -1; } img_y = img_out; img_cb = img_y + dinfo.output_width * dinfo.output_height; img_cr = img_cb + (dinfo.output_width * dinfo.output_height) / 4; /* Allocate space for one line. */ line = (*dinfo.mem->alloc_sarray)((j_common_ptr) &dinfo, JPOOL_IMAGE, dinfo.output_width * dinfo.output_components, 1); wline = line[0]; offset_y = 0; while (dinfo.output_scanline < dinfo.output_height) { jpeg_read_scanlines(&dinfo, line, 1); for (i = 0; i < (dinfo.output_width * 3); i += 3) { img_y[i / 3] = wline[i]; if (i & 1) { img_cb[(i / 3) / 2] = wline[i + 1]; img_cr[(i / 3) / 2] = wline[i + 2]; } } img_y += dinfo.output_width; if (offset_y++ & 1) { img_cb += dinfo.output_width / 2; img_cr += dinfo.output_width / 2; } } jpeg_finish_decompress(&dinfo); jpeg_destroy_decompress(&dinfo); /* * If there are too many warnings, this means that * only a partial image could be returned which would * trigger many false positive motion detections */ if (jerr.warning_seen > 2) return -1; return 0; }