diff options
author | Aman Gupta <aman@tmm1.net> | 2017-11-10 12:25:39 -0800 |
---|---|---|
committer | Aman Gupta <aman@tmm1.net> | 2017-11-13 14:32:48 -0800 |
commit | 9519983c0f39d01fd86544dc56adbbf15bdd3c3c (patch) | |
tree | 626c230412f199e7ebdbd2f2df90048cd5f925bc /libavcodec/videotoolbox.c | |
parent | 872add08540fb36b2d2ca75df86da7d8ac9579a1 (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.c | 43 |
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, |