y4mdec: Use the correct strides as used by y4m and convert to GStreamer strides if...
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Fri, 22 Mar 2013 14:49:18 +0000 (15:49 +0100)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Fri, 22 Mar 2013 14:53:08 +0000 (15:53 +0100)
https://bugzilla.gnome.org/show_bug.cgi?id=696361

gst/y4m/gsty4mdec.c
gst/y4m/gsty4mdec.h

index 8c68a9f2155298193fd553742fc4442aade8a093..93c5c437aade0c6f86ba1c6ee622cd75dea13d9a 100644 (file)
@@ -196,10 +196,13 @@ gst_y4m_dec_finalize (GObject * object)
 static GstStateChangeReturn
 gst_y4m_dec_change_state (GstElement * element, GstStateChange transition)
 {
+  GstY4mDec *y4mdec;
   GstStateChangeReturn ret;
 
   g_return_val_if_fail (GST_IS_Y4M_DEC (element), GST_STATE_CHANGE_FAILURE);
 
+  y4mdec = GST_Y4M_DEC (element);
+
   switch (transition) {
     case GST_STATE_CHANGE_NULL_TO_READY:
       break;
@@ -217,6 +220,11 @@ gst_y4m_dec_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
       break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
+      if (y4mdec->pool) {
+        gst_buffer_pool_set_active (y4mdec->pool, FALSE);
+        gst_object_unref (y4mdec->pool);
+      }
+      y4mdec->pool = NULL;
       break;
     case GST_STATE_CHANGE_READY_TO_NULL:
       break;
@@ -392,7 +400,49 @@ gst_y4m_dec_parse_header (GstY4mDec * y4mdec, char *header)
   }
 
   gst_video_info_init (&y4mdec->info);
-  gst_video_info_set_format (&y4mdec->info, format, width, height);
+  gst_video_info_set_format (&y4mdec->out_info, format, width, height);
+  y4mdec->info = y4mdec->out_info;
+
+  switch (y4mdec->info.finfo->format) {
+    case GST_VIDEO_FORMAT_I420:
+      y4mdec->info.offset[0] = 0;
+      y4mdec->info.stride[0] = width;
+      y4mdec->info.offset[1] = y4mdec->info.stride[0] * height;
+      y4mdec->info.stride[1] = GST_ROUND_UP_2 (width) / 2;
+      y4mdec->info.offset[2] =
+          y4mdec->info.offset[1] +
+          y4mdec->info.stride[1] * (GST_ROUND_UP_2 (height) / 2);
+      y4mdec->info.stride[2] = GST_ROUND_UP_2 (width) / 2;
+      y4mdec->info.size =
+          y4mdec->info.offset[2] +
+          y4mdec->info.stride[2] * (GST_ROUND_UP_2 (height) / 2);
+      break;
+    case GST_VIDEO_FORMAT_Y42B:
+      y4mdec->info.offset[0] = 0;
+      y4mdec->info.stride[0] = width;
+      y4mdec->info.offset[1] = y4mdec->info.stride[0] * height;
+      y4mdec->info.stride[1] = GST_ROUND_UP_2 (width) / 2;
+      y4mdec->info.offset[2] =
+          y4mdec->info.offset[1] + y4mdec->info.stride[1] * height;
+      y4mdec->info.stride[2] = GST_ROUND_UP_2 (width) / 2;
+      y4mdec->info.size =
+          y4mdec->info.offset[2] + y4mdec->info.stride[2] * height;
+      break;
+    case GST_VIDEO_FORMAT_Y444:
+      y4mdec->info.offset[0] = 0;
+      y4mdec->info.stride[0] = width;
+      y4mdec->info.offset[1] = y4mdec->info.stride[0] * height;
+      y4mdec->info.stride[1] = width;
+      y4mdec->info.offset[2] =
+          y4mdec->info.offset[1] + y4mdec->info.stride[1] * height;
+      y4mdec->info.stride[2] = width;
+      y4mdec->info.size =
+          y4mdec->info.offset[2] + y4mdec->info.stride[2] * height;
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
 
   switch (interlaced_char) {
     case 0:
@@ -457,6 +507,7 @@ gst_y4m_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
   if (!y4mdec->have_header) {
     gboolean ret;
     GstCaps *caps;
+    GstQuery *query;
 
     if (n_avail < MAX_HEADER_LENGTH)
       return GST_FLOW_OK;
@@ -481,6 +532,78 @@ gst_y4m_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
 
     caps = gst_video_info_to_caps (&y4mdec->info);
     ret = gst_pad_set_caps (y4mdec->srcpad, caps);
+
+    query = gst_query_new_allocation (caps, FALSE);
+    y4mdec->video_meta = FALSE;
+
+    if (y4mdec->pool) {
+      gst_buffer_pool_set_active (y4mdec->pool, FALSE);
+      gst_object_unref (y4mdec->pool);
+    }
+    y4mdec->pool = NULL;
+
+    if (gst_pad_peer_query (y4mdec->srcpad, query)) {
+      y4mdec->video_meta =
+          gst_query_find_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE,
+          NULL);
+
+      /* We only need a pool if we need to do stride conversion for downstream */
+      if (!y4mdec->video_meta && memcmp (&y4mdec->info, &y4mdec->out_info,
+              sizeof (y4mdec->info)) != 0) {
+        GstBufferPool *pool = NULL;
+        GstAllocator *allocator = NULL;
+        GstAllocationParams params;
+        GstStructure *config;
+        guint size, min, max;
+
+        if (gst_query_get_n_allocation_params (query) > 0) {
+          gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
+        } else {
+          allocator = NULL;
+          gst_allocation_params_init (&params);
+        }
+
+        if (gst_query_get_n_allocation_pools (query) > 0) {
+          gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min,
+              &max);
+          size = MAX (size, y4mdec->out_info.size);
+        } else {
+          pool = NULL;
+          size = y4mdec->out_info.size;
+          min = max = 0;
+        }
+
+        if (pool == NULL) {
+          pool = gst_video_buffer_pool_new ();
+        }
+
+        config = gst_buffer_pool_get_config (pool);
+        gst_buffer_pool_config_set_params (config, caps, size, min, max);
+        gst_buffer_pool_config_set_allocator (config, allocator, &params);
+        gst_buffer_pool_set_config (pool, config);
+
+        if (allocator)
+          gst_object_unref (allocator);
+
+        y4mdec->pool = pool;
+      }
+    } else if (memcmp (&y4mdec->info, &y4mdec->out_info,
+            sizeof (y4mdec->info)) != 0) {
+      GstBufferPool *pool;
+      GstStructure *config;
+
+      /* No pool, create our own if we need to do stride conversion */
+      pool = gst_video_buffer_pool_new ();
+      config = gst_buffer_pool_get_config (pool);
+      gst_buffer_pool_config_set_params (config, caps, y4mdec->out_info.size, 0,
+          0);
+      gst_buffer_pool_set_config (pool, config);
+      y4mdec->pool = pool;
+    }
+    if (y4mdec->pool) {
+      gst_buffer_pool_set_active (y4mdec->pool, TRUE);
+    }
+    gst_query_unref (query);
     gst_caps_unref (caps);
     if (!ret) {
       GST_DEBUG_OBJECT (y4mdec, "Couldn't set caps on src pad");
@@ -554,6 +677,52 @@ gst_y4m_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
 
     y4mdec->frame_index++;
 
+    if (y4mdec->video_meta) {
+      gst_buffer_add_video_meta_full (buffer, 0, y4mdec->info.finfo->format,
+          y4mdec->info.width, y4mdec->info.height, y4mdec->info.finfo->n_planes,
+          y4mdec->info.offset, y4mdec->info.stride);
+    } else if (memcmp (&y4mdec->info, &y4mdec->out_info,
+            sizeof (y4mdec->info)) != 0) {
+      GstBuffer *outbuf;
+      GstVideoFrame iframe, oframe;
+      gint i, j;
+      gint w, h, istride, ostride;
+      guint8 *src, *dest;
+
+      /* Allocate a new buffer and do stride conversion */
+      g_assert (y4mdec->pool != NULL);
+
+      flow_ret = gst_buffer_pool_acquire_buffer (y4mdec->pool, &outbuf, NULL);
+      if (flow_ret != GST_FLOW_OK) {
+        gst_buffer_unref (buffer);
+        break;
+      }
+
+      gst_video_frame_map (&iframe, &y4mdec->info, buffer, GST_MAP_READ);
+      gst_video_frame_map (&oframe, &y4mdec->out_info, outbuf, GST_MAP_WRITE);
+
+      for (i = 0; i < 3; i++) {
+        w = GST_VIDEO_FRAME_COMP_WIDTH (&iframe, i);;
+        h = GST_VIDEO_FRAME_COMP_HEIGHT (&iframe, i);;
+        istride = GST_VIDEO_FRAME_COMP_STRIDE (&iframe, i);;
+        ostride = GST_VIDEO_FRAME_COMP_STRIDE (&oframe, i);;
+        src = GST_VIDEO_FRAME_COMP_DATA (&iframe, i);
+        dest = GST_VIDEO_FRAME_COMP_DATA (&oframe, i);
+
+        for (j = 0; j < h; j++) {
+          memcpy (dest, src, w);
+
+          dest += ostride;
+          src += istride;
+        }
+      }
+
+      gst_video_frame_unmap (&iframe);
+      gst_video_frame_unmap (&oframe);
+      gst_buffer_unref (buffer);
+      buffer = outbuf;
+    }
+
     flow_ret = gst_pad_push (y4mdec->srcpad, buffer);
     if (flow_ret != GST_FLOW_OK)
       break;
index eab23b54bc5dbb6db37f5df1a025a04563f1be76..c2eb9b0c645b4809e05a6decc2fab62f899100fb 100644 (file)
@@ -51,6 +51,9 @@ struct _GstY4mDec
   GstSegment segment;
 
   GstVideoInfo info;
+  GstVideoInfo out_info;
+  gboolean video_meta;
+  GstBufferPool *pool;
 };
 
 struct _GstY4mDecClass