vpxdec: Check that output width and height != 0
[platform/upstream/gstreamer.git] / ext / vpx / gstvpxdec.c
index 1d2ddca..e860715 100644 (file)
@@ -62,6 +62,20 @@ gst_vpx_dec_post_processing_flags_get_type (void)
     {C_FLAGS (VP8_DEBLOCK), "Deblock", "deblock"},
     {C_FLAGS (VP8_DEMACROBLOCK), "Demacroblock", "demacroblock"},
     {C_FLAGS (VP8_ADDNOISE), "Add noise", "addnoise"},
+#ifndef HAVE_VPX_1_8
+    {C_FLAGS (VP8_DEBUG_TXT_FRAME_INFO),
+          "Print frame information",
+        "visualize-frame-info"},
+    {C_FLAGS (VP8_DEBUG_TXT_MBLK_MODES),
+          "Show macroblock mode selection overlaid on image",
+        "visualize-macroblock-modes"},
+    {C_FLAGS (VP8_DEBUG_TXT_DC_DIFF),
+          "Show dc diff for each macro block overlaid on image",
+        "visualize-dc-diff"},
+    {C_FLAGS (VP8_DEBUG_TXT_RATE_INFO),
+          "Print video rate info",
+        "visualize-rate-info"},
+#endif
     {C_FLAGS (VP8_MFQE), "Multi-frame quality enhancement", "mfqe"},
     {0, NULL, NULL}
   };
@@ -361,7 +375,6 @@ gst_vpx_dec_default_send_tags (GstVPXDec * dec)
       gst_event_new_tag (list));
 }
 
-#ifdef HAVE_VPX_1_4
 struct Frame
 {
   GstMapInfo info;
@@ -482,16 +495,19 @@ gst_vpx_dec_release_buffer_cb (gpointer priv, vpx_codec_frame_buffer_t * fb)
 {
   struct Frame *frame = fb->priv;
 
+  /* We're sometimes called without a frame */
+  if (!frame)
+    return 0;
+
   GST_TRACE_OBJECT (priv, "Release buffer %p", frame->buffer);
 
-  g_assert (frame);
   gst_buffer_unmap (frame->buffer, &frame->info);
   gst_buffer_unref (frame->buffer);
   g_free (frame);
+  fb->priv = NULL;
 
   return 0;
 }
-#endif
 
 static void
 gst_vpx_dec_image_to_buffer (GstVPXDec * dec, const vpx_image_t * img,
@@ -564,12 +580,18 @@ gst_vpx_dec_open_codec (GstVPXDec * dec, GstVideoCodecFrame * frame)
   if (status != VPX_CODEC_OK) {
     GST_WARNING_OBJECT (dec, "VPX preprocessing error: %s",
         gst_vpx_error_name (status));
-    gst_video_decoder_drop_frame (GST_VIDEO_DECODER (dec), frame);
     return GST_FLOW_CUSTOM_SUCCESS_1;
   }
   if (!stream_info.is_kf) {
     GST_WARNING_OBJECT (dec, "No keyframe, skipping");
-    gst_video_decoder_drop_frame (GST_VIDEO_DECODER (dec), frame);
+    return GST_FLOW_CUSTOM_SUCCESS_1;
+  }
+  if (stream_info.w == 0 || stream_info.h == 0) {
+    /* For VP8 it's possible to signal width or height to be 0, but it does
+     * not make sense to do so. For VP9 it's impossible. Hence, we most likely
+     * have a corrupt stream if width or height is 0. */
+    GST_INFO_OBJECT (dec, "Invalid resolution %d x %d", stream_info.w,
+        stream_info.h);
     return GST_FLOW_CUSTOM_SUCCESS_1;
   }
 
@@ -579,7 +601,11 @@ gst_vpx_dec_open_codec (GstVPXDec * dec, GstVideoCodecFrame * frame)
 
   cfg.w = stream_info.w;
   cfg.h = stream_info.h;
-  cfg.threads = dec->threads;
+
+  if (dec->threads > 0)
+    cfg.threads = dec->threads;
+  else
+    cfg.threads = g_get_num_processors ();
 
   caps = vpx_codec_get_caps (vpxclass->codec_algo);
 
@@ -613,10 +639,8 @@ gst_vpx_dec_open_codec (GstVPXDec * dec, GstVideoCodecFrame * frame)
           gst_vpx_error_name (status));
     }
   }
-#ifdef HAVE_VPX_1_4
   vpx_codec_set_frame_buffer_functions (&dec->decoder,
       gst_vpx_dec_get_buffer_cb, gst_vpx_dec_release_buffer_cb, dec);
-#endif
 
   dec->decoder_inited = TRUE;
 
@@ -644,10 +668,13 @@ gst_vpx_dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
 
   if (!dec->decoder_inited) {
     ret = vpxclass->open_codec (dec, frame);
-    if (ret == GST_FLOW_CUSTOM_SUCCESS_1)
+    if (ret == GST_FLOW_CUSTOM_SUCCESS_1) {
+      gst_video_decoder_drop_frame (decoder, frame);
       return GST_FLOW_OK;
-    else if (ret != GST_FLOW_OK)
+    } else if (ret != GST_FLOW_OK) {
+      gst_video_codec_frame_unref (frame);
       return ret;
+    }
   }
 
   deadline = gst_video_decoder_get_max_decode_time (decoder, frame);
@@ -661,6 +688,7 @@ gst_vpx_dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
 
   if (!gst_buffer_map (frame->input_buffer, &minfo, GST_MAP_READ)) {
     GST_ERROR_OBJECT (dec, "Failed to map input buffer");
+    gst_video_codec_frame_unref (frame);
     return GST_FLOW_ERROR;
   }
 
@@ -672,6 +700,7 @@ gst_vpx_dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
   if (status) {
     GST_VIDEO_DECODER_ERROR (decoder, 1, LIBRARY, ENCODE,
         ("Failed to decode frame"), ("%s", gst_vpx_error_name (status)), ret);
+    gst_video_codec_frame_unref (frame);
     return ret;
   }
 
@@ -682,6 +711,7 @@ gst_vpx_dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
       GST_ELEMENT_ERROR (decoder, LIBRARY, ENCODE,
           ("Failed to decode frame"), ("Unsupported color format %d",
               img->fmt));
+      gst_video_codec_frame_unref (frame);
       return GST_FLOW_ERROR;
     }
 
@@ -691,13 +721,10 @@ gst_vpx_dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
       gst_video_decoder_drop_frame (decoder, frame);
     } else {
       gst_vpx_dec_handle_resolution_change (dec, img, fmt);
-#ifdef HAVE_VPX_1_4
       if (img->fb_priv && dec->have_video_meta) {
         frame->output_buffer = gst_vpx_dec_prepare_image (dec, img);
         ret = gst_video_decoder_finish_frame (decoder, frame);
-      } else
-#endif
-      {
+      } else {
         ret = gst_video_decoder_allocate_output_frame (decoder, frame);
 
         if (ret == GST_FLOW_OK) {