Hi,
the bistream filtering API in lavc is one of the few remaining ancient horrors
and some of my other evil plans involve fixing it.
The problems with it are rather obvious:
- it uses raw data buffers instead of AVPackets
- is completely undocumented
- the filtering function takes a very questionable set of parameters:
* a codec context (not clear from where it's
supposed to come from), unspecified stuff is done on it
* an opaque 'args' string
* 'keyframe' (wtf?)
I've drafted a new API, attached below. The basic usage is something like:
av_bsf_alloc();
set options through AVOptions
send packets in with av_bsf_add_packet()
get (in general a different number of) packets out with av_bsf_get_packet()
av_bsf_free();
some notes:
- at this stage, if the caller has multiple filters in chain, he has to manage
them himself. I considered wrapping them in something similar to AVFilterGraph
in lavfi, but then decided against it because there's a high risk of adding
something that's either not sufficiently general or too overdesigned. We have
too few bitstream filters currently and almost none of them make sense in a
chain, so I'd postpone a higher-level filter-chain API until it's actually
needed and we have a better idea what features it should have. Then we should
be able to just extend the API without breaking any existing callers.
- I'm quite sure we _don't_ want the filter to get an external codec context of
any kind and mess with it. Currently existing filters mainly use the codec
context for extradata (both reading and writing). For writing, we can use the
NEW_EXTRADATA packet side data, though this probably means we'll have to teach
more muxers to deal with this side data. I see a larger problem in reading
extradata -- one idea is to make lavc encoding and lavf demuxing to set the
NEW_EXTRADATA side data on the first packet. Other/better ideas welcome.
- reconfiguration - do we want an open/close pattern to change options at
runtime? Or do we want the caller to be able to av_opt_set() at any point and
the filter has to detect that? Or another insane way is to send updated
options in a dict in side data of the input packets. Again, better ideas
welcome
Please comment.
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 4ce6d61..39f1bbb 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -4171,35 +4171,165 @@ int av_get_exact_bits_per_sample(enum AVCodecID
codec_id);
*/
int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes);
+typedef struct AVBSFInternal AVBSFInternal;
+typedef struct AVBSFContext {
+ /**
+ * A class for logging and AVOptions;
+ */
+ const AVClass *av_class;
+
+ /**
+ * The bitstream filter this context is an instance of.
+ */
+ const AVBitStreamFilter *filter;
+
+ /**
+ * Opaque libavcodec internal data.
+ */
+ AVBSFInternal *internal;
+
+ /**
+ * Opaque filter-specific private data.
+ */
+ void *priv_data;
+
+ /**
+ * Codec id this bitstream filter was initialized for.
+ * Set by libavcodec in av_bsf_alloc().
+ */
+ enum AVCodecID codec_id;
+} AVBSFContext;
+
+/**
+ * @return a bitstream filter with the specified name or NULL if no such
+ * bitstream filter is registered.
+ */
+const AVBitStreamFilter *av_bsf_get_by_name(const char *name);
+
+/**
+ * Iterate over all registered bitstream filters.
+ *
+ * @param prev the bistream filter returned from the previous call to this
+ * function or NULL to start iterating.
+ *
+ * @return the next registered bitstream filter or NULL when prev is the last
+ * registered filter
+ */
+const AVBitStreamFilter *av_bsf_next(const AVBitStreamFilter *prev);
+
+/**
+ * Allocate a context for a given bitstream 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.
+ * @param codec_id a codec id identifying the kind of data that will be sent to
+ * the filter.
+ *
+ * @return newly-allocated bitstream filter context or NULL on failure
+ */
+int av_bsf_alloc(const AVBitStreamFilter *filter, AVBSFContext **ctx,
+ enum AVCodecID codec_id);
+
+/**
+ * Add a packet for filtering.
+ *
+ * @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.
+ *
+ * @return 0 on success, a negative AVERROR on error.
+ */
+int av_bsf_add_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.
+ *
+ * @return 0 on success. AVERROR(EAGAIN) if more packets need to be sent to the
+ * filter (using av_bsf_add_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 adding
+ * a packet with av_bsf_add_packet(), this function needs to be called
+ * repeatedly until it returns AVERROR(EAGAIN) or AVERROR_EOF.
+ */
+int av_bsf_get_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);
+
+#if FF_API_OLD_BSF
typedef struct AVBitStreamFilterContext {
void *priv_data;
struct AVBitStreamFilter *filter;
AVCodecParserContext *parser;
struct AVBitStreamFilterContext *next;
-} AVBitStreamFilterContext;
-
+} AVBitStreamFilterContext attribute_deprecated;
+#endif
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);
+ void (*close)(AVBSFContext *ctx);
+
struct AVBitStreamFilter *next;
} AVBitStreamFilter;
+#if FF_API_OLD_BSF
+attribute_deprecated
void av_register_bitstream_filter(AVBitStreamFilter *bsf);
+attribute_deprecated
AVBitStreamFilterContext *av_bitstream_filter_init(const char *name);
+attribute_deprecated
int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc,
AVCodecContext *avctx, const char *args,
uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size, int keyframe);
+attribute_deprecated
void av_bitstream_filter_close(AVBitStreamFilterContext *bsf);
+attribute_deprecated
AVBitStreamFilter *av_bitstream_filter_next(AVBitStreamFilter *f);
+#endif
/* memory */
--
Anton Khirnov
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel