vdpau: add better error handling to GstVdpOutputSrcPad
authorCarl-Anton Ingmarsson <ca.ingmarsson@gmail.com>
Wed, 17 Mar 2010 19:59:08 +0000 (20:59 +0100)
committerCarl-Anton Ingmarsson <ca.ingmarsson@gmail.com>
Sat, 1 May 2010 12:46:11 +0000 (14:46 +0200)
gst_vdp_output_src_pad_push, gst_vdp_output_src_pad_alloc_buffer and
gst_vdp_output_src_pad_get_device now take a GError parameter to be able to
signal errors to the caller

sys/vdpau/Makefile.am
sys/vdpau/gstvdpoutputbuffer.c
sys/vdpau/gstvdpoutputbuffer.h
sys/vdpau/gstvdpoutputsrcpad.c
sys/vdpau/gstvdpoutputsrcpad.h
sys/vdpau/gstvdpvideopostprocess.c
sys/vdpau/gstvdpvideopostprocess.h

index 4332d6e..98c874a 100644 (file)
@@ -3,8 +3,7 @@ plugin_LTLIBRARIES = libgstvdpau.la
 libgstvdpau_la_SOURCES = \
        gstvdpmpegdec.c \
        mpegutil.c \
-       gstvdp.c \
-       gstvdputils.c \
+       gstvdpau.c \
        gstvdpvideopostprocess.c \
        gstvdpsink.c
 
@@ -26,10 +25,12 @@ lib_LTLIBRARIES = libgstvdp-@GST_MAJORMINOR@.la
  
 libgstvdp_@GST_MAJORMINOR@_la_SOURCES = \
        gstvdpdevice.c \
+       gstvdputils.c \
        gstvdpvideobuffer.c \
        gstvdpoutputbuffer.c \
        gstvdpvideosrcpad.c \
-       gstvdpoutputsrcpad.c
+       gstvdpoutputsrcpad.c \
+       gstvdp.c 
        
 libgstvdp_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/vdpau
 libgstvdp_@GST_MAJORMINOR@include_HEADERS = \
@@ -39,8 +40,12 @@ libgstvdp_@GST_MAJORMINOR@include_HEADERS = \
        gstvdpvideosrcpad.h \
        gstvdpoutputsrcpad.h
  
-libgstvdp_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(X11_CFLAGS) $(VDPAU_CFLAGS)
-libgstvdp_@GST_MAJORMINOR@_la_LIBADD = $(GST_LIBS) $(VDPAU_LIBS) $(X11_LIBS) -lgstvideo-$(GST_MAJORMINOR)
+libgstvdp_@GST_MAJORMINOR@_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \
+  $(GST_PLUGINS_BASE_CFLAGS) $(X11_CFLAGS) $(VDPAU_CFLAGS)
+  
+libgstvdp_@GST_MAJORMINOR@_la_LIBADD = $(GST_LIBS) $(X11_LIBS) $(VDPAU_LIBS) \
+  -lgstvideo-$(GST_MAJORMINOR)
+  
 libgstvdp_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_LT_LDFLAGS) $(GST_ALL_LDFLAGS)
 libgstvdp_@GST_MAJORMINOR@_la_LIBTOOLFLAGS = --tag=disable-static
        
index 443895c..04a3cb5 100644 (file)
@@ -28,7 +28,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_vdp_output_buffer_debug);
 #define GST_CAT_DEFAULT gst_vdp_output_buffer_debug
 
 #define DEBUG_INIT(bla) \
-GST_DEBUG_CATEGORY_INIT (gst_vdp_output_buffer_debug, "vdpauoutputbuffer", 0, "VDPAU output buffer");
+GST_DEBUG_CATEGORY_INIT (gst_vdp_output_buffer_debug, "vdpoutputbuffer", 0, "VDPAU output buffer");
 
 GstVdpOutputBuffer *
 gst_vdp_output_buffer_new (GstVdpDevice * device, VdpRGBAFormat rgba_format,
@@ -47,6 +47,7 @@ gst_vdp_output_buffer_new (GstVdpDevice * device, VdpRGBAFormat rgba_format,
     return NULL;
   }
 
+
   buffer =
       (GstVdpOutputBuffer *) gst_mini_object_new (GST_TYPE_VDP_OUTPUT_BUFFER);
 
@@ -339,6 +340,7 @@ gst_vdp_output_buffer_calculate_size (GstVdpOutputBuffer * output_buf,
     }
 
     default:
+      g_assert_not_reached ();
       return FALSE;
   }
 
@@ -347,7 +349,7 @@ gst_vdp_output_buffer_calculate_size (GstVdpOutputBuffer * output_buf,
 
 gboolean
 gst_vdp_output_buffer_download (GstVdpOutputBuffer * output_buf,
-    GstBuffer * outbuf)
+    GstBuffer * outbuf, GError ** error)
 {
   guint8 *data[1];
   guint32 stride[1];
@@ -387,9 +389,10 @@ gst_vdp_output_buffer_download (GstVdpOutputBuffer * output_buf,
       stride);
   GST_LOG_OBJECT (output_buf,
       "Got status %d from vdp_output_get_bits_native", status);
+
   if (G_UNLIKELY (status != VDP_STATUS_OK)) {
-    GST_ERROR_OBJECT (output_buf,
-        "Couldn't get data from vdpau, Error returned from vdpau was: %s",
+    g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_READ,
+        "Couldn't get data from vdpau, error returned from vdpau was: %s",
         device->vdp_get_error_string (status));
     return FALSE;
   }
index f67ba66..be6a30e 100644 (file)
@@ -50,7 +50,7 @@ GstCaps *gst_vdp_output_buffer_get_allowed_caps (GstVdpDevice *device);
 gboolean gst_vdp_caps_to_rgba_format (GstCaps *caps, VdpRGBAFormat *rgba_format);
 
 gboolean gst_vdp_output_buffer_calculate_size (GstVdpOutputBuffer *output_buf, guint *size);
-gboolean gst_vdp_output_buffer_download (GstVdpOutputBuffer *output_buf, GstBuffer *outbuf);
+gboolean gst_vdp_output_buffer_download (GstVdpOutputBuffer *output_buf, GstBuffer *outbuf, GError **error);
 
 #define GST_VDP_OUTPUT_CAPS \
   "video/x-vdpau-output, " \
index 1f0404f..571610a 100644 (file)
@@ -18,6 +18,7 @@
  * Boston, MA 02111-1307, USA.
  */
 
+#include "gstvdputils.h"
 #include "gstvdpvideobuffer.h"
 
 #include "gstvdpoutputsrcpad.h"
@@ -47,6 +48,7 @@ struct _GstVdpOutputSrcPad
   GstCaps *caps;
   GstVdpDevice *device;
 
+  GstCaps *input_caps;
   GstVdpOutputSrcPadFormat output_format;
   VdpRGBAFormat rgba_format;
   gint width, height;
@@ -69,10 +71,10 @@ G_DEFINE_TYPE_WITH_CODE (GstVdpOutputSrcPad, gst_vdp_output_src_pad,
 
 GstFlowReturn
 gst_vdp_output_src_pad_push (GstVdpOutputSrcPad * vdp_pad,
-    GstVdpOutputBuffer * output_buf)
+    GstVdpOutputBuffer * output_buf, GError ** error)
 {
   GstPad *pad;
-  GstBuffer *out_buf;
+  GstBuffer *outbuf;
 
   g_return_val_if_fail (GST_IS_VDP_OUTPUT_SRC_PAD (vdp_pad), GST_FLOW_ERROR);
   g_return_val_if_fail (GST_IS_VDP_OUTPUT_BUFFER (output_buf), GST_FLOW_ERROR);
@@ -87,31 +89,27 @@ gst_vdp_output_src_pad_push (GstVdpOutputSrcPad * vdp_pad,
     {
       guint size;
 
-      if (!gst_vdp_output_buffer_calculate_size (output_buf, &size)) {
-        GST_ERROR_OBJECT (vdp_pad, "Couldn't calculate buffer size for caps");
-        gst_buffer_unref (GST_BUFFER_CAST (output_buf));
-        return GST_FLOW_ERROR;
-      }
+      gst_vdp_output_buffer_calculate_size (output_buf, &size);
 
-      out_buf = gst_buffer_new_and_alloc (size);
-      gst_buffer_set_caps (out_buf, GST_PAD_CAPS (vdp_pad));
+      /* FIXME: we don't do pad_alloc here since we really want a buffer of
+       * the specified size */
+      outbuf = gst_buffer_new_and_alloc (size);
+      gst_buffer_set_caps (outbuf, GST_PAD_CAPS (vdp_pad));
 
-      if (!gst_vdp_output_buffer_download (output_buf, out_buf)) {
-        GST_ERROR_OBJECT (vdp_pad,
-            "Couldn't convert from GstVdpVideoBuffer to the requested format");
+      if (!gst_vdp_output_buffer_download (output_buf, outbuf, error)) {
         gst_buffer_unref (GST_BUFFER_CAST (output_buf));
-        gst_buffer_unref (out_buf);
+        gst_buffer_unref (outbuf);
+        return GST_FLOW_ERROR;
       }
 
-      gst_buffer_copy_metadata (out_buf, (const GstBuffer *) output_buf,
+      gst_buffer_copy_metadata (outbuf, (const GstBuffer *) output_buf,
           GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
       gst_buffer_unref (GST_BUFFER_CAST (output_buf));
       break;
     }
-
     case GST_VDP_OUTPUT_SRC_PAD_FORMAT_VDPAU:
     {
-      out_buf = GST_BUFFER_CAST (output_buf);
+      outbuf = GST_BUFFER_CAST (output_buf);
       break;
     }
 
@@ -120,9 +118,9 @@ gst_vdp_output_src_pad_push (GstVdpOutputSrcPad * vdp_pad,
       break;
   }
 
-  gst_buffer_set_caps (out_buf, GST_PAD_CAPS (vdp_pad));
+  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (vdp_pad));
 
-  return gst_pad_push (pad, out_buf);
+  return gst_pad_push (pad, outbuf);
 }
 
 static void
@@ -140,11 +138,92 @@ gst_vdp_output_src_pad_update_caps (GstVdpOutputSrcPad * vdp_pad)
     gst_caps_unref (allowed_caps);
   } else
     vdp_pad->caps = allowed_caps;
+
+  GST_DEBUG_OBJECT (vdp_pad, "allowed caps: %" GST_PTR_FORMAT, vdp_pad->caps);
+}
+
+static GstFlowReturn
+gst_vdp_output_src_pad_create_buffer (GstVdpOutputSrcPad * vdp_pad,
+    GstVdpOutputBuffer ** output_buf, GError ** error)
+{
+  GstFlowReturn ret;
+  GstBuffer *neg_buf;
+  GstStructure *structure;
+
+  /* negotiate */
+  ret = gst_pad_alloc_buffer_and_set_caps (GST_PAD_CAST (vdp_pad),
+      GST_BUFFER_OFFSET_NONE, 0, GST_PAD_CAPS (vdp_pad), &neg_buf);
+
+  if (ret == GST_FLOW_OK) {
+    gint new_width, new_height;
+
+    structure = gst_caps_get_structure (GST_BUFFER_CAPS (neg_buf), 0);
+    if (!gst_structure_get_int (structure, "width", &new_width) ||
+        !gst_structure_get_int (structure, "height", &new_height))
+      goto invalid_caps;
+
+    if (new_width != vdp_pad->width || new_height != vdp_pad->height) {
+      GST_DEBUG_OBJECT (vdp_pad, "new dimensions: %dx%d", new_width,
+          new_height);
+
+      vdp_pad->width = new_width;
+      vdp_pad->height = new_height;
+
+      gst_caps_set_simple (vdp_pad->input_caps,
+          "width", G_TYPE_INT, new_width,
+          "height", G_TYPE_INT, new_height, NULL);
+    }
+
+    gst_buffer_unref (neg_buf);
+  }
+
+  *output_buf = gst_vdp_output_buffer_new (vdp_pad->device,
+      vdp_pad->rgba_format, vdp_pad->width, vdp_pad->height);
+  if (!*output_buf)
+    goto output_buf_error;
+
+  gst_buffer_set_caps (GST_BUFFER_CAST (*output_buf), vdp_pad->input_caps);
+
+  return GST_FLOW_OK;
+
+invalid_caps:
+  gst_buffer_unref (neg_buf);
+
+  g_set_error (error, GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED,
+      "Sink element allocated buffer with invalid caps");
+  return GST_FLOW_ERROR;
+
+output_buf_error:
+  gst_buffer_unref (neg_buf);
+  g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_READ,
+      "Couldn't create a GstVdpOutputBuffer");
+  return GST_FLOW_ERROR;
+
+}
+
+static gboolean
+gst_vdp_output_src_pad_open_device (GstVdpOutputSrcPad * vdp_pad,
+    GError ** error)
+{
+  GstVdpDevice *device;
+
+  vdp_pad->device = device = gst_vdp_get_device (vdp_pad->display);
+  if (G_UNLIKELY (!vdp_pad->device))
+    goto device_error;
+
+  gst_vdp_output_src_pad_update_caps (vdp_pad);
+
+  return TRUE;
+
+device_error:
+  g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_OPEN_READ,
+      "Couldn't create GstVdpDevice");
+  return FALSE;
 }
 
 GstFlowReturn
 gst_vdp_output_src_pad_alloc_buffer (GstVdpOutputSrcPad * vdp_pad,
-    GstVdpOutputBuffer ** output_buf)
+    GstVdpOutputBuffer ** output_buf, GError ** error)
 {
   GstCaps *caps;
   GstFlowReturn ret;
@@ -158,47 +237,15 @@ gst_vdp_output_src_pad_alloc_buffer (GstVdpOutputSrcPad * vdp_pad,
   switch (vdp_pad->output_format) {
     case GST_VDP_OUTPUT_SRC_PAD_FORMAT_RGB:
     {
-      GstVdpDevice *device;
-
-      GstBuffer *neg_buf;
-      GstStructure *structure;
-      gint width, height;
-
       if (G_UNLIKELY (!vdp_pad->device)) {
-        vdp_pad->device = gst_vdp_get_device (vdp_pad->display);
-        if (G_UNLIKELY (!vdp_pad->device))
-          goto device_error;
-
-        gst_vdp_output_src_pad_update_caps (vdp_pad);
+        if (!gst_vdp_output_src_pad_open_device (vdp_pad, error))
+          return GST_FLOW_ERROR;
       }
-      device = vdp_pad->device;
 
-      /* negotiate */
-      ret = gst_pad_alloc_buffer (GST_PAD_CAST (vdp_pad),
-          GST_BUFFER_OFFSET_NONE, 0, caps, &neg_buf);
+      ret = gst_vdp_output_src_pad_create_buffer (vdp_pad, output_buf, error);
       if (ret != GST_FLOW_OK)
         return ret;
 
-      structure = gst_caps_get_structure (GST_BUFFER_CAPS (neg_buf), 0);
-      if (!gst_structure_get_int (structure, "width", &width) ||
-          !gst_structure_get_int (structure, "height", &height)) {
-        gst_buffer_unref (neg_buf);
-        GST_ERROR_OBJECT (vdp_pad,
-            "Sink element allocated buffer with invalid caps");
-        return GST_FLOW_ERROR;
-      }
-
-      *output_buf = gst_vdp_output_buffer_new (device, vdp_pad->rgba_format,
-          width, height);
-      if (!*output_buf) {
-        gst_buffer_unref (neg_buf);
-        goto output_buf_error;
-      }
-
-      gst_buffer_set_caps (GST_BUFFER_CAST (*output_buf),
-          GST_BUFFER_CAPS (neg_buf));
-      gst_buffer_unref (neg_buf);
-
       break;
     }
 
@@ -232,40 +279,53 @@ gst_vdp_output_src_pad_alloc_buffer (GstVdpOutputSrcPad * vdp_pad,
 
   return GST_FLOW_OK;
 
-device_error:
-  GST_ERROR_OBJECT (vdp_pad, "Couldn't create GstVdpDevice");
-  return GST_FLOW_ERROR;
-
-output_buf_error:
-  GST_ERROR_OBJECT (vdp_pad, "Couldn't create GstVdpVideoBuffer");
-  return GST_FLOW_ERROR;
-
 wrong_caps:
-  GST_ERROR_OBJECT (vdp_pad, "Sink element returned buffer with wrong caps");
   gst_buffer_unref (GST_BUFFER_CAST (*output_buf));
+
+  g_set_error (error, GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED,
+      "Sink element returned buffer with wrong caps");
   return GST_FLOW_ERROR;
 }
 
 gboolean
-gst_vdp_output_src_pad_set_caps (GstVdpOutputSrcPad * vdp_pad, GstCaps * caps)
+gst_vdp_output_src_pad_negotiate_output (GstVdpOutputSrcPad * vdp_pad,
+    GstCaps * video_caps)
 {
+  GstCaps *allowed_caps, *output_caps, *src_caps;
   const GstStructure *structure;
 
   g_return_val_if_fail (GST_IS_VDP_OUTPUT_SRC_PAD (vdp_pad), FALSE);
+  g_return_val_if_fail (GST_IS_CAPS (video_caps), FALSE);
 
-  if (G_UNLIKELY (!caps))
-    return gst_pad_set_caps (GST_PAD (vdp_pad), caps);
+  allowed_caps = gst_pad_get_caps (GST_PAD_CAST (vdp_pad));
+  GST_DEBUG ("caps: %" GST_PTR_FORMAT, allowed_caps);
+  allowed_caps = gst_pad_peer_get_caps (GST_PAD_CAST (vdp_pad));
+  GST_DEBUG ("peer_caps: %" GST_PTR_FORMAT, allowed_caps);
 
-  if (G_UNLIKELY (!GST_IS_CAPS (caps) || !gst_caps_is_fixed (caps)))
-    return FALSE;
+  allowed_caps = gst_pad_get_allowed_caps (GST_PAD_CAST (vdp_pad));
+  if (G_UNLIKELY (!allowed_caps))
+    goto allowed_caps_error;
+  if (G_UNLIKELY (gst_caps_is_empty (allowed_caps))) {
+    gst_caps_unref (allowed_caps);
+    goto allowed_caps_error;
+  }
+  GST_DEBUG ("allowed_caps: %" GST_PTR_FORMAT, allowed_caps);
+
+  output_caps = gst_vdp_video_to_output_caps (video_caps);
+  src_caps = gst_caps_intersect (output_caps, allowed_caps);
+  gst_caps_unref (output_caps);
+  gst_caps_unref (allowed_caps);
+
+  if (gst_caps_is_empty (src_caps))
+    goto not_negotiated;
+
+  gst_pad_fixate_caps (GST_PAD_CAST (vdp_pad), src_caps);
+
+  GST_DEBUG ("src_caps: %" GST_PTR_FORMAT, src_caps);
 
-  structure = gst_caps_get_structure (caps, 0);
+  structure = gst_caps_get_structure (src_caps, 0);
   if (gst_structure_has_name (structure, "video/x-raw-rgb")) {
-    if (!gst_vdp_caps_to_rgba_format (caps, &vdp_pad->rgba_format))
-      return FALSE;
-    if (!gst_structure_get_int (structure, "width", &vdp_pad->width))
-      return FALSE;
-    if (!gst_structure_get_int (structure, "height", &vdp_pad->height))
+    if (!gst_vdp_caps_to_rgba_format (src_caps, &vdp_pad->rgba_format))
       return FALSE;
 
     vdp_pad->output_format = GST_VDP_OUTPUT_SRC_PAD_FORMAT_RGB;
@@ -273,21 +333,35 @@ gst_vdp_output_src_pad_set_caps (GstVdpOutputSrcPad * vdp_pad, GstCaps * caps)
     if (!gst_structure_get_int (structure, "rgba-format",
             (gint *) & vdp_pad->rgba_format))
       return FALSE;
-    if (!gst_structure_get_int (structure, "width", &vdp_pad->width))
-      return FALSE;
-    if (!gst_structure_get_int (structure, "height", &vdp_pad->height))
-      return FALSE;
 
     vdp_pad->output_format = GST_VDP_OUTPUT_SRC_PAD_FORMAT_VDPAU;
   } else
     return FALSE;
 
-  return gst_pad_set_caps (GST_PAD (vdp_pad), caps);
+  if (!gst_structure_get_int (structure, "width", &vdp_pad->width))
+    return FALSE;
+  if (!gst_structure_get_int (structure, "height", &vdp_pad->height))
+    return FALSE;
+
+  if (gst_pad_set_caps (GST_PAD (vdp_pad), src_caps)) {
+    vdp_pad->input_caps = gst_caps_copy (video_caps);
+    return TRUE;
+  }
+  return FALSE;
+
+allowed_caps_error:
+  GST_ERROR_OBJECT (vdp_pad, "Got invalid allowed caps");
+  return FALSE;
+
+not_negotiated:
+  gst_caps_unref (src_caps);
+  GST_ERROR_OBJECT (vdp_pad, "Couldn't find suitable output format");
+  return FALSE;
 }
 
 GstFlowReturn
 gst_vdp_output_src_pad_get_device (GstVdpOutputSrcPad * vdp_pad,
-    GstVdpDevice ** device)
+    GstVdpDevice ** device, GError ** error)
 {
   g_return_val_if_fail (GST_IS_VDP_OUTPUT_SRC_PAD (vdp_pad), FALSE);
 
@@ -305,9 +379,10 @@ gst_vdp_output_src_pad_get_device (GstVdpOutputSrcPad * vdp_pad,
 
     structure = gst_caps_get_structure (src_caps, 0);
     if (gst_structure_has_name (structure, "video/x-raw-rgb")) {
-      vdp_pad->device = gst_vdp_get_device (vdp_pad->display);
-      if (G_UNLIKELY (!vdp_pad->device))
-        goto device_error;
+      if (!gst_vdp_output_src_pad_open_device (vdp_pad, error)) {
+        gst_caps_unref (src_caps);
+        return GST_FLOW_ERROR;
+      }
     }
 
     else {
@@ -317,7 +392,7 @@ gst_vdp_output_src_pad_get_device (GstVdpOutputSrcPad * vdp_pad,
       ret = gst_pad_alloc_buffer (GST_PAD (vdp_pad), 0, 0, src_caps, &buf);
       if (ret != GST_FLOW_OK) {
         gst_caps_unref (src_caps);
-        return ret;
+        goto alloc_failed;
       }
 
       if (!gst_caps_is_equal_fixed (src_caps, GST_BUFFER_CAPS (buf))) {
@@ -335,12 +410,14 @@ gst_vdp_output_src_pad_get_device (GstVdpOutputSrcPad * vdp_pad,
   *device = vdp_pad->device;
   return GST_FLOW_OK;
 
-device_error:
-  GST_ERROR_OBJECT (vdp_pad, "Couldn't create GstVdpDevice");
+alloc_failed:
+  g_set_error (error, GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED,
+      "Couldn't allocate buffer");
   return GST_FLOW_ERROR;
 
 wrong_caps:
-  GST_ERROR_OBJECT (vdp_pad, "Sink element returned buffer with wrong caps");
+  g_set_error (error, GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED,
+      "Sink element returned buffer with wrong caps");
   return GST_FLOW_ERROR;
 }
 
index e9fc61f..64ce157 100644 (file)
@@ -38,12 +38,12 @@ G_BEGIN_DECLS
 typedef struct _GstVdpOutputSrcPad GstVdpOutputSrcPad;
 typedef struct _GstVdpOutputSrcPadClass GstVdpOutputSrcPadClass;
 
-GstFlowReturn gst_vdp_output_src_pad_push (GstVdpOutputSrcPad *vdp_pad, GstVdpOutputBuffer *output_buf);
-GstFlowReturn gst_vdp_output_src_pad_alloc_buffer (GstVdpOutputSrcPad *vdp_pad, GstVdpOutputBuffer **output_buf);
+GstFlowReturn gst_vdp_output_src_pad_push (GstVdpOutputSrcPad *vdp_pad, GstVdpOutputBuffer *output_buf, GError **error);
+GstFlowReturn gst_vdp_output_src_pad_alloc_buffer (GstVdpOutputSrcPad *vdp_pad, GstVdpOutputBuffer **output_buf, GError **error);
 
-GstFlowReturn gst_vdp_output_src_pad_get_device (GstVdpOutputSrcPad *vdp_pad, GstVdpDevice **device);
+GstFlowReturn gst_vdp_output_src_pad_get_device (GstVdpOutputSrcPad *vdp_pad, GstVdpDevice **device, GError **error);
 
-gboolean gst_vdp_output_src_pad_set_caps (GstVdpOutputSrcPad *vdp_pad, GstCaps *caps);
+gboolean gst_vdp_output_src_pad_negotiate_output (GstVdpOutputSrcPad *vdp_pad, GstCaps *video_caps);
 
 GstVdpOutputSrcPad *gst_vdp_output_src_pad_new (GstCaps * templ_caps);
 GType gst_vdp_output_src_pad_get_type (void) G_GNUC_CONST;
index 9f762ca..ef1ebc5 100644 (file)
@@ -352,16 +352,30 @@ gst_vdp_vpp_add_buffer (GstVdpVideoPostProcess * vpp, GstVdpVideoBuffer * buf)
   }
 }
 
+static void
+gst_vdp_vpp_post_error (GstVdpVideoPostProcess * vpp, GError * error)
+{
+  GstMessage *message;
+
+  message = gst_message_new_error (GST_OBJECT (vpp), error, NULL);
+  gst_element_post_message (GST_ELEMENT (vpp), message);
+}
+
 static GstFlowReturn
 gst_vdp_vpp_open_device (GstVdpVideoPostProcess * vpp)
 {
   GstFlowReturn ret;
+  GError *err = NULL;
 
   GST_DEBUG ("open_device");
 
   ret =
       gst_vdp_output_src_pad_get_device (GST_VDP_OUTPUT_SRC_PAD (vpp->srcpad),
-      &vpp->device);
+      &vpp->device, &err);
+  if (ret == GST_FLOW_ERROR) {
+    gst_vdp_vpp_post_error (vpp, err);
+    g_error_free (err);
+  }
 
   return ret;
 }
@@ -477,11 +491,33 @@ gst_vdp_vpp_sink_setcaps (GstPad * pad, GstCaps * caps)
   GstVdpVideoPostProcess *vpp =
       GST_VDP_VIDEO_POST_PROCESS (gst_pad_get_parent (pad));
   GstStructure *structure;
-  GstCaps *output_caps, *allowed_caps, *src_caps;
+  GstCaps *video_caps = NULL;
   gboolean res = FALSE;
 
-  /* extract interlaced flag */
+  /* check if the input is non native */
   structure = gst_caps_get_structure (caps, 0);
+  if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
+    if (!gst_structure_get_fourcc (structure, "format", &vpp->fourcc))
+      goto done;
+    vpp->native_input = FALSE;
+    video_caps = gst_vdp_video_buffer_parse_yuv_caps (caps);
+    if (!video_caps)
+      goto done;
+  } else {
+    vpp->native_input = TRUE;
+    video_caps = gst_caps_copy (caps);
+  }
+
+
+  structure = gst_caps_get_structure (video_caps, 0);
+  if (!gst_structure_get_int (structure, "width", &vpp->width) ||
+      !gst_structure_get_int (structure, "height", &vpp->height) ||
+      !gst_structure_get_int (structure, "chroma-type",
+          (gint *) & vpp->chroma_type))
+    goto done;
+
+
+  /* get interlaced flag */
   gst_structure_get_boolean (structure, "interlaced", &vpp->interlaced);
 
   /* extract par */
@@ -493,54 +529,9 @@ gst_vdp_vpp_sink_setcaps (GstPad * pad, GstCaps * caps)
   } else
     vpp->got_par = FALSE;
 
-  if (gst_structure_has_name (structure, "video/x-vdpau-video")) {
-
-    if (!gst_structure_get_int (structure, "width", &vpp->width) ||
-        !gst_structure_get_int (structure, "height", &vpp->height) ||
-        !gst_structure_get_int (structure, "chroma-type",
-            (gint *) & vpp->chroma_type))
-      goto done;
-
-    output_caps = gst_vdp_video_to_output_caps (caps);
-    vpp->native_input = TRUE;
-  } else {
-    vpp->native_input = FALSE;
-    if (!gst_vdp_video_buffer_parse_yuv_caps (caps, &vpp->chroma_type,
-            &vpp->width, &vpp->height))
-      goto done;
-    if (!gst_structure_get_fourcc (structure, "format", &vpp->fourcc))
-      goto done;
-
-    output_caps = gst_vdp_yuv_to_output_caps (caps);
-  }
-  GST_DEBUG ("output_caps: %" GST_PTR_FORMAT, output_caps);
-
-  allowed_caps = gst_pad_get_allowed_caps (vpp->srcpad);
-  GST_DEBUG ("allowed_caps: %" GST_PTR_FORMAT, allowed_caps);
-  if (G_UNLIKELY (!allowed_caps))
-    goto allowed_caps_error;
-  if (G_UNLIKELY (gst_caps_is_empty (allowed_caps))) {
-    gst_caps_unref (allowed_caps);
-    goto allowed_caps_error;
-  }
-
-  src_caps = gst_caps_intersect (output_caps, allowed_caps);
-  gst_caps_unref (output_caps);
-  gst_caps_unref (allowed_caps);
-
-  if (gst_caps_is_empty (src_caps)) {
-    gst_caps_unref (src_caps);
-    goto not_negotiated;
-  }
-  gst_pad_fixate_caps (vpp->srcpad, src_caps);
-
-  GST_DEBUG ("src_caps: %" GST_PTR_FORMAT, src_caps);
-
   if (gst_vdp_vpp_is_interlaced (vpp)) {
     gint fps_n, fps_d;
 
-    structure = gst_caps_get_structure (src_caps, 0);
-
     if (gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)) {
       gst_fraction_double (&fps_n, &fps_d);
       gst_structure_set (structure, "framerate", GST_TYPE_FRACTION, fps_n,
@@ -551,21 +542,16 @@ gst_vdp_vpp_sink_setcaps (GstPad * pad, GstCaps * caps)
     gst_structure_remove_field (structure, "interlaced");
   }
 
-  res = gst_vdp_output_src_pad_set_caps (GST_VDP_OUTPUT_SRC_PAD (vpp->srcpad),
-      src_caps);
+  res =
+      gst_vdp_output_src_pad_negotiate_output (GST_VDP_OUTPUT_SRC_PAD
+      (vpp->srcpad), video_caps);
 
 done:
   gst_object_unref (vpp);
-  return res;
+  if (video_caps)
+    gst_caps_unref (video_caps);
 
-allowed_caps_error:
-  gst_caps_unref (output_caps);
-  goto done;
-
-not_negotiated:
-  GST_DEBUG_OBJECT (vpp, "Couldn't find suitable output format");
-  res = FALSE;
-  goto done;
+  return res;
 }
 
 static void
@@ -632,6 +618,7 @@ gst_vdp_vpp_drain (GstVdpVideoPostProcess * vpp)
           &current_pic,
           &video_surfaces_past_count, video_surfaces_past,
           &video_surfaces_future_count, video_surfaces_future)) {
+    GError *err;
     GstVdpOutputBuffer *outbuf;
 
     GstStructure *structure;
@@ -643,14 +630,12 @@ gst_vdp_vpp_drain (GstVdpVideoPostProcess * vpp)
     GstVdpDevice *device;
     VdpStatus status;
 
+    err = NULL;
     ret =
         gst_vdp_output_src_pad_alloc_buffer ((GstVdpOutputSrcPad *) vpp->srcpad,
-        &outbuf);
+        &outbuf, &err);
     if (ret != GST_FLOW_OK)
-      break;
-
-    gst_vdp_output_src_pad_set_caps ((GstVdpOutputSrcPad *) vpp->srcpad,
-        GST_BUFFER_CAPS (outbuf));
+      goto output_pad_error;
 
     src_r.w = vpp->width;
     src_r.h = vpp->height;
@@ -664,10 +649,8 @@ gst_vdp_vpp_drain (GstVdpVideoPostProcess * vpp)
 
     structure = gst_caps_get_structure (GST_BUFFER_CAPS (outbuf), 0);
     if (!gst_structure_get_int (structure, "width", &dest_r.w) ||
-        !gst_structure_get_int (structure, "height", &dest_r.h)) {
-      gst_buffer_unref (GST_BUFFER (outbuf));
+        !gst_structure_get_int (structure, "height", &dest_r.h))
       goto invalid_caps;
-    }
 
     if (vpp->force_aspect_ratio) {
       GstVideoRectangle res_r;
@@ -690,14 +673,8 @@ gst_vdp_vpp_drain (GstVdpVideoPostProcess * vpp)
         current_pic.structure, video_surfaces_past_count, video_surfaces_past,
         current_pic.buf->surface, video_surfaces_future_count,
         video_surfaces_future, NULL, outbuf->surface, NULL, &rect, 0, NULL);
-    if (status != VDP_STATUS_OK) {
-      gst_buffer_unref (GST_BUFFER (outbuf));
-      GST_ELEMENT_ERROR (vpp, RESOURCE, READ,
-          ("Could not postprocess frame"),
-          ("Error returned from vdpau was: %s",
-              device->vdp_get_error_string (status)));
-      return GST_FLOW_ERROR;
-    }
+    if (status != VDP_STATUS_OK)
+      goto render_error;
 
     GST_BUFFER_TIMESTAMP (outbuf) = current_pic.timestamp;
     if (gst_vdp_vpp_is_interlaced (vpp))
@@ -714,21 +691,38 @@ gst_vdp_vpp_drain (GstVdpVideoPostProcess * vpp)
     if (GST_BUFFER_FLAG_IS_SET (current_pic.buf, GST_BUFFER_FLAG_GAP))
       GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
 
+    err = NULL;
     ret =
         gst_vdp_output_src_pad_push ((GstVdpOutputSrcPad *) vpp->srcpad,
-        outbuf);
+        outbuf, &err);
     if (ret != GST_FLOW_OK)
-      break;
+      goto output_pad_error;
 
     continue;
+
+  render_error:
+    gst_buffer_unref (GST_BUFFER (outbuf));
+    GST_ELEMENT_ERROR (vpp, RESOURCE, READ,
+        ("Could not postprocess frame"),
+        ("Error returned from vdpau was: %s",
+            device->vdp_get_error_string (status)));
+    ret = GST_FLOW_ERROR;
+
+  invalid_caps:
+    gst_buffer_unref (GST_BUFFER (outbuf));
+    GST_ELEMENT_ERROR (vpp, STREAM, FAILED, ("Invalid output caps"), (NULL));
+    ret = GST_FLOW_ERROR;
+    break;
+
+  output_pad_error:
+    if (ret == GST_FLOW_ERROR && err != NULL) {
+      gst_vdp_vpp_post_error (vpp, err);
+      g_error_free (err);
+    }
+    break;
   }
 
   return ret;
-
-invalid_caps:
-  GST_ELEMENT_ERROR (vpp, STREAM, FAILED, ("Invalid output caps"), (NULL));
-  return GST_FLOW_ERROR;
-
 }
 
 static GstFlowReturn
index a1a03b6..537b3d4 100644 (file)
@@ -45,6 +45,7 @@ typedef enum
   GST_VDP_DEINTERLACE_MODE_INTERLACED,
   GST_VDP_DEINTERLACE_MODE_DISABLED
 } GstVdpDeinterlaceModes;
+
 typedef enum
 {
   GST_VDP_DEINTERLACE_METHOD_BOB,