From 108fa0bb550f9b7355bfd5ae5340220fd1a4c9b5 Mon Sep 17 00:00:00 2001 From: Don Darling Date: Thu, 5 Aug 2010 15:09:54 -0500 Subject: [PATCH 7/8] Add support for pad-allocated buffers in TIDmaiVideoSink. This feature is currently only tested and enabled for DM365. --- .../ticodecplugin/src/gsttidmaibuffertransport.c | 4 +- .../ticodecplugin/src/gsttidmaibuffertransport.h | 6 +- .../ticodecplugin/src/gsttidmaivideosink.c | 197 ++++++++++++++++++-- 3 files changed, 191 insertions(+), 16 deletions(-) diff --git a/gstreamer_ti/ti_build/ticodecplugin/src/gsttidmaibuffertransport.c b/gstreamer_ti/ti_build/ticodecplugin/src/gsttidmaibuffertransport.c index 5fad371..9c69285 100644 --- a/gstreamer_ti/ti_build/ticodecplugin/src/gsttidmaibuffertransport.c +++ b/gstreamer_ti/ti_build/ticodecplugin/src/gsttidmaibuffertransport.c @@ -136,8 +136,8 @@ static void gst_tidmaibuffertransport_finalize(GstBuffer *gstbuffer) */ if (Buffer_getBufTab(self->dmaiBuffer) != NULL) { GST_LOG("clearing GStreamer useMask bit\n"); - Buffer_freeUseMask(self->dmaiBuffer, - gst_tidmaibuffer_GST_FREE); + Buffer_freeUseMask(self->dmaiBuffer, gst_tidmaibuffer_GST_FREE); + Buffer_freeUseMask(self->dmaiBuffer, gst_tidmaibuffer_VIDEOSINK_FREE); } else { GST_LOG("calling Buffer_delete()\n"); Buffer_delete(self->dmaiBuffer); diff --git a/gstreamer_ti/ti_build/ticodecplugin/src/gsttidmaibuffertransport.h b/gstreamer_ti/ti_build/ticodecplugin/src/gsttidmaibuffertransport.h index 0265e70..20945f3 100644 --- a/gstreamer_ti/ti_build/ticodecplugin/src/gsttidmaibuffertransport.h +++ b/gstreamer_ti/ti_build/ticodecplugin/src/gsttidmaibuffertransport.h @@ -52,8 +52,10 @@ G_BEGIN_DECLS GstTIDmaiBufferTransportClass)) /* Use mask flags that keep track of where buffer is in use */ -#define gst_tidmaibuffer_GST_FREE 0x1 -#define gst_tidmaibuffer_CODEC_FREE 0x2 +#define gst_tidmaibuffer_GST_FREE 0x1 +#define gst_tidmaibuffer_CODEC_FREE 0x2 +#define gst_tidmaibuffer_VIDEOSINK_FREE 0x4 +#define gst_tidmaibuffer_DISPLAY_FREE 0x8 typedef struct _GstTIDmaiBufferTransport GstTIDmaiBufferTransport; typedef struct _GstTIDmaiBufferTransportClass GstTIDmaiBufferTransportClass; diff --git a/gstreamer_ti/ti_build/ticodecplugin/src/gsttidmaivideosink.c b/gstreamer_ti/ti_build/ticodecplugin/src/gsttidmaivideosink.c index 0125ed2..7b84a8e 100644 --- a/gstreamer_ti/ti_build/ticodecplugin/src/gsttidmaivideosink.c +++ b/gstreamer_ti/ti_build/ticodecplugin/src/gsttidmaivideosink.c @@ -151,6 +151,9 @@ static GstStateChangeReturn gst_tidmaivideosink_change_state(GstElement * element, GstStateChange transition); static GstFlowReturn + gst_tidmaivideosink_buffer_alloc(GstBaseSink * bsink, guint64 offset, + guint size, GstCaps * caps, GstBuffer ** buf); +static GstFlowReturn gst_tidmaivideosink_preroll(GstBaseSink * bsink, GstBuffer * buffer); static int gst_tidmaivideosink_videostd_get_attrs(VideoStd_Type videoStd, @@ -353,6 +356,13 @@ static void gst_tidmaivideosink_class_init(GstTIDmaiVideoSinkClass * klass) GST_DEBUG_FUNCPTR(gst_tidmaivideosink_preroll); gstbase_sink_class->render = GST_DEBUG_FUNCPTR(gst_tidmaivideosink_render); + gstbase_sink_class->buffer_alloc = + GST_DEBUG_FUNCPTR(gst_tidmaivideosink_buffer_alloc); + + /* Pad-buffer allocation is currently only supported for DM365 */ + #if !defined(Platform_dm365) + gstbase_sink_class->buffer_alloc = NULL; + #endif } @@ -663,6 +673,132 @@ static gboolean gst_tidmaivideosink_event(GstBaseSink * bsink, /****************************************************************************** + * gst_tidmaivideosink_buffer_alloc + ******************************************************************************/ +static GstFlowReturn gst_tidmaivideosink_buffer_alloc(GstBaseSink * bsink, + guint64 offset, guint size, GstCaps * caps, + GstBuffer ** buf) +{ + GstTIDmaiVideoSink *dmaisink = GST_TIDMAIVIDEOSINK(bsink); + BufferGfx_Attrs gfxAttrs = BufferGfx_Attrs_DEFAULT; + gboolean alloc_unref = FALSE; + Buffer_Handle hDispBuf = NULL; + GstCaps *alloc_caps; + + *buf = NULL; + + GST_LOG_OBJECT(dmaisink, + "a buffer of %d bytes was requested with caps %" GST_PTR_FORMAT + " and offset %" G_GUINT64_FORMAT, size, caps, offset); + + /* assume we're going to alloc what was requested, keep track of wheter we + * need to unref or not. When we suggest a new format upstream we will + * create a new caps that we need to unref. */ + alloc_caps = caps; + + /* Process the buffer caps */ + if (!gst_tidmaivideosink_process_caps(bsink, alloc_caps)) { + return GST_FLOW_UNEXPECTED; + } + + /* Pad buffer allocation requires that we use user-allocated display + * buffers. + */ + if (!dmaisink->useUserptrBufs && dmaisink->hDisplay) { + GST_ELEMENT_ERROR(dmaisink, RESOURCE, FAILED, + ("Cannot use pad buffer allocation after mmap buffers already " + "in use\n"), (NULL)); + return GST_FLOW_UNEXPECTED; + } + else { + dmaisink->useUserptrBufs = TRUE; + } + + /* Allocate the display buffers */ + if (!dmaisink->hDispBufTab && dmaisink->useUserptrBufs) { + + /* Set the display attributes now so we can allocate display buffers */ + if (!gst_tidmaivideosink_set_display_attrs(dmaisink, + dmaisink->dGfxAttrs.colorSpace)) { + GST_ERROR("Error while trying to set the display attributes\n"); + return GST_FLOW_UNEXPECTED; + } + + if (!gst_tidmaivideosink_alloc_display_buffers(dmaisink, size)) { + GST_ERROR("Failed to allocate display buffers"); + return GST_FLOW_UNEXPECTED; + } + } + + /* Get a buffer from the BufTab or display driver */ + if (!(hDispBuf = gst_tidmaibuftab_get_buf(dmaisink->hDispBufTab))) { + if (dmaisink->hDisplay && + Display_get(dmaisink->hDisplay, &hDispBuf) < 0) { + GST_ELEMENT_ERROR(dmaisink, RESOURCE, FAILED, + ("Failed to get display buffer\n"), (NULL)); + return GST_FLOW_UNEXPECTED; + } + } + + /* If the geometry doesn't match, generate a new caps for it */ + Buffer_getAttrs(hDispBuf, BufferGfx_getBufferAttrs(&gfxAttrs)); + + if (gfxAttrs.dim.width != dmaisink->dGfxAttrs.dim.width || + gfxAttrs.dim.height != dmaisink->dGfxAttrs.dim.height || + gfxAttrs.colorSpace != dmaisink->dGfxAttrs.colorSpace) { + + GstCaps *desired_caps; + GstStructure *desired_struct; + + /* make a copy of the incomming caps to create the new suggestion. We + * can't use make_writable because we might then destroy the original + * caps which we still need when the peer does not accept the + * suggestion. + */ + desired_caps = gst_caps_copy (caps); + desired_struct = gst_caps_get_structure (desired_caps, 0); + + GST_DEBUG ("we prefer to receive a %ldx%ld video; %ldx%ld was requested", + gfxAttrs.dim.width, gfxAttrs.dim.height, + dmaisink->dGfxAttrs.dim.width, dmaisink->dGfxAttrs.dim.height); + gst_structure_set (desired_struct, "width", G_TYPE_INT, + gfxAttrs.dim.width, NULL); + gst_structure_set (desired_struct, "height", G_TYPE_INT, + gfxAttrs.dim.height, NULL); + + if (gst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (dmaisink), + desired_caps)) { + alloc_caps = desired_caps; + alloc_unref = TRUE; + + if (!gst_tidmaivideosink_process_caps(bsink, alloc_caps)) { + return GST_FLOW_UNEXPECTED; + } + GST_DEBUG ("peer pad accepts our desired caps %" GST_PTR_FORMAT, + desired_caps); + } + else { + GST_DEBUG ("peer pad does not accept our desired caps %" + GST_PTR_FORMAT, desired_caps); + } + } + + /* Return the display buffer */ + BufferGfx_resetDimensions(hDispBuf); + Buffer_freeUseMask(hDispBuf, gst_tidmaibuffer_DISPLAY_FREE); + *buf = gst_tidmaibuffertransport_new(hDispBuf, NULL); + gst_buffer_set_caps(*buf, alloc_caps); + + /* If we allocated new caps, unref them now */ + if (alloc_unref) { + gst_caps_unref (alloc_caps); + } + + return GST_FLOW_OK; +} + + +/****************************************************************************** * gst_tidmaivideosink_preroll ******************************************************************************/ static GstFlowReturn gst_tidmaivideosink_preroll(GstBaseSink * bsink, @@ -1282,6 +1418,18 @@ static gboolean gst_tidmaivideosink_init_display(GstTIDmaiVideoSink * sink) return FALSE; } + /* If we own the display buffers, tell DMAI to delay starting the + * display until we call Display_put for the first time. + */ + if (sink->hDispBufTab) { + #if defined(Platform_dm365) + sink->dAttrs.delayStreamon = TRUE; + #else + GST_ERROR("delayed V4L2 streamon not supported\n"); + return FALSE; + #endif + } + /* Allocate user-allocated display buffers, if requested */ if (!sink->hDispBufTab && sink->useUserptrBufs) { if (!gst_tidmaivideosink_alloc_display_buffers(sink, 0)) { @@ -1416,9 +1564,6 @@ static gboolean gst_tidmaivideosink_process_caps(GstBaseSink * bsink, gst_structure_get_fraction(structure, "framerate", &framerateNum, &framerateDen); - /* Error check new values against existing ones */ - /* TBD */ - /* Populate the display graphics attributes */ dmaisink->dGfxAttrs.bAttrs.reference = dmaisink->contiguousInputFrame; dmaisink->dGfxAttrs.dim.width = width; @@ -1445,9 +1590,10 @@ static gboolean gst_tidmaivideosink_process_caps(GstBaseSink * bsink, static GstFlowReturn gst_tidmaivideosink_render(GstBaseSink * bsink, GstBuffer * buf) { - Buffer_Handle hDispBuf = NULL; - Buffer_Handle inBuf = NULL; - GstTIDmaiVideoSink *sink = GST_TIDMAIVIDEOSINK(bsink); + Buffer_Handle hDispBuf = NULL; + Buffer_Handle inBuf = NULL; + gboolean inBufIsOurs = FALSE; + GstTIDmaiVideoSink *sink = GST_TIDMAIVIDEOSINK(bsink); BufferGfx_Dimensions dim; gchar dur_str[64]; gchar ts_str[64]; @@ -1470,7 +1616,10 @@ static GstFlowReturn gst_tidmaivideosink_render(GstBaseSink * bsink, * generated via videotestsrc plugin. */ if (GST_IS_TIDMAIBUFFERTRANSPORT(buf)) { - inBuf = GST_TIDMAIBUFFERTRANSPORT_DMAIBUF(buf); + inBuf = GST_TIDMAIBUFFERTRANSPORT_DMAIBUF(buf); + inBufIsOurs = (sink->hDispBufTab && + GST_TIDMAIBUFTAB_BUFTAB(sink->hDispBufTab) == + Buffer_getBufTab(inBuf)); } else { /* allocate DMAI buffer */ if (sink->tempDmaiBuf == NULL) { @@ -1532,11 +1681,33 @@ static GstFlowReturn gst_tidmaivideosink_render(GstBaseSink * bsink, */ for (i = 0; i < sink->framerepeat; i++) { - /* Get a buffer from the display driver */ - if (Display_get(sink->hDisplay, &hDispBuf) < 0) { - GST_ELEMENT_ERROR(sink, RESOURCE, FAILED, - ("Failed to get display buffer\n"), (NULL)); - goto cleanup; + /* If the input buffer originated from this element via pad allocation, + * simply give it back to the display and continue. + */ + if (inBufIsOurs) { + + /* Mark buffer as in-use by the display so it can't be re-used + * until it comes back from Display_get */ + Buffer_setUseMask(inBuf, Buffer_getUseMask(inBuf) | + gst_tidmaibuffer_DISPLAY_FREE); + + if (Display_put(sink->hDisplay, inBuf) < 0) { + GST_ELEMENT_ERROR(sink, RESOURCE, FAILED, + ("Failed to put display buffer\n"), (NULL)); + goto cleanup; + } + continue; + } + + /* Otherwise, our input buffer originated from up-stream. Retrieve a + * display buffer to copy the contents into. + */ + else { + if (Display_get(sink->hDisplay, &hDispBuf) < 0) { + GST_ELEMENT_ERROR(sink, RESOURCE, FAILED, + ("Failed to get display buffer\n"), (NULL)); + goto cleanup; + } } /* Retrieve the dimensions of the display buffer */ @@ -1844,8 +2015,10 @@ static gboolean gst_tidmaivideosink_alloc_display_buffers( gfxAttrs.dim.height, gfxAttrs.dim.lineLength, gfxAttrs.colorSpace); } + gfxAttrs.bAttrs.useMask = gst_tidmaibuffer_VIDEOSINK_FREE; sink->hDispBufTab = gst_tidmaibuftab_new(sink->dAttrs.numBufs, bufSize, BufferGfx_getBufferAttrs(&gfxAttrs)); + gst_tidmaibuftab_set_blocking(sink->hDispBufTab, FALSE); return TRUE; } -- 1.7.0.4