From: Wind Yuan Date: Mon, 4 Jun 2012 07:52:19 +0000 (+0800) Subject: jpeg: make gst_jpeg_parse() support multiple scans. X-Git-Tag: 0.4.0~156 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4c5cc7eff9137e9f0a4421f53e1bf4f02f42aebc;p=platform%2Fupstream%2Fgstreamer-vaapi.git jpeg: make gst_jpeg_parse() support multiple scans. gst_jpeg_parse() now gathers all scans available in the supplied buffer. A scan comprises of the scan header and any entropy-coded segments or restart marker following it. The size and offset to the associated data (ECS + RST segments) are append to a new GstJpegScanOffsetSize structure. Signed-off-by: Gwenole Beauchesne --- diff --git a/gst-libs/gst/codecparsers/gstjpegparser.c b/gst-libs/gst/codecparsers/gstjpegparser.c index a56c3df..ff7989c 100644 --- a/gst-libs/gst/codecparsers/gstjpegparser.c +++ b/gst-libs/gst/codecparsers/gstjpegparser.c @@ -438,6 +438,41 @@ gst_jpeg_get_default_quantization_table (GstJpegQuantTable *quant_tables, guint sizeof(GstJpegQuantTable)); } +static gint32 +jpeg_scan_to_end (const guint8 *start, guint32 size) +{ + const guint8 *pos = start, *end = start + size; + + for (; pos < end; ++pos) { + if (*pos != 0xFF) + continue; + while (*pos == 0xFF && pos + 1 < end) + ++pos; + if (*pos == 0x00 || *pos == 0xFF || + (*pos >= GST_JPEG_MARKER_RST_MIN && *pos <= GST_JPEG_MARKER_RST_MAX)) + continue; + break; + } + if (pos >= end) + return size; + return pos - start - 1; +} + +static GstJpegTypeOffsetSize * +gst_jpeg_segment_new (guint8 marker, guint offset, gint size) +{ + GstJpegTypeOffsetSize *seg; + + if (GST_JPEG_MARKER_SOS == marker) + seg = g_malloc0 (sizeof (GstJpegScanOffsetSize)); + else + seg = g_malloc0 (sizeof (GstJpegTypeOffsetSize)); + seg->type = marker; + seg->offset = offset; + seg->size = size; + return seg; +} + GList * gst_jpeg_parse(const guint8 * data, gsize size, guint offset) { @@ -446,6 +481,8 @@ gst_jpeg_parse(const guint8 * data, gsize size, guint offset) guint16 header_length; GList *segments = NULL; GstJpegTypeOffsetSize *seg; + const guint8 *scan_start; + gint scan_size = 0; size -= offset; @@ -470,16 +507,24 @@ gst_jpeg_parse(const guint8 * data, gsize size, guint offset) gst_byte_reader_get_remaining (&bytes_reader) < header_length - 2) goto failed; - seg = g_malloc (sizeof (GstJpegTypeOffsetSize)); - seg->type = marker; - seg->offset = gst_byte_reader_get_pos(&bytes_reader) + offset; - seg->size = header_length - 2; + seg = gst_jpeg_segment_new (marker, + gst_byte_reader_get_pos(&bytes_reader) + offset, + header_length - 2); segments = g_list_prepend(segments, seg); gst_byte_reader_skip (&bytes_reader, header_length - 2); - /* parser should stop at first scan */ - if (seg->type == GST_JPEG_MARKER_SOS) - break; + if (seg->type == GST_JPEG_MARKER_SOS) { + GstJpegScanOffsetSize * const scan_seg = (GstJpegScanOffsetSize *)seg; + scan_start = gst_byte_reader_peek_data_unchecked (&bytes_reader); + scan_size = jpeg_scan_to_end (scan_start, + gst_byte_reader_get_remaining (&bytes_reader)); + if (scan_size <= 0) + break; + + scan_seg->data_offset = gst_byte_reader_get_pos (&bytes_reader) + offset; + scan_seg->data_size = scan_size; + gst_byte_reader_skip (&bytes_reader, scan_size); + } } return g_list_reverse (segments); diff --git a/gst-libs/gst/codecparsers/gstjpegparser.h b/gst-libs/gst/codecparsers/gstjpegparser.h index 34a33a2..c18be6c 100644 --- a/gst-libs/gst/codecparsers/gstjpegparser.h +++ b/gst-libs/gst/codecparsers/gstjpegparser.h @@ -59,6 +59,7 @@ typedef struct _GstJpegScanHdr GstJpegScanHdr; typedef struct _GstJpegFrameComponent GstJpegFrameComponent; typedef struct _GstJpegFrameHdr GstJpegFrameHdr; typedef struct _GstJpegTypeOffsetSize GstJpegTypeOffsetSize; +typedef struct _GstJpegScanOffsetSize GstJpegScanOffsetSize; /** * GstJpegParserResult: @@ -242,6 +243,25 @@ struct _GstJpegTypeOffsetSize }; /** + * GstJpegScanOffsetSize: + * @header: The header info associated to the scan + * @data_offset: The offset to the first entropy-coded segment in bytes + * @data_size: The size in bytes of the scan data, including all ECS + * and RST segments, or -1 if the end was not found + * + * A structure that contains information on a scan. A scan comprises of the + * scan @header, and all entropy-coded segment (ECS) and restart marker (RST) + * associated to it. The header type MUST be set to @GST_JPEG_MARKER_SOS. + */ +struct _GstJpegScanOffsetSize +{ + GstJpegTypeOffsetSize header; + guint data_offset; + gint data_size; +}; + + +/** * gst_jpeg_parse: * @data: The data to parse * @size: The size of @data diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c b/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c index cb083b3..c1456ed 100644 --- a/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c +++ b/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c @@ -433,66 +433,19 @@ decode_restart_interval( return GST_VAAPI_DECODER_STATUS_SUCCESS; } -static gint32 -scan_to_end(const guint8 *start, guint32 size) -{ - const guint8 *pos = start, *end = start + size; - - for (; pos < end; ++pos) { - if (*pos != 0xFF) - continue; - while (*pos == 0xFF && pos + 1 < end) - ++pos; - if (*pos == 0x00 || *pos == 0xFF || - (*pos >= GST_JPEG_MARKER_RST_MIN && *pos <= GST_JPEG_MARKER_RST_MAX)) - continue; - break; - } - if (pos >= end) - return size; - return pos - start - 1; -} - -static gboolean -scan_to_next_scan(guint8 *data, guint32 size, - guint8 **scan, guint32 *scan_header_size, guint32 *scan_left_size) -{ - GList *seg_list = NULL; - gboolean ret = FALSE; - - if (!data || !size) - return FALSE; - - seg_list = gst_jpeg_parse(data, size, 0); - for (; seg_list; seg_list = seg_list->next) { - GstJpegTypeOffsetSize * const seg = seg_list->data; - if (seg->type != GST_JPEG_MARKER_SOS) - continue; - *scan = seg->offset + data; - *scan_header_size = seg->size; - *scan_left_size = size - seg->offset - seg->size; - ret = TRUE; - break; - } - g_list_free_full(seg_list, g_free); - return ret; -} - static GstVaapiDecoderStatus decode_scan( GstVaapiDecoderJpeg *decoder, - guchar *scan, + guchar *scan_header, guint scan_header_size, - guint scan_left_size) + guchar *scan_data, + guint scan_data_size) { GstVaapiDecoderJpegPrivate * const priv = decoder->priv; GstVaapiPicture *picture = priv->current_picture; GstJpegParserResult result = GST_JPEG_PARSER_OK; VASliceParameterBufferJPEG *slice_param; GstVaapiSlice *gst_slice; - guint8 *mcu_start, *next_mark; - guint8 *buf_end = scan + scan_header_size + scan_left_size; - guint mcu_size; guint total_h_samples, total_v_samples; GstJpegScanHdr scan_hdr; guint i; @@ -512,53 +465,40 @@ decode_scan( return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; } - mcu_size = scan_left_size; - while (scan_left_size) { - memset(&scan_hdr, 0, sizeof(scan_hdr)); - result = gst_jpeg_parse_scan_hdr(&scan_hdr, scan, scan_header_size, 0); - if (result != GST_JPEG_PARSER_OK) { - GST_DEBUG("Jpeg parsed scan failed."); - return get_status(result); - } - mcu_start = scan + scan_header_size; - mcu_size = scan_to_end(mcu_start, scan_left_size); - - gst_slice = GST_VAAPI_SLICE_NEW(JPEG, decoder, mcu_start, mcu_size); - gst_vaapi_picture_add_slice(picture, gst_slice); - - slice_param = gst_slice->param; - slice_param->num_components = scan_hdr.num_components; - for (i = 0; i < scan_hdr.num_components; i++) { - slice_param->components[i].component_id = scan_hdr.components[i].component_selector; - slice_param->components[i].dc_selector = scan_hdr.components[i].dc_selector; - slice_param->components[i].ac_selector = scan_hdr.components[i].ac_selector; - } - slice_param->restart_interval = priv->mcu_restart; - if (scan_hdr.num_components == 1) { /*non-interleaved*/ - slice_param->slice_horizontal_position = 0; - slice_param->slice_vertical_position = 0; - /* Y mcu numbers*/ - if (slice_param->components[0].component_id == priv->frame_hdr.components[0].identifier) { - slice_param->num_mcus = (priv->frame_hdr.width/8)*(priv->frame_hdr.height/8); - } else { /*Cr, Cb mcu numbers*/ - slice_param->num_mcus = (priv->frame_hdr.width/16)*(priv->frame_hdr.height/16); - } - } else { /* interleaved */ - slice_param->slice_horizontal_position = 0; - slice_param->slice_vertical_position = 0; - total_v_samples = get_max_vertical_samples(&priv->frame_hdr); - total_h_samples = get_max_horizontal_samples(&priv->frame_hdr); - slice_param->num_mcus = ((priv->frame_hdr.width + total_h_samples*8 - 1)/(total_h_samples*8)) * - ((priv->frame_hdr.height + total_v_samples*8 -1)/(total_v_samples*8)); - } + memset(&scan_hdr, 0, sizeof(scan_hdr)); + result = gst_jpeg_parse_scan_hdr(&scan_hdr, scan_header, scan_header_size, 0); + if (result != GST_JPEG_PARSER_OK) { + GST_DEBUG("Jpeg parsed scan failed."); + return get_status(result); + } - next_mark = mcu_start + mcu_size; - scan_left_size = buf_end - next_mark; - if (scan_left_size < 4) /* Mark_code(2-bytes) + header_length(2-bytes)*/ - break; + gst_slice = GST_VAAPI_SLICE_NEW(JPEG, decoder, scan_data, scan_data_size); + gst_vaapi_picture_add_slice(picture, gst_slice); - if (!scan_to_next_scan(next_mark, scan_left_size, &scan, &scan_header_size, &scan_left_size)) - break; + slice_param = gst_slice->param; + slice_param->num_components = scan_hdr.num_components; + for (i = 0; i < scan_hdr.num_components; i++) { + slice_param->components[i].component_id = scan_hdr.components[i].component_selector; + slice_param->components[i].dc_selector = scan_hdr.components[i].dc_selector; + slice_param->components[i].ac_selector = scan_hdr.components[i].ac_selector; + } + slice_param->restart_interval = priv->mcu_restart; + if (scan_hdr.num_components == 1) { /*non-interleaved*/ + slice_param->slice_horizontal_position = 0; + slice_param->slice_vertical_position = 0; + /* Y mcu numbers*/ + if (slice_param->components[0].component_id == priv->frame_hdr.components[0].identifier) { + slice_param->num_mcus = (priv->frame_hdr.width/8)*(priv->frame_hdr.height/8); + } else { /*Cr, Cb mcu numbers*/ + slice_param->num_mcus = (priv->frame_hdr.width/16)*(priv->frame_hdr.height/16); + } + } else { /* interleaved */ + slice_param->slice_horizontal_position = 0; + slice_param->slice_vertical_position = 0; + total_v_samples = get_max_vertical_samples(&priv->frame_hdr); + total_h_samples = get_max_horizontal_samples(&priv->frame_hdr); + slice_param->num_mcus = ((priv->frame_hdr.width + total_h_samples*8 - 1)/(total_h_samples*8)) * + ((priv->frame_hdr.height + total_v_samples*8 -1)/(total_v_samples*8)); } if (picture->slices && picture->slices->len) @@ -608,10 +548,15 @@ decode_buffer(GstVaapiDecoderJpeg *decoder, GstBuffer *buffer) case GST_JPEG_MARKER_DRI: status = decode_restart_interval(decoder, buf + seg->offset, seg->size); break; - case GST_JPEG_MARKER_SOS: - status = decode_scan(decoder, buf + seg->offset, seg->size, buf_size - seg->offset - seg->size); + case GST_JPEG_MARKER_SOS: { + GstJpegScanOffsetSize * const scan = (GstJpegScanOffsetSize *)seg; + status = decode_scan( + decoder, buf + scan->header.offset, scan->header.size, + buf + scan->data_offset, scan->data_size + ); scan_found = TRUE; break; + } default: if (seg->type >= GST_JPEG_MARKER_SOF_MIN && seg->type <= GST_JPEG_MARKER_SOF_MAX)