From 972c71e9cb63e24f57ee481e413199c7d88a8813 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 12 Nov 2016 17:43:55 +0100 Subject: [PATCH] lavc: add support for filtering packets before decoding --- configure | 1 + libavcodec/avcodec.h | 6 ++ libavcodec/decode.c | 163 ++++++++++++++++++++++++++++++++++++++---- libavcodec/decode.h | 2 + libavcodec/internal.h | 6 ++ libavcodec/utils.c | 3 + 6 files changed, 169 insertions(+), 12 deletions(-) diff --git a/configure b/configure index 6d809f7780..05047e9a15 100755 --- a/configure +++ b/configure @@ -2467,6 +2467,7 @@ transcode_aac_example_deps="avcodec avformat avresample" # libraries, in linking order avcodec_deps="avutil" +avcodec_select="null_bsf" avdevice_deps="avformat avcodec avutil" avfilter_deps="avutil" avformat_deps="avcodec avutil" diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 1827711b50..0997141e2c 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -3243,6 +3243,12 @@ typedef struct AVCodec { * See FF_CODEC_CAP_* in internal.h */ int caps_internal; + + /** + * Decoding only, a comma-separated list of bitstream filters to apply to + * packets before decoding. + */ + const char *bsfs; } AVCodec; /** diff --git a/libavcodec/decode.c b/libavcodec/decode.c index a1908ecf4b..0fd41ab482 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -154,6 +154,116 @@ static int unrefcount_frame(AVCodecInternal *avci, AVFrame *frame) return 0; } +static int bsfs_init(AVCodecContext *avctx) +{ + AVCodecInternal *avci = avctx->internal; + DecodeFilterContext *s = &avci->filter; + const char *bsfs_str; + int ret; + + if (s->nb_bsfs) + return 0; + + bsfs_str = avctx->codec->bsfs ? avctx->codec->bsfs : "null"; + while (bsfs_str && *bsfs_str) { + AVBSFContext **tmp; + const AVBitStreamFilter *filter; + char *bsf; + + bsf = av_get_token(&bsfs_str, ","); + if (!bsf) { + ret = AVERROR(ENOMEM); + goto fail; + } + + filter = av_bsf_get_by_name(bsf); + if (!filter) { + av_log(avctx, AV_LOG_ERROR, "A non-existing bitstream filter %s " + "requested by a decoder. This is a bug, please report it.\n", + bsf); + ret = AVERROR_BUG; + av_freep(&bsf); + goto fail; + } + av_freep(&bsf); + + tmp = av_realloc_array(s->bsfs, s->nb_bsfs + 1, sizeof(*s->bsfs)); + if (!tmp) { + ret = AVERROR(ENOMEM); + goto fail; + } + s->bsfs = tmp; + s->nb_bsfs++; + + ret = av_bsf_alloc(filter, &s->bsfs[s->nb_bsfs - 1]); + if (ret < 0) + goto fail; + + if (s->nb_bsfs == 1) { + /* We do not currently have an API for passing the input timebase into decoders, + * but no filters used here should actually need it. + * So we make up some plausible-looking number (the MPEG 90kHz timebase) */ + s->bsfs[s->nb_bsfs - 1]->time_base_in = (AVRational){ 1, 90000 }; + ret = avcodec_parameters_from_context(s->bsfs[s->nb_bsfs - 1]->par_in, + avctx); + } else { + s->bsfs[s->nb_bsfs - 1]->time_base_in = s->bsfs[s->nb_bsfs - 2]->time_base_out; + ret = avcodec_parameters_copy(s->bsfs[s->nb_bsfs - 1]->par_in, + s->bsfs[s->nb_bsfs - 2]->par_out); + } + if (ret < 0) + goto fail; + + ret = av_bsf_init(s->bsfs[s->nb_bsfs - 1]); + if (ret < 0) + goto fail; + } + + return 0; +fail: + ff_decode_bsfs_uninit(avctx); + return ret; +} + +/* try to get one output packet from the filter chain */ +static int bsfs_poll(AVCodecContext *avctx, AVPacket *pkt) +{ + DecodeFilterContext *s = &avctx->internal->filter; + int idx, ret; + + /* start with the last filter in the chain */ + idx = s->nb_bsfs - 1; + while (idx >= 0) { + /* request a packet from the currently selected filter */ + ret = av_bsf_receive_packet(s->bsfs[idx], pkt); + if (ret == AVERROR(EAGAIN)) { + /* no packets available, try the next filter up the chain */ + ret = 0; + idx--; + continue; + } else if (ret < 0 && ret != AVERROR_EOF) { + return ret; + } + + /* got a packet or EOF -- pass it to the caller or to the next filter + * down the chain */ + if (idx == s->nb_bsfs - 1) { + return ret; + } else { + idx++; + ret = av_bsf_send_packet(s->bsfs[idx], ret < 0 ? NULL : pkt); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, + "Error pre-processing a packet before decoding\n"); + av_packet_unref(pkt); + return ret; + } + } + } + + return AVERROR(EAGAIN); +} + int ff_decode_get_packet(AVCodecContext *avctx, AVPacket *pkt) { AVCodecInternal *avci = avctx->internal; @@ -162,10 +272,11 @@ int ff_decode_get_packet(AVCodecContext *avctx, AVPacket *pkt) if (avci->draining) return AVERROR_EOF; - if (!avci->buffer_pkt->data && !avci->buffer_pkt->side_data_elems) - return AVERROR(EAGAIN); - - av_packet_move_ref(pkt, avci->buffer_pkt); + ret = bsfs_poll(avctx, pkt); + if (ret == AVERROR_EOF) + avci->draining = 1; + if (ret < 0) + return ret; ret = extract_packet_props(avctx->internal, pkt); if (ret < 0) @@ -313,17 +424,23 @@ int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacke if (avctx->internal->draining) return AVERROR_EOF; - if (avci->buffer_pkt->data || avci->buffer_pkt->side_data_elems) - return AVERROR(EAGAIN); + ret = bsfs_init(avctx); + if (ret < 0) + return ret; - if (!avpkt || !avpkt->size) { - avctx->internal->draining = 1; - } else { + av_packet_unref(avci->buffer_pkt); + if (avpkt && (avpkt->data || avpkt->side_data_elems)) { ret = av_packet_ref(avci->buffer_pkt, avpkt); if (ret < 0) return ret; } + ret = av_bsf_send_packet(avci->filter.bsfs[0], avci->buffer_pkt); + if (ret < 0) { + av_packet_unref(avci->buffer_pkt); + return ret; + } + if (!avci->buffer_frame->buf[0]) { ret = decode_receive_frame_internal(avctx, avci->buffer_frame); if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) @@ -343,6 +460,10 @@ 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 { @@ -415,13 +536,18 @@ static int compat_decode(AVCodecContext *avctx, AVFrame *frame, } } - if (avci->draining || avci->compat_decode_consumed < pkt->size) + if (avci->draining || (!avctx->codec->bsfs && avci->compat_decode_consumed < pkt->size)) break; } finish: - if (ret == 0) - ret = FFMIN(avci->compat_decode_consumed, pkt->size); + if (ret == 0) { + /* if there are any bsfs then assume full packet is always consumed */ + if (avctx->codec->bsfs) + ret = pkt->size; + else + ret = FFMIN(avci->compat_decode_consumed, pkt->size); + } avci->compat_decode_consumed = 0; avci->compat_decode_partial_size = (ret >= 0) ? pkt->size - ret : 0; @@ -958,6 +1084,19 @@ void avcodec_flush_buffers(AVCodecContext *avctx) else if (avctx->codec->flush) avctx->codec->flush(avctx); + ff_decode_bsfs_uninit(avctx); + if (!avctx->refcounted_frames) av_frame_unref(avctx->internal->to_free); } + +void ff_decode_bsfs_uninit(AVCodecContext *avctx) +{ + DecodeFilterContext *s = &avctx->internal->filter; + int i; + + for (i = 0; i < s->nb_bsfs; i++) + av_bsf_free(&s->bsfs[i]); + av_freep(&s->bsfs); + s->nb_bsfs = 0; +} diff --git a/libavcodec/decode.h b/libavcodec/decode.h index 21c7c3e07a..c1e6457f77 100644 --- a/libavcodec/decode.h +++ b/libavcodec/decode.h @@ -32,4 +32,6 @@ */ int ff_decode_get_packet(AVCodecContext *avctx, AVPacket *pkt); +void ff_decode_bsfs_uninit(AVCodecContext *avctx); + #endif /* AVCODEC_DECODE_H */ diff --git a/libavcodec/internal.h b/libavcodec/internal.h index dc24e8f764..796d45ff6e 100644 --- a/libavcodec/internal.h +++ b/libavcodec/internal.h @@ -99,6 +99,11 @@ typedef struct DecodeSimpleContext { AVFrame *out_frame; } DecodeSimpleContext; +typedef struct DecodeFilterContext { + AVBSFContext **bsfs; + int nb_bsfs; +} DecodeFilterContext; + typedef struct AVCodecInternal { /** * Whether the parent AVCodecContext is a copy of the context which had @@ -136,6 +141,7 @@ typedef struct AVCodecInternal { void *thread_ctx; DecodeSimpleContext ds; + DecodeFilterContext filter; /** * Properties (timestamps+side data) extracted from the last packet passed diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 8a422d7669..2978109a23 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -40,6 +40,7 @@ #include "libavutil/samplefmt.h" #include "libavutil/dict.h" #include "avcodec.h" +#include "decode.h" #include "libavutil/opt.h" #include "me_cmp.h" #include "mpegvideo.h" @@ -789,6 +790,8 @@ av_cold int avcodec_close(AVCodecContext *avctx) avctx->hwaccel->uninit(avctx); av_freep(&avctx->internal->hwaccel_priv_data); + ff_decode_bsfs_uninit(avctx); + av_freep(&avctx->internal); }