Discussion:
[libav-devel] [PATCH 0/6] Add decoding/encoding API with decoupled input/output
wm4
2016-03-07 20:12:19 UTC
Permalink
This has been often discussed, and everyone agreed it was a good idea.
Here are patches which add such an API, but without making proper use
of it yet.

wm4 (6):
lavu: improve documentation of some AVFrame functions
lavc: factor apply_param_change() AV_EF_EXPLODE handling
lavc: introduce a new decoding/encoding API with decoupled
input/output
avconv: remove sub-frame warning
avconv: use new decode API
avconv: use new encode API

avconv.c | 82 ++++++++++-----
avconv.h | 1 -
libavcodec/avcodec.h | 221 ++++++++++++++++++++++++++++++++++++++++
libavcodec/internal.h | 12 +++
libavcodec/utils.c | 276 +++++++++++++++++++++++++++++++++++++++++++++++---
libavutil/frame.h | 14 ++-
6 files changed, 562 insertions(+), 44 deletions(-)
--
2.7.0
wm4
2016-03-07 20:12:21 UTC
Permalink
Rather than refactoring everything, add a function that resembles the
avcodec_decode_audio4() API.
---
avconv.c | 31 +++++++++++++++++++++++++++----
1 file changed, 27 insertions(+), 4 deletions(-)

diff --git a/avconv.c b/avconv.c
index d878646..c74b4b8 100644
--- a/avconv.c
+++ b/avconv.c
@@ -1079,6 +1079,31 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
write_frame(of->ctx, &opkt, ost);
}

+static int decode(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *pkt)
+{
+ int ret;
+ int consumed = 0;
+
+ *got_frame = 0;
+
+ // This relies on the fact that the decoder will not buffer additional
+ // packets internally, but returns AVERROR(EAGAIN) if there are still
+ // decoded frames to be returned.
+ ret = avcodec_send_packet(avctx, pkt);
+ if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
+ return ret;
+ if (ret >= 0)
+ consumed = pkt->size;
+
+ ret = avcodec_receive_frame(avctx, frame);
+ if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
+ return ret;
+ if (ret >= 0)
+ *got_frame = 1;
+
+ return consumed;
+}
+
int guess_input_channel_layout(InputStream *ist)
{
AVCodecContext *dec = ist->dec_ctx;
@@ -1109,7 +1134,7 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
return AVERROR(ENOMEM);
decoded_frame = ist->decoded_frame;

- ret = avcodec_decode_audio4(avctx, decoded_frame, got_output, pkt);
+ ret = decode(avctx, decoded_frame, got_output, pkt);
if (!*got_output || ret < 0)
return ret;

@@ -1200,8 +1225,7 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
return AVERROR(ENOMEM);
decoded_frame = ist->decoded_frame;

- ret = avcodec_decode_video2(ist->dec_ctx,
- decoded_frame, got_output, pkt);
+ ret = decode(ist->dec_ctx, decoded_frame, got_output, pkt);
if (!*got_output || ret < 0)
return ret;

@@ -1216,7 +1240,6 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)

decoded_frame->pts = guess_correct_pts(&ist->pts_ctx, decoded_frame->pkt_pts,
decoded_frame->pkt_dts);
- pkt->size = 0;

if (ist->st->sample_aspect_ratio.num)
decoded_frame->sample_aspect_ratio = ist->st->sample_aspect_ratio;
--
2.7.0
wm4
2016-03-07 20:12:20 UTC
Permalink
Until now, the decoding API was restricted to outputting 0 or 1 frames
per input packet. It also enforces a somewhat rigid dataflow in general.

This new API seeks to relax these restrictions by decoupling input and
output. Instead of doing a single call on each decode step, which may
consume the packet and may produce output, the new API requires the user
to send input first, and then ask for output.

For now, there are no codecs supporting this API. The API can work with
codecs using the old API, and most code added here it to make them
interopate. The reverse is not possible, although for audio it might.
---
libavcodec/avcodec.h | 223 +++++++++++++++++++++++++++++++++++++++++++
libavcodec/internal.h | 12 +++
libavcodec/utils.c | 258 +++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 491 insertions(+), 2 deletions(-)

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 33de8ec..3c1bda5 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -2211,6 +2211,8 @@ typedef struct AVCodecContext {
* Otherwise, the decoded frames must not be freed by the caller and are
* only valid until the next decode call.
*
+ * This is always automatically enabled if avcodec_receive_frame() is used.
+ *
* - encoding: unused
* - decoding: set by the caller before avcodec_open2().
*/
@@ -3090,6 +3092,21 @@ typedef struct AVCodec {
int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt);
int (*close)(AVCodecContext *);
/**
+ * Decode/encode API with decoupled packet/frame dataflow. The API is the
+ * same as the avcodec_ prefixed APIs (avcodec_send_frame() etc.), except
+ * that:
+ * - never called if the codec is closed or the wrong type
+ * - AVPacket parameter change side data is applied right before calling
+ * AVCodec->send_packet
+ * - if AV_CODEC_CAP_DELAY is not set, drain packets or frames are never sent
+ * - only one drain packet is ever passed down (until the next flush())
+ * - a drain AVPacket is always NULL (no need to check for avpkt->size).
+ */
+ int (*send_frame)(AVCodecContext *avctx, const AVFrame *frame);
+ int (*send_packet)(AVCodecContext *avctx, const AVPacket *avpkt);
+ int (*receive_frame)(AVCodecContext *avctx, AVFrame *frame);
+ int (*receive_packet)(AVCodecContext *avctx, AVPacket *avpkt);
+ /**
* Flush buffers.
* Will be called when seeking
*/
@@ -4080,6 +4097,212 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
AVPacket *avpkt);

/**
+ * send/receive API overview (xxx: where does this go?)
+ *
+ * The avcodec_send_packet()/avcodec_receive_frame()/avcodec_send_frame()/
+ * avcodec_receive_packet() provide a encode/decode API, which decouples input
+ * and output.
+ *
+ * The API is very similar for encoding/decoding and audio/video, and works as
+ * follows:
+ * - Setup and open the AVCodecContext as usual.
+ * - Send valid input:
+ * - For decoding, call avcodec_send_packet() to give the decoder raw
+ * compressed data in an AVPacket.
+ * - For encoding, call avcodec_send_frame() to give the decoder an AVFrame
+ * containing uncompressed audio or video.
+ * In both cases, it's recommended that AVPackets and AVFrames are refcounted,
+ * or libavcodec might have to copy the input data. (libavformat always
+ * returns refcounted AVPackets, and av_frame_get_buffer() allocates
+ * refcounted AVFrames.)
+ * - Receive output in a loop. Periodically call one of the avcodec_receive_*()
+ * functions and process their output:
+ * - For decoding, call avcodec_receive_frame(). On success, it will return
+ * a AVFrame containing uncompressed audio or video data.
+ * - For encoding, call avcodec_receive_packet(). On success, it will return
+ * an AVPacket with a compressed frame.
+ * Repeat this call until it returns AVERROR(EAGAIN) or an error. The
+ * AVERROR(EAGAIN) return value means that new input data is required to
+ * return new output. In this case, continue with sending input. For each
+ * input frame/packet, the codec will typically return 1 output frame/packet,
+ * but it can also be 0 or more than 1.
+ *
+ * At the beginning of decoding or encoding, the codec might accept multiple
+ * input frames/packets without returning a frame, until its internal buffers
+ * are filled. This situation is handled transparently if you follow the steps
+ * outlined above.
+ *
+ * End of stream situations. These require "flushing" (aka draining) the codec,
+ * as the codec might buffer multiple frames or packets internally for
+ * performance or out of necessity (consider B-frames).
+ * This is handled as follows:
+ * - Instead of valid input, send NULL to the avcodec_send_packet() (decoding)
+ * or avcodec_send_frame() (encoding) functions. This will enter draining
+ * mode.
+ * - Call avcodec_receive_frame() (decoding) or avcodec_receive_packet()
+ * (encoding) in a loop until AVERROR_EOF is returned. The functions will
+ * not return AVERROR(EAGAIN), unless you forgot to enter draining mode.
+ * - Before decoding can be resumed again, the codec has to be reset with
+ * avcodec_flush_buffers().
+ *
+ * Using the API as outlined above is highly recommended. But it's also possible
+ * to call functions outside of this rigid schema. For example, you can call
+ * avcodec_send_packet() repeatedly without calling avcodec_receive_frame(). In
+ * this case, avcodec_send_packet() will succeed until the codec's internal
+ * buffer has been filled up (which is typically of size 1 per output frame,
+ * after initial input), and then reject input with AVERROR(EAGAIN). Once it
+ * starts rejecting input, you have no choice but to read at least some output.
+ *
+ * Not all codecs will follow a rigid and predictable dataflow; the only
+ * guarantee is that an AVERROR(EAGAIN) return value on a send/receive call on
+ * one end implies that a receive/send call on the other end will succeed. In
+ * general, no codec will permit unlimited buffering of input or output.
+ *
+ * This API replaces the following legacy functions:
+ * - avcodec_decode_video2() and avcodec_decode_audio4():
+ * Use avcodec_send_packet() to feed input to the decoder, then use
+ * avcodec_receive_frame() to receive decoded frames after each packet.
+ * Unlike with the old video decoding API, multiple frames might result from
+ * a packet. For audio, splitting the input packet into frames by partially
+ * decoding packets becomes transparent to the API user. You never need to
+ * feed an AVPacket to the API twice.
+ * Additionally, sending a flush/draining packet is required only once.
+ * - avcodec_encode_video2()/avcodec_encode_audio2():
+ * Use avcodec_send_frame() to feed input to the encoder, then use
+ * avcodec_receive_packet() to receive encoded packets.
+ * Providing user-allocated buffers for avcodec_receive_packet() is not
+ * possible.
+ * - The new API does not handle subtitles yet.
+ *
+ * Mixing new and old function calls on the same AVCodecContext is not allowed,
+ * and will result in arbitrary behavior.
+ *
+ * Some codecs might require using the new API; using the old API will return
+ * an error when calling it.
+ */
+
+/**
+ * Supply raw packet data as input to a decoder.
+ *
+ * Internally, this call will copy relevant AVCodecContext fields, which can
+ * influence decoding per-packet, and apply them when the packet is actually
+ * decoded. (For example AVCodecContext.skip_frame, which might direct the
+ * decoder to drop the frame contained by the packet sent with this function.)
+ *
+ * @warning The input buffer, avpkt->data must be AV_INPUT_BUFFER_PADDING_SIZE
+ * larger than the actual read bytes because some optimized bitstream
+ * readers read 32 or 64 bits at once and could read over the end.
+ *
+ * @warning Do not mix this API with the legacy API (like avcodec_decode_video2())
+ * on the same AVCodecContext. It will return unexpected results now
+ * or in future libavcodec versions.
+ *
+ * @note The AVCodecContext MUST have been opened with @ref avcodec_open2()
+ * before packets may be fed to the decoder.
+ *
+ * @param avctx codec context
+ * @param[in] avpkt The input AVPacket. Usually, this will be a single video
+ * frame, or several complete audio frames.
+ * Ownership of the packet remains with the caller, and the
+ * decoder will not write to the packet. The decoder may create
+ * a reference to the packet data (or copy it if the packet is
+ * not reference-counted).
+ * Unlike with older APIs, the packet is always fully consumed,
+ * and if it contains multiple frames (e.g. some audio codecs),
+ * will require you to call avcodec_receive_frame() multiple
+ * times afterwards before you can send a new packet.
+ * It can be NULL (or an AVPacket with data set to NULL and size
+ * set to 0); in this case, it's considered a flush packet, which
+ * signals the end of the stream. Sending the first flush
+ * packet will return success. Subsequent ones are unnecessary
+ * and will return AVERROR_EOF. If the decoder still has frames
+ * buffered, it will return them after sending a flush packet.
+ *
+ * @return 0 on success, otherwise negative error code:
+ * AVERROR(EAGAIN): input is not accepted right now - the packet must be
+ * resent after trying to read output
+ * AVERROR_EOF: the decoder has been flushed, and no new packets can
+ * be sent to it (also returned if more than 1 flush
+ * packet is sent)
+ * AVERROR(EINVAL): codec not opened, it's an encoder, or requires flush
+ * AVERROR(ENOMEM): failed to add packet to internal queue, or similar
+ * other errors: legitimate decoding errors
+ */
+int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);
+
+/**
+ * Return decoded output data from a decoder.
+ *
+ * @param avctx codec context
+ * @param frame This will be set to a reference-counted video or audio
+ * frame (depending on the decoder type) allocated by the
+ * decoder. Note that the function will always call
+ * av_frame_unref(frame) before doing anything else.
+ *
+ * @return
+ * 0: success, a frame was returned
+ * AVERROR(EAGAIN): output is not available right now - user must try
+ * to send new input
+ * AVERROR_EOF: the decoder has been fully flushed, and there will be
+ * no more output frames
+ * AVERROR(EINVAL): codec not opened, or it's an encoder
+ * other negative values: legitimate decoding errors
+ */
+int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);
+
+/**
+ * Supply a raw video or audio frame to the encoder. Use avcodec_receive_packet()
+ * to retrieve buffered output packets.
+ *
+ * @param avctx codec context
+ * @param[in] frame AVFrame containing the raw audio or video frame to be encoded.
+ * Ownership of the frame remains with the caller, and the
+ * encoder will not write to the frame. The encoder may create
+ * a reference to the frame data (or copy it if the frame is
+ * not reference-counted).
+ * It can be NULL, in which case it's considered a flush packet.
+ * This signals the end of the stream. If the encoder still has
+ * packets buffered, it will return them after this call. Once
+ * flushing mode has been entered, additional flush packets are
+ * ignored, and sending frames will return AVERROR_EOF.
+ *
+ * For audio:
+ * If AV_CODEC_CAP_VARIABLE_FRAME_SIZE is set, then each frame
+ * can have any number of samples.
+ * If it is not set, frame->nb_samples must be equal to
+ * avctx->frame_size for all frames except the last.
+ * The final frame may be smaller than avctx->frame_size.
+ * @return 0 on success, otherwise negative error code:
+ * AVERROR(EAGAIN): input is not accepted right now - the frame must be
+ * resent after trying to read output packets
+ * AVERROR_EOF: the encoder has been flushed, and no new frames can
+ * be sent to it
+ * AVERROR(EINVAL): codec not opened, refcounted_frames not set, it's a
+ * decoder, or requires flush
+ * AVERROR(ENOMEM): failed to add packet to internal queue, or similar
+ * other errors: legitimate decoding errors
+ */
+int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame);
+
+/**
+ * Read encoded data from the encoder.
+ *
+ * @param avctx codec context
+ * @param avpkt This will be set to a reference-counted packet allocated by the
+ * encoder. Note that the function will always call
+ * av_frame_unref(frame) before doing anything else.
+ * @return 0 on success, otherwise negative error code:
+ * AVERROR(EAGAIN): output is not available right now - user must try
+ * to send input
+ * AVERROR_EOF: the encoder has been fully flushed, and there will be
+ * no more output packets
+ * AVERROR(EINVAL): codec not opened, or it's an encoder
+ * other errors: legitimate decoding errors
+ */
+int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt);
+
+
+/**
* @defgroup lavc_parsing Frame parsing
* @{
*/
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index 3c1583d..2144987 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -140,6 +140,18 @@ typedef struct AVCodecInternal {
* hwaccel-specific private data
*/
void *hwaccel_priv_data;
+
+ /**
+ * checks API usage: after codec draining, flush is required to resume operation
+ */
+ int draining;
+
+ /**
+ * buffers for using new encode/decode API through legacy API
+ */
+ AVPacket *buffer_pkt;
+ int buffer_pkt_valid; // encoding: packet without data can be valid
+ AVFrame *buffer_frame;
} AVCodecInternal;

struct AVCodecDefault {
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 866cdfc..51b0651 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -95,12 +95,12 @@ static av_cold void avcodec_init(void)

int av_codec_is_encoder(const AVCodec *codec)
{
- return codec && (codec->encode_sub || codec->encode2);
+ return codec && (codec->encode_sub || codec->encode2 ||codec->send_frame);
}

int av_codec_is_decoder(const AVCodec *codec)
{
- return codec && codec->decode;
+ return codec && (codec->decode || codec->send_packet);
}

av_cold void avcodec_register(AVCodec *codec)
@@ -882,6 +882,18 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
goto free_and_end;
}

+ avctx->internal->buffer_frame = av_frame_alloc();
+ if (!avctx->internal->buffer_frame) {
+ ret = AVERROR(ENOMEM);
+ goto free_and_end;
+ }
+
+ avctx->internal->buffer_pkt = av_packet_alloc();
+ if (!avctx->internal->buffer_pkt) {
+ ret = AVERROR(ENOMEM);
+ goto free_and_end;
+ }
+
if (codec->priv_data_size > 0) {
if (!avctx->priv_data) {
avctx->priv_data = av_mallocz(codec->priv_data_size);
@@ -1220,6 +1232,11 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,

*got_packet_ptr = 0;

+ if (!avctx->codec->encode2) {
+ av_log(avctx, AV_LOG_ERROR, "This encoder requires using the avcodec_send_frame() API.\n");
+ return AVERROR(ENOSYS);
+ }
+
if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY) && !frame) {
av_packet_unref(avpkt);
av_init_packet(avpkt);
@@ -1327,6 +1344,11 @@ int attribute_align_arg avcodec_encode_video2(AVCodecContext *avctx,

*got_packet_ptr = 0;

+ if (!avctx->codec->encode2) {
+ av_log(avctx, AV_LOG_ERROR, "This encoder requires using the avcodec_send_frame() API.\n");
+ return AVERROR(ENOSYS);
+ }
+
if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY) && !frame) {
av_packet_unref(avpkt);
av_init_packet(avpkt);
@@ -1498,6 +1520,11 @@ int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *pi
if ((avctx->coded_width || avctx->coded_height) && av_image_check_size(avctx->coded_width, avctx->coded_height, 0, avctx))
return -1;

+ if (!avctx->codec->decode) {
+ av_log(avctx, AV_LOG_ERROR, "This decoder requires using the avcodec_send_packet() API.\n");
+ return AVERROR(ENOSYS);
+ }
+
avctx->internal->pkt = avpkt;
ret = apply_param_change(avctx, avpkt);
if (ret < 0)
@@ -1557,6 +1584,11 @@ int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,

*got_frame_ptr = 0;

+ if (!avctx->codec->decode) {
+ av_log(avctx, AV_LOG_ERROR, "This decoder requires using the avcodec_send_packet() API.\n");
+ return AVERROR(ENOSYS);
+ }
+
avctx->internal->pkt = avpkt;

if (!avpkt->data && avpkt->size) {
@@ -1624,6 +1656,221 @@ void avsubtitle_free(AVSubtitle *sub)
memset(sub, 0, sizeof(AVSubtitle));
}

+static int do_decode(AVCodecContext *avctx, AVPacket *pkt)
+{
+ int got_frame;
+ int ret;
+
+ av_assert0(!avctx->internal->buffer_frame->buf[0]);
+
+ if (!pkt)
+ pkt = avctx->internal->buffer_pkt;
+
+ // This is the lesser evil. The field is for compatibility with legacy users
+ // of the legacy API, and users using the new API should not be forced to
+ // even know about this field.
+ avctx->refcounted_frames = 1;
+
+ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+ ret = avcodec_decode_video2(avctx, avctx->internal->buffer_frame,
+ &got_frame, pkt);
+ if (ret >= 0)
+ ret = pkt->size;
+ } else if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
+ ret = avcodec_decode_audio4(avctx, avctx->internal->buffer_frame,
+ &got_frame, pkt);
+ } else {
+ ret = AVERROR(EINVAL);
+ }
+
+ if (ret < 0)
+ return ret;
+
+ if (ret >= pkt->size) {
+ av_packet_unref(avctx->internal->buffer_pkt);
+ } else {
+ int consumed = ret;
+
+ if (pkt != avctx->internal->buffer_pkt) {
+ if ((ret = av_packet_ref(avctx->internal->buffer_pkt, pkt)) < 0)
+ return ret;
+ }
+
+ avctx->internal->buffer_pkt->data += consumed;
+ avctx->internal->buffer_pkt->size -= consumed;
+ }
+
+ if (got_frame)
+ av_assert0(avctx->internal->buffer_frame->buf[0]);
+
+ return ret;
+}
+
+int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt)
+{
+ int ret;
+
+ if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec))
+ return AVERROR(EINVAL);
+
+ if (avctx->internal->draining)
+ return AVERROR_EOF;
+
+ if (!avpkt || !avpkt->size) {
+ avctx->internal->draining = 1;
+ avpkt = NULL;
+
+ if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY))
+ return 0;
+ }
+
+ if (avctx->codec->send_packet) {
+ ret = apply_param_change(avctx, (AVPacket *)avpkt);
+ if (ret < 0)
+ return ret;
+ return avctx->codec->send_packet(avctx, avpkt);
+ }
+
+ // Emulation via old API. Assume avpkt is likely not refcounted, while
+ // decoder output is always refcounted, and avoid copying.
+
+ if (avctx->internal->buffer_pkt->size || avctx->internal->buffer_frame->buf[0])
+ return AVERROR(EAGAIN);
+
+ // The goal is decoding the first frame of the packet without using memcpy,
+ // because the common case is having only 1 frame per packet (especially
+ // with video, but audio too). In other cases, it can't be avoided, unless
+ // the user is feeding refcounted packets.
+ return do_decode(avctx, (AVPacket *)avpkt);
+}
+
+int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)
+{
+ int ret;
+
+ av_frame_unref(frame);
+
+ if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec))
+ return AVERROR(EINVAL);
+
+ if (avctx->codec->receive_frame) {
+ if (avctx->internal->draining && !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY))
+ return AVERROR_EOF;
+ return avctx->codec->receive_frame(avctx, frame);
+ }
+
+ // Emulation via old API.
+
+ if (!avctx->internal->buffer_frame->buf[0]) {
+ if (!avctx->internal->buffer_pkt->size && !avctx->internal->draining)
+ return AVERROR(EAGAIN);
+
+ if ((ret = do_decode(avctx, avctx->internal->buffer_pkt)) < 0) {
+ av_packet_unref(avctx->internal->buffer_pkt);
+ return ret;
+ }
+ }
+
+ if (!avctx->internal->buffer_frame->buf[0])
+ return avctx->internal->draining ? AVERROR_EOF : AVERROR(EAGAIN);
+
+ av_frame_move_ref(frame, avctx->internal->buffer_frame);
+ return 0;
+}
+
+static int do_encode(AVCodecContext *avctx, const AVFrame *frame, int *got_packet)
+{
+ int ret;
+ *got_packet = 0;
+
+ av_packet_unref(avctx->internal->buffer_pkt);
+ avctx->internal->buffer_pkt_valid = 0;
+
+ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+ ret = avcodec_encode_video2(avctx, avctx->internal->buffer_pkt,
+ frame, got_packet);
+ } else if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
+ ret = avcodec_encode_audio2(avctx, avctx->internal->buffer_pkt,
+ frame, got_packet);
+ } else {
+ ret = AVERROR(EINVAL);
+ }
+
+ if (ret >= 0 && *got_packet) {
+ // Encoders must always return ref-counted buffers.
+ // Side-data only packets have no data and can be not ref-counted.
+ av_assert0(!avctx->internal->buffer_pkt->data || avctx->internal->buffer_pkt->buf);
+ avctx->internal->buffer_pkt_valid = 1;
+ ret = 0;
+ } else {
+ av_packet_unref(avctx->internal->buffer_pkt);
+ }
+
+ return ret;
+}
+
+int attribute_align_arg avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame)
+{
+ if (!avcodec_is_open(avctx) || !av_codec_is_encoder(avctx->codec))
+ return AVERROR(EINVAL);
+
+ if (avctx->internal->draining)
+ return AVERROR_EOF;
+
+ if (!frame) {
+ avctx->internal->draining = 1;
+
+ if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY))
+ return 0;
+ }
+
+ if (avctx->codec->send_frame)
+ return avctx->codec->send_frame(avctx, frame);
+
+ // Emulation via old API. Do it here instead of avcodec_receive_packet, because:
+ // 1. if the AVFrame is not refcounted, the copying will be much more
+ // expensive than copying the packet data
+ // 2. assume few users use non-refcounted AVPackets, so usually no copy is
+ // needed
+
+ if (avctx->internal->buffer_pkt_valid)
+ return AVERROR(EAGAIN);
+
+ return do_encode(avctx, frame, &(int){0});
+}
+
+int attribute_align_arg avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
+{
+ av_packet_unref(avpkt);
+
+ if (!avcodec_is_open(avctx) || !av_codec_is_encoder(avctx->codec))
+ return AVERROR(EINVAL);
+
+ if (avctx->codec->receive_packet) {
+ if (avctx->internal->draining && !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY))
+ return AVERROR_EOF;
+ return avctx->codec->receive_packet(avctx, avpkt);
+ }
+
+ // Emulation via old API.
+
+ if (!avctx->internal->buffer_pkt_valid) {
+ int got_packet;
+ int ret;
+ if (!avctx->internal->draining)
+ return AVERROR(EAGAIN);
+ ret = do_encode(avctx, NULL, &got_packet);
+ if (ret < 0)
+ return ret;
+ if (ret >= 0 && !got_packet)
+ return AVERROR_EOF;
+ }
+
+ av_packet_move_ref(avpkt, avctx->internal->buffer_pkt);
+ avctx->internal->buffer_pkt_valid = 0;
+ return 0;
+}
+
av_cold int avcodec_close(AVCodecContext *avctx)
{
int i;
@@ -1636,6 +1883,8 @@ av_cold int avcodec_close(AVCodecContext *avctx)
if (avctx->codec && avctx->codec->close)
avctx->codec->close(avctx);
av_frame_free(&avctx->internal->to_free);
+ av_frame_free(&avctx->internal->buffer_frame);
+ av_packet_free(&avctx->internal->buffer_pkt);
for (i = 0; i < FF_ARRAY_ELEMS(pool->pools); i++)
av_buffer_pool_uninit(&pool->pools[i]);
av_freep(&avctx->internal->pool);
@@ -1966,6 +2215,11 @@ const char *avcodec_license(void)

void avcodec_flush_buffers(AVCodecContext *avctx)
{
+ avctx->internal->draining = 0;
+ av_frame_unref(avctx->internal->buffer_frame);
+ av_packet_unref(avctx->internal->buffer_pkt);
+ avctx->internal->buffer_pkt_valid = 0;
+
if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME)
ff_thread_flush(avctx);
else if (avctx->codec->flush)
--
2.7.0
wm4
2016-03-07 20:12:22 UTC
Permalink
The flushing case is a bit strange; not simplifying it so the change is
less noisy.
---
avconv.c | 80 +++++++++++++++++++++++++++++++++++++++++-----------------------
1 file changed, 51 insertions(+), 29 deletions(-)

diff --git a/avconv.c b/avconv.c
index c74b4b8..8823858 100644
--- a/avconv.c
+++ b/avconv.c
@@ -360,7 +360,7 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost,
{
AVCodecContext *enc = ost->enc_ctx;
AVPacket pkt;
- int got_packet = 0;
+ int ret;

av_init_packet(&pkt);
pkt.data = NULL;
@@ -373,15 +373,25 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost,
ost->samples_encoded += frame->nb_samples;
ost->frames_encoded++;

- if (avcodec_encode_audio2(enc, &pkt, frame, &got_packet) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
- exit_program(1);
- }
+ ret = avcodec_send_frame(enc, frame);
+ if (ret < 0)
+ goto error;
+
+ while (1) {
+ ret = avcodec_receive_packet(enc, &pkt);
+ if (ret == AVERROR(EAGAIN))
+ break;
+ if (ret < 0)
+ goto error;

- if (got_packet) {
av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
write_frame(s, &pkt, ost);
}
+
+ return;
+error:
+ av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
+ exit_program(1);
}

static void do_subtitle_out(AVFormatContext *s,
@@ -458,7 +468,7 @@ static void do_video_out(AVFormatContext *s,
AVFrame *in_picture,
int *frame_size)
{
- int ret, format_video_sync, got_packet;
+ int ret, format_video_sync;
AVPacket pkt;
AVCodecContext *enc = ost->enc_ctx;

@@ -508,13 +518,17 @@ static void do_video_out(AVFormatContext *s,

ost->frames_encoded++;

- ret = avcodec_encode_video2(enc, &pkt, in_picture, &got_packet);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
- exit_program(1);
- }
+ ret = avcodec_send_frame(enc, in_picture);
+ if (ret < 0)
+ goto error;
+
+ while (1) {
+ ret = avcodec_receive_packet(enc, &pkt);
+ if (ret == AVERROR(EAGAIN))
+ break;
+ if (ret < 0)
+ goto error;

- if (got_packet) {
av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
write_frame(s, &pkt, ost);
*frame_size = pkt.size;
@@ -523,15 +537,21 @@ static void do_video_out(AVFormatContext *s,
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
}
+
+ ost->sync_opts++;
+ /*
+ * For video, number of frames in == number of packets out.
+ * But there may be reordering, so we can't throw away frames on encoder
+ * flush, we need to limit them here, before they go into encoder.
+ */
+ ost->frame_number++;
}

- ost->sync_opts++;
- /*
- * For video, number of frames in == number of packets out.
- * But there may be reordering, so we can't throw away frames on encoder
- * flush, we need to limit them here, before they go into encoder.
- */
- ost->frame_number++;
+ return;
+error:
+ av_assert0(ret != AVERROR(EAGAIN) && ret != AVERROR_EOF);
+ av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
+ exit_program(1);
}

static double psnr(double d)
@@ -946,39 +966,41 @@ static void flush_encoders(void)
if (enc->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <= 1)
continue;

+ if (enc->codec_type != AVMEDIA_TYPE_VIDEO && enc->codec_type != AVMEDIA_TYPE_AUDIO)
+ continue;
+
+ avcodec_send_frame(enc, NULL);
+
for (;;) {
- int (*encode)(AVCodecContext*, AVPacket*, const AVFrame*, int*) = NULL;
- const char *desc;
+ const char *desc = NULL;

switch (enc->codec_type) {
case AVMEDIA_TYPE_AUDIO:
- encode = avcodec_encode_audio2;
desc = "Audio";
break;
case AVMEDIA_TYPE_VIDEO:
- encode = avcodec_encode_video2;
desc = "Video";
break;
default:
- stop_encoding = 1;
+ av_assert0(0);
}

- if (encode) {
+ if (1) {
AVPacket pkt;
int got_packet;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;

- ret = encode(enc, &pkt, NULL, &got_packet);
- if (ret < 0) {
+ ret = avcodec_receive_packet(enc, &pkt);
+ if (ret < 0 && ret != AVERROR_EOF) {
av_log(NULL, AV_LOG_FATAL, "%s encoding failed\n", desc);
exit_program(1);
}
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
}
- if (!got_packet) {
+ if (ret == AVERROR_EOF) {
stop_encoding = 1;
break;
}
--
2.7.0
wm4
2016-03-07 20:12:23 UTC
Permalink
This needs to be explicitly supported by the AVCodec. Async mode can
be enabled for AVCodecs without explicit support too, which is treated
as if the codec performs all work instantly.
---
libavcodec/avcodec.h | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++
libavcodec/utils.c | 30 ++++++++++++++
2 files changed, 140 insertions(+)

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 3c1bda5..3517584 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -726,6 +726,12 @@ typedef struct RcOverride{
* Discard cropping information from SPS.
*/
#define AV_CODEC_FLAG2_IGNORE_CROP (1 << 16)
+/**
+ * Enable asynchronous encoding/decoding mode. This depends on codec support,
+ * and will be effectively ignored in most cases. See also AV_CODEC_CAP_ASYNC.
+ * See asynchronous mode section for details.
+ */
+#define AV_CODEC_FLAG2_ASYNC_MODE (1 << 17)

/* Unsupported options :
* Syntax Arithmetic coding (SAC)
@@ -815,6 +821,17 @@ typedef struct RcOverride{
* Audio encoder supports receiving a different number of samples in each call.
*/
#define AV_CODEC_CAP_VARIABLE_FRAME_SIZE (1 << 16)
+/**
+ * This codec has full support for AV_CODEC_FLAG2_ASYNC_MODE. This means it will
+ * never block the decoder (opening/flushing/closing it might still block, but
+ * not sending/receiving packets or frames). See asynchronous mode section for
+ * details.
+ */
+#define AV_CODEC_CAP_ASYNC (1 << 17)
+/**
+ * This codec requires AV_CODEC_FLAG2_ASYNC_MODE to be set.
+ */
+#define AV_CODEC_CAP_ASYNC_ONLY (1 << 18)

#if FF_API_WITHOUT_PREFIX
/**
@@ -2987,6 +3004,16 @@ typedef struct AVCodecContext {
* afterwards owned and managed by libavcodec.
*/
AVBufferRef *hw_frames_ctx;
+
+ /**
+ * Notification callback for asynchronous decoding mode. Must be set if
+ * asynchronous mode is enabled. See asynchronous mode section for details.
+ *
+ * The callback can access the avcodec_send_/_receive_* functions, as long
+ * as the caller guarantees that only one thread accesses the AVCodecContext
+ * concurrently. Other accesses must be done outside of the callback.
+ */
+ int (*async_notification)(struct AVCodecContext *s);
} AVCodecContext;

/**
@@ -3107,6 +3134,10 @@ typedef struct AVCodec {
int (*receive_frame)(AVCodecContext *avctx, AVFrame *frame);
int (*receive_packet)(AVCodecContext *avctx, AVPacket *avpkt);
/**
+ * Required for AV_CODEC_CAP_ASYNC. Behaves like avcodec_check_async_progress().
+ */
+ int (*check_async_progress)(AVCodecContext *avctx);
+ /**
* Flush buffers.
* Will be called when seeking
*/
@@ -4182,6 +4213,35 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
*/

/**
+ * send/receive asynchronous mode API overview (xxx: where does this go?)
+ *
+ * Asynchronous mode can be enabled by setting AV_CODEC_FLAG2_ASYNC_MODE in
+ * AVCodecContext.flags2 before opening the decoder. You must set the
+ * AVCodecContext.async_notification callback as well.
+ *
+ * Decoding and encoding work like in synchronous mode, except that:
+ * - avcodec_send_packet()/avcodec_send_frame()/avcodec_receive_packet()/
+ * avcodec_receive_frame() potentially never block, and may return
+ * AVERROR(EAGAIN) without making any real progress. This breaks the
+ * guarantee that if e.g. avcodec_send_packet() return AVERROR(EAGAIN),
+ * that avcodec_receive_frame() will definitely return a frame.
+ * - If these functions all return AVERROR(EAGAIN), then the codec is doing
+ * decoding or encoding on a worker thread, and the API user has to wait
+ * until data is returned. The async_notification callback will be invoked
+ * by the decoder as soon as there is a change to be expected.
+ * - To avoid race conditions, the function avcodec_check_async_progress()
+ * exists. Before going to sleep until async_notification is called, this
+ * function must be called to determine whether there is actually more
+ * required input or available output.
+ *
+ * Not all codecs support true asynchronous operation. Those which do are
+ * marked with AV_CODEC_CAP_ASYNC. While other codecs will likely just block
+ * the caller and do work on the caller's thread, the asynchronous mode API
+ * will (strictly speaking) still work and fulfill the guarantees given by
+ * it.
+ */
+
+/**
* Supply raw packet data as input to a decoder.
*
* Internally, this call will copy relevant AVCodecContext fields, which can
@@ -4301,6 +4361,56 @@ int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame);
*/
int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt);

+/**
+ * Determine whether there is still work to do (sending input or receiving
+ * output). See asynchronous mode section for an overview.
+ *
+ * If this returns 0, the caller thread can go to sleep (or do something else)
+ * while the codec is processing previously sent input data on a worker thread.
+ * It is guaranteed that AVCodecContext.async_notification will be called once
+ * the API user can do more progress by calling the usual functions for sending/
+ * receiving input/output. Strictly speaking, the callback could be invoked
+ * _while_ the function call returns to the caller.
+ *
+ * Here is an example that should avoid missed wakeups due to race conditions:
+ *
+ * sem_t semaphore;
+ * void user_async_notification(AVCodecContext *ctx) {
+ * // unblock the decoding loop
+ * sem_post(&semaphore);
+ * }
+ * void decode() {
+ * AVCodecContext *ctx = ...alloc and setup context...;
+ * ctx->flags2 |= AV_CODEC_FLAG2_ASYNC_MODE;
+ * ctx->async_notification = user_async_notification;
+ * sem_init(&semaphore, 0, 0);
+ * avcodec_open2(ctx, codec, NULL);
+ * // decoding loop
+ * while (1) {
+ * // exchanges packets/frames; either or both of these
+ * // might return AVERROR(EAGAIN)
+ * avcodec_send_packet(ctx, ...);
+ * avcodec_receive_frame(ctx, ...);
+ * // reset the wait count to avoid unnecessary wakeups
+ * while (!sem_try_wait(&semaphore));
+ * // the important part is that user_async_notification
+ * // could be called starting from here (_during_ and not
+ * // _after_ the avcodec_check_async_progress call)
+ * if (avcodec_check_async_progress(ctx) == 0)
+ * sem_wait(&semaphore);
+ * }
+ * ...
+ * }
+ *
+ * If asynchronous mode is not enabled with AV_CODEC_FLAG2_ASYNC_MODE, this
+ * function will always return 1, and async_notification will never be called.
+ *
+ * @return 0 if caller can go to sleep (and wait for the async_notification
+ * callback),
+ * >0 if caller has to send new input or receive output,
+ * negative error code on error.
+ */
+int avcodec_check_async_progress(AVCodecContext *avctx);

/**
* @defgroup lavc_parsing Frame parsing
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 51b0651..863334e 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -864,6 +864,25 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
}
}

+ if (codec->capabilities & AV_CODEC_CAP_ASYNC)
+ av_assert0(codec->check_async_progress);
+
+ if (avctx->flags2 & AV_CODEC_FLAG2_ASYNC_MODE) {
+ if (!avctx->async_notification) {
+ av_log(avctx, AV_LOG_ERROR,
+ "AV_CODEC_FLAG2_ASYNC_MODE set, but no "
+ "AVCodecContext.async_notification callback provided.\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+ } else if (codec->capabilities & AV_CODEC_CAP_ASYNC_ONLY) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Decoder is marked as AV_CODEC_CAP_ASYNC_ONLY, but "
+ "AV_CODEC_FLAG2_ASYNC_MODE not set.\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
avctx->internal = av_mallocz(sizeof(AVCodecInternal));
if (!avctx->internal) {
ret = AVERROR(ENOMEM);
@@ -1871,6 +1890,17 @@ int attribute_align_arg avcodec_receive_packet(AVCodecContext *avctx, AVPacket *
return 0;
}

+int attribute_align_arg avcodec_check_async_progress(AVCodecContext *avctx)
+{
+ if (!avcodec_is_open(avctx))
+ return AVERROR(EINVAL);
+
+ if (!(avctx->flags2 & AV_CODEC_FLAG2_ASYNC_MODE))
+ return 1;
+
+ return avctx->codec->check_async_progress(avctx);
+}
+
av_cold int avcodec_close(AVCodecContext *avctx)
{
int i;
--
2.7.0
wm4
2016-03-07 20:12:24 UTC
Permalink
---
libavformat/utils.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/libavformat/utils.c b/libavformat/utils.c
index 31faa95..6df1a32 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -1945,22 +1945,22 @@ FF_ENABLE_DEPRECATION_WARNINGS
(!st->codec_info_nb_frames &&
(avctx->codec->capabilities & AV_CODEC_CAP_CHANNEL_CONF)))) {
got_picture = 0;
- switch (avctx->codec_type) {
- case AVMEDIA_TYPE_VIDEO:
- ret = avcodec_decode_video2(avctx, frame,
- &got_picture, &pkt);
- break;
- case AVMEDIA_TYPE_AUDIO:
- ret = avcodec_decode_audio4(avctx, frame, &got_picture, &pkt);
- break;
- default:
- break;
+ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO ||
+ avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
+ ret = avcodec_send_packet(avctx, &pkt);
+ if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
+ break;
+ if (ret >= 0)
+ pkt.size = 0;
+ ret = avcodec_receive_frame(avctx, frame);
+ if (ret >= 0)
+ got_picture = 1;
+ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
+ ret = 0;
}
if (ret >= 0) {
if (got_picture)
st->info->nb_decoded_frames++;
- pkt.data += ret;
- pkt.size -= ret;
ret = got_picture;
}
}
--
2.7.0
wm4
2016-03-07 20:12:25 UTC
Permalink
And replace some doxygen references to them.
---
libavcodec/avcodec.h | 12 +++++++++---
libavformat/avformat.h | 4 ++--
2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 3517584..0d15d13 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -1501,7 +1501,7 @@ typedef struct AVCodecContext {
* the decoded frame is cropped before being output.
*
* @note Those field may not match the value of the last
- * AVFrame outputted by avcodec_decode_video2 due frame
+ * AVFrame outputted by avcodec_receive_frame() due frame
* reordering.
*
* - encoding: unused
@@ -1528,7 +1528,7 @@ typedef struct AVCodecContext {
* May be overriden by the decoder if it knows better.
*
* @note This field may not match the value of the last
- * AVFrame outputted by avcodec_decode_video2 due frame
+ * AVFrame outputted by avcodec_receive_frame() due frame
* reordering.
*
* - encoding: Set by user.
@@ -3655,7 +3655,7 @@ int avcodec_parameters_to_context(AVCodecContext *codec,
* @warning This function is not thread safe!
*
* @note Always call this function before using decoding routines (such as
- * @ref avcodec_decode_video2()).
+ * @ref avcodec_receive_frame()).
*
* @code
* avcodec_register_all();
@@ -4053,7 +4053,10 @@ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height,
* @return A negative error code is returned if an error occurred during
* decoding, otherwise the number of bytes consumed from the input
* AVPacket is returned.
+ *
+* @deprecated Use avcodec_send_packet() and avcodec_receive_frame().
*/
+attribute_deprecated
int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame,
int *got_frame_ptr, AVPacket *avpkt);

@@ -4099,7 +4102,10 @@ int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame,
* @param[in,out] got_picture_ptr Zero if no frame could be decompressed, otherwise, it is nonzero.
* @return On error a negative value is returned, otherwise the number of bytes
* used or zero if no frame could be decompressed.
+ *
+ * @deprecated Use avcodec_send_packet() and avcodec_receive_frame().
*/
+attribute_deprecated
int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
int *got_picture_ptr,
AVPacket *avpkt);
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 6db17f7..1a99948 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -149,8 +149,8 @@
* av_read_frame() on it. Each call, if successful, will return an AVPacket
* containing encoded data for one AVStream, identified by
* AVPacket.stream_index. This packet may be passed straight into the libavcodec
- * decoding functions avcodec_decode_video2(), avcodec_decode_audio4() or
- * avcodec_decode_subtitle2() if the caller wishes to decode the data.
+ * decoding functions avcodec_send_packet() or avcodec_decode_subtitle2() if the
+ * caller wishes to decode the data.
*
* AVPacket.pts, AVPacket.dts and AVPacket.duration timing information will be
* set if known. They may also be unset (i.e. AV_NOPTS_VALUE for
--
2.7.0
Vittorio Giovara
2016-03-07 20:23:40 UTC
Permalink
Post by wm4
And replace some doxygen references to them.
---
libavcodec/avcodec.h | 12 +++++++++---
libavformat/avformat.h | 4 ++--
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 3517584..0d15d13 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -1501,7 +1501,7 @@ typedef struct AVCodecContext {
* the decoded frame is cropped before being output.
*
- * AVFrame outputted by avcodec_decode_video2 due frame
+ * AVFrame outputted by avcodec_receive_frame() due frame
* reordering.
*
* - encoding: unused
@@ -1528,7 +1528,7 @@ typedef struct AVCodecContext {
* May be overriden by the decoder if it knows better.
*
- * AVFrame outputted by avcodec_decode_video2 due frame
+ * AVFrame outputted by avcodec_receive_frame() due frame
* reordering.
*
* - encoding: Set by user.
@@ -3655,7 +3655,7 @@ int avcodec_parameters_to_context(AVCodecContext *codec,
*
*
* avcodec_register_all();
@@ -4053,7 +4053,10 @@ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height,
* decoding, otherwise the number of bytes consumed from the input
* AVPacket is returned.
+ *
*/
+attribute_deprecated
int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame,
int *got_frame_ptr, AVPacket *avpkt);
@@ -4099,7 +4102,10 @@ int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame,
* used or zero if no frame could be decompressed.
+ *
*/
+attribute_deprecated
int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
int *got_picture_ptr,
AVPacket *avpkt);
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 6db17f7..1a99948 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -149,8 +149,8 @@
* av_read_frame() on it. Each call, if successful, will return an AVPacket
* containing encoded data for one AVStream, identified by
* AVPacket.stream_index. This packet may be passed straight into the libavcodec
- * decoding functions avcodec_decode_video2(), avcodec_decode_audio4() or
- * avcodec_decode_subtitle2() if the caller wishes to decode the data.
+ * decoding functions avcodec_send_packet() or avcodec_decode_subtitle2() if the
+ * caller wishes to decode the data.
*
* AVPacket.pts, AVPacket.dts and AVPacket.duration timing information will be
* set if known. They may also be unset (i.e. AV_NOPTS_VALUE for
--
2.7.0
I would add more info in doc/APIchanges too.
--
Vittorio
wm4
2016-03-07 20:34:34 UTC
Permalink
On Mon, 7 Mar 2016 15:23:40 -0500
Post by Vittorio Giovara
Post by wm4
And replace some doxygen references to them.
---
libavcodec/avcodec.h | 12 +++++++++---
libavformat/avformat.h | 4 ++--
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 3517584..0d15d13 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -1501,7 +1501,7 @@ typedef struct AVCodecContext {
* the decoded frame is cropped before being output.
*
- * AVFrame outputted by avcodec_decode_video2 due frame
+ * AVFrame outputted by avcodec_receive_frame() due frame
* reordering.
*
* - encoding: unused
@@ -1528,7 +1528,7 @@ typedef struct AVCodecContext {
* May be overriden by the decoder if it knows better.
*
- * AVFrame outputted by avcodec_decode_video2 due frame
+ * AVFrame outputted by avcodec_receive_frame() due frame
* reordering.
*
* - encoding: Set by user.
@@ -3655,7 +3655,7 @@ int avcodec_parameters_to_context(AVCodecContext *codec,
*
*
* avcodec_register_all();
@@ -4053,7 +4053,10 @@ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height,
* decoding, otherwise the number of bytes consumed from the input
* AVPacket is returned.
+ *
*/
+attribute_deprecated
int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame,
int *got_frame_ptr, AVPacket *avpkt);
@@ -4099,7 +4102,10 @@ int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame,
* used or zero if no frame could be decompressed.
+ *
*/
+attribute_deprecated
int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
int *got_picture_ptr,
AVPacket *avpkt);
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 6db17f7..1a99948 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -149,8 +149,8 @@
* av_read_frame() on it. Each call, if successful, will return an AVPacket
* containing encoded data for one AVStream, identified by
* AVPacket.stream_index. This packet may be passed straight into the libavcodec
- * decoding functions avcodec_decode_video2(), avcodec_decode_audio4() or
- * avcodec_decode_subtitle2() if the caller wishes to decode the data.
+ * decoding functions avcodec_send_packet() or avcodec_decode_subtitle2() if the
+ * caller wishes to decode the data.
*
* AVPacket.pts, AVPacket.dts and AVPacket.duration timing information will be
* set if known. They may also be unset (i.e. AV_NOPTS_VALUE for
--
2.7.0
I would add more info in doc/APIchanges too.
Sure, and the examples also have to be updated. This stuff can be done
later. First we should discuss whether we want to deprecate these
functions at all yet.

(Also, the commit message should read "deprecate old encode/decode
functions".)
Anton Khirnov
2016-03-08 08:04:31 UTC
Permalink
Quoting wm4 (2016-03-07 21:34:34)
Post by wm4
Sure, and the examples also have to be updated. This stuff can be done
later. First we should discuss whether we want to deprecate these
functions at all yet.
I already stated my reasons for deprecating them now. Is anyone against?
--
Anton Khirnov
Loading...