Make sure gst_vaapi_decoder_get_surface() gets unblocked on error.
authorgb <gb@5584edef-b1fe-4b99-b61b-dd2bab72e969>
Wed, 28 Apr 2010 23:09:52 +0000 (23:09 +0000)
committerGwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Mon, 20 Sep 2010 10:55:40 +0000 (12:55 +0200)
gst-libs/gst/vaapi/gstvaapidecoder.c

index a2d9400..2820048 100644 (file)
 
 G_DEFINE_TYPE(GstVaapiDecoder, gst_vaapi_decoder, G_TYPE_OBJECT);
 
+/* XXX: Make it a GstVaapiDecodedSurface + propagate PTS */
+typedef struct _DecodedSurface DecodedSurface;
+struct _DecodedSurface {
+    GstVaapiSurfaceProxy *proxy;
+    GstVaapiDecoderStatus status;
+};
+
 enum {
     PROP_0,
 
@@ -54,6 +61,12 @@ gst_vaapi_decoder_stop(GstVaapiDecoder *decoder);
 static GstBuffer *
 pop_buffer(GstVaapiDecoder *decoder);
 
+static gboolean
+push_surface(GstVaapiDecoder *decoder, GstVaapiSurface *surface);
+
+static DecodedSurface *
+pop_surface(GstVaapiDecoder *decoder, GTimeVal *end_time);
+
 static gpointer
 decoder_thread_cb(gpointer data)
 {
@@ -72,6 +85,8 @@ decoder_thread_cb(gpointer data)
         case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
             break;
         default:
+            /*  Send an empty surface to signal an error */
+            push_surface(decoder, NULL);
             priv->decoder_thread_cancel = TRUE;
             break;
         }
@@ -164,6 +179,50 @@ pop_buffer(GstVaapiDecoder *decoder)
     return buffer;
 }
 
+static inline DecodedSurface *
+create_surface(void)
+{
+    return g_slice_new0(DecodedSurface);
+}
+
+static inline void
+destroy_surface(DecodedSurface *ds)
+{
+    g_slice_free(DecodedSurface, ds);
+}
+
+static gboolean
+push_surface(GstVaapiDecoder *decoder, GstVaapiSurface *surface)
+{
+    GstVaapiDecoderPrivate * const priv = decoder->priv;
+    GstVaapiDecoderStatus status = priv->decoder_status;
+    DecodedSurface *ds;
+
+    ds = create_surface();
+    if (!ds)
+        return FALSE;
+
+    if (surface) {
+        GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT,
+                  GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(surface)));
+        ds->proxy = gst_vaapi_surface_proxy_new(priv->context, surface);
+        if (!ds->proxy)
+            status = GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    }
+    ds->status = status;
+
+    g_async_queue_push(priv->surfaces, ds);
+    return TRUE;
+}
+
+static inline DecodedSurface *
+pop_surface(GstVaapiDecoder *decoder, GTimeVal *end_time)
+{
+    GstVaapiDecoderPrivate * const priv = decoder->priv;
+
+    return g_async_queue_timed_pop(priv->surfaces, end_time);
+}
+
 static inline void
 set_codec_data(GstVaapiDecoder *decoder, GstBuffer *codec_data)
 {
@@ -179,12 +238,12 @@ set_codec_data(GstVaapiDecoder *decoder, GstBuffer *codec_data)
 }
 
 static void
-clear_async_queue(GAsyncQueue *q)
+clear_async_queue(GAsyncQueue *q, GDestroyNotify destroy)
 {
     guint i, qlen = g_async_queue_length(q);
 
     for (i = 0; i < qlen; i++)
-        g_object_unref(g_async_queue_pop(q));
+        destroy(g_async_queue_pop(q));
 }
 
 static void
@@ -203,13 +262,13 @@ gst_vaapi_decoder_finalize(GObject *object)
     }
 
     if (priv->buffers) {
-        clear_async_queue(priv->buffers);
+        clear_async_queue(priv->buffers, (GDestroyNotify)g_object_unref);
         g_object_unref(priv->buffers);
         priv->buffers = NULL;
     }
 
     if (priv->surfaces) {
-        clear_async_queue(priv->surfaces);
+        clear_async_queue(priv->surfaces, (GDestroyNotify)destroy_surface);
         g_object_unref(priv->surfaces);
         priv->surfaces = NULL;
     }
@@ -532,24 +591,20 @@ _gst_vaapi_decoder_get_surface(
     GstVaapiDecoderStatus *pstatus
 )
 {
-    GstVaapiDecoderPrivate * const priv = decoder->priv;
     GstVaapiDecoderStatus status;
-    GstVaapiSurface *surface;
-    GstVaapiSurfaceProxy *proxy = NULL;
-
-    surface = g_async_queue_timed_pop(priv->surfaces, end_time);
-
-    if (surface) {
-        proxy  = gst_vaapi_surface_proxy_new(priv->context, surface);
-        status = (proxy ?
-                  GST_VAAPI_DECODER_STATUS_SUCCESS :
-                  GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED);
-        g_object_unref(surface);
+    GstVaapiSurfaceProxy *proxy;
+    DecodedSurface *ds;
+
+    ds = pop_surface(decoder, end_time);
+    if (ds) {
+        proxy  = ds->proxy;
+        status = ds->status;
+        destroy_surface(ds);
     }
-    else if (end_time)
+    else {
+        proxy  = NULL;
         status = GST_VAAPI_DECODER_STATUS_TIMEOUT;
-    else
-        status = priv->decoder_status;
+    }
 
     if (pstatus)
         *pstatus = status;
@@ -629,13 +684,5 @@ gst_vaapi_decoder_push_surface(
     GstVaapiSurface *surface
 )
 {
-    GstVaapiDecoderPrivate * const priv = decoder->priv;
-
-    g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
-
-    GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT,
-              GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(surface)));
-
-    g_async_queue_push(priv->surfaces, g_object_ref(surface));
-    return TRUE;
+    return push_surface(decoder, surface);
 }