jpeg: make gst_jpeg_parse() support multiple scans.
authorWind Yuan <feng.yuan@intel.com>
Mon, 4 Jun 2012 07:52:19 +0000 (15:52 +0800)
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>
Thu, 21 Jun 2012 13:30:53 +0000 (15:30 +0200)
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 <gwenole.beauchesne@intel.com>
gst-libs/gst/codecparsers/gstjpegparser.c
gst-libs/gst/codecparsers/gstjpegparser.h
gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c

index a56c3df..ff7989c 100644 (file)
@@ -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);
 
index 34a33a2..c18be6c 100644 (file)
@@ -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
index cb083b3..c1456ed 100644 (file)
@@ -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)