mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-11-21 10:55:51 +02:00
libavcodec/videotoolbox: fix decoding of h264 streams with minor SPS changes
Previously the codec kept an entire copy of the SPS, and restarted the VT decoder session whenever it changed. This fixed decoding errors in [1], as described in9519983c
. On further inspection, that sample features an SPS change from High/4.0 to High/3.2 while moving from one scene to another. Yesterday I received [2], which contains minor SPS changes where the profile and level do not change. These occur frequently and are not associated with scene changes. After9519983c
, the VT decoder session is recreated unnecessarily when these are encountered causing visual glitches. This commit simplifies the state kept in the VTContext to include just the first three bytes of the SPS, containing the profile and level details. This is populated initially when the VT decoder session is created, and used to detect changes and force a restart. This means minor SPS changes are fed directly into the existing decoder, whereas profile/level changes force the decoder session to be recreated with the new parameters. After this commit, both samples [1] and [2] playback as expected. [1] https://s3.amazonaws.com/tmm1/videotoolbox/spschange.ts [2] https://s3.amazonaws.com/tmm1/videotoolbox/spschange2.ts Signed-off-by: Aman Gupta <aman@tmm1.net>
This commit is contained in:
parent
9302d77525
commit
259dc4e013
@ -90,6 +90,7 @@ int ff_videotoolbox_alloc_frame(AVCodecContext *avctx, AVFrame *frame)
|
||||
|
||||
CFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx)
|
||||
{
|
||||
VTContext *vtctx = avctx->internal->hwaccel_priv_data;
|
||||
H264Context *h = avctx->priv_data;
|
||||
CFDataRef data = NULL;
|
||||
uint8_t *p;
|
||||
@ -116,6 +117,10 @@ CFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx)
|
||||
p += 3 + h->ps.pps->data_size;
|
||||
av_assert0(p - vt_extradata == vt_extradata_size);
|
||||
|
||||
// save sps header (profile/level) used to create decoder session,
|
||||
// so we can detect changes and recreate it.
|
||||
memcpy(vtctx->sps, h->ps.sps->data + 1, 3);
|
||||
|
||||
data = CFDataCreate(kCFAllocatorDefault, vt_extradata, vt_extradata_size);
|
||||
av_free(vt_extradata);
|
||||
return data;
|
||||
@ -320,16 +325,13 @@ static int videotoolbox_h264_decode_params(AVCodecContext *avctx,
|
||||
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);
|
||||
if (size > 4 && memcmp(vtctx->sps, buffer + 1, 3) != 0) {
|
||||
vtctx->reconfig_needed = true;
|
||||
vtctx->sps_len = size;
|
||||
memcpy(vtctx->sps, buffer + 1, 3);
|
||||
}
|
||||
}
|
||||
|
||||
// pass-through new PPS to the decoder
|
||||
// pass-through SPS/PPS changes to the decoder
|
||||
return ff_videotoolbox_h264_decode_slice(avctx, buffer, size);
|
||||
}
|
||||
|
||||
@ -365,7 +367,6 @@ 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);
|
||||
}
|
||||
|
@ -40,9 +40,7 @@ typedef struct VTContext {
|
||||
struct AVVideotoolboxContext *vt_ctx;
|
||||
|
||||
// Current H264 parameters (used to trigger decoder restart on SPS changes).
|
||||
uint8_t *sps;
|
||||
uint32_t sps_len;
|
||||
unsigned int sps_capa;
|
||||
uint8_t sps[3];
|
||||
bool reconfig_needed;
|
||||
} VTContext;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user