summaryrefslogtreecommitdiff
path: root/libavcodec/videotoolbox.c
diff options
context:
space:
mode:
authorAman Gupta <aman@tmm1.net>2017-11-10 12:25:39 -0800
committerAman Gupta <aman@tmm1.net>2017-11-13 14:32:48 -0800
commit9519983c0f39d01fd86544dc56adbbf15bdd3c3c (patch)
tree626c230412f199e7ebdbd2f2df90048cd5f925bc /libavcodec/videotoolbox.c
parent872add08540fb36b2d2ca75df86da7d8ac9579a1 (diff)
avcodec/videotoolbox: use decode_params to propagate H264 PPS changes and restart on SPS changes
This fixes decoding of H264 video samples with SPS and PPS changes. See for example https://s3.amazonaws.com/tmm1/videotoolbox/spschange.ts, which previously stalled the decoder and failed to produce any new frames after the SPS change. Also see https://s3.amazonaws.com/tmm1/videotoolbox/ppschange.ts, which uses multiple PPS and would previously cause VT decode failures. If the VideoToolbox session needs to be restarted, and videotoolbox_start() fails for some reason (for instance, if the video is interlaced and the decoder is running on iOS), avcodec will return AVERROR_EXTERNAL. This can be used by the API user to switch to another decoder. Signed-off-by: Aman Gupta <aman@tmm1.net>
Diffstat (limited to 'libavcodec/videotoolbox.c')
-rw-r--r--libavcodec/videotoolbox.c43
1 files changed, 41 insertions, 2 deletions
diff --git a/libavcodec/videotoolbox.c b/libavcodec/videotoolbox.c
index 4fe89a27e9..c24f5aa3f3 100644
--- a/libavcodec/videotoolbox.c
+++ b/libavcodec/videotoolbox.c
@@ -42,6 +42,9 @@ enum { kCMVideoCodecType_HEVC = 'hvc1' };
#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;
@@ -307,6 +310,27 @@ int ff_videotoolbox_h264_start_frame(AVCodecContext *avctx,
return 0;
}
+static int videotoolbox_h264_decode_params(AVCodecContext *avctx,
+ int type,
+ const uint8_t *buffer,
+ uint32_t size)
+{
+ VTContext *vtctx = avctx->internal->hwaccel_priv_data;
+
+ if (type == H264_NAL_SPS) {
+ if (!vtctx->sps || vtctx->sps_len != size || memcmp(buffer, vtctx->sps, size) != 0) {
+ vtctx->sps = av_fast_realloc(vtctx->sps, &vtctx->sps_capa, size);
+ if (vtctx->sps)
+ memcpy(vtctx->sps, buffer, size);
+ vtctx->reconfig_needed = true;
+ vtctx->sps_len = size;
+ }
+ }
+
+ // pass-through new PPS to the decoder
+ return ff_videotoolbox_h264_decode_slice(avctx, buffer, size);
+}
+
int ff_videotoolbox_h264_decode_slice(AVCodecContext *avctx,
const uint8_t *buffer,
uint32_t size)
@@ -339,6 +363,7 @@ int ff_videotoolbox_uninit(AVCodecContext *avctx)
VTContext *vtctx = avctx->internal->hwaccel_priv_data;
if (vtctx) {
av_freep(&vtctx->bitstream);
+ av_freep(&vtctx->sps);
if (vtctx->frame)
CVPixelBufferRelease(vtctx->frame);
}
@@ -591,17 +616,30 @@ static int videotoolbox_common_end_frame(AVCodecContext *avctx, AVFrame *frame)
AVVideotoolboxContext *videotoolbox = videotoolbox_get_context(avctx);
VTContext *vtctx = avctx->internal->hwaccel_priv_data;
- if (!videotoolbox->session || !vtctx->bitstream)
+ if (vtctx->reconfig_needed == true) {
+ vtctx->reconfig_needed = false;
+ av_log(avctx, AV_LOG_VERBOSE, "VideoToolbox decoder needs reconfig, restarting..\n");
+ videotoolbox_stop(avctx);
+ if (videotoolbox_start(avctx) != 0) {
+ return AVERROR_EXTERNAL;
+ }
+ }
+
+ if (!videotoolbox->session || !vtctx->bitstream || !vtctx->bitstream_size)
return AVERROR_INVALIDDATA;
status = videotoolbox_session_decode_frame(avctx);
if (status != noErr) {
+ if (status == kVTVideoDecoderMalfunctionErr || status == kVTInvalidSessionErr)
+ vtctx->reconfig_needed = true;
av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%s, %d)\n", videotoolbox_error_string(status), (int)status);
return AVERROR_UNKNOWN;
}
- if (!vtctx->frame)
+ if (!vtctx->frame) {
+ vtctx->reconfig_needed = true;
return AVERROR_UNKNOWN;
+ }
return videotoolbox_buffer_create(avctx, frame);
}
@@ -1018,6 +1056,7 @@ AVHWAccel ff_h264_videotoolbox_hwaccel = {
.alloc_frame = ff_videotoolbox_alloc_frame,
.start_frame = ff_videotoolbox_h264_start_frame,
.decode_slice = ff_videotoolbox_h264_decode_slice,
+ .decode_params = videotoolbox_h264_decode_params,
.end_frame = videotoolbox_h264_end_frame,
.frame_params = videotoolbox_frame_params,
.init = videotoolbox_common_init,