diff options
author | Derek Buitenhuis <derek.buitenhuis@gmail.com> | 2016-04-17 18:47:25 +0100 |
---|---|---|
committer | Derek Buitenhuis <derek.buitenhuis@gmail.com> | 2016-04-17 18:47:40 +0100 |
commit | af9cac1be1750ecc0e12c6788a3aeed1f1a778be (patch) | |
tree | 2e34226dbd4010774f6ffef448aab4b7d4f88544 /libavcodec | |
parent | 6d160afab2fa8d3bfb216fee96d3537ffc9e86e8 (diff) | |
parent | 33d18982fa03feb061c8f744a4f0a9175c1f63ab (diff) | |
download | ffmpeg-af9cac1be1750ecc0e12c6788a3aeed1f1a778be.tar.gz |
Merge commit '33d18982fa03feb061c8f744a4f0a9175c1f63ab'
* commit '33d18982fa03feb061c8f744a4f0a9175c1f63ab':
lavc: add a new bitstream filtering API
Conversions-by: Hendrik Leppkes <h.leppkes@gmail.com>
Conversions-by: Derek Buitenguis <derek.buitenhuis@gmail.com>
Merged-by: Derek Buitenhuis <derek.buitenhuis@gmail.com>
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/Makefile | 2 | ||||
-rw-r--r-- | libavcodec/aac_adtstoasc_bsf.c | 100 | ||||
-rw-r--r-- | libavcodec/allcodecs.c | 25 | ||||
-rw-r--r-- | libavcodec/avcodec.h | 197 | ||||
-rw-r--r-- | libavcodec/bitstream_filter.c | 155 | ||||
-rw-r--r-- | libavcodec/bitstream_filters.c | 137 | ||||
-rw-r--r-- | libavcodec/bsf.c | 219 | ||||
-rw-r--r-- | libavcodec/bsf.h | 33 | ||||
-rw-r--r-- | libavcodec/chomp_bsf.c | 24 | ||||
-rw-r--r-- | libavcodec/dca_core_bsf.c | 36 | ||||
-rw-r--r-- | libavcodec/dump_extradata_bsf.c | 93 | ||||
-rw-r--r-- | libavcodec/h264_mp4toannexb_bsf.c | 222 | ||||
-rw-r--r-- | libavcodec/hevc_mp4toannexb_bsf.c | 151 | ||||
-rw-r--r-- | libavcodec/imx_dump_header_bsf.c | 62 | ||||
-rw-r--r-- | libavcodec/mjpeg2jpeg_bsf.c | 75 | ||||
-rw-r--r-- | libavcodec/mjpega_dump_header_bsf.c | 105 | ||||
-rw-r--r-- | libavcodec/movsub_bsf.c | 86 | ||||
-rw-r--r-- | libavcodec/mp3_header_decompress_bsf.c | 73 | ||||
-rw-r--r-- | libavcodec/mpeg4_unpack_bframes_bsf.c | 131 | ||||
-rw-r--r-- | libavcodec/noise_bsf.c | 70 | ||||
-rw-r--r-- | libavcodec/remove_extradata_bsf.c | 109 | ||||
-rw-r--r-- | libavcodec/version.h | 7 | ||||
-rw-r--r-- | libavcodec/vp9_superframe_bsf.c | 120 |
23 files changed, 1580 insertions, 652 deletions
diff --git a/libavcodec/Makefile b/libavcodec/Makefile index ec4144631a..6a2450ed28 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -26,6 +26,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 9c117c6005..48889fc48e 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,68 +35,75 @@ 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; } - av_free(avctx->extradata); - avctx->extradata_size = 2 + pce_size; - avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!avctx->extradata) { - avctx->extradata_size = 0; - return AVERROR(ENOMEM); + + extradata = av_mallocz(2 + pce_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!extradata) { + ret = AVERROR(ENOMEM); + goto fail; } - init_put_bits(&pb, avctx->extradata, avctx->extradata_size); + 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); @@ -104,20 +112,44 @@ 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); } + bsfc->par_out->extradata = extradata; + bsfc->par_out->extradata_size = 2 + 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; } -AVBitStreamFilter ff_aac_adtstoasc_bsf = { +static int aac_adtstoasc_init(AVBSFContext *ctx) +{ + av_freep(&ctx->par_out->extradata); + ctx->par_out->extradata_size = 0; + + return 0; +} + +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 3214e35e08..f88c0ff9e1 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; @@ -667,22 +660,4 @@ void avcodec_register_all(void) REGISTER_PARSER(VP3, vp3); REGISTER_PARSER(VP8, vp8); REGISTER_PARSER(VP9, vp9); - - /* bitstream filters */ - REGISTER_BSF(AAC_ADTSTOASC, aac_adtstoasc); - REGISTER_BSF(CHOMP, chomp); - REGISTER_BSF(DUMP_EXTRADATA, dump_extradata); - REGISTER_BSF(DCA_CORE, dca_core); - 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(MP3_HEADER_DECOMPRESS, mp3_header_decompress); - REGISTER_BSF(MPEG4_UNPACK_BFRAMES, mpeg4_unpack_bframes); - REGISTER_BSF(MOV2TEXTSUB, mov2textsub); - REGISTER_BSF(NOISE, noise); - REGISTER_BSF(REMOVE_EXTRADATA, remove_extradata); - REGISTER_BSF(TEXT2MOVSUB, text2movsub); - REGISTER_BSF(VP9_SUPERFRAME, vp9_superframe); } diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 784b1c1284..9a8a0f0cc1 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -5386,7 +5386,7 @@ 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; @@ -5398,19 +5398,102 @@ typedef struct AVBitStreamFilterContext { */ char *args; } 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 /** * Register a bitstream filter. * @@ -5420,6 +5503,7 @@ typedef struct AVBitStreamFilter { * * @see avcodec_register_all() */ +attribute_deprecated void av_register_bitstream_filter(AVBitStreamFilter *bsf); /** @@ -5432,6 +5516,7 @@ void av_register_bitstream_filter(AVBitStreamFilter *bsf); * @return a bitstream filter context if a matching filter was found * and successfully initialized, NULL otherwise */ +attribute_deprecated AVBitStreamFilterContext *av_bitstream_filter_init(const char *name); /** @@ -5463,6 +5548,7 @@ AVBitStreamFilterContext *av_bitstream_filter_init(const char *name); * its starting address). A special case is if *poutbuf was set to NULL and * *poutbuf_size was set to 0, which indicates the packet should be dropped. */ +attribute_deprecated int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, uint8_t **poutbuf, int *poutbuf_size, @@ -5474,6 +5560,7 @@ int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, * @param bsf the bitstream filter context created with * av_bitstream_filter_init(), can be NULL */ +attribute_deprecated void av_bitstream_filter_close(AVBitStreamFilterContext *bsf); /** @@ -5484,7 +5571,103 @@ void av_bitstream_filter_close(AVBitStreamFilterContext *bsf); * This function can be used to iterate over all registered bitstream * filters. */ +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 fb690b6821..d9bafbe432 100644 --- a/libavcodec/bitstream_filter.c +++ b/libavcodec/bitstream_filter.c @@ -22,59 +22,75 @@ #include "avcodec.h" #include "libavutil/atomic.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) { - do { - bsf->next = first_bitstream_filter; - } while(bsf->next != avpriv_atomic_ptr_cas((void * volatile *)&first_bitstream_filter, bsf->next, bsf)); } +typedef struct BSFCompatContext { + AVBSFContext *ctx; + int extradata_updated; +} BSFCompatContext; + AVBitStreamFilterContext *av_bitstream_filter_init(const char *name) { - AVBitStreamFilter *bsf = NULL; - - while (bsf = av_bitstream_filter_next(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; - } - } + 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) { + BSFCompatContext *priv; + if (!bsfc) return; - if (bsfc->filter->close) - bsfc->filter->close(bsfc); + + priv = bsfc->priv_data; + + av_bsf_free(&priv->ctx); av_freep(&bsfc->priv_data); - av_freep(&bsfc->args); - av_parser_close(bsfc->parser); av_free(bsfc); } @@ -83,8 +99,75 @@ 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 ? args : bsfc->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; + } + + 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); + } + + if (!priv->extradata_updated) { + /* update extradata in avctx from the output codec parameters */ + if (priv->ctx->par_out->extradata_size && (!args || !strstr(args, "private_spspps_buf"))) { + 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; + } + + priv->extradata_updated = 1; + } + + 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..51f3cd9799 --- /dev/null +++ b/libavcodec/bitstream_filters.c @@ -0,0 +1,137 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; 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_dca_core_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_mp3_header_decompress_bsf; +extern const AVBitStreamFilter ff_mpeg4_unpack_bframes_bsf; +extern const AVBitStreamFilter ff_mov2textsub_bsf; +extern const AVBitStreamFilter ff_noise_bsf; +extern const AVBitStreamFilter ff_remove_extradata_bsf; +extern const AVBitStreamFilter ff_text2movsub_bsf; +extern const AVBitStreamFilter ff_vp9_superframe_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_DCA_CORE_BSF + &ff_dca_core_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_mjpega_dump_header_bsf, +#endif +#if CONFIG_MP3_HEADER_DECOMPRESS_BSF + &ff_mp3_header_decompress_bsf, +#endif +#if CONFIG_MPEG4_UNPACK_BFRAMES_BSF + &ff_mpeg4_unpack_bframes_bsf, +#endif +#if CONFIG_MOV2TEXTSUB_BSF + &ff_mov2textsub_bsf, +#endif +#if CONFIG_NOISE_BSF + &ff_noise_bsf, +#endif +#if CONFIG_REMOVE_EXTRADATA_BSF + &ff_remove_extradata_bsf, +#endif +#if CONFIG_TEXT2MOVSUB_BSF + &ff_text2movsub_bsf, +#endif +#if CONFIG_VP9_SUPERFRAME_BSF + &ff_vp9_superframe_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..88b7f29fe5 --- /dev/null +++ b/libavcodec/bsf.c @@ -0,0 +1,219 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> + +#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..0ca64a78f0 --- /dev/null +++ b/libavcodec/bsf.h @@ -0,0 +1,33 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; 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 2b93fa999e..cc94380535 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,7 +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 = { +const AVBitStreamFilter ff_chomp_bsf = { .name = "chomp", .filter = chomp_filter, }; diff --git a/libavcodec/dca_core_bsf.c b/libavcodec/dca_core_bsf.c index 7d372369ef..9edc0cfd61 100644 --- a/libavcodec/dca_core_bsf.c +++ b/libavcodec/dca_core_bsf.c @@ -19,21 +19,23 @@ */ #include "avcodec.h" +#include "bsf.h" #include "bytestream.h" #include "dca_syncwords.h" #include "libavutil/mem.h" -static int dca_core(AVBitStreamFilterContext *bsfc, - AVCodecContext *avctx, const char *args, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, - int keyframe) +static int dca_core_filter(AVBSFContext *ctx, AVPacket *out) { + AVPacket *in; GetByteContext gb; uint32_t syncword; - int core_size = 0; + int core_size = 0, ret; - bytestream2_init(&gb, buf, buf_size); + ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; + + bytestream2_init(&gb, in->data, in->size); syncword = bytestream2_get_be32(&gb); bytestream2_skip(&gb, 1); @@ -43,18 +45,22 @@ static int dca_core(AVBitStreamFilterContext *bsfc, break; } - *poutbuf = (uint8_t *)buf; + av_packet_move_ref(out, in); + av_packet_free(&in); - if (core_size > 0 && core_size <= buf_size) { - *poutbuf_size = core_size; - } else { - *poutbuf_size = buf_size; + if (core_size > 0 && core_size <= out->size) { + out->size = core_size; } return 0; } -AVBitStreamFilter ff_dca_core_bsf = { - .name = "dca_core", - .filter = dca_core, +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_DTS, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_dca_core_bsf = { + .name = "dca_core", + .filter = dca_core_filter, + .codec_ids = codec_ids, }; diff --git a/libavcodec/dump_extradata_bsf.c b/libavcodec/dump_extradata_bsf.c index 08c422704d..1f91e21112 100644 --- a/libavcodec/dump_extradata_bsf.c +++ b/libavcodec/dump_extradata_bsf.c @@ -21,34 +21,81 @@ #include <string.h> #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={ - .name = "dump_extra", - .filter = 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 2d447f7550..828bf1845e 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 { int32_t sps_offset; @@ -33,66 +35,53 @@ typedef struct H264BSFContext { uint8_t idr_sps_seen; uint8_t idr_pps_seen; int extradata_parsed; - - /* When private_spspps is zero then spspps_buf points to global extradata - and bsf does replace a global extradata to own-allocated version (default - behaviour). - When private_spspps is non-zero the bsf uses a private version of spspps buf. - This mode necessary when bsf uses in decoder, else bsf has issues after - decoder re-initialization. Use the "private_spspps_buf" argument to - activate this mode. - */ - int private_spspps; - uint8_t *spspps_buf; - uint32_t spspps_size; } 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(H264BSFContext *ctx, AVCodecContext *avctx, const int padding) +static int h264_extradata_to_annexb(AVBSFContext *ctx, const int padding) { + H264BSFContext *s = ctx->priv_data; 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 - ctx->sps_offset = ctx->pps_offset = -1; + s->sps_offset = s->pps_offset = -1; /* retrieve sps and pps unit(s) */ unit_nb = *extradata++ & 0x1f; /* number of sps unit(s) */ if (!unit_nb) { goto pps; } else { - ctx->sps_offset = 0; + s->sps_offset = 0; sps_seen = 1; } @@ -102,13 +91,13 @@ static int h264_extradata_to_annexb(H264BSFContext *ctx, AVCodecContext *avctx, unit_size = AV_RB16(extradata); total_size += unit_size + 4; if (total_size > INT_MAX - padding) { - av_log(avctx, AV_LOG_ERROR, + av_log(ctx, AV_LOG_ERROR, "Too big extradata size, corrupted stream or invalid MP4/AVCC bitstream\n"); av_free(out); return AVERROR(EINVAL); } - if (extradata + 2 + unit_size > avctx->extradata + avctx->extradata_size) { - av_log(avctx, AV_LOG_ERROR, "Packet header is not contained in global extradata, " + if (extradata + 2 + unit_size > ctx->par_in->extradata + ctx->par_in->extradata_size) { + av_log(ctx, AV_LOG_ERROR, "Packet header is not contained in global extradata, " "corrupted stream or invalid MP4/AVCC bitstream\n"); av_free(out); return AVERROR(EINVAL); @@ -122,7 +111,7 @@ pps: if (!unit_nb && !sps_done++) { unit_nb = *extradata++; /* number of pps unit(s) */ if (unit_nb) { - ctx->pps_offset = total_size; + s->pps_offset = total_size; pps_seen = 1; } } @@ -132,93 +121,100 @@ pps: memset(out + total_size, 0, padding); 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"); - if (!ctx->private_spspps) { - av_free(avctx->extradata); - avctx->extradata = out; - avctx->extradata_size = total_size; - } - ctx->spspps_buf = out; - ctx->spspps_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; - int i; + 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->new_idr = 1; + s->idr_sps_seen = 0; + s->idr_pps_seen = 0; + 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; - int ret = 0; + const uint8_t *buf; + const uint8_t *buf_end; + int buf_size; + int ret = 0, i; + + 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) { - if (args && strstr(args, "private_spspps_buf")) - ctx->private_spspps = 1; + buf = in->data; + buf_size = in->size; + buf_end = in->data + in->size; - ret = h264_extradata_to_annexb(ctx, avctx, AV_INPUT_BUFFER_PADDING_SIZE); - if (ret < 0) - return ret; - ctx->length_size = ret; - ctx->new_idr = 1; - ctx->idr_sps_seen = 0; - ctx->idr_pps_seen = 0; - ctx->extradata_parsed = 1; - } - - *poutbuf_size = 0; - *poutbuf = NULL; do { ret= AVERROR(EINVAL); - if (buf + ctx->length_size > buf_end) + if (buf + s->length_size > buf_end) goto fail; - for (nal_size = 0, i = 0; i<ctx->length_size; i++) + for (nal_size = 0, i = 0; i<s->length_size; i++) nal_size = (nal_size << 8) | buf[i]; - buf += ctx->length_size; + buf += s->length_size; unit_type = *buf & 0x1f; if (nal_size > buf_end - buf || nal_size < 0) goto fail; if (unit_type == 7) - ctx->idr_sps_seen = ctx->new_idr = 1; + s->idr_sps_seen = s->new_idr = 1; else if (unit_type == 8) { - ctx->idr_pps_seen = ctx->new_idr = 1; + s->idr_pps_seen = s->new_idr = 1; /* if SPS has not been seen yet, prepend the AVCC one to PPS */ - if (!ctx->idr_sps_seen) { - if (ctx->sps_offset == -1) - av_log(avctx, AV_LOG_WARNING, "SPS not present in the stream, nor in AVCC, stream may be unreadable\n"); + if (!s->idr_sps_seen) { + if (s->sps_offset == -1) + av_log(ctx, AV_LOG_WARNING, "SPS not present in the stream, nor in AVCC, stream may be unreadable\n"); else { - if ((ret = alloc_and_copy(poutbuf, poutbuf_size, - ctx->spspps_buf + ctx->sps_offset, - ctx->pps_offset != -1 ? ctx->pps_offset : ctx->spspps_size - ctx->sps_offset, + if ((ret = alloc_and_copy(out, + ctx->par_out->extradata + s->sps_offset, + s->pps_offset != -1 ? s->pps_offset : ctx->par_out->extradata_size - s->sps_offset, buf, nal_size)) < 0) goto fail; - ctx->idr_sps_seen = 1; + s->idr_sps_seen = 1; goto next_nal; } } @@ -227,61 +223,61 @@ static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc, /* if this is a new IDR picture following an IDR picture, reset the idr flag. * Just check first_mb_in_slice to be 0 as this is the simplest solution. * This could be checking idr_pic_id instead, but would complexify the parsing. */ - if (!ctx->new_idr && unit_type == 5 && (buf[1] & 0x80)) - ctx->new_idr = 1; + if (!s->new_idr && unit_type == 5 && (buf[1] & 0x80)) + s->new_idr = 1; /* prepend only to the first type 5 NAL unit of an IDR picture, if no sps/pps are already present */ - if (ctx->new_idr && unit_type == 5 && !ctx->idr_sps_seen && !ctx->idr_pps_seen) { - if ((ret=alloc_and_copy(poutbuf, poutbuf_size, - ctx->spspps_buf, ctx->spspps_size, + if (s->new_idr && unit_type == 5 && !s->idr_sps_seen && !s->idr_pps_seen) { + if ((ret=alloc_and_copy(out, + ctx->par_out->extradata, ctx->par_out->extradata_size, buf, nal_size)) < 0) goto fail; - ctx->new_idr = 0; + s->new_idr = 0; /* if only SPS has been seen, also insert PPS */ - } else if (ctx->new_idr && unit_type == 5 && ctx->idr_sps_seen && !ctx->idr_pps_seen) { - if (ctx->pps_offset == -1) { - av_log(avctx, AV_LOG_WARNING, "PPS not present in the stream, nor in AVCC, stream may be unreadable\n"); - if ((ret = alloc_and_copy(poutbuf, poutbuf_size, - NULL, 0, buf, nal_size)) < 0) + } else if (s->new_idr && unit_type == 5 && s->idr_sps_seen && !s->idr_pps_seen) { + if (s->pps_offset == -1) { + av_log(ctx, AV_LOG_WARNING, "PPS not present in the stream, nor in AVCC, stream may be unreadable\n"); + if ((ret = alloc_and_copy(out, NULL, 0, buf, nal_size)) < 0) goto fail; - } else if ((ret = alloc_and_copy(poutbuf, poutbuf_size, - ctx->spspps_buf + ctx->pps_offset, ctx->spspps_size - ctx->pps_offset, + } else if ((ret = alloc_and_copy(out, + ctx->par_out->extradata + s->pps_offset, ctx->par_out->extradata_size - s->pps_offset, buf, nal_size)) < 0) goto fail; } else { - if ((ret=alloc_and_copy(poutbuf, poutbuf_size, - NULL, 0, buf, nal_size)) < 0) + if ((ret=alloc_and_copy(out, NULL, 0, buf, nal_size)) < 0) goto fail; - if (!ctx->new_idr && unit_type == 1) { - ctx->new_idr = 1; - ctx->idr_sps_seen = 0; - ctx->idr_pps_seen = 0; + if (!s->new_idr && unit_type == 1) { + s->new_idr = 1; + s->idr_sps_seen = 0; + s->idr_pps_seen = 0; } } next_nal: 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; + if (ret < 0) + av_packet_unref(out); + av_packet_free(&in); + return ret; } -static void h264_mp4toannexb_filter_close(AVBitStreamFilterContext *bsfc) -{ - H264BSFContext *ctx = bsfc->priv_data; - if (ctx->private_spspps) - av_freep(&ctx->spspps_buf); -} +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_H264, AV_CODEC_ID_NONE, +}; -AVBitStreamFilter ff_h264_mp4toannexb_bsf = { +const AVBitStreamFilter ff_h264_mp4toannexb_bsf = { .name = "h264_mp4toannexb", .priv_data_size = sizeof(H264BSFContext), + .init = h264_mp4toannexb_init, .filter = h264_mp4toannexb_filter, - .close = h264_mp4toannexb_filter_close, + .codec_ids = codec_ids, }; diff --git a/libavcodec/hevc_mp4toannexb_bsf.c b/libavcodec/hevc_mp4toannexb_bsf.c index d6feb998f8..5cc642b0d3 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,23 +34,9 @@ typedef struct HEVCBSFContext { uint8_t length_size; int extradata_parsed; - - int logged_nonmp4_warning; - - /* When private_spspps is zero then spspps_buf points to global extradata - and bsf does replace a global extradata to own-allocated version (default - behaviour). - When private_spspps is non-zero the bsf uses a private version of spspps buf. - This mode necessary when bsf uses in decoder, else bsf has issues after - decoder re-initialization. Use the "private_spspps_buf" argument to - activate this mode. - */ - int private_spspps; - uint8_t *spspps_buf; - uint32_t spspps_size; } HEVCBSFContext; -static int hevc_extradata_to_annexb(HEVCBSFContext* ctx, AVCodecContext *avctx) +static int hevc_extradata_to_annexb(AVBSFContext *ctx) { GetByteContext gb; int length_size, num_arrays, i, j; @@ -58,7 +45,7 @@ static int hevc_extradata_to_annexb(HEVCBSFContext* ctx, 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; @@ -70,7 +57,7 @@ static int hevc_extradata_to_annexb(HEVCBSFContext* ctx, 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; @@ -94,16 +81,12 @@ static int hevc_extradata_to_annexb(HEVCBSFContext* ctx, AVCodecContext *avctx) } } - if (!ctx->private_spspps) { - av_freep(&avctx->extradata); - avctx->extradata = new_extradata; - avctx->extradata_size = new_extradata_size; - } - ctx->spspps_buf = new_extradata; - ctx->spspps_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: @@ -111,54 +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 *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 *ctx = bsfc->priv_data; + 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 = (uint8_t *)buf; - *poutbuf_size = buf_size; - return 0; - } - if (args && strstr(args, "private_spspps_buf")) - ctx->private_spspps = 1; + ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; - ret = hevc_extradata_to_annexb(ctx, 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; @@ -166,47 +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 * ctx->spspps_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, ctx->spspps_buf, 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; } -static void hevc_mp4toannexb_close(AVBitStreamFilterContext *bsfc) -{ - HEVCBSFContext *ctx = bsfc->priv_data; - if (ctx->private_spspps) - av_freep(&ctx->spspps_buf); -} +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_HEVC, AV_CODEC_ID_NONE, +}; -AVBitStreamFilter ff_hevc_mp4toannexb_bsf = { - "hevc_mp4toannexb", - sizeof(HEVCBSFContext), - hevc_mp4toannexb_filter, - hevc_mp4toannexb_close, +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 3a69e98c04..9a9de05f05 100644 --- a/libavcodec/imx_dump_header_bsf.c +++ b/libavcodec/imx_dump_header_bsf.c @@ -26,35 +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 = { - .name = "imxdump", - .filter = 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 92dc3ca230..2d4cee2ac1 100644 --- a/libavcodec/mjpeg2jpeg_bsf.c +++ b/libavcodec/mjpeg2jpeg_bsf.c @@ -31,6 +31,7 @@ #include "libavutil/intreadwrite.h" #include "avcodec.h" +#include "bsf.h" #include "jpegtables.h" #include "mjpeg.h" @@ -77,46 +78,64 @@ 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 (AV_RB16(buf) != 0xffd8) { - av_log(avctx, AV_LOG_ERROR, "input is not MJPEG\n"); - return AVERROR_INVALIDDATA; + if (AV_RB16(in->data) != 0xffd8) { + av_log(ctx, AV_LOG_ERROR, "input is not MJPEG\n"); + ret = AVERROR_INVALIDDATA; + goto fail; } - if (buf[2] == 0xff && buf[3] == APP0) { - input_skip = (buf[4] << 8) + buf[5] + 4; + if (in->data[2] == 0xff && in->data[3] == APP0) { + input_skip = (in->data[4] << 8) + in->data[5] + 4; } else { input_skip = 2; } - if (buf_size < input_skip) { - av_log(avctx, AV_LOG_ERROR, "input is truncated\n"); - return AVERROR_INVALIDDATA; + 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 = { +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_MJPEG, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_mjpeg2jpeg_bsf = { .name = "mjpeg2jpeg", .filter = mjpeg2jpeg_filter, + .codec_ids = codec_ids, }; diff --git a/libavcodec/mjpega_dump_header_bsf.c b/libavcodec/mjpega_dump_header_bsf.c index d6d41e6bbb..ca5fb3a377 100644 --- a/libavcodec/mjpega_dump_header_bsf.c +++ b/libavcodec/mjpega_dump_header_bsf.c @@ -26,70 +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 = { - .name = "mjpegadump", - .filter = 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 8ee7a3a42d..3cb1183cd8 100644 --- a/libavcodec/movsub_bsf.c +++ b/libavcodec/movsub_bsf.c @@ -21,39 +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={ +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={ +const AVBitStreamFilter ff_mov2textsub_bsf = { .name = "mov2textsub", .filter = mov2textsub, }; diff --git a/libavcodec/mp3_header_decompress_bsf.c b/libavcodec/mp3_header_decompress_bsf.c index 95c0b5b769..22c1ef0220 100644 --- a/libavcodec/mp3_header_decompress_bsf.c +++ b/libavcodec/mp3_header_decompress_bsf.c @@ -21,32 +21,43 @@ #include "libavutil/common.h" #include "libavutil/intreadwrite.h" #include "avcodec.h" +#include "bsf.h" #include "mpegaudiodecheader.h" #include "mpegaudiodata.h" -static int mp3_header_decompress(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, int keyframe){ +static int mp3_header_decompress(AVBSFContext *ctx, AVPacket *out) +{ + AVPacket *in; uint32_t header; - int sample_rate= avctx->sample_rate; + int sample_rate= ctx->par_in->sample_rate; int sample_rate_index=0; - int lsf, mpeg25, bitrate_index, frame_size; + int lsf, mpeg25, bitrate_index, frame_size, ret; + uint8_t *buf; + int buf_size; + + ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; + + buf = in->data; + buf_size = in->size; header = AV_RB32(buf); if(ff_mpa_check_header(header) >= 0){ - *poutbuf= (uint8_t *) buf; - *poutbuf_size= buf_size; + av_packet_move_ref(out, in); + av_packet_free(&in); return 0; } - if(avctx->extradata_size != 15 || strcmp(avctx->extradata, "FFCMP3 0.0")){ - av_log(avctx, AV_LOG_ERROR, "Extradata invalid %d\n", avctx->extradata_size); - return -1; + if(ctx->par_in->extradata_size != 15 || strcmp(ctx->par_in->extradata, "FFCMP3 0.0")){ + av_log(ctx, AV_LOG_ERROR, "Extradata invalid %d\n", ctx->par_in->extradata_size); + ret = AVERROR(EINVAL); + goto fail; } - header= AV_RB32(avctx->extradata+11) & MP3_MASK; + header= AV_RB32(ctx->par_in->extradata+11) & MP3_MASK; lsf = sample_rate < (24000+32000)/2; mpeg25 = sample_rate < (12000+16000)/2; @@ -62,20 +73,27 @@ static int mp3_header_decompress(AVBitStreamFilterContext *bsfc, AVCodecContext break; } if(bitrate_index == 30){ - av_log(avctx, AV_LOG_ERROR, "Could not find bitrate_index.\n"); - return -1; + av_log(ctx, AV_LOG_ERROR, "Could not find bitrate_index.\n"); + ret = AVERROR(EINVAL); + goto fail; } header |= (bitrate_index&1)<<9; header |= (bitrate_index>>1)<<12; header |= (frame_size == buf_size + 4)<<16; //FIXME actually set a correct crc instead of 0 - *poutbuf_size= frame_size; - *poutbuf= av_malloc(frame_size + AV_INPUT_BUFFER_PADDING_SIZE); - memcpy(*poutbuf + frame_size - buf_size, buf, buf_size + AV_INPUT_BUFFER_PADDING_SIZE); + ret = av_new_packet(out, frame_size); + if (ret < 0) + goto fail; + ret = av_packet_copy_props(out, in); + if (ret < 0) { + av_packet_free(&out); + goto fail; + } + memcpy(out->data + frame_size - buf_size, buf, buf_size + AV_INPUT_BUFFER_PADDING_SIZE); - if(avctx->channels==2){ - uint8_t *p= *poutbuf + frame_size - buf_size; + if(ctx->par_in->channels==2){ + uint8_t *p= out->data + frame_size - buf_size; if(lsf){ FFSWAP(int, p[1], p[2]); header |= (p[1] & 0xC0)>>2; @@ -86,12 +104,21 @@ static int mp3_header_decompress(AVBitStreamFilterContext *bsfc, AVCodecContext } } - AV_WB32(*poutbuf, header); + AV_WB32(out->data, header); - return 1; + ret = 0; + +fail: + av_packet_free(&in); + return ret; } -AVBitStreamFilter ff_mp3_header_decompress_bsf={ - .name = "mp3decomp", - .filter = mp3_header_decompress, +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_MP3, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_mp3_header_decompress_bsf = { + .name = "mp3decomp", + .filter = mp3_header_decompress, + .codec_ids = codec_ids, }; diff --git a/libavcodec/mpeg4_unpack_bframes_bsf.c b/libavcodec/mpeg4_unpack_bframes_bsf.c index df49d3f407..0615621830 100644 --- a/libavcodec/mpeg4_unpack_bframes_bsf.c +++ b/libavcodec/mpeg4_unpack_bframes_bsf.c @@ -20,12 +20,12 @@ */ #include "avcodec.h" +#include "bsf.h" #include "mpeg4video.h" typedef struct UnpackBFramesBSFContext { uint8_t *b_frame_buf; int b_frame_buf_size; - int updated_extradata; } UnpackBFramesBSFContext; /* search next start code */ @@ -83,112 +83,109 @@ static uint8_t *create_new_buffer(const uint8_t *src, int size) { return dst; } -static int mpeg4_unpack_bframes_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 mpeg4_unpack_bframes_filter(AVBSFContext *ctx, AVPacket *out) { - UnpackBFramesBSFContext *ctx = bsfc->priv_data; + UnpackBFramesBSFContext *s = ctx->priv_data; int pos_p = -1, nb_vop = 0, pos_vop2 = -1, ret = 0; + AVPacket *in; - if (avctx->codec_id != AV_CODEC_ID_MPEG4) { - av_log(avctx, AV_LOG_ERROR, - "The mpeg4_unpack_bframes bitstream filter is only useful for mpeg4.\n"); - return AVERROR(EINVAL); - } - - if (!ctx->updated_extradata && avctx->extradata) { - int pos_p_ext = -1; - scan_buffer(avctx->extradata, avctx->extradata_size, &pos_p_ext, NULL, NULL); - if (pos_p_ext >= 0) { - av_log(avctx, AV_LOG_DEBUG, - "Updating DivX userdata (remove trailing 'p') in extradata.\n"); - avctx->extradata[pos_p_ext] = '\0'; - } - ctx->updated_extradata = 1; - } + ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; - scan_buffer(buf, buf_size, &pos_p, &nb_vop, &pos_vop2); - av_log(avctx, AV_LOG_DEBUG, "Found %d VOP startcode(s) in this packet.\n", nb_vop); + scan_buffer(in->data, in->size, &pos_p, &nb_vop, &pos_vop2); + av_log(ctx, AV_LOG_DEBUG, "Found %d VOP startcode(s) in this packet.\n", nb_vop); if (pos_vop2 >= 0) { - if (ctx->b_frame_buf) { - av_log(avctx, AV_LOG_WARNING, + if (s->b_frame_buf) { + av_log(ctx, AV_LOG_WARNING, "Missing one N-VOP packet, discarding one B-frame.\n"); - av_freep(&ctx->b_frame_buf); - ctx->b_frame_buf_size = 0; + av_freep(&s->b_frame_buf); + s->b_frame_buf_size = 0; } /* store the packed B-frame in the BSFContext */ - ctx->b_frame_buf_size = buf_size - pos_vop2; - ctx->b_frame_buf = create_new_buffer(buf + pos_vop2, ctx->b_frame_buf_size); - if (!ctx->b_frame_buf) { - ctx->b_frame_buf_size = 0; + s->b_frame_buf_size = in->size - pos_vop2; + s->b_frame_buf = create_new_buffer(in->data + pos_vop2, s->b_frame_buf_size); + if (!s->b_frame_buf) { + s->b_frame_buf_size = 0; + av_packet_free(&in); return AVERROR(ENOMEM); } } if (nb_vop > 2) { - av_log(avctx, AV_LOG_WARNING, + av_log(ctx, AV_LOG_WARNING, "Found %d VOP headers in one packet, only unpacking one.\n", nb_vop); } - if (nb_vop == 1 && ctx->b_frame_buf) { + if (nb_vop == 1 && s->b_frame_buf) { /* use frame from BSFContext */ - *poutbuf = ctx->b_frame_buf; - *poutbuf_size = ctx->b_frame_buf_size; - /* the output buffer is distinct from the input buffer */ - ret = 1; - if (buf_size <= MAX_NVOP_SIZE) { + av_packet_from_data(out, s->b_frame_buf, s->b_frame_buf_size); + if (in->size <= MAX_NVOP_SIZE) { /* N-VOP */ - av_log(avctx, AV_LOG_DEBUG, "Skipping N-VOP.\n"); - ctx->b_frame_buf = NULL; - ctx->b_frame_buf_size = 0; + av_log(ctx, AV_LOG_DEBUG, "Skipping N-VOP.\n"); + s->b_frame_buf = NULL; + s->b_frame_buf_size = 0; } else { /* copy packet into BSFContext */ - ctx->b_frame_buf_size = buf_size; - ctx->b_frame_buf = create_new_buffer(buf , buf_size); - if (!ctx->b_frame_buf) { - ctx->b_frame_buf_size = 0; - av_freep(poutbuf); - *poutbuf_size = 0; + s->b_frame_buf_size = in->size; + s->b_frame_buf = create_new_buffer(in->data, in->size); + if (!s->b_frame_buf) { + s->b_frame_buf_size = 0; + av_packet_unref(out); + av_packet_free(&in); return AVERROR(ENOMEM); } } } else if (nb_vop >= 2) { /* use first frame of the packet */ - *poutbuf = (uint8_t *) buf; - *poutbuf_size = pos_vop2; + av_packet_move_ref(out, in); + out->size = pos_vop2; } else if (pos_p >= 0) { - av_log(avctx, AV_LOG_DEBUG, "Updating DivX userdata (remove trailing 'p').\n"); - *poutbuf_size = buf_size; - *poutbuf = create_new_buffer(buf, buf_size); - if (!*poutbuf) { - *poutbuf_size = 0; - return AVERROR(ENOMEM); - } + av_log(ctx, AV_LOG_DEBUG, "Updating DivX userdata (remove trailing 'p').\n"); + av_packet_move_ref(out, in); /* remove 'p' (packed) from the end of the (DivX) userdata string */ - (*poutbuf)[pos_p] = '\0'; - /* the output buffer is distinct from the input buffer */ - ret = 1; + out->data[pos_p] = '\0'; } else { /* copy packet */ - *poutbuf = (uint8_t *) buf; - *poutbuf_size = buf_size; + av_packet_move_ref(out, in); + } + + av_packet_free(&in); + + return 0; +} + +static int mpeg4_unpack_bframes_init(AVBSFContext *ctx) +{ + if (ctx->par_in->extradata) { + int pos_p_ext = -1; + scan_buffer(ctx->par_in->extradata, ctx->par_in->extradata_size, &pos_p_ext, NULL, NULL); + if (pos_p_ext >= 0) { + av_log(ctx, AV_LOG_DEBUG, + "Updating DivX userdata (remove trailing 'p') in extradata.\n"); + ctx->par_out->extradata[pos_p_ext] = '\0'; + } } - return ret; + return 0; } -static void mpeg4_unpack_bframes_close(AVBitStreamFilterContext *bsfc) +static void mpeg4_unpack_bframes_close(AVBSFContext *bsfc) { UnpackBFramesBSFContext *ctx = bsfc->priv_data; av_freep(&ctx->b_frame_buf); } -AVBitStreamFilter ff_mpeg4_unpack_bframes_bsf = { +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_MPEG4, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_mpeg4_unpack_bframes_bsf = { .name = "mpeg4_unpack_bframes", .priv_data_size = sizeof(UnpackBFramesBSFContext), + .init = mpeg4_unpack_bframes_init, .filter = mpeg4_unpack_bframes_filter, - .close = mpeg4_unpack_bframes_close + .close = mpeg4_unpack_bframes_close, + .codec_ids = codec_ids, }; diff --git a/libavcodec/noise_bsf.c b/libavcodec/noise_bsf.c index 556ad5c549..9b4f4e4961 100644 --- a/libavcodec/noise_bsf.c +++ b/libavcodec/noise_bsf.c @@ -22,34 +22,70 @@ #include <string.h> #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(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; +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; - if(amount <= 0) + if (amount <= 0) return AVERROR(EINVAL); - *poutbuf= av_malloc(buf_size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!*poutbuf) - return AVERROR(ENOMEM); + 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; + + memcpy(out->data, in->data, in->size); - memcpy(*poutbuf, buf, buf_size + AV_INPUT_BUFFER_PADDING_SIZE); - for(i=0; i<buf_size; i++){ - (*state) += (*poutbuf)[i] + 1; - if(*state % amount == 0) - (*poutbuf)[i] = *state; + 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={ +#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 6bb3576cea..c18356741a 100644 --- a/libavcodec/remove_extradata_bsf.c +++ b/libavcodec/remove_extradata_bsf.c @@ -18,38 +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={ - .name = "remove_extra", - .filter = 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 c24f0fc42c..b8ef9c5193 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -28,8 +28,8 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 57 -#define LIBAVCODEC_VERSION_MINOR 34 -#define LIBAVCODEC_VERSION_MICRO 102 +#define LIBAVCODEC_VERSION_MINOR 35 +#define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ @@ -214,5 +214,8 @@ #ifndef FF_API_ASS_TIMING #define FF_API_ASS_TIMING (LIBAVCODEC_VERSION_MAJOR < 59) #endif +#ifndef FF_API_OLD_BSF +#define FF_API_OLD_BSF (LIBAVCODEC_VERSION_MAJOR < 59) +#endif #endif /* AVCODEC_VERSION_H */ diff --git a/libavcodec/vp9_superframe_bsf.c b/libavcodec/vp9_superframe_bsf.c index d4a61eea04..b686adbe16 100644 --- a/libavcodec/vp9_superframe_bsf.c +++ b/libavcodec/vp9_superframe_bsf.c @@ -21,6 +21,7 @@ #include "libavutil/avassert.h" #include "avcodec.h" +#include "bsf.h" #include "get_bits.h" #define MAX_CACHE 8 @@ -50,20 +51,20 @@ static void stats(const struct CachedBuf *in, int n_in, *_sum = sum; } -static int merge_superframe(const struct CachedBuf *in, int n_in, - uint8_t **poutbuf, int *poutbuf_size) +static int merge_superframe(const struct CachedBuf *in, int n_in, AVPacket *out) { unsigned max, sum, mag, marker, n, sz; uint8_t *ptr; + int res; stats(in, n_in, &max, &sum); mag = av_log2(max) >> 3; marker = 0xC0 + (mag << 3) + (n_in - 1); - sz = *poutbuf_size = sum + 2 + (mag + 1) * n_in; - ptr = *poutbuf = av_malloc(sz); - if (!ptr) - return AVERROR(ENOMEM); - + sz = sum + 2 + (mag + 1) * n_in; + res = av_new_packet(out, sz); + if (res < 0) + return res; + ptr = out->data; for (n = 0; n < n_in; n++) { memcpy(ptr, in[n].data, in[n].size); ptr += in[n].size; @@ -92,31 +93,32 @@ static int merge_superframe(const struct CachedBuf *in, int n_in, break; } *ptr++ = marker; - av_assert0(ptr == &(*poutbuf)[*poutbuf_size]); + av_assert0(ptr == &out->data[out->size]); return 0; } -static int vp9_superframe_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 vp9_superframe_filter(AVBSFContext *ctx, AVPacket *out) { GetBitContext gb; - VP9BSFContext *ctx = bsfc->priv_data; + VP9BSFContext *s = ctx->priv_data; + AVPacket *in; int res, invisible, profile, marker, uses_superframe_syntax = 0, n; - marker = buf[buf_size - 1]; + res = ff_bsf_get_packet(ctx, &in); + if (res < 0) + return res; + + marker = in->data[in->size - 1]; if ((marker & 0xe0) == 0xc0) { int nbytes = 1 + ((marker >> 3) & 0x3); int n_frames = 1 + (marker & 0x7), idx_sz = 2 + n_frames * nbytes; - uses_superframe_syntax = buf_size >= idx_sz && buf[buf_size - idx_sz] == marker; + uses_superframe_syntax = in->size >= idx_sz && in->data[in->size - idx_sz] == marker; } - if ((res = init_get_bits8(&gb, buf, buf_size)) < 0) - return res; + if ((res = init_get_bits8(&gb, in->data, in->size)) < 0) + goto done; get_bits(&gb, 2); // frame marker profile = get_bits1(&gb); @@ -130,60 +132,74 @@ static int vp9_superframe_filter(AVBitStreamFilterContext *bsfc, invisible = !get_bits1(&gb); } - if (uses_superframe_syntax && ctx->n_cache > 0) { - av_log(avctx, AV_LOG_ERROR, + if (uses_superframe_syntax && s->n_cache > 0) { + av_log(ctx, AV_LOG_ERROR, "Mixing of superframe syntax and naked VP9 frames not supported"); - return AVERROR_INVALIDDATA; - } else if ((!invisible || uses_superframe_syntax) && !ctx->n_cache) { + res = AVERROR_INVALIDDATA; + goto done; + } else if ((!invisible || uses_superframe_syntax) && !s->n_cache) { // passthrough - *poutbuf = (uint8_t *) buf; - *poutbuf_size = buf_size; - return 0; - } else if (ctx->n_cache + 1 >= MAX_CACHE) { - av_log(avctx, AV_LOG_ERROR, + av_packet_move_ref(out, in); + goto done; + } else if (s->n_cache + 1 >= MAX_CACHE) { + av_log(ctx, AV_LOG_ERROR, "Too many invisible frames"); - return AVERROR_INVALIDDATA; + res = AVERROR_INVALIDDATA; + goto done; } - ctx->cache[ctx->n_cache].size = buf_size; + s->cache[s->n_cache].size = in->size; if (invisible && !uses_superframe_syntax) { - ctx->cache[ctx->n_cache].data = av_malloc(buf_size); - if (!ctx->cache[ctx->n_cache].data) - return AVERROR(ENOMEM); - memcpy(ctx->cache[ctx->n_cache++].data, buf, buf_size); - *poutbuf = NULL; - *poutbuf_size = 0; - return 0; + s->cache[s->n_cache].data = av_malloc(in->size); + if (!s->cache[s->n_cache].data) { + res = AVERROR(ENOMEM); + goto done; + } + memcpy(s->cache[s->n_cache++].data, in->data, in->size); + res = AVERROR(EAGAIN); + goto done; } - av_assert0(ctx->n_cache > 0); + av_assert0(s->n_cache > 0); - ctx->cache[ctx->n_cache].data = (uint8_t *) buf; + s->cache[s->n_cache].data = in->data; // build superframe - if ((res = merge_superframe(ctx->cache, ctx->n_cache + 1, - poutbuf, poutbuf_size)) < 0) - return res; - - for (n = 0; n < ctx->n_cache; n++) - av_freep(&ctx->cache[n].data); - ctx->n_cache = 0; - - return 0; + if ((res = merge_superframe(s->cache, s->n_cache + 1, out)) < 0) + goto done; + + for (n = 0; n < s->n_cache; n++) + av_freep(&s->cache[n].data); + s->n_cache = 0; + + res = av_packet_copy_props(out, in); + if (res < 0) + goto done; + +done: + if (res < 0) + av_packet_unref(out); + av_packet_free(&in); + return res; } -static void vp9_superframe_close(AVBitStreamFilterContext *bsfc) +static void vp9_superframe_close(AVBSFContext *ctx) { - VP9BSFContext *ctx = bsfc->priv_data; + VP9BSFContext *s = ctx->priv_data; int n; // free cached data - for (n = 0; n < ctx->n_cache; n++) - av_freep(&ctx->cache[n].data); + for (n = 0; n < s->n_cache; n++) + av_freep(&s->cache[n].data); } -AVBitStreamFilter ff_vp9_superframe_bsf = { +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_VP9, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_vp9_superframe_bsf = { .name = "vp9_superframe", .priv_data_size = sizeof(VP9BSFContext), .filter = vp9_superframe_filter, .close = vp9_superframe_close, + .codec_ids = codec_ids, }; |