[FFmpeg-devel] [PATCH 3/3] avcodec/videotoolbox: restart decompression session on bad data errors

Aman Gupta ffmpeg at tmm1.net
Thu Feb 16 20:29:38 EET 2017


From: Aman Gupta <aman at tmm1.net>

On some platforms (observed on macOS Sierra with 12" macbook), the VT
decoder will start returning errors when encountering an SPS change in
the h264 bitstream. With this patch, the kVTVideoDecoderBadDataErr
response from the decoder is caught and the decompression session is
recreated with a new avcC. The "bad data" is then fed into the new
decompression session so that it can be decoded correctly.

I discovered the underlying issue here by running ffmpeg with lldb,
which causes macOS to display debug information from the VT hardware
decoder on stderr. The following errors were shown, which indicated the
need to restart the decoder session with a new SPS/avcC:

  ffmpeg[15127:4094995] GVA error: SPS mismatch ...
  ffmpeg[15127:4094995] GVA error: AVF_PushMetaData, first field kAVF_QT0_SPSPPSBoundaryMarker
  ffmpeg[15127:4094995] GVA error: pushMetaData, submitNewJobs
  ffmpeg[15127:4094995] GVA warning: OutputQueueReadyCallback status = 1, buffer == 0x0

Tested with the following sample, which contains an SPS change midstream:
http://tmm1.s3.amazonaws.com/videotoolbox/spschange.ts
---
 libavcodec/videotoolbox.c | 28 ++++++++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/libavcodec/videotoolbox.c b/libavcodec/videotoolbox.c
index 9be7bee..159d98d 100644
--- a/libavcodec/videotoolbox.c
+++ b/libavcodec/videotoolbox.c
@@ -38,6 +38,9 @@
 
 #define VIDEOTOOLBOX_ESDS_EXTRADATA_PADDING  12
 
+static void videotoolbox_stop(AVCodecContext *avctx);
+static int videotoolbox_start(AVCodecContext *avctx);
+
 static void videotoolbox_buffer_release(void *opaque, uint8_t *data)
 {
     CVPixelBufferRef cv_buffer = (CVImageBufferRef)data;
@@ -350,13 +353,25 @@ static int videotoolbox_common_end_frame(AVCodecContext *avctx, AVFrame *frame)
     int status;
     AVVideotoolboxContext *videotoolbox = avctx->hwaccel_context;
     VTContext *vtctx = avctx->internal->hwaccel_priv_data;
+    int retry;
 
     av_buffer_unref(&frame->buf[0]);
 
     if (!videotoolbox->session || !vtctx->bitstream)
         return AVERROR_INVALIDDATA;
 
-    status = videotoolbox_session_decode_frame(avctx);
+    for (retry = 0; retry < 2; retry++) {
+        status = videotoolbox_session_decode_frame(avctx);
+
+        if (status == kVTVideoDecoderBadDataErr) {
+            av_log(avctx, AV_LOG_DEBUG, "vt decoder got bad data error, restarting..\n");
+            videotoolbox_stop(avctx);
+            videotoolbox_start(avctx);
+            continue;
+        } else {
+            break;
+        }
+    }
 
     if (status) {
         av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status);
@@ -506,7 +521,7 @@ static CMVideoFormatDescriptionRef videotoolbox_format_desc_create(CMVideoCodecT
     return cm_fmt_desc;
 }
 
-static int videotoolbox_default_init(AVCodecContext *avctx)
+static int videotoolbox_start(AVCodecContext *avctx)
 {
     AVVideotoolboxContext *videotoolbox = avctx->hwaccel_context;
     OSStatus status;
@@ -587,7 +602,12 @@ static int videotoolbox_default_init(AVCodecContext *avctx)
     }
 }
 
-static void videotoolbox_default_free(AVCodecContext *avctx)
+static int videotoolbox_default_init(AVCodecContext *avctx)
+{
+    return videotoolbox_start(avctx);
+}
+
+static void videotoolbox_stop(AVCodecContext *avctx)
 {
     AVVideotoolboxContext *videotoolbox = avctx->hwaccel_context;
     if (!videotoolbox)
@@ -696,7 +716,7 @@ int av_videotoolbox_default_init2(AVCodecContext *avctx, AVVideotoolboxContext *
 void av_videotoolbox_default_free(AVCodecContext *avctx)
 {
 
-    videotoolbox_default_free(avctx);
+    videotoolbox_stop(avctx);
     av_freep(&avctx->hwaccel_context);
 }
 #endif /* CONFIG_VIDEOTOOLBOX */
-- 
2.10.1 (Apple Git-78)



More information about the ffmpeg-devel mailing list