From e5a264465c1c77d5fc18eeb51b99c79fc3f28a3e Mon Sep 17 00:00:00 2001
From: Don Darling <don.osc2@gmail.com>
Date: Tue, 8 Jun 2010 13:48:51 -0500
Subject: [PATCH 8/8] Add support for pad-allocated buffers in TIViddec2.

When padAllocOutbufs=TRUE is specified to the TIViddec2 element, it will
attempt to allocate buffers from downstream instead of allocating its own.

Downstream buffers will only be used if it can be determined that they are
all members of a DMAI BufTab, which means they are CMEM-based, and will work
with the codecs.  Currently, the only known downstream element that can provide
these buffers is TIDmaiVideoSink, and it is only supported for DM365.

There is currently no support for centering small clips in the middle of the
display screen -- this would require additional support in the display driver.
As a result, pad-allocation can currently only be used with clips that are at
least as large as the display, and this feature not enabled by default because
of these strict clip-size requirements.

On DM365, there are known issues with the MPEG-2 decoder's output buffer size
calculation that cause it not to work with D1 resolutions unless you hard-code
the size.  H.264 and MPEG-4 decoders work as expected, and MPEG-2 works as
expected for 720p.
---
 .../ti_build/ticodecplugin/src/gsttividdec2.c      |  159 ++++++++++++++++----
 .../ti_build/ticodecplugin/src/gsttividdec2.h      |    1 +
 2 files changed, 127 insertions(+), 33 deletions(-)

diff --git a/gstreamer_ti/ti_build/ticodecplugin/src/gsttividdec2.c b/gstreamer_ti/ti_build/ticodecplugin/src/gsttividdec2.c
index c39208f..ec3cb05 100644
--- a/gstreamer_ti/ti_build/ticodecplugin/src/gsttividdec2.c
+++ b/gstreamer_ti/ti_build/ticodecplugin/src/gsttividdec2.c
@@ -73,7 +73,8 @@ enum
   PROP_FRAMERATE,       /* framerate      (GstFraction) */
   PROP_DISPLAY_BUFFER,  /* displayBuffer  (boolean) */
   PROP_GEN_TIMESTAMPS,  /* genTimeStamps  (boolean) */
-  PROP_RTCODECTHREAD    /* rtCodecThread (boolean) */
+  PROP_RTCODECTHREAD,   /* rtCodecThread (boolean) */
+  PROP_PAD_ALLOC_OUTBUFS /* padAllocOutbufs (boolean) */
 };
 
 /* Define sink (input) pad capabilities.  Currently, MPEG and H264 are 
@@ -170,8 +171,8 @@ static GstClockTime
  gst_tividdec2_frame_duration(GstTIViddec2 *viddec2);
 static gboolean
  gst_tividdec2_resizeBufTab(GstTIViddec2 *viddec2);
-static gboolean 
-    gst_tividdec2_codec_start (GstTIViddec2  *viddec2);
+static gboolean
+    gst_tividdec2_codec_start (GstTIViddec2  *viddec2, GstBuffer **padBuffer);
 static gboolean 
     gst_tividdec2_codec_stop (GstTIViddec2  *viddec2);
 static void 
@@ -324,6 +325,11 @@ static void gst_tividdec2_class_init(GstTIViddec2Class *klass)
         g_param_spec_boolean("genTimeStamps", "Generate Time Stamps",
             "Set timestamps on output buffers",
             TRUE, G_PARAM_WRITABLE));
+
+    g_object_class_install_property(gobject_class, PROP_PAD_ALLOC_OUTBUFS,
+        g_param_spec_boolean("padAllocOutbufs", "Use pad allocation",
+            "Try to allocate buffers with pad allocation",
+            FALSE, G_PARAM_WRITABLE));
 }
 
 /******************************************************************************
@@ -448,6 +454,7 @@ static void gst_tividdec2_init(GstTIViddec2 *viddec2, GstTIViddec2Class *gclass)
 
     viddec2->numOutputBufs      = 0UL;
     viddec2->hOutBufTab         = NULL;
+    viddec2->padAllocOutbufs    = FALSE;
     viddec2->circBuf            = NULL;
 
     viddec2->sps_pps_data       = NULL;
@@ -548,6 +555,10 @@ static void gst_tividdec2_set_property(GObject *object, guint prop_id,
             viddec2->rtCodecThread = g_value_get_boolean(value);
             GST_LOG("setting \"RTCodecThread\" to \"%s\"\n",
                 viddec2->rtCodecThread ? "TRUE" : "FALSE");
+        case PROP_PAD_ALLOC_OUTBUFS:
+            viddec2->padAllocOutbufs = g_value_get_boolean(value);
+            GST_LOG("setting \"padAllocOutbufs\" to \"%s\"\n",
+                viddec2->padAllocOutbufs ? "TRUE" : "FALSE");
             break;
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -1079,9 +1090,9 @@ static gboolean gst_tividdec2_init_video(GstTIViddec2 *viddec2)
      */
     Rendezvous_meet(viddec2->waitOnDecodeThread);
 
-    if (viddec2->circBuf == NULL || viddec2->hOutBufTab == NULL) {
+    if (viddec2->circBuf == NULL) {
         GST_ELEMENT_ERROR(viddec2, RESOURCE, FAILED,
-        ("decode thread failed to create circbuf or display buffer handles\n"),
+        ("decode thread failed to create circbuf handles\n"),
         (NULL));
         return FALSE;
     }
@@ -1260,11 +1271,13 @@ static gboolean gst_tividdec2_codec_stop (GstTIViddec2  *viddec2)
  * gst_tividdec2_codec_start
  *     Initialize codec engine
  *****************************************************************************/
-static gboolean gst_tividdec2_codec_start (GstTIViddec2  *viddec2)
+static gboolean gst_tividdec2_codec_start (GstTIViddec2  *viddec2,
+           GstBuffer **padBuffer)
 {
-    VIDDEC2_Params         params    = Vdec2_Params_DEFAULT;
-    VIDDEC2_DynamicParams  dynParams = Vdec2_DynamicParams_DEFAULT;
-    BufferGfx_Attrs        gfxAttrs  = BufferGfx_Attrs_DEFAULT;
+    VIDDEC2_Params         params      = Vdec2_Params_DEFAULT;
+    VIDDEC2_DynamicParams  dynParams   = Vdec2_DynamicParams_DEFAULT;
+    BufferGfx_Attrs        gfxAttrs    = BufferGfx_Attrs_DEFAULT;
+    BufTab_Handle          codecBufTab = NULL;
     Cpu_Device             device;
     ColorSpace_Type        colorSpace;
     Int                    defaultNumBufs;
@@ -1364,30 +1377,77 @@ static gboolean gst_tividdec2_codec_start (GstTIViddec2  *viddec2)
         viddec2->numOutputBufs = defaultNumBufs;
     }
 
-    /* Create codec output buffers */
-    GST_LOG("creating output buffer table\n");
-    gfxAttrs.colorSpace     = colorSpace;
-    gfxAttrs.dim.width      = params.maxWidth;
-    gfxAttrs.dim.height     = params.maxHeight;
-    gfxAttrs.dim.lineLength = BufferGfx_calcLineLength(
-                                  gfxAttrs.dim.width, gfxAttrs.colorSpace);
+    /* Try to allocate a buffer from downstream.  To do this, we must first
+     * set the framerate to a reasonable default if one hasn't been specified,
+     * and we need to set the source pad caps with the stream information we
+     * have so far.
+     */
+    gst_tividdec2_frame_duration(viddec2);
+    gst_tividdec2_set_source_caps_base(viddec2, params.maxWidth,
+        params.maxHeight, colorSpace);
+
+    *padBuffer = NULL;
+    if (viddec2->padAllocOutbufs) {
+        if (gst_pad_alloc_buffer(viddec2->srcpad, 0,
+            Vdec2_getOutBufSize(viddec2->hVd), GST_PAD_CAPS(viddec2->srcpad),
+            padBuffer) != GST_FLOW_OK) {
+            GST_LOG("failed to allocate a downstream buffer\n");
+            *padBuffer = NULL;
+        }
+
+        if (*padBuffer && !GST_IS_TIDMAIBUFFERTRANSPORT(*padBuffer)) {
+            GST_LOG("downstream buffer is not a DMAI buffer; disabling use of "
+                "pad-allocated buffers\n");
+            gst_buffer_unref(*padBuffer);
+            *padBuffer = NULL;
+        }
+
+        if (*padBuffer) {
+            codecBufTab = Buffer_getBufTab(
+                GST_TIDMAIBUFFERTRANSPORT_DMAIBUF(*padBuffer));
+
+            if (!codecBufTab) {
+                GST_LOG("downstream buffer is not a BufTab member; disabling "
+                    "use of pad-allocated buffers\n");
+                gst_buffer_unref(*padBuffer);
+                *padBuffer = NULL;
+            }
+        }
+    }
+
+    /* If we can't use pad-allocated buffers, allocate our own BufTab for
+     * output buffers to push downstream.
+     */
+    if (!(*padBuffer)) {
+
+        GST_LOG("creating output buffer table\n");
+        gfxAttrs.colorSpace     = colorSpace;
+        gfxAttrs.dim.width      = params.maxWidth;
+        gfxAttrs.dim.height     = params.maxHeight;
+        gfxAttrs.dim.lineLength = BufferGfx_calcLineLength(
+                                      gfxAttrs.dim.width, gfxAttrs.colorSpace);
 
-    /* By default, new buffers are marked as in-use by the codec */
-    gfxAttrs.bAttrs.useMask = gst_tidmaibuffer_CODEC_FREE;
+        /* By default, new buffers are marked as in-use by the codec */
+        gfxAttrs.bAttrs.useMask = gst_tidmaibuffer_CODEC_FREE;
 
-    viddec2->hOutBufTab = gst_tidmaibuftab_new(
-        viddec2->numOutputBufs, Vdec2_getOutBufSize(viddec2->hVd),
-        BufferGfx_getBufferAttrs(&gfxAttrs));
+        viddec2->hOutBufTab = gst_tidmaibuftab_new(
+            viddec2->numOutputBufs, Vdec2_getOutBufSize(viddec2->hVd),
+            BufferGfx_getBufferAttrs(&gfxAttrs));
+
+        codecBufTab = GST_TIDMAIBUFTAB_BUFTAB(viddec2->hOutBufTab);
+    }
 
-    if (viddec2->hOutBufTab == NULL) {
+    /* The value of codecBufTab should now either point to a downstream
+     * BufTab or our own BufTab.
+     */
+    if (codecBufTab == NULL) {
         GST_ELEMENT_ERROR(viddec2, RESOURCE, NO_SPACE_LEFT,
-        ("failed to create output buffers\n"), (NULL));
+            ("no BufTab available for codec output\n"), (NULL));
         return FALSE;
     }
 
-    /* Tell the Vdec module that hOutBufTab will be used for display buffers */
-    Vdec2_setBufTab(viddec2->hVd,
-        GST_TIDMAIBUFTAB_BUFTAB(viddec2->hOutBufTab));
+    /* Tell the Vdec module what BufTab it will be using for its output */
+    Vdec2_setBufTab(viddec2->hVd, codecBufTab);
 
     return TRUE;
 }
@@ -1403,8 +1463,10 @@ static void* gst_tividdec2_decode_thread(void *arg)
 {
     GstTIViddec2  *viddec2        = GST_TIVIDDEC2(gst_object_ref(arg));
     GstBuffer     *encDataWindow  = NULL;
+    GstBuffer     *padBuffer      = NULL;
     Buffer_Attrs   bAttrs         = Buffer_Attrs_DEFAULT;
     gboolean       codecFlushed   = FALSE;
+    gboolean       usePadBufs     = FALSE;
     void          *threadRet      = GstTIThreadSuccess;
     Buffer_Handle  hDummyInputBuf = NULL;
     Buffer_Handle  hDstBuf;
@@ -1420,7 +1482,8 @@ static void* gst_tividdec2_decode_thread(void *arg)
     GST_LOG("init video decode_thread \n");
 
     /* Initialize codec engine */
-    ret = gst_tividdec2_codec_start(viddec2);
+    ret = gst_tividdec2_codec_start(viddec2, &padBuffer);
+    usePadBufs = (padBuffer != NULL);
 
     /* Notify main thread that is ok to continue initialization */
     Rendezvous_meet(viddec2->waitOnDecodeThread);
@@ -1476,7 +1539,34 @@ static void* gst_tividdec2_decode_thread(void *arg)
         }
 
         /* Obtain a free output buffer for the decoded data */
-        if (!(hDstBuf = gst_tidmaibuftab_get_buf(viddec2->hOutBufTab))) {
+        if (usePadBufs) {
+
+            /* First time through this loop, padBuffer will already be set
+             * to the buffer we got in codec_start.  It will be NULL for every
+             * frame after that.
+             */
+            if (G_LIKELY(!padBuffer)) {
+                if (gst_pad_alloc_buffer(viddec2->srcpad, 0, 0,
+                        GST_PAD_CAPS(viddec2->srcpad), &padBuffer)
+                        != GST_FLOW_OK) {
+                    GST_ELEMENT_ERROR(viddec2, RESOURCE, READ,
+                        ("failed to allocate a downstream buffer\n"), (NULL));
+                    padBuffer = NULL;
+                    goto thread_exit;
+                }
+            }
+            hDstBuf = GST_TIDMAIBUFFERTRANSPORT_DMAIBUF(padBuffer);
+            gst_buffer_unref(padBuffer);
+            padBuffer = NULL;
+
+            /* Set the CODEC_FREE flag -- this isn't done automatically when
+             * allocating buffers from downstream.
+             */
+            Buffer_setUseMask(hDstBuf, Buffer_getUseMask(hDstBuf) |
+                gst_tidmaibuffer_CODEC_FREE);
+
+        }
+        else if (!(hDstBuf = gst_tidmaibuftab_get_buf(viddec2->hOutBufTab))) {
             GST_ELEMENT_ERROR(viddec2, RESOURCE, READ,
                 ("failed to get a free contiguous buffer from BufTab\n"), 
                 (NULL));
@@ -1623,12 +1713,15 @@ thread_failure:
 thread_exit:
 
     /* Re-claim any buffers owned by the codec */
-    bufIdx = BufTab_getNumBufs(GST_TIDMAIBUFTAB_BUFTAB(viddec2->hOutBufTab));
+    if (viddec2->hOutBufTab) {
+        bufIdx =
+            BufTab_getNumBufs(GST_TIDMAIBUFTAB_BUFTAB(viddec2->hOutBufTab));
 
-    while (bufIdx-- > 0) {
-        Buffer_Handle hBuf = BufTab_getBuf(
-            GST_TIDMAIBUFTAB_BUFTAB(viddec2->hOutBufTab), bufIdx);
-        Buffer_freeUseMask(hBuf, gst_tidmaibuffer_CODEC_FREE);
+        while (bufIdx-- > 0) {
+            Buffer_Handle hBuf = BufTab_getBuf(
+                GST_TIDMAIBUFTAB_BUFTAB(viddec2->hOutBufTab), bufIdx);
+            Buffer_freeUseMask(hBuf, gst_tidmaibuffer_CODEC_FREE);
+        }
     }
 
     /* Release the last buffer we retrieved from the circular buffer */
diff --git a/gstreamer_ti/ti_build/ticodecplugin/src/gsttividdec2.h b/gstreamer_ti/ti_build/ticodecplugin/src/gsttividdec2.h
index b16e9c5..6b09d2a 100644
--- a/gstreamer_ti/ti_build/ticodecplugin/src/gsttividdec2.h
+++ b/gstreamer_ti/ti_build/ticodecplugin/src/gsttividdec2.h
@@ -91,6 +91,7 @@ struct _GstTIViddec2
   UInt32           numOutputBufs;
   GstTIDmaiBufTab *hOutBufTab;
   GstTICircBuffer *circBuf;
+  gboolean         padAllocOutbufs;
 
   /* Quicktime h264 header  */
   GstBuffer       *sps_pps_data;
-- 
1.7.0.4

