From e1e1e8dbb204085443d95a05f91a5c33574792ce Mon Sep 17 00:00:00 2001 From: James Almer Date: Fri, 27 Jul 2018 13:18:29 -0300 Subject: [PATCH 1/7] bsf: add a flushing mechanism to AVBSFContext Meant to reset the internal bsf state without the need to reinitialize it. Signed-off-by: James Almer --- doc/APIchanges | 3 +++ libavcodec/avcodec.h | 6 ++++++ libavcodec/bsf.c | 10 ++++++++++ libavcodec/version.h | 2 +- 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/doc/APIchanges b/doc/APIchanges index d385d73b0c..9ba03648c5 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -13,6 +13,9 @@ libavutil: 2017-03-23 API changes, most recent first: +2018-xx-xx - xxxxxxx - lavc 58.10.0 - avcodec.h + Add av_bsf_flush(). + 2018-02-xx - xxxxxxx - lavfi 7.1.0 - avfilter.h Add AVFilterContext.extra_hw_frames. diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index eb234a40d6..fb8e34e7d5 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -4927,6 +4927,7 @@ typedef struct AVBitStreamFilter { int (*init)(AVBSFContext *ctx); int (*filter)(AVBSFContext *ctx, AVPacket *pkt); void (*close)(AVBSFContext *ctx); + void (*flush)(AVBSFContext *ctx); } AVBitStreamFilter; #if FF_API_OLD_BSF @@ -5029,6 +5030,11 @@ int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt); */ int av_bsf_receive_packet(AVBSFContext *ctx, AVPacket *pkt); +/** + * Reset the internal bitstream filter state / flush internal buffers. + */ +void av_bsf_flush(AVBSFContext *ctx); + /** * Free a bitstream filter context and everything associated with it; write NULL * into the supplied pointer. diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c index 284c7c8044..05cad546de 100644 --- a/libavcodec/bsf.c +++ b/libavcodec/bsf.c @@ -170,6 +170,16 @@ int av_bsf_init(AVBSFContext *ctx) return 0; } +void av_bsf_flush(AVBSFContext *ctx) +{ + ctx->internal->eof = 0; + + av_packet_unref(ctx->internal->buffer_pkt); + + if (ctx->filter->flush) + ctx->filter->flush(ctx); +} + int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt) { if (!pkt || !pkt->data) { diff --git a/libavcodec/version.h b/libavcodec/version.h index 36a014959e..32486a83c1 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -28,7 +28,7 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 58 -#define LIBAVCODEC_VERSION_MINOR 9 +#define LIBAVCODEC_VERSION_MINOR 10 #define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ From d6321851ba3561bd16d847e4f6a8014ff983b36c Mon Sep 17 00:00:00 2001 From: James Almer Date: Fri, 27 Jul 2018 13:21:16 -0300 Subject: [PATCH 2/7] h264_mp4toannexb_bsf: implement a AVBSFContext.flush() callback Signed-off-by: James Almer --- libavcodec/h264_mp4toannexb_bsf.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libavcodec/h264_mp4toannexb_bsf.c b/libavcodec/h264_mp4toannexb_bsf.c index c65aaeb98a..c45ecd8ce7 100644 --- a/libavcodec/h264_mp4toannexb_bsf.c +++ b/libavcodec/h264_mp4toannexb_bsf.c @@ -232,6 +232,13 @@ fail: return ret; } +static void h264_mp4toannexb_flush(AVBSFContext *ctx) +{ + H264BSFContext *s = ctx->priv_data; + + s->first_idr = s->extradata_parsed; +} + static const enum AVCodecID codec_ids[] = { AV_CODEC_ID_H264, AV_CODEC_ID_NONE, }; @@ -241,5 +248,6 @@ const AVBitStreamFilter ff_h264_mp4toannexb_bsf = { .priv_data_size = sizeof(H264BSFContext), .init = h264_mp4toannexb_init, .filter = h264_mp4toannexb_filter, + .flush = h264_mp4toannexb_flush, .codec_ids = codec_ids, }; From eb1d1c764c7fcd824a834cfdd7487bdad64c6bab Mon Sep 17 00:00:00 2001 From: James Almer Date: Fri, 27 Jul 2018 13:22:34 -0300 Subject: [PATCH 3/7] vp9_superframe_split_bsf: implement a AVBSFContext.flush() callback Signed-off-by: James Almer --- libavcodec/vp9_superframe_split_bsf.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libavcodec/vp9_superframe_split_bsf.c b/libavcodec/vp9_superframe_split_bsf.c index 4e635a3070..0d31123874 100644 --- a/libavcodec/vp9_superframe_split_bsf.c +++ b/libavcodec/vp9_superframe_split_bsf.c @@ -131,6 +131,12 @@ fail: return ret; } +static void vp9_superframe_split_flush(AVBSFContext *ctx) +{ + VP9SFSplitContext *s = ctx->priv_data; + av_packet_free(&s->buffer_pkt); +} + static void vp9_superframe_split_uninit(AVBSFContext *ctx) { VP9SFSplitContext *s = ctx->priv_data; @@ -140,6 +146,7 @@ static void vp9_superframe_split_uninit(AVBSFContext *ctx) const AVBitStreamFilter ff_vp9_superframe_split_bsf = { .name = "vp9_superframe_split", .priv_data_size = sizeof(VP9SFSplitContext), + .flush = vp9_superframe_split_flush, .close = vp9_superframe_split_uninit, .filter = vp9_superframe_split_filter, .codec_ids = (const enum AVCodecID []){ AV_CODEC_ID_VP9, AV_CODEC_ID_NONE }, From 7f01c209f219def901e9783fdb1eeb54b235616c Mon Sep 17 00:00:00 2001 From: James Almer Date: Fri, 27 Jul 2018 13:23:44 -0300 Subject: [PATCH 4/7] vp9_superframe_bsf: implement a AVBSFContext.flush() callback Signed-off-by: James Almer --- libavcodec/vp9_superframe_bsf.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libavcodec/vp9_superframe_bsf.c b/libavcodec/vp9_superframe_bsf.c index ad66cb599b..04b158fa12 100644 --- a/libavcodec/vp9_superframe_bsf.c +++ b/libavcodec/vp9_superframe_bsf.c @@ -191,6 +191,17 @@ static int vp9_superframe_init(AVBSFContext *ctx) return 0; } +static void vp9_superframe_flush(AVBSFContext *ctx) +{ + VP9BSFContext *s = ctx->priv_data; + int n; + + // unref cached data + for (n = 0; n < s->n_cache; n++) + av_packet_unref(s->cache[n]); + s->n_cache = 0; +} + static void vp9_superframe_close(AVBSFContext *ctx) { VP9BSFContext *s = ctx->priv_data; @@ -210,6 +221,7 @@ const AVBitStreamFilter ff_vp9_superframe_bsf = { .priv_data_size = sizeof(VP9BSFContext), .filter = vp9_superframe_filter, .init = vp9_superframe_init, + .flush = vp9_superframe_flush, .close = vp9_superframe_close, .codec_ids = codec_ids, }; From 0e27e2767001d22fd25164b87b42793a9e9bcfc3 Mon Sep 17 00:00:00 2001 From: James Almer Date: Fri, 27 Jul 2018 13:24:53 -0300 Subject: [PATCH 5/7] h264_redundant_pps_bsf: implement a AVBSFContext.flush() callback Signed-off-by: James Almer --- libavcodec/h264_redundant_pps_bsf.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libavcodec/h264_redundant_pps_bsf.c b/libavcodec/h264_redundant_pps_bsf.c index 24b7b67300..d806427da9 100644 --- a/libavcodec/h264_redundant_pps_bsf.c +++ b/libavcodec/h264_redundant_pps_bsf.c @@ -35,6 +35,7 @@ typedef struct H264RedundantPPSContext { int global_pic_init_qp; int current_pic_init_qp; + int extradata_pic_init_qp; } H264RedundantPPSContext; @@ -145,6 +146,7 @@ static int h264_redundant_pps_init(AVBSFContext *bsf) h264_redundant_pps_fixup_pps(ctx, au->units[i].content); } + ctx->extradata_pic_init_qp = ctx->current_pic_init_qp; err = ff_cbs_write_extradata(ctx->output, bsf->par_out, au); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to write extradata.\n"); @@ -157,6 +159,12 @@ static int h264_redundant_pps_init(AVBSFContext *bsf) return 0; } +static void h264_redundant_pps_flush(AVBSFContext *bsf) +{ + H264RedundantPPSContext *ctx = bsf->priv_data; + ctx->current_pic_init_qp = ctx->extradata_pic_init_qp; +} + static void h264_redundant_pps_close(AVBSFContext *bsf) { H264RedundantPPSContext *ctx = bsf->priv_data; @@ -172,6 +180,7 @@ const AVBitStreamFilter ff_h264_redundant_pps_bsf = { .name = "h264_redundant_pps", .priv_data_size = sizeof(H264RedundantPPSContext), .init = &h264_redundant_pps_init, + .flush = &h264_redundant_pps_flush, .close = &h264_redundant_pps_close, .filter = &h264_redundant_pps_filter, .codec_ids = h264_redundant_pps_codec_ids, From ad99cbc9b3f4e0fae5c9bc5291d422d477dbf069 Mon Sep 17 00:00:00 2001 From: James Almer Date: Fri, 27 Jul 2018 13:27:45 -0300 Subject: [PATCH 6/7] decode: flush the internal bsfs instead of constantly reinitalizing them Signed-off-by: James Almer --- libavcodec/decode.c | 20 ++++++++++---------- libavcodec/decode.h | 2 ++ libavcodec/utils.c | 7 +++++++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/libavcodec/decode.c b/libavcodec/decode.c index 8635aec949..2dab7f2a71 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -156,7 +156,7 @@ static int unrefcount_frame(AVCodecInternal *avci, AVFrame *frame) return 0; } -static int bsfs_init(AVCodecContext *avctx) +int ff_decode_bsfs_init(AVCodecContext *avctx) { AVCodecInternal *avci = avctx->internal; DecodeFilterContext *s = &avci->filter; @@ -449,10 +449,6 @@ int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacke if (avctx->internal->draining) return AVERROR_EOF; - ret = bsfs_init(avctx); - if (ret < 0) - return ret; - av_packet_unref(avci->buffer_pkt); if (avpkt && (avpkt->data || avpkt->side_data_elems)) { ret = av_packet_ref(avci->buffer_pkt, avpkt); @@ -511,10 +507,6 @@ int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *fr if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec)) return AVERROR(EINVAL); - ret = bsfs_init(avctx); - if (ret < 0) - return ret; - if (avci->buffer_frame->buf[0]) { av_frame_move_ref(frame, avci->buffer_frame); } else { @@ -1394,6 +1386,14 @@ int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame) return 0; } +static void bsfs_flush(AVCodecContext *avctx) +{ + DecodeFilterContext *s = &avctx->internal->filter; + + for (int i = 0; i < s->nb_bsfs; i++) + av_bsf_flush(s->bsfs[i]); +} + void avcodec_flush_buffers(AVCodecContext *avctx) { avctx->internal->draining = 0; @@ -1410,7 +1410,7 @@ void avcodec_flush_buffers(AVCodecContext *avctx) else if (avctx->codec->flush) avctx->codec->flush(avctx); - ff_decode_bsfs_uninit(avctx); + bsfs_flush(avctx); if (!avctx->refcounted_frames) av_frame_unref(avctx->internal->to_free); diff --git a/libavcodec/decode.h b/libavcodec/decode.h index 37b2e45c63..4a76d7a852 100644 --- a/libavcodec/decode.h +++ b/libavcodec/decode.h @@ -69,6 +69,8 @@ typedef struct FrameDecodeData { */ int ff_decode_get_packet(AVCodecContext *avctx, AVPacket *pkt); +int ff_decode_bsfs_init(AVCodecContext *avctx); + void ff_decode_bsfs_uninit(AVCodecContext *avctx); /** diff --git a/libavcodec/utils.c b/libavcodec/utils.c index ba3457664a..701ef5072b 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -512,6 +512,12 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code avctx->time_base.den = avctx->sample_rate; } + if (av_codec_is_decoder(avctx->codec)) { + ret = ff_decode_bsfs_init(avctx); + if (ret < 0) + goto free_and_end; + } + if (HAVE_THREADS) { ret = ff_thread_init(avctx); if (ret < 0) { @@ -706,6 +712,7 @@ FF_ENABLE_DEPRECATION_WARNINGS av_packet_free(&avctx->internal->last_pkt_props); av_packet_free(&avctx->internal->ds.in_pkt); + ff_decode_bsfs_uninit(avctx); av_freep(&avctx->internal->pool); } From 662558f985f50834eebe82d6b6854c66f33ab320 Mon Sep 17 00:00:00 2001 From: James Almer Date: Fri, 27 Jul 2018 13:29:03 -0300 Subject: [PATCH 7/7] decode: copy the output parameters from the last bsf in the chain back to the AVCodecContext Signed-off-by: James Almer --- libavcodec/decode.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libavcodec/decode.c b/libavcodec/decode.c index 2dab7f2a71..d10a2c8b58 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -221,6 +221,10 @@ int ff_decode_bsfs_init(AVCodecContext *avctx) goto fail; } + ret = avcodec_parameters_to_context(avctx, s->bsfs[s->nb_bsfs - 1]->par_out); + if (ret < 0) + return ret; + return 0; fail: ff_decode_bsfs_uninit(avctx);