Commit 061a0c14 authored by Anton Khirnov's avatar Anton Khirnov

decode: restructure the core decoding code

Currently, the new decoding API is pretty much just a wrapper around the
old deprecated one. This is problematic, since it interferes with making
full use of the flexibility added by the new API. The old API should
also be removed at some future point.

Reorganize the code so that the new send_packet/receive_frame functions
call the actual decoding directly and change the old deprecated
avcodec_decode_* functions into wrappers around the new API.

The new internal API for decoders is now changing as well. Before this
commit, it mirrors the public API, so the decoders need to implement
send_packet() and receive_frame() callbacks. This turns out to require
awkward constructs in both the decoders and the generic code. After this
commit, the decoders only implement the receive_frame() callback and
call a new internal function, ff_decode_get_packet() to obtain input
data, in the same manner to how the bitstream filters now work.

avcodec will now always make a reference to the input packet, which means
that non-refcounted input packets will be copied. Keeping the previous
behaviour, where this copy could sometimes be avoided, would make the
code significantly more complex and fragile for only dubious gains,
since packets are typically small and everyone who cares about
performance should use refcounted packets anyway.
parent 549d0bdc
...@@ -3217,20 +3217,22 @@ typedef struct AVCodec { ...@@ -3217,20 +3217,22 @@ typedef struct AVCodec {
int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt); int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt);
int (*close)(AVCodecContext *); int (*close)(AVCodecContext *);
/** /**
* Decode/encode API with decoupled packet/frame dataflow. The API is the * Encode API with decoupled packet/frame dataflow. The API is the
* same as the avcodec_ prefixed APIs (avcodec_send_frame() etc.), except * same as the avcodec_ prefixed APIs (avcodec_send_frame() etc.), except
* that: * that:
* - never called if the codec is closed or the wrong type, * - never called if the codec is closed or the wrong type,
* - AVPacket parameter change side data is applied right before calling * - if AV_CODEC_CAP_DELAY is not set, drain frames are never sent,
* AVCodec->send_packet, * - only one drain frame is ever passed down,
* - 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_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); int (*receive_packet)(AVCodecContext *avctx, AVPacket *avpkt);
/**
* Decode API with decoupled packet/frame dataflow. This function is called
* to get one output frame. It should call ff_decode_get_packet() to obtain
* input data.
*/
int (*receive_frame)(AVCodecContext *avctx, AVFrame *frame);
/** /**
* Flush buffers. * Flush buffers.
* Will be called when seeking * Will be called when seeking
......
This diff is collapsed.
/*
* generic decoding-related code
*
* This file is part of Libav.
*
* Libav is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Libav is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_DECODE_H
#define AVCODEC_DECODE_H
/**
* Called by decoders to get the next packet for decoding.
*
* @param pkt An empty packet to be filled with data.
* @return 0 if a new reference has been successfully written to pkt
* AVERROR(EAGAIN) if no data is currently available
* AVERROR_EOF if and end of stream has been reached, so no more data
* will be available
*/
int ff_decode_get_packet(AVCodecContext *avctx, AVPacket *pkt);
#endif /* AVCODEC_DECODE_H */
...@@ -94,6 +94,11 @@ typedef struct FramePool { ...@@ -94,6 +94,11 @@ typedef struct FramePool {
int samples; int samples;
} FramePool; } FramePool;
typedef struct DecodeSimpleContext {
AVPacket *in_pkt;
AVFrame *out_frame;
} DecodeSimpleContext;
typedef struct AVCodecInternal { typedef struct AVCodecInternal {
/** /**
* Whether the parent AVCodecContext is a copy of the context which had * Whether the parent AVCodecContext is a copy of the context which had
...@@ -130,6 +135,8 @@ typedef struct AVCodecInternal { ...@@ -130,6 +135,8 @@ typedef struct AVCodecInternal {
void *thread_ctx; void *thread_ctx;
DecodeSimpleContext ds;
/** /**
* Properties (timestamps+side data) extracted from the last packet passed * Properties (timestamps+side data) extracted from the last packet passed
* for decoding. * for decoding.
...@@ -153,6 +160,16 @@ typedef struct AVCodecInternal { ...@@ -153,6 +160,16 @@ typedef struct AVCodecInternal {
int buffer_pkt_valid; // encoding: packet without data can be valid int buffer_pkt_valid; // encoding: packet without data can be valid
AVFrame *buffer_frame; AVFrame *buffer_frame;
int draining_done; int draining_done;
/* set to 1 when the caller is using the old decoding API */
int compat_decode;
int compat_decode_warned;
/* this variable is set by the decoder internals to signal to the old
* API compat wrappers the amount of data consumed from the last packet */
size_t compat_decode_consumed;
/* when a partial packet has been consumed, this stores the remaining size
* of the packet (that should be submitted in the next decode call */
size_t compat_decode_partial_size;
AVFrame *compat_decode_frame;
} AVCodecInternal; } AVCodecInternal;
struct AVCodecDefault { struct AVCodecDefault {
......
...@@ -100,7 +100,7 @@ int av_codec_is_encoder(const AVCodec *codec) ...@@ -100,7 +100,7 @@ int av_codec_is_encoder(const AVCodec *codec)
int av_codec_is_decoder(const AVCodec *codec) int av_codec_is_decoder(const AVCodec *codec)
{ {
return codec && (codec->decode || codec->send_packet); return codec && (codec->decode || codec->receive_frame);
} }
av_cold void avcodec_register(AVCodec *codec) av_cold void avcodec_register(AVCodec *codec)
...@@ -421,6 +421,12 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code ...@@ -421,6 +421,12 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
goto free_and_end; goto free_and_end;
} }
avctx->internal->compat_decode_frame = av_frame_alloc();
if (!avctx->internal->compat_decode_frame) {
ret = AVERROR(ENOMEM);
goto free_and_end;
}
avctx->internal->buffer_frame = av_frame_alloc(); avctx->internal->buffer_frame = av_frame_alloc();
if (!avctx->internal->buffer_frame) { if (!avctx->internal->buffer_frame) {
ret = AVERROR(ENOMEM); ret = AVERROR(ENOMEM);
...@@ -433,6 +439,12 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code ...@@ -433,6 +439,12 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
goto free_and_end; goto free_and_end;
} }
avctx->internal->ds.in_pkt = av_packet_alloc();
if (!avctx->internal->ds.in_pkt) {
ret = AVERROR(ENOMEM);
goto free_and_end;
}
avctx->internal->last_pkt_props = av_packet_alloc(); avctx->internal->last_pkt_props = av_packet_alloc();
if (!avctx->internal->last_pkt_props) { if (!avctx->internal->last_pkt_props) {
ret = AVERROR(ENOMEM); ret = AVERROR(ENOMEM);
...@@ -717,9 +729,13 @@ FF_ENABLE_DEPRECATION_WARNINGS ...@@ -717,9 +729,13 @@ FF_ENABLE_DEPRECATION_WARNINGS
av_freep(&avctx->priv_data); av_freep(&avctx->priv_data);
if (avctx->internal) { if (avctx->internal) {
av_frame_free(&avctx->internal->to_free); av_frame_free(&avctx->internal->to_free);
av_frame_free(&avctx->internal->compat_decode_frame);
av_frame_free(&avctx->internal->buffer_frame); av_frame_free(&avctx->internal->buffer_frame);
av_packet_free(&avctx->internal->buffer_pkt); av_packet_free(&avctx->internal->buffer_pkt);
av_packet_free(&avctx->internal->last_pkt_props); av_packet_free(&avctx->internal->last_pkt_props);
av_packet_free(&avctx->internal->ds.in_pkt);
av_freep(&avctx->internal->pool); av_freep(&avctx->internal->pool);
} }
av_freep(&avctx->internal); av_freep(&avctx->internal);
...@@ -758,9 +774,13 @@ av_cold int avcodec_close(AVCodecContext *avctx) ...@@ -758,9 +774,13 @@ av_cold int avcodec_close(AVCodecContext *avctx)
if (avctx->codec && avctx->codec->close) if (avctx->codec && avctx->codec->close)
avctx->codec->close(avctx); avctx->codec->close(avctx);
av_frame_free(&avctx->internal->to_free); av_frame_free(&avctx->internal->to_free);
av_frame_free(&avctx->internal->compat_decode_frame);
av_frame_free(&avctx->internal->buffer_frame); av_frame_free(&avctx->internal->buffer_frame);
av_packet_free(&avctx->internal->buffer_pkt); av_packet_free(&avctx->internal->buffer_pkt);
av_packet_free(&avctx->internal->last_pkt_props); av_packet_free(&avctx->internal->last_pkt_props);
av_packet_free(&avctx->internal->ds.in_pkt);
for (i = 0; i < FF_ARRAY_ELEMS(pool->pools); i++) for (i = 0; i < FF_ARRAY_ELEMS(pool->pools); i++)
av_buffer_pool_uninit(&pool->pools[i]); av_buffer_pool_uninit(&pool->pools[i]);
av_freep(&avctx->internal->pool); av_freep(&avctx->internal->pool);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment