From 33d18982fa03feb061c8f744a4f0a9175c1f63ab Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 23 Nov 2013 11:43:13 +0100 Subject: lavc: add a new bitstream filtering API Deprecate the current bitstream filtering API. --- configure | 2 +- doc/APIchanges | 4 + libavcodec/Makefile | 2 + libavcodec/aac_adtstoasc_bsf.c | 104 +++++++++++------ libavcodec/allcodecs.c | 21 ---- libavcodec/avcodec.h | 202 +++++++++++++++++++++++++++++++-- libavcodec/bitstream_filter.c | 147 ++++++++++++++++++------ libavcodec/bitstream_filters.c | 121 ++++++++++++++++++++ libavcodec/bsf.c | 219 ++++++++++++++++++++++++++++++++++++ libavcodec/bsf.h | 33 ++++++ libavcodec/chomp_bsf.c | 29 ++--- libavcodec/dump_extradata_bsf.c | 94 ++++++++++++---- libavcodec/h264_mp4toannexb_bsf.c | 151 ++++++++++++++----------- libavcodec/hevc_mp4toannexb_bsf.c | 127 +++++++++++---------- libavcodec/imx_dump_header_bsf.c | 63 +++++++---- libavcodec/mjpeg2jpeg_bsf.c | 69 +++++++----- libavcodec/mjpega_dump_header_bsf.c | 106 +++++++++-------- libavcodec/movsub_bsf.c | 96 +++++++++++----- libavcodec/noise_bsf.c | 77 +++++++++---- libavcodec/remove_extradata_bsf.c | 110 ++++++++++++++---- libavcodec/version.h | 5 +- 21 files changed, 1350 insertions(+), 432 deletions(-) create mode 100644 libavcodec/bitstream_filters.c create mode 100644 libavcodec/bsf.c create mode 100644 libavcodec/bsf.h diff --git a/configure b/configure index 5376e672f4..ba1fd47d24 100755 --- a/configure +++ b/configure @@ -2517,7 +2517,6 @@ ENCODER_LIST=$(find_things encoder ENC libavcodec/allcodecs.c) DECODER_LIST=$(find_things decoder DEC libavcodec/allcodecs.c) HWACCEL_LIST=$(find_things hwaccel HWACCEL libavcodec/allcodecs.c) PARSER_LIST=$(find_things parser PARSER libavcodec/allcodecs.c) -BSF_LIST=$(find_things bsf BSF libavcodec/allcodecs.c) MUXER_LIST=$(find_things muxer _MUX libavformat/allformats.c) DEMUXER_LIST=$(find_things demuxer DEMUX libavformat/allformats.c) OUTDEV_LIST=$(find_things outdev OUTDEV libavdevice/alldevices.c) @@ -2531,6 +2530,7 @@ find_things_extern(){ sed -n "s/^[^#]*extern.*$pattern *ff_\([^ ]*\)_$thing;/\1_$thing/p" "$file" } +BSF_LIST=$(find_things_extern bsf AVBitStreamFilter libavcodec/bitstream_filters.c) PROTOCOL_LIST=$(find_things_extern protocol URLProtocol libavformat/protocols.c) ALL_COMPONENTS=" diff --git a/doc/APIchanges b/doc/APIchanges index e0c46787b5..c50faa68f8 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -13,6 +13,10 @@ libavutil: 2015-08-28 API changes, most recent first: +2016-xx-xx - xxxxxxx - lavc 57.15.0 - avcodec.h + Add a new bitstream filtering API working with AVPackets. + Deprecate the old bistream filtering API. + 2016-xx-xx - xxxxxxx - lavfi 6.3.0 - avfilter.h Add AVFilterContext.hw_device_ctx. diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 256dee3a4d..ba1661d1df 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -19,6 +19,8 @@ OBJS = allcodecs.o \ avpicture.o \ bitstream.o \ bitstream_filter.o \ + bitstream_filters.o \ + bsf.o \ codec_desc.o \ d3d11va.o \ dirac.o \ diff --git a/libavcodec/aac_adtstoasc_bsf.c b/libavcodec/aac_adtstoasc_bsf.c index d3cbeae9d0..9168e2b0f3 100644 --- a/libavcodec/aac_adtstoasc_bsf.c +++ b/libavcodec/aac_adtstoasc_bsf.c @@ -21,6 +21,7 @@ #include "avcodec.h" #include "aacadtsdec.h" +#include "bsf.h" #include "put_bits.h" #include "get_bits.h" #include "mpeg4audio.h" @@ -34,65 +35,76 @@ typedef struct AACBSFContext { * This filter creates an MPEG-4 AudioSpecificConfig from an MPEG-2/4 * ADTS header and removes the ADTS header. */ -static int aac_adtstoasc_filter(AVBitStreamFilterContext *bsfc, - AVCodecContext *avctx, const char *args, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, - int keyframe) +static int aac_adtstoasc_filter(AVBSFContext *bsfc, AVPacket *out) { + AACBSFContext *ctx = bsfc->priv_data; + GetBitContext gb; PutBitContext pb; AACADTSHeaderInfo hdr; + AVPacket *in; + int ret; - AACBSFContext *ctx = bsfc->priv_data; + ret = ff_bsf_get_packet(bsfc, &in); + if (ret < 0) + return ret; - init_get_bits(&gb, buf, AAC_ADTS_HEADER_SIZE*8); + if (in->size < AAC_ADTS_HEADER_SIZE) + goto packet_too_small; - *poutbuf = (uint8_t*) buf; - *poutbuf_size = buf_size; + init_get_bits(&gb, in->data, AAC_ADTS_HEADER_SIZE * 8); - if (avctx->extradata) - if (show_bits(&gb, 12) != 0xfff) - return 0; + if (bsfc->par_in->extradata && show_bits(&gb, 12) != 0xfff) + goto finish; if (avpriv_aac_parse_header(&gb, &hdr) < 0) { - av_log(avctx, AV_LOG_ERROR, "Error parsing ADTS frame header!\n"); - return AVERROR_INVALIDDATA; + av_log(bsfc, AV_LOG_ERROR, "Error parsing ADTS frame header!\n"); + ret = AVERROR_INVALIDDATA; + goto fail; } if (!hdr.crc_absent && hdr.num_aac_frames > 1) { - avpriv_report_missing_feature(avctx, + avpriv_report_missing_feature(bsfc, "Multiple RDBs per frame with CRC"); - return AVERROR_PATCHWELCOME; + ret = AVERROR_PATCHWELCOME; + goto fail; } - buf += AAC_ADTS_HEADER_SIZE + 2*!hdr.crc_absent; - buf_size -= AAC_ADTS_HEADER_SIZE + 2*!hdr.crc_absent; + in->size -= AAC_ADTS_HEADER_SIZE + 2 * !hdr.crc_absent; + if (in->size <= 0) + goto packet_too_small; + in->data += AAC_ADTS_HEADER_SIZE + 2 * !hdr.crc_absent; if (!ctx->first_frame_done) { int pce_size = 0; uint8_t pce_data[MAX_PCE_SIZE]; + uint8_t *extradata; + if (!hdr.chan_config) { - init_get_bits(&gb, buf, buf_size * 8); + init_get_bits(&gb, in->data, in->size * 8); if (get_bits(&gb, 3) != 5) { - avpriv_report_missing_feature(avctx, + avpriv_report_missing_feature(bsfc, "PCE-based channel configuration " "without PCE as first syntax " "element"); - return AVERROR_PATCHWELCOME; + ret = AVERROR_PATCHWELCOME; + goto fail; } init_put_bits(&pb, pce_data, MAX_PCE_SIZE); pce_size = avpriv_copy_pce_data(&pb, &gb)/8; flush_put_bits(&pb); - buf_size -= get_bits_count(&gb)/8; - buf += get_bits_count(&gb)/8; + in->size -= get_bits_count(&gb)/8; + in->data += get_bits_count(&gb)/8; } - avctx->extradata_size = 2 + pce_size; - avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!avctx->extradata) - return AVERROR(ENOMEM); - init_put_bits(&pb, avctx->extradata, avctx->extradata_size); + extradata = av_packet_new_side_data(in, AV_PKT_DATA_NEW_EXTRADATA, + 2 + pce_size); + if (!extradata) { + ret = AVERROR(ENOMEM); + goto fail; + } + + init_put_bits(&pb, extradata, 2 + pce_size); put_bits(&pb, 5, hdr.object_type); put_bits(&pb, 4, hdr.sampling_index); put_bits(&pb, 4, hdr.chan_config); @@ -101,20 +113,42 @@ static int aac_adtstoasc_filter(AVBitStreamFilterContext *bsfc, put_bits(&pb, 1, 0); //is not extension flush_put_bits(&pb); if (pce_size) { - memcpy(avctx->extradata + 2, pce_data, pce_size); + memcpy(extradata + 2, pce_data, pce_size); } ctx->first_frame_done = 1; } - *poutbuf = (uint8_t*) buf; - *poutbuf_size = buf_size; +finish: + av_packet_move_ref(out, in); + av_packet_free(&in); + + return 0; + +packet_too_small: + av_log(bsfc, AV_LOG_ERROR, "Input packet too small\n"); + ret = AVERROR_INVALIDDATA; +fail: + av_packet_free(&in); + return ret; +} + +static int aac_adtstoasc_init(AVBSFContext *ctx) +{ + av_freep(&ctx->par_out->extradata); + ctx->par_out->extradata_size = 0; return 0; } -AVBitStreamFilter ff_aac_adtstoasc_bsf = { - "aac_adtstoasc", - sizeof(AACBSFContext), - aac_adtstoasc_filter, +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_AAC, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_aac_adtstoasc_bsf = { + .name = "aac_adtstoasc", + .priv_data_size = sizeof(AACBSFContext), + .init = aac_adtstoasc_init, + .filter = aac_adtstoasc_filter, + .codec_ids = codec_ids, }; diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 7c2ab50b83..f0b57d5b28 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -58,13 +58,6 @@ av_register_codec_parser(&ff_##x##_parser); \ } -#define REGISTER_BSF(X, x) \ - { \ - extern AVBitStreamFilter ff_##x##_bsf; \ - if (CONFIG_##X##_BSF) \ - av_register_bitstream_filter(&ff_##x##_bsf); \ - } - void avcodec_register_all(void) { static int initialized; @@ -536,18 +529,4 @@ void avcodec_register_all(void) REGISTER_PARSER(VORBIS, vorbis); REGISTER_PARSER(VP3, vp3); REGISTER_PARSER(VP8, vp8); - - /* bitstream filters */ - REGISTER_BSF(AAC_ADTSTOASC, aac_adtstoasc); - REGISTER_BSF(CHOMP, chomp); - REGISTER_BSF(DUMP_EXTRADATA, dump_extradata); - REGISTER_BSF(H264_MP4TOANNEXB, h264_mp4toannexb); - REGISTER_BSF(HEVC_MP4TOANNEXB, hevc_mp4toannexb); - REGISTER_BSF(IMX_DUMP_HEADER, imx_dump_header); - REGISTER_BSF(MJPEG2JPEG, mjpeg2jpeg); - REGISTER_BSF(MJPEGA_DUMP_HEADER, mjpega_dump_header); - REGISTER_BSF(MOV2TEXTSUB, mov2textsub); - REGISTER_BSF(NOISE, noise); - REGISTER_BSF(REMOVE_EXTRADATA, remove_extradata); - REGISTER_BSF(TEXT2MOVSUB, text2movsub); } diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 33de8ec409..0ff31a0b94 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -4692,35 +4692,221 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes); */ int av_get_audio_frame_duration2(AVCodecParameters *par, int frame_bytes); - +#if FF_API_OLD_BSF typedef struct AVBitStreamFilterContext { void *priv_data; struct AVBitStreamFilter *filter; AVCodecParserContext *parser; struct AVBitStreamFilterContext *next; } AVBitStreamFilterContext; +#endif + +typedef struct AVBSFInternal AVBSFInternal; + +/** + * The bitstream filter state. + * + * This struct must be allocated with av_bsf_alloc() and freed with + * av_bsf_free(). + * + * The fields in the struct will only be changed (by the caller or by the + * filter) as described in their documentation, and are to be considered + * immutable otherwise. + */ +typedef struct AVBSFContext { + /** + * A class for logging and AVOptions + */ + const AVClass *av_class; + + /** + * The bitstream filter this context is an instance of. + */ + const struct AVBitStreamFilter *filter; + + /** + * Opaque libavcodec internal data. Must not be touched by the caller in any + * way. + */ + AVBSFInternal *internal; + + /** + * Opaque filter-specific private data. If filter->priv_class is non-NULL, + * this is an AVOptions-enabled struct. + */ + void *priv_data; + + /** + * Parameters of the input stream. Set by the caller before av_bsf_init(). + */ + AVCodecParameters *par_in; + /** + * Parameters of the output stream. Set by the filter in av_bsf_init(). + */ + AVCodecParameters *par_out; + + /** + * The timebase used for the timestamps of the input packets. Set by the + * caller before av_bsf_init(). + */ + AVRational time_base_in; + + /** + * The timebase used for the timestamps of the output packets. Set by the + * filter in av_bsf_init(). + */ + AVRational time_base_out; +} AVBSFContext; typedef struct AVBitStreamFilter { const char *name; + + /** + * A list of codec ids supported by the filter, terminated by + * AV_CODEC_ID_NONE. + * May be NULL, in that case the bitstream filter works with any codec id. + */ + const enum AVCodecID *codec_ids; + + /** + * A class for the private data, used to declare bitstream filter private + * AVOptions. This field is NULL for bitstream filters that do not declare + * any options. + * + * If this field is non-NULL, the first member of the filter private data + * must be a pointer to AVClass, which will be set by libavcodec generic + * code to this class. + */ + const AVClass *priv_class; + + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavcodec and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + int priv_data_size; - int (*filter)(AVBitStreamFilterContext *bsfc, - AVCodecContext *avctx, const char *args, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, int keyframe); - void (*close)(AVBitStreamFilterContext *bsfc); - struct AVBitStreamFilter *next; + int (*init)(AVBSFContext *ctx); + int (*filter)(AVBSFContext *ctx, AVPacket *pkt); + void (*close)(AVBSFContext *ctx); } AVBitStreamFilter; +#if FF_API_OLD_BSF +/** + * @deprecated the old bitstream filtering API (using AVBitStreamFilterContext) + * is deprecated. Use the new bitstream filtering API (using AVBSFContext). + */ +attribute_deprecated void av_register_bitstream_filter(AVBitStreamFilter *bsf); +attribute_deprecated AVBitStreamFilterContext *av_bitstream_filter_init(const char *name); +attribute_deprecated int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size, int keyframe); +attribute_deprecated void av_bitstream_filter_close(AVBitStreamFilterContext *bsf); - +attribute_deprecated AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f); +#endif + +/** + * @return a bitstream filter with the specified name or NULL if no such + * bitstream filter exists. + */ +const AVBitStreamFilter *av_bsf_get_by_name(const char *name); + +/** + * Iterate over all registered bitstream filters. + * + * @param opaque a pointer where libavcodec will store the iteration state. Must + * point to NULL to start the iteration. + * + * @return the next registered bitstream filter or NULL when the iteration is + * finished + */ +const AVBitStreamFilter *av_bsf_next(void **opaque); + +/** + * Allocate a context for a given bitstream filter. The caller must fill in the + * context parameters as described in the documentation and then call + * av_bsf_init() before sending any data to the filter. + * + * @param filter the filter for which to allocate an instance. + * @param ctx a pointer into which the pointer to the newly-allocated context + * will be written. It must be freed with av_bsf_free() after the + * filtering is done. + * + * @return 0 on success, a negative AVERROR code on failure + */ +int av_bsf_alloc(const AVBitStreamFilter *filter, AVBSFContext **ctx); + +/** + * Prepare the filter for use, after all the parameters and options have been + * set. + */ +int av_bsf_init(AVBSFContext *ctx); + +/** + * Submit a packet for filtering. + * + * After sending each packet, the filter must be completely drained by calling + * av_bsf_receive_packet() repeatedly until it returns AVERROR(EAGAIN) or + * AVERROR_EOF. + * + * @param pkt the packet to filter. The bitstream filter will take ownership of + * the packet and reset the contents of pkt. pkt is not touched if an error occurs. + * This parameter may be NULL, which signals the end of the stream (i.e. no more + * packets will be sent). That will cause the filter to output any packets it + * may have buffered internally. + * + * @return 0 on success, a negative AVERROR on error. + */ +int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt); + +/** + * Retrieve a filtered packet. + * + * @param[out] pkt this struct will be filled with the contents of the filtered + * packet. It is owned by the caller and must be freed using + * av_packet_unref() when it is no longer needed. + * This parameter should be "clean" (i.e. freshly allocated + * with av_packet_alloc() or unreffed with av_packet_unref()) + * when this function is called. If this function returns + * successfully, the contents of pkt will be completely + * overwritten by the returned data. On failure, pkt is not + * touched. + * + * @return 0 on success. AVERROR(EAGAIN) if more packets need to be sent to the + * filter (using av_bsf_send_packet()) to get more output. AVERROR_EOF if there + * will be no further output from the filter. Another negative AVERROR value if + * an error occurs. + * + * @note one input packet may result in several output packets, so after sending + * a packet with av_bsf_send_packet(), this function needs to be called + * repeatedly until it stops returning 0. It is also possible for a filter to + * output fewer packets than were sent to it, so this function may return + * AVERROR(EAGAIN) immediately after a successful av_bsf_send_packet() call. + */ +int av_bsf_receive_packet(AVBSFContext *ctx, AVPacket *pkt); + +/** + * Free a bitstream filter context and everything associated with it; write NULL + * into the supplied pointer. + */ +void av_bsf_free(AVBSFContext **ctx); + +/** + * Get the AVClass for AVBSFContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *av_bsf_get_class(void); /* memory */ diff --git a/libavcodec/bitstream_filter.c b/libavcodec/bitstream_filter.c index 3b19bbdc76..ab608a99cd 100644 --- a/libavcodec/bitstream_filter.c +++ b/libavcodec/bitstream_filter.c @@ -21,56 +21,70 @@ #include #include "avcodec.h" + +#include "libavutil/internal.h" #include "libavutil/mem.h" -static AVBitStreamFilter *first_bitstream_filter = NULL; +#if FF_API_OLD_BSF +FF_DISABLE_DEPRECATION_WARNINGS AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f) { - if (f) - return f->next; - else - return first_bitstream_filter; + const AVBitStreamFilter *filter = NULL; + void *opaque = NULL; + + while (filter != f) + filter = av_bsf_next(&opaque); + + return av_bsf_next(&opaque); } void av_register_bitstream_filter(AVBitStreamFilter *bsf) { - bsf->next = first_bitstream_filter; - first_bitstream_filter = bsf; } +typedef struct BSFCompatContext { + AVBSFContext *ctx; +} BSFCompatContext; + AVBitStreamFilterContext *av_bitstream_filter_init(const char *name) { - AVBitStreamFilter *bsf = first_bitstream_filter; - - while (bsf) { - if (!strcmp(name, bsf->name)) { - AVBitStreamFilterContext *bsfc = - av_mallocz(sizeof(AVBitStreamFilterContext)); - if (!bsfc) - return NULL; - bsfc->filter = bsf; - bsfc->priv_data = NULL; - if (bsf->priv_data_size) { - bsfc->priv_data = av_mallocz(bsf->priv_data_size); - if (!bsfc->priv_data) { - av_freep(&bsfc); - return NULL; - } - } - return bsfc; - } - bsf = bsf->next; - } + AVBitStreamFilterContext *ctx = NULL; + BSFCompatContext *priv = NULL; + const AVBitStreamFilter *bsf; + + bsf = av_bsf_get_by_name(name); + if (!bsf) + return NULL; + + ctx = av_mallocz(sizeof(*ctx)); + if (!ctx) + return NULL; + + priv = av_mallocz(sizeof(*priv)); + if (!priv) + goto fail; + + + ctx->filter = bsf; + ctx->priv_data = priv; + + return ctx; + +fail: + if (priv) + av_bsf_free(&priv->ctx); + av_freep(&priv); + av_freep(&ctx); return NULL; } void av_bitstream_filter_close(AVBitStreamFilterContext *bsfc) { - if (bsfc->filter->close) - bsfc->filter->close(bsfc); + BSFCompatContext *priv = bsfc->priv_data; + + av_bsf_free(&priv->ctx); av_freep(&bsfc->priv_data); - av_parser_close(bsfc->parser); av_free(bsfc); } @@ -79,8 +93,71 @@ int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size, int keyframe) { - *poutbuf = (uint8_t *)buf; - *poutbuf_size = buf_size; - return bsfc->filter->filter(bsfc, avctx, args, poutbuf, poutbuf_size, - buf, buf_size, keyframe); + BSFCompatContext *priv = bsfc->priv_data; + AVPacket pkt = { 0 }; + int ret; + + if (!priv->ctx) { + ret = av_bsf_alloc(bsfc->filter, &priv->ctx); + if (ret < 0) + return ret; + + ret = avcodec_parameters_from_context(priv->ctx->par_in, avctx); + if (ret < 0) + return ret; + + priv->ctx->time_base_in = avctx->time_base; + + ret = av_bsf_init(priv->ctx); + if (ret < 0) + return ret; + + if (priv->ctx->par_out->extradata_size) { + av_freep(&avctx->extradata); + avctx->extradata_size = 0; + avctx->extradata = av_mallocz(priv->ctx->par_out->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) + return AVERROR(ENOMEM); + memcpy(avctx->extradata, priv->ctx->par_out->extradata, + priv->ctx->par_out->extradata_size); + avctx->extradata_size = priv->ctx->par_out->extradata_size; + } + } + + pkt.data = buf; + pkt.size = buf_size; + + ret = av_bsf_send_packet(priv->ctx, &pkt); + if (ret < 0) + return ret; + + *poutbuf = NULL; + *poutbuf_size = 0; + + ret = av_bsf_receive_packet(priv->ctx, &pkt); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + return 0; + else if (ret < 0) + return ret; + + *poutbuf = av_malloc(pkt.size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!*poutbuf) { + av_packet_unref(&pkt); + return AVERROR(ENOMEM); + } + + *poutbuf_size = pkt.size; + memcpy(*poutbuf, pkt.data, pkt.size); + + av_packet_unref(&pkt); + + /* drain all the remaining packets we cannot return */ + while (ret >= 0) { + ret = av_bsf_receive_packet(priv->ctx, &pkt); + av_packet_unref(&pkt); + } + + return 1; } +FF_ENABLE_DEPRECATION_WARNINGS +#endif diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c new file mode 100644 index 0000000000..897e1f8fa3 --- /dev/null +++ b/libavcodec/bitstream_filters.c @@ -0,0 +1,121 @@ +/* + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/common.h" +#include "libavutil/log.h" + +#include "avcodec.h" +#include "bsf.h" + +extern const AVBitStreamFilter ff_aac_adtstoasc_bsf; +extern const AVBitStreamFilter ff_chomp_bsf; +extern const AVBitStreamFilter ff_dump_extradata_bsf; +extern const AVBitStreamFilter ff_h264_mp4toannexb_bsf; +extern const AVBitStreamFilter ff_hevc_mp4toannexb_bsf; +extern const AVBitStreamFilter ff_imx_dump_header_bsf; +extern const AVBitStreamFilter ff_mjpeg2jpeg_bsf; +extern const AVBitStreamFilter ff_mjpega_dump_header_bsf; +extern const AVBitStreamFilter ff_mov2textsub_bsf; +extern const AVBitStreamFilter ff_text2movsub_bsf; +extern const AVBitStreamFilter ff_noise_bsf; +extern const AVBitStreamFilter ff_remove_extradata_bsf; + +static const AVBitStreamFilter *bitstream_filters[] = { +#if CONFIG_AAC_ADTSTOASC_BSF + &ff_aac_adtstoasc_bsf, +#endif +#if CONFIG_CHOMP_BSF + &ff_chomp_bsf, +#endif +#if CONFIG_DUMP_EXTRADATA_BSF + &ff_dump_extradata_bsf, +#endif +#if CONFIG_H264_MP4TOANNEXB_BSF + &ff_h264_mp4toannexb_bsf, +#endif +#if CONFIG_HEVC_MP4TOANNEXB_BSF + &ff_hevc_mp4toannexb_bsf, +#endif +#if CONFIG_IMX_DUMP_HEADER_BSF + &ff_imx_dump_header_bsf, +#endif +#if CONFIG_MJPEG2JPEG_BSF + &ff_mjpeg2jpeg_bsf, +#endif +#if CONFIG_MJPEGA_DUMP_HEADER_BSF + &ff_mjpeg2jpeg_bsf, +#endif +#if CONFIG_MOV2TEXTSUB_BSF + &ff_mov2textsub_bsf, +#endif +#if CONFIG_TEXT2MOVSUB_BSF + &ff_text2movsub_bsf, +#endif +#if CONFIG_NOISE_BSF + &ff_noise_bsf, +#endif +#if CONFIG_REMOVE_EXTRADATA_BSF + &ff_remove_extradata_bsf, +#endif + NULL, +}; + +const AVBitStreamFilter *av_bsf_next(void **opaque) +{ + uintptr_t i = (uintptr_t)*opaque; + const AVBitStreamFilter *f = bitstream_filters[i]; + + if (f) + *opaque = (void*)(i + 1); + + return f; +} + +const AVBitStreamFilter *av_bsf_get_by_name(const char *name) +{ + int i; + + for (i = 0; bitstream_filters[i]; i++) { + const AVBitStreamFilter *f = bitstream_filters[i]; + if (!strcmp(f->name, name)) + return f; + } + + return NULL; +} + +const AVClass *ff_bsf_child_class_next(const AVClass *prev) +{ + int i; + + /* find the filter that corresponds to prev */ + for (i = 0; prev && bitstream_filters[i]; i++) { + if (bitstream_filters[i]->priv_class == prev) { + i++; + break; + } + } + + /* find next filter with priv options */ + for (; bitstream_filters[i]; i++) + if (bitstream_filters[i]->priv_class) + return bitstream_filters[i]->priv_class; + return NULL; +} diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c new file mode 100644 index 0000000000..284c7c8044 --- /dev/null +++ b/libavcodec/bsf.c @@ -0,0 +1,219 @@ +/* + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/log.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" + +#include "avcodec.h" +#include "bsf.h" + +struct AVBSFInternal { + AVPacket *buffer_pkt; + int eof; +}; + +void av_bsf_free(AVBSFContext **pctx) +{ + AVBSFContext *ctx; + + if (!pctx || !*pctx) + return; + ctx = *pctx; + + if (ctx->filter->close) + ctx->filter->close(ctx); + if (ctx->filter->priv_class && ctx->priv_data) + av_opt_free(ctx->priv_data); + + av_opt_free(ctx); + + av_packet_free(&ctx->internal->buffer_pkt); + av_freep(&ctx->internal); + av_freep(&ctx->priv_data); + + avcodec_parameters_free(&ctx->par_in); + avcodec_parameters_free(&ctx->par_out); + + av_freep(pctx); +} + +static void *bsf_child_next(void *obj, void *prev) +{ + AVBSFContext *ctx = obj; + if (!prev && ctx->filter->priv_class) + return ctx->priv_data; + return NULL; +} + +static const AVClass bsf_class = { + .class_name = "AVBSFContext", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .child_next = bsf_child_next, + .child_class_next = ff_bsf_child_class_next, +}; + +const AVClass *av_bsf_get_class(void) +{ + return &bsf_class; +} + +int av_bsf_alloc(const AVBitStreamFilter *filter, AVBSFContext **pctx) +{ + AVBSFContext *ctx; + int ret; + + ctx = av_mallocz(sizeof(*ctx)); + if (!ctx) + return AVERROR(ENOMEM); + + ctx->av_class = &bsf_class; + ctx->filter = filter; + + ctx->par_in = avcodec_parameters_alloc(); + ctx->par_out = avcodec_parameters_alloc(); + if (!ctx->par_in || !ctx->par_out) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ctx->internal = av_mallocz(sizeof(*ctx->internal)); + if (!ctx->internal) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ctx->internal->buffer_pkt = av_packet_alloc(); + if (!ctx->internal->buffer_pkt) { + ret = AVERROR(ENOMEM); + goto fail; + } + + av_opt_set_defaults(ctx); + + /* allocate priv data and init private options */ + if (filter->priv_data_size) { + ctx->priv_data = av_mallocz(filter->priv_data_size); + if (!ctx->priv_data) { + ret = AVERROR(ENOMEM); + goto fail; + } + if (filter->priv_class) { + *(const AVClass **)ctx->priv_data = filter->priv_class; + av_opt_set_defaults(ctx->priv_data); + } + } + + *pctx = ctx; + return 0; +fail: + av_bsf_free(&ctx); + return ret; +} + +int av_bsf_init(AVBSFContext *ctx) +{ + int ret, i; + + /* check that the codec is supported */ + if (ctx->filter->codec_ids) { + for (i = 0; ctx->filter->codec_ids[i] != AV_CODEC_ID_NONE; i++) + if (ctx->par_in->codec_id == ctx->filter->codec_ids[i]) + break; + if (ctx->filter->codec_ids[i] == AV_CODEC_ID_NONE) { + const AVCodecDescriptor *desc = avcodec_descriptor_get(ctx->par_in->codec_id); + av_log(ctx, AV_LOG_ERROR, "Codec '%s' (%d) is not supported by the " + "bitstream filter '%s'. Supported codecs are: ", + desc ? desc->name : "unknown", ctx->par_in->codec_id, ctx->filter->name); + for (i = 0; ctx->filter->codec_ids[i] != AV_CODEC_ID_NONE; i++) { + desc = avcodec_descriptor_get(ctx->filter->codec_ids[i]); + av_log(ctx, AV_LOG_ERROR, "%s (%d) ", + desc ? desc->name : "unknown", ctx->filter->codec_ids[i]); + } + av_log(ctx, AV_LOG_ERROR, "\n"); + return AVERROR(EINVAL); + } + } + + /* initialize output parameters to be the same as input + * init below might overwrite that */ + ret = avcodec_parameters_copy(ctx->par_out, ctx->par_in); + if (ret < 0) + return ret; + + ctx->time_base_out = ctx->time_base_in; + + if (ctx->filter->init) { + ret = ctx->filter->init(ctx); + if (ret < 0) + return ret; + } + + return 0; +} + +int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt) +{ + if (!pkt || !pkt->data) { + ctx->internal->eof = 1; + return 0; + } + + if (ctx->internal->eof) { + av_log(ctx, AV_LOG_ERROR, "A non-NULL packet sent after an EOF.\n"); + return AVERROR(EINVAL); + } + + if (ctx->internal->buffer_pkt->data || + ctx->internal->buffer_pkt->side_data_elems) + return AVERROR(EAGAIN); + + av_packet_move_ref(ctx->internal->buffer_pkt, pkt); + + return 0; +} + +int av_bsf_receive_packet(AVBSFContext *ctx, AVPacket *pkt) +{ + return ctx->filter->filter(ctx, pkt); +} + +int ff_bsf_get_packet(AVBSFContext *ctx, AVPacket **pkt) +{ + AVBSFInternal *in = ctx->internal; + AVPacket *tmp_pkt; + + if (in->eof) + return AVERROR_EOF; + + if (!ctx->internal->buffer_pkt->data && + !ctx->internal->buffer_pkt->side_data_elems) + return AVERROR(EAGAIN); + + tmp_pkt = av_packet_alloc(); + if (!tmp_pkt) + return AVERROR(ENOMEM); + + *pkt = ctx->internal->buffer_pkt; + ctx->internal->buffer_pkt = tmp_pkt; + + return 0; +} diff --git a/libavcodec/bsf.h b/libavcodec/bsf.h new file mode 100644 index 0000000000..9e05f0b8ce --- /dev/null +++ b/libavcodec/bsf.h @@ -0,0 +1,33 @@ +/* + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_BSF_H +#define AVCODEC_BSF_H + +#include "avcodec.h" + +/** + * Called by the biststream filters to get the next packet for filtering. + * The filter is responsible for either freeing the packet or passing it to the + * caller. + */ +int ff_bsf_get_packet(AVBSFContext *ctx, AVPacket **pkt); + +const AVClass *ff_bsf_child_class_next(const AVClass *prev); + +#endif /* AVCODEC_BSF_H */ diff --git a/libavcodec/chomp_bsf.c b/libavcodec/chomp_bsf.c index 9ed7496930..2e7611335f 100644 --- a/libavcodec/chomp_bsf.c +++ b/libavcodec/chomp_bsf.c @@ -20,19 +20,23 @@ */ #include "avcodec.h" +#include "bsf.h" #include "internal.h" -static int chomp_filter(AVBitStreamFilterContext *bsfc, - AVCodecContext *avctx, const char *args, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, - int keyframe) +static int chomp_filter(AVBSFContext *ctx, AVPacket *out) { - while (buf_size > 0 && !buf[buf_size-1]) - buf_size--; + AVPacket *in; + int ret; - *poutbuf = (uint8_t*) buf; - *poutbuf_size = buf_size; + ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; + + while (in->size > 0 && !in->data[in->size - 1]) + in->size--; + + av_packet_move_ref(out, in); + av_packet_free(&in); return 0; } @@ -40,8 +44,7 @@ static int chomp_filter(AVBitStreamFilterContext *bsfc, /** * This filter removes a string of NULL bytes from the end of a packet. */ -AVBitStreamFilter ff_chomp_bsf = { - "chomp", - 0, - chomp_filter, +const AVBitStreamFilter ff_chomp_bsf = { + .name = "chomp", + .filter = chomp_filter, }; diff --git a/libavcodec/dump_extradata_bsf.c b/libavcodec/dump_extradata_bsf.c index 3f54899794..c960d6a233 100644 --- a/libavcodec/dump_extradata_bsf.c +++ b/libavcodec/dump_extradata_bsf.c @@ -21,35 +21,81 @@ #include #include "avcodec.h" +#include "bsf.h" + +#include "libavutil/log.h" #include "libavutil/mem.h" +#include "libavutil/opt.h" + +enum DumpFreq { + DUMP_FREQ_KEYFRAME, + DUMP_FREQ_ALL, +}; + +typedef struct DumpExtradataContext { + const AVClass *class; + int freq; +} DumpExtradataContext; + +static int dump_extradata(AVBSFContext *ctx, AVPacket *out) +{ + DumpExtradataContext *s = ctx->priv_data; + AVPacket *in; + int ret = 0; + + ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; + + if (ctx->par_in->extradata && + (s->freq == DUMP_FREQ_ALL || + (s->freq == DUMP_FREQ_KEYFRAME && in->flags & AV_PKT_FLAG_KEY))) { + if (in->size >= INT_MAX - ctx->par_in->extradata_size) { + ret = AVERROR(ERANGE); + goto fail; + } + ret = av_new_packet(out, in->size + ctx->par_in->extradata_size); + if (ret < 0) + goto fail; -static int dump_extradata(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, int keyframe){ - int cmd= args ? *args : 0; - /* cast to avoid warning about discarding qualifiers */ - if(avctx->extradata){ - if( (keyframe && (avctx->flags2 & AV_CODEC_FLAG2_LOCAL_HEADER) && cmd == 'a') - ||(keyframe && (cmd=='k' || !cmd)) - ||(cmd=='e') - /*||(? && (s->flags & PARSER_FLAG_DUMP_EXTRADATA_AT_BEGIN)*/){ - int size= buf_size + avctx->extradata_size; - *poutbuf_size= size; - *poutbuf= av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!*poutbuf) - return AVERROR(ENOMEM); - - memcpy(*poutbuf, avctx->extradata, avctx->extradata_size); - memcpy((*poutbuf) + avctx->extradata_size, buf, buf_size + AV_INPUT_BUFFER_PADDING_SIZE); - return 1; + ret = av_packet_copy_props(out, in); + if (ret < 0) { + av_packet_unref(out); + goto fail; } + + memcpy(out->data, ctx->par_in->extradata, ctx->par_in->extradata_size); + memcpy(out->data + ctx->par_in->extradata_size, in->data, in->size); + } else { + av_packet_move_ref(out, in); } - return 0; + +fail: + av_packet_free(&in); + + return ret; } -AVBitStreamFilter ff_dump_extradata_bsf={ - "dump_extra", - 0, - dump_extradata, +#define OFFSET(x) offsetof(DumpExtradataContext, x) +static const AVOption options[] = { + { "freq", "When do dump extradata", OFFSET(freq), AV_OPT_TYPE_INT, + { .i64 = DUMP_FREQ_KEYFRAME }, DUMP_FREQ_KEYFRAME, DUMP_FREQ_ALL, 0, "freq" }, + { "keyframe", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = DUMP_FREQ_KEYFRAME }, .unit = "freq" }, + { "all", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = DUMP_FREQ_ALL }, .unit = "freq" }, + { NULL }, +}; + +static const AVClass dump_extradata_class = { + .class_name = "dump_extradata bsf", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_MAJOR, +}; + +const AVBitStreamFilter ff_dump_extradata_bsf = { + .name = "dump_extra", + .priv_data_size = sizeof(DumpExtradataContext), + .priv_class = &dump_extradata_class, + .filter = dump_extradata, }; diff --git a/libavcodec/h264_mp4toannexb_bsf.c b/libavcodec/h264_mp4toannexb_bsf.c index eeb250f595..c1e2a28adc 100644 --- a/libavcodec/h264_mp4toannexb_bsf.c +++ b/libavcodec/h264_mp4toannexb_bsf.c @@ -23,7 +23,9 @@ #include "libavutil/intreadwrite.h" #include "libavutil/mem.h" + #include "avcodec.h" +#include "bsf.h" typedef struct H264BSFContext { uint8_t length_size; @@ -31,41 +33,39 @@ typedef struct H264BSFContext { int extradata_parsed; } H264BSFContext; -static int alloc_and_copy(uint8_t **poutbuf, int *poutbuf_size, +static int alloc_and_copy(AVPacket *out, const uint8_t *sps_pps, uint32_t sps_pps_size, const uint8_t *in, uint32_t in_size) { - uint32_t offset = *poutbuf_size; + uint32_t offset = out->size; uint8_t nal_header_size = offset ? 3 : 4; int err; - *poutbuf_size += sps_pps_size + in_size + nal_header_size; - if ((err = av_reallocp(poutbuf, - *poutbuf_size + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) { - *poutbuf_size = 0; + err = av_grow_packet(out, sps_pps_size + in_size + nal_header_size); + if (err < 0) return err; - } + if (sps_pps) - memcpy(*poutbuf + offset, sps_pps, sps_pps_size); - memcpy(*poutbuf + sps_pps_size + nal_header_size + offset, in, in_size); + memcpy(out->data + offset, sps_pps, sps_pps_size); + memcpy(out->data + sps_pps_size + nal_header_size + offset, in, in_size); if (!offset) { - AV_WB32(*poutbuf + sps_pps_size, 1); + AV_WB32(out->data + sps_pps_size, 1); } else { - (*poutbuf + offset + sps_pps_size)[0] = - (*poutbuf + offset + sps_pps_size)[1] = 0; - (*poutbuf + offset + sps_pps_size)[2] = 1; + (out->data + offset + sps_pps_size)[0] = + (out->data + offset + sps_pps_size)[1] = 0; + (out->data + offset + sps_pps_size)[2] = 1; } return 0; } -static int h264_extradata_to_annexb(AVCodecContext *avctx, const int padding) +static int h264_extradata_to_annexb(AVBSFContext *ctx, const int padding) { uint16_t unit_size; uint64_t total_size = 0; uint8_t *out = NULL, unit_nb, sps_done = 0, sps_seen = 0, pps_seen = 0; - const uint8_t *extradata = avctx->extradata + 4; + const uint8_t *extradata = ctx->par_in->extradata + 4; static const uint8_t nalu_header[4] = { 0, 0, 0, 1 }; int length_size = (*extradata++ & 0x3) + 1; // retrieve length coded size @@ -90,8 +90,8 @@ static int h264_extradata_to_annexb(AVCodecContext *avctx, const int padding) unit_size = AV_RB16(extradata); total_size += unit_size + 4; if (total_size > INT_MAX - padding || - extradata + 2 + unit_size > avctx->extradata + - avctx->extradata_size) { + extradata + 2 + unit_size > ctx->par_in->extradata + + ctx->par_in->extradata_size) { av_free(out); return AVERROR(EINVAL); } @@ -112,100 +112,125 @@ static int h264_extradata_to_annexb(AVCodecContext *avctx, const int padding) memset(out + total_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); if (!sps_seen) - av_log(avctx, AV_LOG_WARNING, + av_log(ctx, AV_LOG_WARNING, "Warning: SPS NALU missing or invalid. " "The resulting stream may not play.\n"); if (!pps_seen) - av_log(avctx, AV_LOG_WARNING, + av_log(ctx, AV_LOG_WARNING, "Warning: PPS NALU missing or invalid. " "The resulting stream may not play.\n"); - av_free(avctx->extradata); - avctx->extradata = out; - avctx->extradata_size = total_size; + av_freep(&ctx->par_out->extradata); + ctx->par_out->extradata = out; + ctx->par_out->extradata_size = total_size; return length_size; } -static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc, - AVCodecContext *avctx, const char *args, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, - int keyframe) +static int h264_mp4toannexb_init(AVBSFContext *ctx) { - H264BSFContext *ctx = bsfc->priv_data; + H264BSFContext *s = ctx->priv_data; + int ret; + + /* retrieve sps and pps NAL units from extradata */ + if (ctx->par_in->extradata_size >= 6) { + ret = h264_extradata_to_annexb(ctx, AV_INPUT_BUFFER_PADDING_SIZE); + if (ret < 0) + return ret; + + s->length_size = ret; + s->first_idr = 1; + s->extradata_parsed = 1; + } + + return 0; +} + +static int h264_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) +{ + H264BSFContext *s = ctx->priv_data; + + AVPacket *in; uint8_t unit_type; int32_t nal_size; uint32_t cumul_size = 0; - const uint8_t *buf_end = buf + buf_size; + const uint8_t *buf; + const uint8_t *buf_end; + int buf_size; int ret = 0; + ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; + /* nothing to filter */ - if (!avctx->extradata || avctx->extradata_size < 6) { - *poutbuf = (uint8_t *)buf; - *poutbuf_size = buf_size; + if (!s->extradata_parsed) { + av_packet_move_ref(out, in); + av_packet_free(&in); return 0; } - /* retrieve sps and pps NAL units from extradata */ - if (!ctx->extradata_parsed) { - ret = h264_extradata_to_annexb(avctx, AV_INPUT_BUFFER_PADDING_SIZE); - if (ret < 0) - return ret; - ctx->length_size = ret; - ctx->first_idr = 1; - ctx->extradata_parsed = 1; - } + buf = in->data; + buf_size = in->size; + buf_end = in->data + in->size; - *poutbuf_size = 0; - *poutbuf = NULL; do { - if (buf + ctx->length_size > buf_end) + if (buf + s->length_size > buf_end) goto fail; - if (ctx->length_size == 1) { + if (s->length_size == 1) { nal_size = buf[0]; - } else if (ctx->length_size == 2) { + } else if (s->length_size == 2) { nal_size = AV_RB16(buf); } else nal_size = AV_RB32(buf); - buf += ctx->length_size; + buf += s->length_size; unit_type = *buf & 0x1f; if (buf + nal_size > buf_end || nal_size < 0) goto fail; /* prepend only to the first type 5 NAL unit of an IDR picture */ - if (ctx->first_idr && unit_type == 5) { - if (alloc_and_copy(poutbuf, poutbuf_size, - avctx->extradata, avctx->extradata_size, + if (s->first_idr && unit_type == 5) { + if (alloc_and_copy(out, + ctx->par_out->extradata, ctx->par_out->extradata_size, buf, nal_size) < 0) goto fail; - ctx->first_idr = 0; + s->first_idr = 0; } else { - if (alloc_and_copy(poutbuf, poutbuf_size, + if (alloc_and_copy(out, NULL, 0, buf, nal_size) < 0) goto fail; - if (!ctx->first_idr && unit_type == 1) - ctx->first_idr = 1; + if (!s->first_idr && unit_type == 1) + s->first_idr = 1; } buf += nal_size; - cumul_size += nal_size + ctx->length_size; + cumul_size += nal_size + s->length_size; } while (cumul_size < buf_size); - return 1; + ret = av_packet_copy_props(out, in); + if (ret < 0) + goto fail; fail: - av_freep(poutbuf); - *poutbuf_size = 0; - return AVERROR(EINVAL); + if (ret < 0) + av_packet_unref(out); + av_packet_free(&in); + + return ret; } -AVBitStreamFilter ff_h264_mp4toannexb_bsf = { - "h264_mp4toannexb", - sizeof(H264BSFContext), - h264_mp4toannexb_filter, +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_H264, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_h264_mp4toannexb_bsf = { + .name = "h264_mp4toannexb", + .priv_data_size = sizeof(H264BSFContext), + .init = h264_mp4toannexb_init, + .filter = h264_mp4toannexb_filter, + .codec_ids = codec_ids, }; diff --git a/libavcodec/hevc_mp4toannexb_bsf.c b/libavcodec/hevc_mp4toannexb_bsf.c index dfecf5e99f..8d7ac58f19 100644 --- a/libavcodec/hevc_mp4toannexb_bsf.c +++ b/libavcodec/hevc_mp4toannexb_bsf.c @@ -25,6 +25,7 @@ #include "libavutil/mem.h" #include "avcodec.h" +#include "bsf.h" #include "bytestream.h" #include "hevc.h" @@ -33,11 +34,9 @@ typedef struct HEVCBSFContext { uint8_t length_size; int extradata_parsed; - - int logged_nonmp4_warning; } HEVCBSFContext; -static int hevc_extradata_to_annexb(AVCodecContext *avctx) +static int hevc_extradata_to_annexb(AVBSFContext *ctx) { GetByteContext gb; int length_size, num_arrays, i, j; @@ -46,7 +45,7 @@ static int hevc_extradata_to_annexb(AVCodecContext *avctx) uint8_t *new_extradata = NULL; size_t new_extradata_size = 0;; - bytestream2_init(&gb, avctx->extradata, avctx->extradata_size); + bytestream2_init(&gb, ctx->par_in->extradata, ctx->par_in->extradata_size); bytestream2_skip(&gb, 21); length_size = (bytestream2_get_byte(&gb) & 3) + 1; @@ -58,7 +57,7 @@ static int hevc_extradata_to_annexb(AVCodecContext *avctx) if (!(type == NAL_VPS || type == NAL_SPS || type == NAL_PPS || type == NAL_SEI_PREFIX || type == NAL_SEI_SUFFIX)) { - av_log(avctx, AV_LOG_ERROR, "Invalid NAL unit type in extradata: %d\n", + av_log(ctx, AV_LOG_ERROR, "Invalid NAL unit type in extradata: %d\n", type); ret = AVERROR_INVALIDDATA; goto fail; @@ -82,12 +81,12 @@ static int hevc_extradata_to_annexb(AVCodecContext *avctx) } } - av_freep(&avctx->extradata); - avctx->extradata = new_extradata; - avctx->extradata_size = new_extradata_size; + av_freep(&ctx->par_out->extradata); + ctx->par_out->extradata = new_extradata; + ctx->par_out->extradata_size = new_extradata_size; if (!new_extradata_size) - av_log(avctx, AV_LOG_WARNING, "No parameter sets in the extradata\n"); + av_log(ctx, AV_LOG_WARNING, "No parameter sets in the extradata\n"); return length_size; fail: @@ -95,52 +94,54 @@ fail: return ret; } -static int hevc_mp4toannexb_filter(AVBitStreamFilterContext *bsfc, - AVCodecContext *avctx, const char *args, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, - int keyframe) +static int hevc_mp4toannexb_init(AVBSFContext *ctx) { - HEVCBSFContext *ctx = bsfc->priv_data; + HEVCBSFContext *s = ctx->priv_data; + int ret; + + if (ctx->par_in->extradata_size < MIN_HEVCC_LENGTH || + AV_RB24(ctx->par_in->extradata) == 1 || + AV_RB32(ctx->par_in->extradata) == 1) { + av_log(ctx, AV_LOG_VERBOSE, + "The input looks like it is Annex B already\n"); + } else { + ret = hevc_extradata_to_annexb(ctx); + if (ret < 0) + return ret; + s->length_size = ret; + s->extradata_parsed = 1; + } + + return 0; +} + +static int hevc_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) +{ + HEVCBSFContext *s = ctx->priv_data; + AVPacket *in; GetByteContext gb; - uint8_t *out = NULL; - size_t out_size = 0; int got_irap = 0; int i, ret = 0; - if (!ctx->extradata_parsed) { - if (avctx->extradata_size < MIN_HEVCC_LENGTH || - AV_RB24(avctx->extradata) == 1 || - AV_RB32(avctx->extradata) == 1) { - if (!ctx->logged_nonmp4_warning) { - av_log(avctx, AV_LOG_VERBOSE, - "The input looks like it is Annex B already\n"); - ctx->logged_nonmp4_warning = 1; - } - *poutbuf = buf; - *poutbuf_size = buf_size; - return 0; - } + ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; - ret = hevc_extradata_to_annexb(avctx); - if (ret < 0) - return ret; - ctx->length_size = ret; - ctx->extradata_parsed = 1; + if (!s->extradata_parsed) { + av_packet_move_ref(out, in); + av_packet_free(&in); + return 0; } - *poutbuf_size = 0; - *poutbuf = NULL; - - bytestream2_init(&gb, buf, buf_size); + bytestream2_init(&gb, in->data, in->size); while (bytestream2_get_bytes_left(&gb)) { uint32_t nalu_size = 0; int nalu_type; - int is_irap, add_extradata, extra_size; + int is_irap, add_extradata, extra_size, prev_size; - for (i = 0; i < ctx->length_size; i++) + for (i = 0; i < s->length_size; i++) nalu_size = (nalu_size << 8) | bytestream2_get_byte(&gb); nalu_type = (bytestream2_peek_byte(&gb) >> 1) & 0x3f; @@ -148,39 +149,47 @@ static int hevc_mp4toannexb_filter(AVBitStreamFilterContext *bsfc, /* prepend extradata to IRAP frames */ is_irap = nalu_type >= 16 && nalu_type <= 23; add_extradata = is_irap && !got_irap; - extra_size = add_extradata * avctx->extradata_size; + extra_size = add_extradata * ctx->par_out->extradata_size; got_irap |= is_irap; - if (SIZE_MAX - out_size < 4 || - SIZE_MAX - out_size - 4 < nalu_size || - SIZE_MAX - out_size - 4 - nalu_size < extra_size) { + if (SIZE_MAX - nalu_size < 4 || + SIZE_MAX - 4 - nalu_size < extra_size) { ret = AVERROR_INVALIDDATA; goto fail; } - ret = av_reallocp(&out, out_size + 4 + nalu_size + extra_size); + prev_size = out->size; + + ret = av_grow_packet(out, 4 + nalu_size + extra_size); if (ret < 0) goto fail; if (add_extradata) - memcpy(out + out_size, avctx->extradata, extra_size); - AV_WB32(out + out_size + extra_size, 1); - bytestream2_get_buffer(&gb, out + out_size + 4 + extra_size, nalu_size); - out_size += 4 + nalu_size + extra_size; + memcpy(out->data + prev_size, ctx->par_out->extradata, extra_size); + AV_WB32(out->data + prev_size + extra_size, 1); + bytestream2_get_buffer(&gb, out->data + prev_size + 4 + extra_size, nalu_size); } - *poutbuf = out; - *poutbuf_size = out_size; - - return 1; + ret = av_packet_copy_props(out, in); + if (ret < 0) + goto fail; fail: - av_freep(&out); + if (ret < 0) + av_packet_unref(out); + av_packet_free(&in); + return ret; } -AVBitStreamFilter ff_hevc_mp4toannexb_bsf = { - "hevc_mp4toannexb", - sizeof(HEVCBSFContext), - hevc_mp4toannexb_filter, +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_HEVC, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_hevc_mp4toannexb_bsf = { + .name = "hevc_mp4toannexb", + .priv_data_size = sizeof(HEVCBSFContext), + .init = hevc_mp4toannexb_init, + .filter = hevc_mp4toannexb_filter, + .codec_ids = codec_ids, }; diff --git a/libavcodec/imx_dump_header_bsf.c b/libavcodec/imx_dump_header_bsf.c index a79039da33..71bda02356 100644 --- a/libavcodec/imx_dump_header_bsf.c +++ b/libavcodec/imx_dump_header_bsf.c @@ -26,36 +26,51 @@ */ #include "avcodec.h" +#include "bsf.h" #include "bytestream.h" -static int imx_dump_header(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, int keyframe) +static int imx_dump_header(AVBSFContext *ctx, AVPacket *out) { /* MXF essence element key */ static const uint8_t imx_header[16] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x05,0x01,0x01,0x00 }; - uint8_t *poutbufp; - - if (avctx->codec_id != AV_CODEC_ID_MPEG2VIDEO) { - av_log(avctx, AV_LOG_ERROR, "imx bitstream filter only applies to mpeg2video codec\n"); - return 0; - } - - *poutbuf = av_malloc(buf_size + 20 + AV_INPUT_BUFFER_PADDING_SIZE); - if (!*poutbuf) - return AVERROR(ENOMEM); - poutbufp = *poutbuf; - bytestream_put_buffer(&poutbufp, imx_header, 16); - bytestream_put_byte(&poutbufp, 0x83); /* KLV BER long form */ - bytestream_put_be24(&poutbufp, buf_size); - bytestream_put_buffer(&poutbufp, buf, buf_size); - *poutbuf_size = poutbufp - *poutbuf; - return 1; + + AVPacket *in; + int ret = 0; + uint8_t *out_buf; + + ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; + + ret = av_new_packet(out, in->size + 20); + if (ret < 0) + goto fail; + + out_buf = out->data; + + bytestream_put_buffer(&out_buf, imx_header, 16); + bytestream_put_byte(&out_buf, 0x83); /* KLV BER long form */ + bytestream_put_be24(&out_buf, in->size); + bytestream_put_buffer(&out_buf, in->data, in->size); + + ret = av_packet_copy_props(out, in); + if (ret < 0) + goto fail; + +fail: + if (ret < 0) + av_packet_unref(out); + av_packet_free(&in); + return ret; } -AVBitStreamFilter ff_imx_dump_header_bsf = { - "imxdump", - 0, - imx_dump_header, +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_MPEG2VIDEO, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_imx_dump_header_bsf = { + .name = "imxdump", + .filter = imx_dump_header, + .codec_ids = codec_ids, }; diff --git a/libavcodec/mjpeg2jpeg_bsf.c b/libavcodec/mjpeg2jpeg_bsf.c index d27793420e..eec3469d51 100644 --- a/libavcodec/mjpeg2jpeg_bsf.c +++ b/libavcodec/mjpeg2jpeg_bsf.c @@ -30,6 +30,7 @@ #include "libavutil/mem.h" #include "avcodec.h" +#include "bsf.h" #include "jpegtables.h" static const uint8_t jpeg_header[] = { @@ -75,42 +76,56 @@ static uint8_t *append_dht_segment(uint8_t *buf) return buf; } -static int mjpeg2jpeg_filter(AVBitStreamFilterContext *bsfc, - AVCodecContext *avctx, const char *args, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, - int keyframe) +static int mjpeg2jpeg_filter(AVBSFContext *ctx, AVPacket *out) { + AVPacket *in; + int ret = 0; int input_skip, output_size; - uint8_t *output, *out; + uint8_t *output; - if (buf_size < 12) { - av_log(avctx, AV_LOG_ERROR, "input is truncated\n"); - return AVERROR_INVALIDDATA; + ret = ff_bsf_get_packet(ctx, &in); + + if (in->size < 12) { + av_log(ctx, AV_LOG_ERROR, "input is truncated\n"); + ret = AVERROR_INVALIDDATA; + goto fail; } - if (memcmp("AVI1", buf + 6, 4)) { - av_log(avctx, AV_LOG_ERROR, "input is not MJPEG/AVI1\n"); - return AVERROR_INVALIDDATA; + if (memcmp("AVI1", in->data + 6, 4)) { + av_log(ctx, AV_LOG_ERROR, "input is not MJPEG/AVI1\n"); + ret = AVERROR_INVALIDDATA; + goto fail; } - input_skip = (buf[4] << 8) + buf[5] + 4; - if (buf_size < input_skip) { - av_log(avctx, AV_LOG_ERROR, "input is truncated\n"); - return AVERROR_INVALIDDATA; + + input_skip = (in->data[4] << 8) + in->data[5] + 4; + if (in->size < input_skip) { + av_log(ctx, AV_LOG_ERROR, "input is truncated\n"); + ret = AVERROR_INVALIDDATA; + goto fail; } - output_size = buf_size - input_skip + + output_size = in->size - input_skip + sizeof(jpeg_header) + dht_segment_size; - output = out = av_malloc(output_size); - if (!output) - return AVERROR(ENOMEM); - out = append(out, jpeg_header, sizeof(jpeg_header)); - out = append_dht_segment(out); - out = append(out, buf + input_skip, buf_size - input_skip); - *poutbuf = output; - *poutbuf_size = output_size; - return 1; + ret = av_new_packet(out, output_size); + if (ret < 0) + goto fail; + + output = out->data; + + output = append(output, jpeg_header, sizeof(jpeg_header)); + output = append_dht_segment(output); + output = append(output, in->data + input_skip, in->size - input_skip); + + ret = av_packet_copy_props(out, in); + if (ret < 0) + goto fail; + +fail: + if (ret < 0) + av_packet_unref(out); + av_packet_free(&in); + return ret; } -AVBitStreamFilter ff_mjpeg2jpeg_bsf = { +const AVBitStreamFilter ff_mjpeg2jpeg_bsf = { .name = "mjpeg2jpeg", .filter = mjpeg2jpeg_filter, }; diff --git a/libavcodec/mjpega_dump_header_bsf.c b/libavcodec/mjpega_dump_header_bsf.c index dfb8916dd9..b3ce26a664 100644 --- a/libavcodec/mjpega_dump_header_bsf.c +++ b/libavcodec/mjpega_dump_header_bsf.c @@ -26,71 +26,83 @@ */ #include "avcodec.h" +#include "bsf.h" #include "bytestream.h" #include "mjpeg.h" -static int mjpega_dump_header(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, int keyframe) +static int mjpega_dump_header(AVBSFContext *ctx, AVPacket *out) { - uint8_t *poutbufp; + AVPacket *in; + uint8_t *out_buf; unsigned dqt = 0, dht = 0, sof0 = 0; - int i; + int ret = 0, i; - if (avctx->codec_id != AV_CODEC_ID_MJPEG) { - av_log(avctx, AV_LOG_ERROR, "mjpega bitstream filter only applies to mjpeg codec\n"); - return 0; - } + ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; + + ret = av_new_packet(out, in->size + 44); + if (ret < 0) + goto fail; + + ret = av_packet_copy_props(out, in); + if (ret < 0) + goto fail; - *poutbuf_size = 0; - *poutbuf = av_malloc(buf_size + 44 + AV_INPUT_BUFFER_PADDING_SIZE); - if (!*poutbuf) - return AVERROR(ENOMEM); - poutbufp = *poutbuf; - bytestream_put_byte(&poutbufp, 0xff); - bytestream_put_byte(&poutbufp, SOI); - bytestream_put_byte(&poutbufp, 0xff); - bytestream_put_byte(&poutbufp, APP1); - bytestream_put_be16(&poutbufp, 42); /* size */ - bytestream_put_be32(&poutbufp, 0); - bytestream_put_buffer(&poutbufp, "mjpg", 4); - bytestream_put_be32(&poutbufp, buf_size + 44); /* field size */ - bytestream_put_be32(&poutbufp, buf_size + 44); /* pad field size */ - bytestream_put_be32(&poutbufp, 0); /* next ptr */ + out_buf = out->data; + bytestream_put_byte(&out_buf, 0xff); + bytestream_put_byte(&out_buf, SOI); + bytestream_put_byte(&out_buf, 0xff); + bytestream_put_byte(&out_buf, APP1); + bytestream_put_be16(&out_buf, 42); /* size */ + bytestream_put_be32(&out_buf, 0); + bytestream_put_buffer(&out_buf, "mjpg", 4); + bytestream_put_be32(&out_buf, in->size + 44); /* field size */ + bytestream_put_be32(&out_buf, in->size + 44); /* pad field size */ + bytestream_put_be32(&out_buf, 0); /* next ptr */ - for (i = 0; i < buf_size - 1; i++) { - if (buf[i] == 0xff) { - switch (buf[i + 1]) { + for (i = 0; i < in->size - 1; i++) { + if (in->data[i] == 0xff) { + switch (in->data[i + 1]) { case DQT: dqt = i + 46; break; case DHT: dht = i + 46; break; case SOF0: sof0 = i + 46; break; case SOS: - bytestream_put_be32(&poutbufp, dqt); /* quant off */ - bytestream_put_be32(&poutbufp, dht); /* huff off */ - bytestream_put_be32(&poutbufp, sof0); /* image off */ - bytestream_put_be32(&poutbufp, i + 46); /* scan off */ - bytestream_put_be32(&poutbufp, i + 46 + AV_RB16(buf + i + 2)); /* data off */ - bytestream_put_buffer(&poutbufp, buf + 2, buf_size - 2); /* skip already written SOI */ - *poutbuf_size = poutbufp - *poutbuf; - return 1; + bytestream_put_be32(&out_buf, dqt); /* quant off */ + bytestream_put_be32(&out_buf, dht); /* huff off */ + bytestream_put_be32(&out_buf, sof0); /* image off */ + bytestream_put_be32(&out_buf, i + 46); /* scan off */ + bytestream_put_be32(&out_buf, i + 46 + AV_RB16(in->data + i + 2)); /* data off */ + bytestream_put_buffer(&out_buf, in->data + 2, in->size - 2); /* skip already written SOI */ + + out->size = out_buf - out->data; + av_packet_free(&in); + return 0; case APP1: - if (i + 8 < buf_size && AV_RL32(buf + i + 8) == AV_RL32("mjpg")) { - av_log(avctx, AV_LOG_ERROR, "bitstream already formatted\n"); - memcpy(*poutbuf, buf, buf_size); - *poutbuf_size = buf_size; - return 1; + if (i + 8 < in->size && AV_RL32(in->data + i + 8) == AV_RL32("mjpg")) { + av_log(ctx, AV_LOG_ERROR, "bitstream already formatted\n"); + av_packet_unref(out); + av_packet_move_ref(out, in); + av_packet_free(&in); + return 0; } } } } - av_freep(poutbuf); - av_log(avctx, AV_LOG_ERROR, "could not find SOS marker in bitstream\n"); - return 0; + av_log(ctx, AV_LOG_ERROR, "could not find SOS marker in bitstream\n"); +fail: + av_packet_unref(out); + av_packet_free(&in); + return AVERROR_INVALIDDATA; } -AVBitStreamFilter ff_mjpega_dump_header_bsf = { - "mjpegadump", - 0, - mjpega_dump_header, +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_MJPEG, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_mjpega_dump_header_bsf = { + .name = "mjpegadump", + .filter = mjpega_dump_header, + .codec_ids = codec_ids, }; diff --git a/libavcodec/movsub_bsf.c b/libavcodec/movsub_bsf.c index 0484303840..fc6b2365e9 100644 --- a/libavcodec/movsub_bsf.c +++ b/libavcodec/movsub_bsf.c @@ -21,41 +21,79 @@ #include "libavutil/common.h" #include "libavutil/intreadwrite.h" #include "avcodec.h" +#include "bsf.h" +static int text2movsub(AVBSFContext *ctx, AVPacket *out) +{ + AVPacket *in; + int ret = 0; -static int text2movsub(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, int keyframe){ - if (buf_size > 0xffff) return 0; - *poutbuf_size = buf_size + 2; - *poutbuf = av_malloc(*poutbuf_size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!*poutbuf) - return AVERROR(ENOMEM); - AV_WB16(*poutbuf, buf_size); - memcpy(*poutbuf + 2, buf, buf_size); - return 1; + ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; + + if (in->size > 0xffff) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + ret = av_new_packet(out, in->size + 2); + if (ret < 0) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = av_packet_copy_props(out, in); + if (ret < 0) + goto fail; + + AV_WB16(out->data, in->size); + memcpy(out->data + 2, in->data, in->size); + +fail: + if (ret < 0) + av_packet_unref(out); + av_packet_free(&in); + return ret; } -AVBitStreamFilter ff_text2movsub_bsf={ - "text2movsub", - 0, - text2movsub, +const AVBitStreamFilter ff_text2movsub_bsf = { + .name = "text2movsub", + .filter = text2movsub, }; -static int mov2textsub(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, int keyframe){ - if (buf_size < 2) return 0; - *poutbuf_size = FFMIN(buf_size - 2, AV_RB16(buf)); - *poutbuf = av_malloc(*poutbuf_size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!*poutbuf) - return AVERROR(ENOMEM); - memcpy(*poutbuf, buf + 2, *poutbuf_size); - return 1; +static int mov2textsub(AVBSFContext *ctx, AVPacket *out) +{ + AVPacket *in; + int ret = 0; + + ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; + + if (in->size < 2) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + ret = av_new_packet(out, FFMIN(in->size - 2, AV_RB16(in->data))); + if (ret < 0) + goto fail; + + ret = av_packet_copy_props(out, in); + if (ret < 0) + goto fail; + + memcpy(out->data, in->data + 2, out->size); + +fail: + if (ret < 0) + av_packet_unref(out); + av_packet_free(&in); + return ret; } -AVBitStreamFilter ff_mov2textsub_bsf={ - "mov2textsub", - 0, - mov2textsub, +const AVBitStreamFilter ff_mov2textsub_bsf = { + .name = "mov2textsub", + .filter = mov2textsub, }; diff --git a/libavcodec/noise_bsf.c b/libavcodec/noise_bsf.c index 81840bd07b..3b41dbffc8 100644 --- a/libavcodec/noise_bsf.c +++ b/libavcodec/noise_bsf.c @@ -22,30 +22,67 @@ #include #include "avcodec.h" +#include "bsf.h" + +#include "libavutil/log.h" #include "libavutil/mem.h" +#include "libavutil/opt.h" + +typedef struct NoiseContext { + const AVClass *class; + int amount; + unsigned int state; +} NoiseContext; + +static int noise(AVBSFContext *ctx, AVPacket *out) +{ + NoiseContext *s = ctx->priv_data; + AVPacket *in; + int amount = s->amount > 0 ? s->amount : (s->state % 10001 + 1); + int i, ret = 0; + + ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; + + ret = av_new_packet(out, in->size); + if (ret < 0) + goto fail; + ret = av_packet_copy_props(out, in); + if (ret < 0) + goto fail; -static int noise(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, int keyframe){ - unsigned int *state= bsfc->priv_data; - int amount= args ? atoi(args) : (*state % 10001+1); - int i; - - *poutbuf= av_malloc(buf_size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!*poutbuf) - return AVERROR(ENOMEM); - memcpy(*poutbuf, buf, buf_size + AV_INPUT_BUFFER_PADDING_SIZE); - for(i=0; idata, in->data, in->size); + + for (i = 0; i < out->size; i++) { + s->state += out->data[i] + 1; + if (s->state % amount == 0) + out->data[i] = s->state; } - return 1; +fail: + if (ret < 0) + av_packet_unref(out); + av_packet_free(&in); + return ret; } -AVBitStreamFilter ff_noise_bsf={ - "noise", - sizeof(int), - noise, +#define OFFSET(x) offsetof(NoiseContext, x) +static const AVOption options[] = { + { "amount", NULL, OFFSET(amount), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX }, + { NULL }, +}; + +static const AVClass noise_class = { + .class_name = "noise", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const AVBitStreamFilter ff_noise_bsf = { + .name = "noise", + .priv_data_size = sizeof(int), + .priv_class = &noise_class, + .filter = noise, }; diff --git a/libavcodec/remove_extradata_bsf.c b/libavcodec/remove_extradata_bsf.c index b82c867f43..a89fa06e61 100644 --- a/libavcodec/remove_extradata_bsf.c +++ b/libavcodec/remove_extradata_bsf.c @@ -18,39 +18,99 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/log.h" +#include "libavutil/opt.h" + #include "avcodec.h" +#include "bsf.h" +enum RemoveFreq { + REMOVE_FREQ_KEYFRAME, + REMOVE_FREQ_ALL, +}; -static int remove_extradata(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, int keyframe){ - int cmd= args ? *args : 0; - AVCodecParserContext *s; +typedef struct RemoveExtradataContext { + const AVClass *class; + int freq; - if(!bsfc->parser){ - bsfc->parser= av_parser_init(avctx->codec_id); - } - s= bsfc->parser; - - if(s && s->parser->split){ - if( (((avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) || - (avctx->flags2 & AV_CODEC_FLAG2_LOCAL_HEADER)) && cmd == 'a') - ||(!keyframe && cmd=='k') - ||(cmd=='e' || !cmd) - ){ - int i= s->parser->split(avctx, buf, buf_size); - buf += i; - buf_size -= i; + AVCodecParserContext *parser; + AVCodecContext *avctx; +} RemoveExtradataContext; + +static int remove_extradata(AVBSFContext *ctx, AVPacket *out) +{ + RemoveExtradataContext *s = ctx->priv_data; + + AVPacket *in; + int ret; + + ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; + + if (s->parser && s->parser->parser->split) { + if (s->freq == REMOVE_FREQ_ALL || + (s->freq == REMOVE_FREQ_KEYFRAME && in->flags & AV_PKT_FLAG_KEY)) { + int i = s->parser->parser->split(s->avctx, in->data, in->size); + in->data += i; + in->size -= i; } } - *poutbuf= (uint8_t *) buf; - *poutbuf_size= buf_size; + + av_packet_move_ref(out, in); + av_packet_free(&in); return 0; } -AVBitStreamFilter ff_remove_extradata_bsf={ - "remove_extra", - 0, - remove_extradata, +static int remove_extradata_init(AVBSFContext *ctx) +{ + RemoveExtradataContext *s = ctx->priv_data; + int ret; + + s->parser = av_parser_init(ctx->par_in->codec_id); + + if (s->parser) { + s->avctx = avcodec_alloc_context3(NULL); + if (!s->avctx) + return AVERROR(ENOMEM); + + ret = avcodec_parameters_to_context(s->avctx, ctx->par_in); + if (ret < 0) + return ret; + } + + return 0; +} + +static void remove_extradata_close(AVBSFContext *ctx) +{ + RemoveExtradataContext *s = ctx->priv_data; + + avcodec_free_context(&s->avctx); + av_parser_close(s->parser); +} + +#define OFFSET(x) offsetof(RemoveExtradataContext, x) +static const AVOption options[] = { + { "freq", NULL, OFFSET(freq), AV_OPT_TYPE_INT, { .i64 = REMOVE_FREQ_KEYFRAME }, REMOVE_FREQ_KEYFRAME, REMOVE_FREQ_ALL, 0, "freq" }, + { "keyframe", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_KEYFRAME }, .unit = "freq" }, + { "all", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_ALL }, .unit = "freq" }, + { NULL }, +}; + +static const AVClass remove_extradata_class = { + .class_name = "remove_extradata", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const AVBitStreamFilter ff_remove_extradata_bsf = { + .name = "remove_extra", + .priv_data_size = sizeof(RemoveExtradataContext), + .priv_class = &remove_extradata_class, + .init = remove_extradata_init, + .close = remove_extradata_close, + .filter = remove_extradata, }; diff --git a/libavcodec/version.h b/libavcodec/version.h index d247c098ce..d5045fb2ca 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -28,7 +28,7 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 57 -#define LIBAVCODEC_VERSION_MINOR 14 +#define LIBAVCODEC_VERSION_MINOR 15 #define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ @@ -197,5 +197,8 @@ #ifndef FF_API_PRIVATE_OPT #define FF_API_PRIVATE_OPT (LIBAVCODEC_VERSION_MAJOR < 59) #endif +#ifndef FF_API_OLD_BSF +#define FF_API_OLD_BSF (LIBAVCODEC_VERSION_MAJOR < 59) +#endif #endif /* AVCODEC_VERSION_H */ -- cgit v1.2.3