ext/theora/theoradec.c: Theora 4:4:4 pixel format support.
authorMichael Smith <msmith@xiph.org>
Fri, 2 Jun 2006 13:43:24 +0000 (13:43 +0000)
committerMichael Smith <msmith@xiph.org>
Fri, 2 Jun 2006 13:43:24 +0000 (13:43 +0000)
Original commit message from CVS:
* ext/theora/theoradec.c: (theora_dec_src_convert),
(theora_handle_type_packet), (theora_handle_422_image),
(theora_handle_444_image), (theora_handle_420_image),
(theora_handle_data_packet):
Theora 4:4:4 pixel format support.

ChangeLog
ext/theora/theoradec.c

index 452dd06e19263c8fa2160dd747c4f7e555106290..f9c02dac5ae1c9e4c3ccbd14a5559c801bc576f5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2006-06-02  Michael Smith  <msmith@fluendo.com>
+
+       * ext/theora/theoradec.c: (theora_dec_src_convert),
+       (theora_handle_type_packet), (theora_handle_422_image),
+       (theora_handle_444_image), (theora_handle_420_image),
+       (theora_handle_data_packet):
+         Theora 4:4:4 pixel format support.
+
 2006-06-02  Thomas Vander Stichele  <thomas at apestaart dot org>
 
        * gst/gdp/gstgdppay.c: (gst_gdp_pay_class_init),
index 6657b7ec3ed640882c4ce541d08b56596c500858..c68ba41a2ef3b172a48d810e68e41bd9d03adb13 100644 (file)
@@ -58,15 +58,12 @@ GST_ELEMENT_DETAILS ("Theora video decoder",
     "Benjamin Otte <in7y118@public.uni-hamburg.de>, "
     "Wim Taymans <wim@fluendo.com>, " "Michael Smith <msmith@fluendo,com>");
 
-/* TODO: Support for other pixel formats (4:4:4) as supported by the
- * theoraexp codebase
- */
 static GstStaticPadTemplate theora_dec_src_factory =
 GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS ("video/x-raw-yuv, "
-        "format = (fourcc) { I420, YUY2 }, "
+        "format = (fourcc) { I420, YUY2, Y444 }, "
         "framerate = (fraction) [0/1, MAX], "
         "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
     );
@@ -714,11 +711,14 @@ theora_handle_type_packet (GstTheoraExpDec * dec, ogg_packet * packet)
      * So, we convert to a widely-supported packed format.
      */
     fourcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
-  } else {
-    /* TODO: Implement 4:4:4, check for reserved/invalid values,
-     * post appropriate error message, ensure callers handle errors here 
-     * properly.
+  } else if (dec->info.pixel_fmt == TH_PF_444) {
+    dec->output_bpp = 24;
+    /* As for I420, we can't define the stride for this, so we need to memcpy,
+     * though at least this is a planar format...
      */
+    fourcc = GST_MAKE_FOURCC ('Y', '4', '4', '4');
+  } else {
+    GST_ERROR_OBJECT (dec, "Invalid pixel format %d", dec->info.pixel_fmt);
     return GST_FLOW_ERROR;
   }
 
@@ -895,7 +895,7 @@ theora_handle_422_image (GstTheoraExpDec * dec, th_ycbcr_buffer yuv,
         *curdest = *src++;
         curdest += 4;
       }
-      src_cr += yuv[1].ystride;
+      src_cr += yuv[2].ystride;
 
       dest += stride;
     }
@@ -920,6 +920,75 @@ no_buffer:
   }
 }
 
+/* Get buffer, populate with original data (we must memcpy to get things to
+ * have the expected strides, etc...), and push.
+ */
+static GstFlowReturn
+theora_handle_444_image (GstTheoraExpDec * dec, th_ycbcr_buffer yuv,
+    GstClockTime outtime)
+{
+  int i, plane;
+  gint width, height;
+  gint out_size;
+  gint stride;
+  GstBuffer *out;
+  GstFlowReturn result;
+
+  width = dec->width;
+  height = dec->height;
+
+  /* TODO: Check if we have any special alignment requirements for the planes,
+   * or for each line within a plane. */
+  stride = width;
+  out_size = stride * height * 3;
+
+  /* now copy over the area contained in offset_x,offset_y,
+   * frame_width, frame_height */
+  result =
+      gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE,
+      out_size, GST_PAD_CAPS (dec->srcpad), &out);
+  if (result != GST_FLOW_OK)
+    goto no_buffer;
+
+  {
+    guchar *dest, *src;
+
+    for (plane = 0; plane < 3; plane++) {
+      /* TODO: do we have to use something different here? */
+      dest = GST_BUFFER_DATA (out) + plane * stride * height;
+
+      src = yuv[plane].data + dec->offset_x +
+          dec->offset_y * yuv[plane].ystride;
+
+      for (i = 0; i < height; i++) {
+        memcpy (dest, src, width);
+
+        dest += stride;
+        src += yuv[plane].ystride;
+      }
+
+    }
+  }
+
+  /* FIXME, frame_nr not correct */
+  GST_BUFFER_OFFSET (out) = dec->frame_nr;
+  dec->frame_nr++;
+  GST_BUFFER_OFFSET_END (out) = dec->frame_nr;
+  GST_BUFFER_DURATION (out) =
+      gst_util_uint64_scale_int (GST_SECOND, dec->info.fps_denominator,
+      dec->info.fps_numerator);
+  GST_BUFFER_TIMESTAMP (out) = outtime;
+
+  return theora_dec_push (dec, out);
+
+no_buffer:
+  {
+    GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s",
+        gst_flow_get_name (result));
+    return result;
+  }
+}
+
 /* Create a (planar, but with special alignment and stride requirements) 'I420'
  * buffer, populate, push.
  */
@@ -988,9 +1057,6 @@ theora_handle_420_image (GstTheoraExpDec * dec, th_ycbcr_buffer yuv,
     src_v = yuv[2].data + offset_v;
 
     for (i = 0; i < cheight; i++) {
-      /* TODO: This, like many other things, is broken for pixel formats other
-       * than OC_PF_420
-       */
       memcpy (dest_u, src_u, cwidth);
       memcpy (dest_v, src_v, cwidth);
 
@@ -1070,9 +1136,10 @@ theora_handle_data_packet (GstTheoraExpDec * dec, ogg_packet * packet,
     result = theora_handle_420_image (dec, yuv, outtime);
   } else if (dec->info.pixel_fmt == TH_PF_422) {
     result = theora_handle_422_image (dec, yuv, outtime);
+  } else if (dec->info.pixel_fmt == TH_PF_444) {
+    result = theora_handle_444_image (dec, yuv, outtime);
   } else {
-    /* Should be unreachable */
-    result = GST_FLOW_ERROR;
+    g_assert_not_reached ();
   }
 
   return result;