API changes, most recent first:
-2016-xx-xx - xxxxxxx - lavfi 6.3.0 - avfilter.h
+ 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.42.0 - avfilter.h
Add AVFilterContext.hw_device_ctx.
-2016-xx-xx - xxxxxxx - lavu 55.9.0 - hwcontext_vaapi.h
+2016-xx-xx - xxxxxxx - lavu 55.22.0 - hwcontext_vaapi.h
Add new installed header with VAAPI-specific hwcontext definitions.
-2016-xx-xx - xxxxxxx - lavu 55.8.0 - pixfmt.h
- Deprecate all AV_PIX_FMT_VAAPI_* formats.
- Replaced by AV_PIX_FMT_VAAPI.
-
-2016-xx-xx - xxxxxxx - lavu 55.7.0 - hwcontext.h
+2016-xx-xx - xxxxxxx - lavu 55.21.0 - hwcontext.h
Add AVHWFramesConstraints and associated API.
-2016-02-23 - 9200514 - lavf 57.5.0 - avformat.h
+2016-04-11 - xxxxxxx - lavf 57.33.0 - avformat.h
Add AVStream.codecpar, deprecate AVStream.codec.
-2016-xx-xx - lavc 57.14.0 - avcodec.h
- 998e1b8 - Add AVCodecParameters and its related API.
- a806834 - Add av_get_audio_frame_duration2().
+2016-04-02 - xxxxxxx - lavu 55.20.100 - base64.h
+ Add AV_BASE64_DECODE_SIZE(x) macro.
+
+2016-xx-xx - lavc 57.33.0 - avcodec.h
+ xxxxxxx - Add AVCodecParameters and its related API.
+ xxxxxxx - Add av_get_audio_frame_duration2().
+
+2016-03-11 - xxxxxxx - lavf/lavc 57.28.101
+ Add requirement to bitstream filtering API that returned packets with
+ size == 0 and side_data_elems == 0 are to be skipped by the caller.
+
+2016-XX-XX - xxxxxxx - lavf 57.28.100
+ Add protocol blacklisting API
+
+2016-02-28 - xxxxxxx - lavc 57.27.101
+ Validate AVFrame returned by get_buffer2 to have required
+ planes not NULL and unused planes set to NULL as crashes
+ and buffer overflow are possible with certain streams if
+ that is not the case.
+
+2016-xx-xx - xxxxxxx - lavc 57.27.100 - avcodec.h
+ "flags2" decoding option now allows the flag "ass_ro_flush_noop" preventing
+ the reset of the ASS ReadOrder field on flush. This affects the content of
+ AVSubtitles.rects[N]->ass when "sub_text_format" is set to "ass" (see
+ previous entry).
+
+2016-xx-xx - xxxxxxx - lavc 57.26.100 - avcodec.h
+ Add a "sub_text_format" subtitles decoding option allowing the values "ass"
+ (recommended) and "ass_with_timings" (not recommended, deprecated, default).
+ The default value for this option will change to "ass" at the next major
+ libavcodec version bump.
+
+ The current default is "ass_with_timings" for compatibility. This means that
+ all subtitles text decoders currently still output ASS with timings printed
+ as strings in the AVSubtitles.rects[N]->ass fields.
+
+ Setting "sub_text_format" to "ass" allows a better timing accuracy (ASS
+ timing is limited to a 1/100 time base, so this is relevant for any subtitles
+ format needing a bigger one), ease timing adjustments, and prevents the need
+ of removing the timing from the decoded string yourself. This form is also
+ known as "the Matroska form". The timing information (start time, duration)
+ can be found in the AVSubtitles fields.
+
+2016-xx-xx - lavc 57.25.0 - avcodec.h
+ Add AVCodecContext.hw_frames_ctx.
-2016-02-22 - ec4c483 - lavf 57.4.0 - avformat.h
- Add AVFormatContext.protocol_whitelist and protocol_blacklist.
- Add 'protocol_whitelist' and 'protocol_blacklist' private options for
- avio_open2().
+2016-xx-xx - lavfi 6.36.0 - avfilter.h
+ xxxxxxx avfilter.h - Add AVFilterLink.hw_frames_ctx.
+ xxxxxxx buffersrc.h - Add AVBufferSrcParameters and functions for handling it.
-2016-02-14 - 7b3214d0 - lavc 57.13.0 - avcodec.h
- Add AVCodecContext.hw_frames_ctx.
+2016-02-xx - xxxxxxx - lavc 57.25.100
+ Add AV_PKT_DATA_MPEGTS_STREAM_ID for exporting the MPEGTS stream ID.
-2016-02-14 - lavfi 6.2.0 - avfilter.h
- b3dd30d avfilter.h - Add AVFilterLink.hw_frames_ctx.
- buffersrc.h - Add AVBufferSrcParameters and functions for handling it.
+2016-xx-xx - lavu 55.18.100
+ xxxxxxx audio_fifo.h - Add av_audio_fifo_peek_at().
-2016-02-14 - lavu 55.6.0
- 721a4ef buffer.h - Add av_buffer_pool_init2().
- 89923e4 hwcontext.h - Add a new installed header hwcontext.h with a new API
+2016-xx-xx - lavu 55.18.0
+ xxxxxxx buffer.h - Add av_buffer_pool_init2().
+ xxxxxxx hwcontext.h - Add a new installed header hwcontext.h with a new API
for handling hwaccel frames.
- ad884d1 hwcontext_cuda.h - Add a new installed header hwcontext_cuda.h with
+ xxxxxxx hwcontext_cuda.h - Add a new installed header hwcontext_cuda.h with
CUDA-specific hwcontext definitions.
- a001ce3 hwcontext_vdpau.h - Add a new installed header hwcontext_vdpau.h with
+ xxxxxxx hwcontext_vdpau.h - Add a new installed header hwcontext_vdpau.h with
VDPAU-specific hwcontext definitions.
- 7bc780c pixfmt.h - Add AV_PIX_FMT_CUDA.
+ xxxxxxx pixfmt.h - Add AV_PIX_FMT_CUDA.
-2016-01-24 - 9f61abc - lavf 57.3.0 - avformat.h
+-------- 8< --------- FFmpeg 3.0 was cut here -------- 8< ---------
+
+2016-02-10 - bc9a596 / 9f61abc - lavf 57.25.100 / 57.3.0 - avformat.h
Add AVFormatContext.opaque, io_open and io_close, allowing custom IO
- for muxers and demuxers that open additional files.
-2015-12-12 - 2c68113 - lavc 57.12.0 - avcodec.h
+2016-02-01 - 1dba837 - lavf 57.24.100 - avformat.h, avio.h
+ Add protocol_whitelist to AVFormatContext, AVIOContext
+
+2016-01-31 - 66e9d2f - lavu 55.17.100 - frame.h
+ Add AV_FRAME_DATA_GOP_TIMECODE for exporting MPEG1/2 GOP timecodes.
+
+2016-01-01 - 5e8b053 / 2c68113 - lavc 57.21.100 / 57.12.0 - avcodec.h
Add AVCodecDescriptor.profiles and avcodec_profile_name().
-2015-12-06 - lavc 57.11.0 - avcodec.h dirac.h
- 31c51f7 - Add av_packet_add_side_data().
- 84adab3 - Add AVCodecContext.coded_side_data.
- f0b769c - Add AVCPBProperties API.
- e02de9d - Add a new public header dirac.h containing
+2015-12-28 - 1f9139b - lavf 57.21.100 - avformat.h
+ Add automatic bitstream filtering; add av_apply_bitstream_filters()
+
+2015-12-22 - 39a09e9 - lavfi 6.21.101 - avfilter.h
+ Deprecate avfilter_link_set_closed().
+ Applications are not supposed to mess with links,
+ they should close the sinks.
+
+2015-12-17 - lavc 57.18.100 / 57.11.0 - avcodec.h dirac.h
+ xxxxxxx - Add av_packet_add_side_data().
+ xxxxxxx - Add AVCodecContext.coded_side_data.
+ xxxxxxx - Add AVCPBProperties API.
+ xxxxxxx - Add a new public header dirac.h containing
av_dirac_parse_sequence_header()
-2015-11-20 - 462a54e - lavc 57.9.1 - avcodec.h
+2015-12-11 - 676a93f - lavf 57.20.100 - avformat.h
+ Add av_program_add_stream_index()
+
+2015-11-29 - 93fb4a4 - lavc 57.16.101 - avcodec.h
Deprecate rtp_callback without replacement, i.e. it won't be possible to
get image slices before the full frame is encoded any more. The libavformat
rtpenc muxer can still be used for RFC-2190 packetization.
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_packet_new_side_data(in, AV_PKT_DATA_NEW_EXTRADATA,
- 2 + pce_size);
++ 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);
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;
}
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(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);
+ REGISTER_PARSER(VP9, vp9);
}
struct AVBitStreamFilter *filter;
AVCodecParserContext *parser;
struct AVBitStreamFilterContext *next;
+ /**
+ * Internal default arguments, used if NULL is passed to av_bitstream_filter_filter().
+ * Not for access by library users.
+ */
+ 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
/**
- * @deprecated the old bitstream filtering API (using AVBitStreamFilterContext)
- * is deprecated. Use the new bitstream filtering API (using AVBSFContext).
+ * Register a bitstream filter.
+ *
+ * The filter will be accessible to the application code through
+ * av_bitstream_filter_next() or can be directly initialized with
+ * av_bitstream_filter_init().
+ *
+ * @see avcodec_register_all()
*/
+ attribute_deprecated
void av_register_bitstream_filter(AVBitStreamFilter *bsf);
+
+/**
+ * Create and initialize a bitstream filter context given a bitstream
+ * filter name.
+ *
+ * The returned context must be freed with av_bitstream_filter_close().
+ *
+ * @param name the name of the bitstream filter
+ * @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);
+
+/**
+ * Filter bitstream.
+ *
+ * This function filters the buffer buf with size buf_size, and places the
+ * filtered buffer in the buffer pointed to by poutbuf.
+ *
+ * The output buffer must be freed by the caller.
+ *
+ * @param bsfc bitstream filter context created by av_bitstream_filter_init()
+ * @param avctx AVCodecContext accessed by the filter, may be NULL.
+ * If specified, this must point to the encoder context of the
+ * output stream the packet is sent to.
+ * @param args arguments which specify the filter configuration, may be NULL
+ * @param poutbuf pointer which is updated to point to the filtered buffer
+ * @param poutbuf_size pointer which is updated to the filtered buffer size in bytes
+ * @param buf buffer containing the data to filter
+ * @param buf_size size in bytes of buf
+ * @param keyframe set to non-zero if the buffer to filter corresponds to a key-frame packet data
+ * @return >= 0 in case of success, or a negative error code in case of failure
+ *
+ * If the return value is positive, an output buffer is allocated and
+ * is available in *poutbuf, and is distinct from the input buffer.
+ *
+ * If the return value is 0, the output buffer is not allocated and
+ * should be considered identical to the input buffer, or in case
+ * *poutbuf was set it points to the input buffer (not necessarily to
+ * 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,
const uint8_t *buf, int buf_size, int keyframe);
+
+/**
+ * Release bitstream filter context.
+ *
+ * @param bsf the bitstream filter context created with
+ * av_bitstream_filter_init(), can be NULL
+ */
+ attribute_deprecated
void av_bitstream_filter_close(AVBitStreamFilterContext *bsf);
+
+/**
+ * If f is NULL, return the first registered bitstream filter,
+ * if f is non-NULL, return the next registered bitstream filter
+ * after f, or NULL if f is the last one.
+ *
+ * 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 */
#include <string.h>
#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)
{
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 = bsfc->priv_data;
++ 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);
}
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;
-
- 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);
+ }
+
++ 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
--- /dev/null
- * This file is part of Libav.
+ /*
- * Libav is free software; you can redistribute it and/or
++ * This file is part of FFmpeg.
+ *
- * Libav is distributed in the hope that it will be useful,
++ * 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.
+ *
- * License along with Libav; if not, write to the Free Software
++ * 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
-extern const AVBitStreamFilter ff_text2movsub_bsf;
++ * 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;
- &ff_mjpeg2jpeg_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
-#if CONFIG_TEXT2MOVSUB_BSF
- &ff_text2movsub_bsf,
-#endif
++ &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;
+ }
--- /dev/null
- * This file is part of Libav.
+ /*
- * Libav is free software; you can redistribute it and/or
++ * This file is part of FFmpeg.
+ *
- * Libav is distributed in the hope that it will be useful,
++ * 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.
+ *
- * License along with Libav; if not, write to the Free Software
++ * 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;
+ }
--- /dev/null
- * This file is part of Libav.
+ /*
- * Libav is free software; you can redistribute it and/or
++ * This file is part of FFmpeg.
+ *
- * Libav is distributed in the hope that it will be useful,
++ * 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.
+ *
- * License along with Libav; if not, write to the Free Software
++ * 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 */
--- /dev/null
- 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)
+/*
+ * Copyright (c) 2016 Paul B Mahol
+ *
+ * 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 "avcodec.h"
++#include "bsf.h"
+#include "bytestream.h"
+#include "dca_syncwords.h"
+#include "libavutil/mem.h"
+
- int core_size = 0;
++static int dca_core_filter(AVBSFContext *ctx, AVPacket *out)
+{
++ AVPacket *in;
+ GetByteContext gb;
+ uint32_t syncword;
- bytestream2_init(&gb, buf, buf_size);
++ int core_size = 0, ret;
+
- *poutbuf = (uint8_t *)buf;
++ 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);
+
+ switch (syncword) {
+ case DCA_SYNCWORD_CORE_BE:
+ core_size = ((bytestream2_get_be24(&gb) >> 4) & 0x3fff) + 1;
+ break;
+ }
+
- if (core_size > 0 && core_size <= buf_size) {
- *poutbuf_size = core_size;
- } else {
- *poutbuf_size = buf_size;
++ av_packet_move_ref(out, in);
++ av_packet_free(&in);
+
- AVBitStreamFilter ff_dca_core_bsf = {
- .name = "dca_core",
- .filter = dca_core,
++ if (core_size > 0 && core_size <= out->size) {
++ out->size = core_size;
+ }
+
+ return 0;
+}
+
++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,
+};
#include "libavutil/intreadwrite.h"
#include "libavutil/mem.h"
+
#include "avcodec.h"
+ #include "bsf.h"
typedef struct H264BSFContext {
+ int32_t sps_offset;
+ int32_t pps_offset;
uint8_t length_size;
- uint8_t first_idr;
+ uint8_t new_idr;
+ 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)
{
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,
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;
- if (length_size == 3)
- return AVERROR(EINVAL);
++ 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) {
- unit_nb = *extradata++; /* number of pps unit(s) */
- sps_done++;
-
- if (unit_nb)
- pps_seen = 1;
+ goto pps;
} else {
- ctx->sps_offset = 0;
++ s->sps_offset = 0;
sps_seen = 1;
}
unit_size = AV_RB16(extradata);
total_size += unit_size + 4;
- if (total_size > INT_MAX - padding ||
- extradata + 2 + unit_size > ctx->par_in->extradata +
- ctx->par_in->extradata_size) {
+ 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);
}
memcpy(out + total_size - unit_size - 4, nalu_header, 4);
memcpy(out + total_size - unit_size, extradata + 2, unit_size);
extradata += 2 + unit_size;
-
+pps:
if (!unit_nb && !sps_done++) {
unit_nb = *extradata++; /* number of pps unit(s) */
- if (unit_nb)
+ if (unit_nb) {
- ctx->pps_offset = total_size;
++ s->pps_offset = total_size;
pps_seen = 1;
+ }
}
}
if (out)
- memset(out + total_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+ 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");
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->first_idr = 1;
++ 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;
++ 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 {
- if (buf + ctx->length_size > buf_end)
+ ret= AVERROR(EINVAL);
+ if (buf + s->length_size > buf_end)
goto fail;
- for (nal_size = 0, i = 0; i<ctx->length_size; i++)
- if (s->length_size == 1) {
- nal_size = buf[0];
- } else if (s->length_size == 2) {
- nal_size = AV_RB16(buf);
- } else
- nal_size = AV_RB32(buf);
++ 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 (buf + nal_size > buf_end || nal_size < 0)
+ if (nal_size > buf_end - buf || nal_size < 0)
goto fail;
- /* prepend only to the first type 5 NAL unit of an IDR picture */
- if (s->first_idr && unit_type == 5) {
- if (alloc_and_copy(out,
+ 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;
+ }
+ }
+ }
+
+ /* 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)
+ 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;
- s->first_idr = 0;
} else {
- if ((ret=alloc_and_copy(poutbuf, poutbuf_size,
- NULL, 0, buf, nal_size)) < 0)
- if (alloc_and_copy(out,
- 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->first_idr && unit_type == 1)
- s->first_idr = 1;
++ 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;
}
int ret = 0;
uint8_t *new_extradata = NULL;
- size_t new_extradata_size = 0;;
+ 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;
#include "libavutil/error.h"
#include "libavutil/mem.h"
+#include "libavutil/intreadwrite.h"
#include "avcodec.h"
+ #include "bsf.h"
#include "jpegtables.h"
+#include "mjpeg.h"
static const uint8_t jpeg_header[] = {
0xff, 0xd8, // SOI
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 (memcmp("AVI1", in->data + 6, 4)) {
- av_log(ctx, AV_LOG_ERROR, "input is not MJPEG/AVI1\n");
++ 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;
-
- input_skip = (in->data[4] << 8) + in->data[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,
};
--- /dev/null
- 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){
+/*
+ * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * 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 "libavutil/common.h"
+#include "libavutil/intreadwrite.h"
+#include "avcodec.h"
++#include "bsf.h"
+#include "mpegaudiodecheader.h"
+#include "mpegaudiodata.h"
+
+
- int sample_rate= avctx->sample_rate;
++static int mp3_header_decompress(AVBSFContext *ctx, AVPacket *out)
++{
++ AVPacket *in;
+ uint32_t header;
- int lsf, mpeg25, bitrate_index, frame_size;
++ int sample_rate= ctx->par_in->sample_rate;
+ int sample_rate_index=0;
- *poutbuf= (uint8_t *) buf;
- *poutbuf_size= buf_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){
- 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;
++ av_packet_move_ref(out, in);
++ av_packet_free(&in);
+
+ return 0;
+ }
+
- header= AV_RB32(avctx->extradata+11) & MP3_MASK;
++ 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;
+ }
+
- av_log(avctx, AV_LOG_ERROR, "Could not find bitrate_index.\n");
- return -1;
++ header= AV_RB32(ctx->par_in->extradata+11) & MP3_MASK;
+
+ lsf = sample_rate < (24000+32000)/2;
+ mpeg25 = sample_rate < (12000+16000)/2;
+ sample_rate_index= (header>>10)&3;
+ sample_rate= avpriv_mpa_freq_tab[sample_rate_index] >> (lsf + mpeg25); //in case sample rate is a little off
+
+ for(bitrate_index=2; bitrate_index<30; bitrate_index++){
+ frame_size = avpriv_mpa_bitrate_tab[lsf][2][bitrate_index>>1];
+ frame_size = (frame_size * 144000) / (sample_rate << lsf) + (bitrate_index&1);
+ if(frame_size == buf_size + 4)
+ break;
+ if(frame_size == buf_size + 6)
+ break;
+ }
+ if(bitrate_index == 30){
- *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);
++ 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
+
- if(avctx->channels==2){
- uint8_t *p= *poutbuf + frame_size - buf_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);
+
- AV_WB32(*poutbuf, header);
++ 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;
+ p[1] &= 0x3F;
+ }else{
+ header |= p[1] & 0x30;
+ p[1] &= 0xCF;
+ }
+ }
+
- return 1;
++ AV_WB32(out->data, header);
+
- AVBitStreamFilter ff_mp3_header_decompress_bsf={
- .name = "mp3decomp",
- .filter = mp3_header_decompress,
++ ret = 0;
++
++fail:
++ av_packet_free(&in);
++ return ret;
+}
+
++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,
+};
--- /dev/null
- int updated_extradata;
+/*
+ * Bitstream filter for unpacking DivX-style packed B-frames in MPEG-4 (divx_packed)
+ * Copyright (c) 2015 Andreas Cadhalpun <Andreas.Cadhalpun@googlemail.com>
+ *
+ * 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 "avcodec.h"
++#include "bsf.h"
+#include "mpeg4video.h"
+
+typedef struct UnpackBFramesBSFContext {
+ uint8_t *b_frame_buf;
+ int b_frame_buf_size;
- 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)
+} UnpackBFramesBSFContext;
+
+/* search next start code */
+static unsigned int find_startcode(const uint8_t *buf, int buf_size, int *pos)
+{
+ unsigned int startcode = 0xFF;
+
+ for (; *pos < buf_size;) {
+ startcode = ((startcode << 8) | buf[*pos]) & 0xFFFFFFFF;
+ *pos +=1;
+ if ((startcode & 0xFFFFFF00) != 0x100)
+ continue; /* no startcode */
+ return startcode;
+ }
+
+ return 0;
+}
+
+/* determine the position of the packed marker in the userdata,
+ * the number of VOPs and the position of the second VOP */
+static void scan_buffer(const uint8_t *buf, int buf_size,
+ int *pos_p, int *nb_vop, int *pos_vop2) {
+ unsigned int startcode;
+ int pos, i;
+
+ for (pos = 0; pos < buf_size;) {
+ startcode = find_startcode(buf, buf_size, &pos);
+
+ if (startcode == USER_DATA_STARTCODE && pos_p) {
+ /* check if the (DivX) userdata string ends with 'p' (packed) */
+ for (i = 0; i < 255 && pos + i + 1 < buf_size; i++) {
+ if (buf[pos + i] == 'p' && buf[pos + i + 1] == '\0') {
+ *pos_p = pos + i;
+ break;
+ }
+ }
+ } else if (startcode == VOP_STARTCODE && nb_vop) {
+ *nb_vop += 1;
+ if (*nb_vop == 2 && pos_vop2) {
+ *pos_vop2 = pos - 4; /* subtract 4 bytes startcode */
+ }
+ }
+ }
+}
+
+/* allocate new buffer and copy size bytes from src */
+static uint8_t *create_new_buffer(const uint8_t *src, int size) {
+ uint8_t *dst = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
+
+ if (dst) {
+ memcpy(dst, src, size);
+ memset(dst + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+ }
+
+ return dst;
+}
+
- UnpackBFramesBSFContext *ctx = bsfc->priv_data;
++static int mpeg4_unpack_bframes_filter(AVBSFContext *ctx, AVPacket *out)
+{
- 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;
- }
++ UnpackBFramesBSFContext *s = ctx->priv_data;
+ int pos_p = -1, nb_vop = 0, pos_vop2 = -1, ret = 0;
++ AVPacket *in;
+
- 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);
++ ret = ff_bsf_get_packet(ctx, &in);
++ if (ret < 0)
++ return ret;
+
- if (ctx->b_frame_buf) {
- av_log(avctx, AV_LOG_WARNING,
++ 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) {
- av_freep(&ctx->b_frame_buf);
- ctx->b_frame_buf_size = 0;
++ if (s->b_frame_buf) {
++ av_log(ctx, AV_LOG_WARNING,
+ "Missing one N-VOP packet, discarding one B-frame.\n");
- 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;
++ av_freep(&s->b_frame_buf);
++ s->b_frame_buf_size = 0;
+ }
+ /* store the packed B-frame in the BSFContext */
- av_log(avctx, AV_LOG_WARNING,
++ 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) {
- if (nb_vop == 1 && ctx->b_frame_buf) {
++ av_log(ctx, AV_LOG_WARNING,
+ "Found %d VOP headers in one packet, only unpacking one.\n", nb_vop);
+ }
+
- *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) {
++ if (nb_vop == 1 && s->b_frame_buf) {
+ /* use frame from BSFContext */
- av_log(avctx, AV_LOG_DEBUG, "Skipping N-VOP.\n");
- ctx->b_frame_buf = NULL;
- ctx->b_frame_buf_size = 0;
++ av_packet_from_data(out, s->b_frame_buf, s->b_frame_buf_size);
++ if (in->size <= MAX_NVOP_SIZE) {
+ /* N-VOP */
- 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;
++ 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 */
- *poutbuf = (uint8_t *) buf;
- *poutbuf_size = pos_vop2;
++ 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 */
- 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_packet_move_ref(out, in);
++ out->size = pos_vop2;
+ } else if (pos_p >= 0) {
- (*poutbuf)[pos_p] = '\0';
- /* the output buffer is distinct from the input buffer */
- ret = 1;
++ 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 = (uint8_t *) buf;
- *poutbuf_size = buf_size;
++ out->data[pos_p] = '\0';
+ } else {
+ /* copy packet */
- return ret;
++ 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';
++ }
+ }
+
- static void mpeg4_unpack_bframes_close(AVBitStreamFilterContext *bsfc)
++ return 0;
+}
+
- AVBitStreamFilter ff_mpeg4_unpack_bframes_bsf = {
++static void mpeg4_unpack_bframes_close(AVBSFContext *bsfc)
+{
+ UnpackBFramesBSFContext *ctx = bsfc->priv_data;
+ av_freep(&ctx->b_frame_buf);
+}
+
- .close = mpeg4_unpack_bframes_close
++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,
++ .codec_ids = codec_ids,
+};
#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,
};
#include "libavutil/version.h"
-#define LIBAVCODEC_VERSION_MAJOR 57
-#define LIBAVCODEC_VERSION_MINOR 15
-#define LIBAVCODEC_VERSION_MICRO 0
+#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, \
#ifndef FF_API_PRIVATE_OPT
#define FF_API_PRIVATE_OPT (LIBAVCODEC_VERSION_MAJOR < 59)
#endif
+#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 */
--- /dev/null
- static int merge_superframe(const struct CachedBuf *in, int n_in,
- uint8_t **poutbuf, int *poutbuf_size)
+/*
+ * Vp9 invisible (alt-ref) frame to superframe merge bitstream filter
+ * Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
+ *
+ * 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 "libavutil/avassert.h"
+#include "avcodec.h"
++#include "bsf.h"
+#include "get_bits.h"
+
+#define MAX_CACHE 8
+typedef struct VP9BSFContext {
+ int n_cache;
+ struct CachedBuf {
+ uint8_t *data;
+ int size;
+ } cache[MAX_CACHE];
+} VP9BSFContext;
+
+static void stats(const struct CachedBuf *in, int n_in,
+ unsigned *_max, unsigned *_sum)
+{
+ int n;
+ unsigned max = 0, sum = 0;
+
+ for (n = 0; n < n_in; n++) {
+ unsigned sz = in[n].size;
+
+ if (sz > max)
+ max = sz;
+ sum += sz;
+ }
+
+ *_max = max;
+ *_sum = sum;
+}
+
- sz = *poutbuf_size = sum + 2 + (mag + 1) * n_in;
- ptr = *poutbuf = av_malloc(sz);
- if (!ptr)
- return AVERROR(ENOMEM);
-
++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);
- av_assert0(ptr == &(*poutbuf)[*poutbuf_size]);
++ 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;
+ }
+
+#define wloop(mag, wr) \
+ for (n = 0; n < n_in; n++) { \
+ wr; \
+ ptr += mag + 1; \
+ }
+
+ // write superframe with marker 110[mag:2][nframes:3]
+ *ptr++ = marker;
+ switch (mag) {
+ case 0:
+ wloop(mag, *ptr = in[n].size);
+ break;
+ case 1:
+ wloop(mag, AV_WL16(ptr, in[n].size));
+ break;
+ case 2:
+ wloop(mag, AV_WL24(ptr, in[n].size));
+ break;
+ case 3:
+ wloop(mag, AV_WL32(ptr, in[n].size));
+ break;
+ }
+ *ptr++ = marker;
- 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)
++ av_assert0(ptr == &out->data[out->size]);
+
+ return 0;
+}
+
- VP9BSFContext *ctx = bsfc->priv_data;
++static int vp9_superframe_filter(AVBSFContext *ctx, AVPacket *out)
+{
+ GetBitContext gb;
- marker = buf[buf_size - 1];
++ VP9BSFContext *s = ctx->priv_data;
++ AVPacket *in;
+ int res, invisible, profile, marker, uses_superframe_syntax = 0, n;
+
- uses_superframe_syntax = buf_size >= idx_sz && buf[buf_size - idx_sz] == marker;
++ 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;
+
- if ((res = init_get_bits8(&gb, buf, buf_size)) < 0)
- return res;
++ uses_superframe_syntax = in->size >= idx_sz && in->data[in->size - idx_sz] == marker;
+ }
+
- if (uses_superframe_syntax && ctx->n_cache > 0) {
- av_log(avctx, AV_LOG_ERROR,
++ if ((res = init_get_bits8(&gb, in->data, in->size)) < 0)
++ goto done;
+
+ get_bits(&gb, 2); // frame marker
+ profile = get_bits1(&gb);
+ profile |= get_bits1(&gb) << 1;
+ if (profile == 3) profile += get_bits1(&gb);
+
+ if (get_bits1(&gb)) {
+ invisible = 0;
+ } else {
+ get_bits1(&gb); // keyframe
+ invisible = !get_bits1(&gb);
+ }
+
- return AVERROR_INVALIDDATA;
- } else if ((!invisible || uses_superframe_syntax) && !ctx->n_cache) {
++ if (uses_superframe_syntax && s->n_cache > 0) {
++ av_log(ctx, AV_LOG_ERROR,
+ "Mixing of superframe syntax and naked VP9 frames not supported");
- *poutbuf = (uint8_t *) buf;
- *poutbuf_size = buf_size;
- return 0;
- } else if (ctx->n_cache + 1 >= MAX_CACHE) {
- av_log(avctx, AV_LOG_ERROR,
++ res = AVERROR_INVALIDDATA;
++ goto done;
++ } else if ((!invisible || uses_superframe_syntax) && !s->n_cache) {
+ // passthrough
- return AVERROR_INVALIDDATA;
++ 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");
- ctx->cache[ctx->n_cache].size = buf_size;
++ res = AVERROR_INVALIDDATA;
++ goto done;
+ }
+
- 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].size = in->size;
+ if (invisible && !uses_superframe_syntax) {
- av_assert0(ctx->n_cache > 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;
+ }
- ctx->cache[ctx->n_cache].data = (uint8_t *) buf;
++ av_assert0(s->n_cache > 0);
+
- 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;
++ s->cache[s->n_cache].data = in->data;
+
+ // build superframe
- static void vp9_superframe_close(AVBitStreamFilterContext *bsfc)
++ 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;
+}
+
- VP9BSFContext *ctx = bsfc->priv_data;
++static void vp9_superframe_close(AVBSFContext *ctx)
+{
- for (n = 0; n < ctx->n_cache; n++)
- av_freep(&ctx->cache[n].data);
++ VP9BSFContext *s = ctx->priv_data;
+ int n;
+
+ // free cached data
- AVBitStreamFilter ff_vp9_superframe_bsf = {
++ for (n = 0; n < s->n_cache; n++)
++ av_freep(&s->cache[n].data);
+}
+
++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,
+};
FF_ENABLE_DEPRECATION_WARNINGS
#endif
++ /* update internal context from codecpar, old bsf api needs this
++ * FIXME: remove when autobsf uses new bsf API */
++ ret = avcodec_parameters_to_context(st->internal->avctx, st->codecpar);
++ if (ret < 0)
++ goto fail;
++
if (!st->time_base.num) {
/* fall back on the default timebase values */
if (par->codec_type == AVMEDIA_TYPE_AUDIO && par->sample_rate)