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.
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.
---
libavcodec/decode.c | 447 ++++++++++++++++++++++++++++++--------------------
libavcodec/internal.h | 17 ++
libavcodec/utils.c | 28 ++++
3 files changed, 315 insertions(+), 177 deletions(-)
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index c03991c..2467800 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -24,6 +24,7 @@
#include "config.h"
#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
#include "libavutil/common.h"
#include "libavutil/frame.h"
#include "libavutil/hwcontext.h"
@@ -152,269 +153,357 @@ static int unrefcount_frame(AVCodecInternal *avci,
AVFrame *frame)
return 0;
}
-static int do_decode(AVCodecContext *avctx, AVPacket *pkt)
+/*
+ * A send/receive wrapper for decoders implementing the "simple" API with fused
+ * input and output.
+ *
+ * @return 0 on success (does NOT mean a frame has been returned)
+ * AVERROR(EAGAIN) when more input is needed
+ * AVERROR_EOF when the flushing has been completed
+ **/
+static int decode_send_receive(AVCodecContext *avctx, AVFrame *frame)
{
+ AVCodecInternal *avci = avctx->internal;
+ DecodeSimpleContext *ds = &avci->ds;
+ AVPacket *pkt = ds->in_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;
+ av_assert0(!frame->buf[0]);
// Some codecs (at least wma lossless) will crash when feeding drain
packets
// after EOF was signaled.
- if (avctx->internal->draining_done)
+ if (avci->draining_done)
return AVERROR_EOF;
- 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);
+ if (!pkt->data) {
+ if (!avci->draining)
+ return AVERROR(EAGAIN);
+
+ if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY ||
+ avctx->active_thread_type & FF_THREAD_FRAME))
+ return AVERROR_EOF;
+ }
+
+ got_frame = 0;
+
+ if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME) {
+ ret = ff_thread_decode_frame(avctx, frame, &got_frame, pkt);
} else {
- ret = AVERROR(EINVAL);
+ ret = avctx->codec->decode(avctx, frame, &got_frame, pkt);
+
+ if (!(avctx->codec->caps_internal & FF_CODEC_CAP_SETS_PKT_DTS))
+ frame->pkt_dts = pkt->dts;
+ /* get_buffer is supposed to set frame parameters */
+ if (!(avctx->codec->capabilities & AV_CODEC_CAP_DR1)) {
+ frame->sample_aspect_ratio = avctx->sample_aspect_ratio;
+ frame->width = avctx->width;
+ frame->height = avctx->height;
+ frame->format = avctx->codec->type ==
AVMEDIA_TYPE_VIDEO ?
+ avctx->pix_fmt : avctx->sample_fmt;
+ }
}
- if (ret < 0)
- return ret;
+ emms_c();
+
+ if (!got_frame)
+ av_frame_unref(frame);
+
+ if (ret >= 0 && avctx->codec->type == AVMEDIA_TYPE_VIDEO)
+ ret = pkt->size;
+
+#if FF_API_AVCTX_TIMEBASE
+ if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
+ avctx->time_base = av_inv_q(avctx->framerate);
+#endif
if (avctx->internal->draining && !got_frame)
- avctx->internal->draining_done = 1;
+ avci->draining_done = 1;
+
+ avctx->internal->compat_decode_consumed += ret;
- if (ret >= pkt->size) {
- av_packet_unref(avctx->internal->buffer_pkt);
+ if (ret >= pkt->size || ret < 0) {
+ av_packet_unref(pkt);
} else {
int consumed = ret;
- if (pkt != avctx->internal->buffer_pkt) {
- av_packet_unref(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;
- avctx->internal->buffer_pkt->pts = AV_NOPTS_VALUE;
- avctx->internal->buffer_pkt->dts = AV_NOPTS_VALUE;
+ pkt->data += consumed;
+ pkt->size -= consumed;
+ pkt->pts = AV_NOPTS_VALUE;
+ pkt->dts = AV_NOPTS_VALUE;
+ avci->last_pkt_props->pts = AV_NOPTS_VALUE;
+ avci->last_pkt_props->dts = AV_NOPTS_VALUE;
}
if (got_frame)
- av_assert0(avctx->internal->buffer_frame->buf[0]);
+ av_assert0(frame->buf[0]);
- return 0;
+ return ret < 0 ? ret : 0;
}
-int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const
AVPacket *avpkt)
+static int decode_simple_send_packet(AVCodecContext *avctx, const AVPacket
*pkt)
{
+ AVCodecInternal *avci = avctx->internal;
+ DecodeSimpleContext *ds = &avci->ds;
int ret;
- if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec))
- return AVERROR(EINVAL);
+ if (ds->out_frame->buf[0])
+ return AVERROR(EAGAIN);
- if (avctx->internal->draining)
- return AVERROR_EOF;
+ if (pkt) {
+ if (ds->in_pkt->data)
+ return AVERROR(EAGAIN);
- if (!avpkt || !avpkt->size) {
- avctx->internal->draining = 1;
- avpkt = NULL;
+ av_packet_unref(ds->in_pkt);
+ ret = av_packet_ref(ds->in_pkt, pkt);
+ if (ret < 0)
+ return ret;
+ }
- if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY))
- return 0;
+ ret = decode_send_receive(avctx, ds->out_frame);
+ return (ret == AVERROR(EAGAIN)) ? 0 : ret;
+}
+
+static int decode_simple_receive_frame(AVCodecContext *avctx, AVFrame *frame)
+{
+ AVCodecInternal *avci = avctx->internal;
+ DecodeSimpleContext *ds = &avci->ds;
+ int ret;
+
+ if (ds->out_frame->buf[0]) {
+ av_frame_move_ref(frame, ds->out_frame);
+ return 0;
}
- if (avctx->codec->send_packet) {
- if (avpkt) {
- ret = apply_param_change(avctx, (AVPacket *)avpkt);
- if (ret < 0)
- return ret;
- }
- return avctx->codec->send_packet(avctx, avpkt);
+ while (!frame->buf[0]) {
+ ret = decode_send_receive(avctx, frame);
+ if (ret < 0)
+ return ret;
}
- // Emulation via old API. Assume avpkt is likely not refcounted, while
- // decoder output is always refcounted, and avoid copying.
+ return frame->buf[0] ? 0 : AVERROR(EAGAIN);
+}
- if (avctx->internal->buffer_pkt->size ||
avctx->internal->buffer_frame->buf[0])
- return AVERROR(EAGAIN);
+/*
+ * Read one frame from the end of the decoding chain (i.e. the actual decoder).
+ */
+static int decode_chain_receive_frame(AVCodecContext *avctx)
+{
+ AVCodecInternal *avci = avctx->internal;
+ AVFrame *frame = avci->buffer_frame;
+ int ret;
+
+ av_assert0(!frame->buf[0]);
- // 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);
+ if (avctx->codec->receive_frame)
+ ret = avctx->codec->receive_frame(avctx, frame);
+ else
+ ret = decode_simple_receive_frame(avctx, frame);
+
+ if (ret == AVERROR_EOF)
+ avci->draining_done = 1;
+
+ return ret;
}
-int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame
*frame)
+static int decode_chain_send_packet(AVCodecContext *avctx)
{
+ AVCodecInternal *avci = avctx->internal;
+ AVPacket *pkt = avci->draining ? NULL : avci->buffer_pkt;
int ret;
- av_frame_unref(frame);
+ if (pkt) {
+ if (!pkt->data && !pkt->side_data_elems)
+ return AVERROR(EAGAIN);
- if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec))
- return AVERROR(EINVAL);
+ ret = extract_packet_props(avctx->internal, pkt);
+ if (ret < 0)
+ goto finish;
- 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);
+ ret = apply_param_change(avctx, pkt);
+ if (ret < 0)
+ goto finish;
}
- // Emulation via old API.
+ if (avctx->codec->send_packet) {
+ ret = avctx->codec->send_packet(avctx, pkt);
+ if (ret >= 0)
+ avci->compat_decode_consumed += pkt->size;
+ } else {
+ ret = decode_simple_send_packet(avctx, pkt);
+ }
- if (!avctx->internal->buffer_frame->buf[0]) {
- if (!avctx->internal->buffer_pkt->size && !avctx->internal->draining)
- return AVERROR(EAGAIN);
+finish:
+ if (pkt && ret != AVERROR(EAGAIN))
+ av_packet_unref(pkt);
- while (1) {
- if ((ret = do_decode(avctx, avctx->internal->buffer_pkt)) < 0) {
- av_packet_unref(avctx->internal->buffer_pkt);
- return ret;
- }
- // Some audio decoders may consume partial data without returning
- // a frame (fate-wmapro-2ch). There is no way to make the caller
- // call avcodec_receive_frame() again without returning a frame,
- // so try to decode more in these cases.
- if (avctx->internal->buffer_frame->buf[0] ||
- !avctx->internal->buffer_pkt->size)
- break;
- }
- }
+ return ret;
+}
+
+static int process_decode_chain(AVCodecContext *avctx)
+{
+ AVCodecInternal *avci = avctx->internal;
+ int ret = 0;
+
+ while (!avci->buffer_frame->buf[0]) {
+ if (avci->draining_done)
+ return AVERROR_EOF;
+
+ ret = decode_chain_receive_frame(avctx);
+ if (ret != AVERROR(EAGAIN))
+ return ret;
- if (!avctx->internal->buffer_frame->buf[0])
- return avctx->internal->draining ? AVERROR_EOF : AVERROR(EAGAIN);
+ ret = decode_chain_send_packet(avctx);
+ if (ret < 0)
+ return (ret == AVERROR(EAGAIN)) ? 0 : ret;
+ }
- av_frame_move_ref(frame, avctx->internal->buffer_frame);
return 0;
}
-int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame
*picture,
- int *got_picture_ptr,
- AVPacket *avpkt)
+int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const
AVPacket *avpkt)
{
AVCodecInternal *avci = avctx->internal;
- int ret;
+ int ret = 0;
- *got_picture_ptr = 0;
- if ((avctx->coded_width || avctx->coded_height) &&
av_image_check_size(avctx->coded_width, avctx->coded_height, 0, avctx))
- return -1;
+ if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec))
+ return AVERROR(EINVAL);
- if (!avctx->codec->decode) {
- av_log(avctx, AV_LOG_ERROR, "This decoder requires using the
avcodec_send_packet() API.\n");
- return AVERROR(ENOSYS);
+ if (avctx->internal->draining)
+ return AVERROR_EOF;
+
+ if (avci->buffer_pkt->data || avci->buffer_pkt->side_data_elems)
+ return AVERROR(EAGAIN);
+
+ if (!avpkt || !avpkt->size) {
+ avctx->internal->draining = 1;
+ } else {
+ ret = av_packet_ref(avci->buffer_pkt, avpkt);
+ if (ret < 0)
+ return ret;
}
- ret = extract_packet_props(avci, avpkt);
+ ret = process_decode_chain(avctx);
if (ret < 0)
return ret;
- ret = apply_param_change(avctx, avpkt);
- if (ret < 0)
- return ret;
+ return 0;
+}
- av_frame_unref(picture);
-
- if ((avctx->codec->capabilities & AV_CODEC_CAP_DELAY) || avpkt->size ||
- (avctx->active_thread_type & FF_THREAD_FRAME)) {
- if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME)
- ret = ff_thread_decode_frame(avctx, picture, got_picture_ptr,
- avpkt);
- else {
- ret = avctx->codec->decode(avctx, picture, got_picture_ptr,
- avpkt);
- if (!(avctx->codec->caps_internal & FF_CODEC_CAP_SETS_PKT_DTS))
- picture->pkt_dts = avpkt->dts;
- /* get_buffer is supposed to set frame parameters */
- if (!(avctx->codec->capabilities & AV_CODEC_CAP_DR1)) {
- picture->sample_aspect_ratio = avctx->sample_aspect_ratio;
- picture->width = avctx->width;
- picture->height = avctx->height;
- picture->format = avctx->pix_fmt;
- }
- }
+int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame
*frame)
+{
+ AVCodecInternal *avci = avctx->internal;
+ int ret;
- emms_c(); //needed to avoid an emms_c() call before every return;
+ av_frame_unref(frame);
- if (*got_picture_ptr) {
- if (!avctx->refcounted_frames) {
- int err = unrefcount_frame(avci, picture);
- if (err < 0)
- return err;
- }
+ if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec))
+ return AVERROR(EINVAL);
- avctx->frame_number++;
- } else
- av_frame_unref(picture);
- } else
- ret = 0;
+ if (!avci->buffer_frame->buf[0]) {
+ ret = process_decode_chain(avctx);
+ if (ret < 0)
+ return ret;
-#if FF_API_AVCTX_TIMEBASE
- if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
- avctx->time_base = av_inv_q(avctx->framerate);
-#endif
+ if (!avci->buffer_frame->buf[0])
+ return AVERROR(EAGAIN);
+ }
- return ret;
+ av_frame_move_ref(frame, avci->buffer_frame);
+ avctx->frame_number++;
+
+ return 0;
}
-int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,
- AVFrame *frame,
- int *got_frame_ptr,
- AVPacket *avpkt)
+static int compat_decode(AVCodecContext *avctx, AVFrame *frame,
+ int *got_frame, AVPacket *pkt)
{
AVCodecInternal *avci = avctx->internal;
- int ret = 0;
-
- *got_frame_ptr = 0;
+ AVFrame *dummy_frame = NULL;
+ int ret;
- if (!avctx->codec->decode) {
- av_log(avctx, AV_LOG_ERROR, "This decoder requires using the
avcodec_send_packet() API.\n");
- return AVERROR(ENOSYS);
- }
+ av_assert0(avci->compat_decode_consumed == 0);
- ret = extract_packet_props(avci, avpkt);
- if (ret < 0)
- return ret;
+ *got_frame = 0;
+ avci->compat_decode = 1;
- if (!avpkt->data && avpkt->size) {
- av_log(avctx, AV_LOG_ERROR, "invalid packet: NULL data, size != 0\n");
- return AVERROR(EINVAL);
+ if (avci->compat_decode_partial_size > 0 &&
+ avci->compat_decode_partial_size != pkt->size) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Got unexpected packet size after a partial decode\n");
+ ret = AVERROR(EINVAL);
+ goto finish;
}
- ret = apply_param_change(avctx, avpkt);
- if (ret < 0)
- return ret;
-
- av_frame_unref(frame);
+ if (!avci->compat_decode_partial_size) {
+ ret = avcodec_send_packet(avctx, pkt);
+ if (ret == AVERROR_EOF)
+ ret = 0;
+ else if (ret == AVERROR(EAGAIN)) {
+ /* we fully drain all the output in each decode call, so this
should not
+ * ever happen */
+ ret = AVERROR_BUG;
+ goto finish;
+ } else if (ret < 0)
+ goto finish;
+ }
- if ((avctx->codec->capabilities & AV_CODEC_CAP_DELAY) || avpkt->size) {
- ret = avctx->codec->decode(avctx, frame, got_frame_ptr, avpkt);
- if (ret >= 0 && *got_frame_ptr) {
- avctx->frame_number++;
- frame->pkt_dts = avpkt->dts;
- if (frame->format == AV_SAMPLE_FMT_NONE)
- frame->format = avctx->sample_fmt;
+ while (ret >= 0) {
+ ret = avcodec_receive_frame(avctx, frame);
+ if (ret < 0) {
+ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
+ ret = 0;
+ goto finish;
+ }
+ if (frame != avci->compat_decode_frame) {
if (!avctx->refcounted_frames) {
- int err = unrefcount_frame(avci, frame);
- if (err < 0)
- return err;
+ ret = unrefcount_frame(avci, frame);
+ if (ret < 0)
+ goto finish;
}
- } else
- av_frame_unref(frame);
+
+ *got_frame = 1;
+ frame = avci->compat_decode_frame;
+ } else {
+ av_frame_unref(dummy_frame);
+ if (!avci->compat_decode_warned) {
+ av_log(avctx, AV_LOG_WARNING, "The deprecated avcodec_decode_*
"
+ "API cannot return all the frames for this decoder. "
+ "Some frames will be dropped. Update your code to the "
+ "new decoding API to fix this.\n");
+ avci->compat_decode_warned = 1;
+ }
+ }
+
+ if (avci->draining || avci->compat_decode_consumed < pkt->size)
+ break;
}
+finish:
+ if (ret == 0)
+ ret = FFMIN(avci->compat_decode_consumed, pkt->size);
+ avci->compat_decode_consumed = 0;
+ avci->compat_decode_partial_size = (ret >= 0) ? pkt->size - ret : 0;
return ret;
}
+int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame
*picture,
+ int *got_picture_ptr,
+ AVPacket *avpkt)
+{
+ return compat_decode(avctx, picture, got_picture_ptr, avpkt);
+}
+
+int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,
+ AVFrame *frame,
+ int *got_frame_ptr,
+ AVPacket *avpkt)
+{
+ return compat_decode(avctx, frame, got_frame_ptr, avpkt);
+}
+
int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
int *got_sub_ptr,
AVPacket *avpkt)
@@ -918,9 +1007,13 @@ void avcodec_flush_buffers(AVCodecContext *avctx)
avctx->internal->draining = 0;
avctx->internal->draining_done = 0;
av_frame_unref(avctx->internal->buffer_frame);
+ av_frame_unref(avctx->internal->compat_decode_frame);
av_packet_unref(avctx->internal->buffer_pkt);
avctx->internal->buffer_pkt_valid = 0;
+ av_packet_unref(avctx->internal->ds.in_pkt);
+ av_frame_unref(avctx->internal->ds.out_frame);
+
if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME)
ff_thread_flush(avctx);
else if (avctx->codec->flush)
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index 2ca7a45..dc24e8f 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -94,6 +94,11 @@ typedef struct FramePool {
int samples;
} FramePool;
+typedef struct DecodeSimpleContext {
+ AVPacket *in_pkt;
+ AVFrame *out_frame;
+} DecodeSimpleContext;
+
typedef struct AVCodecInternal {
/**
* Whether the parent AVCodecContext is a copy of the context which had
@@ -130,6 +135,8 @@ typedef struct AVCodecInternal {
void *thread_ctx;
+ DecodeSimpleContext ds;
+
/**
* Properties (timestamps+side data) extracted from the last packet passed
* for decoding.
@@ -153,6 +160,16 @@ typedef struct AVCodecInternal {
int buffer_pkt_valid; // encoding: packet without data can be valid
AVFrame *buffer_frame;
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;
struct AVCodecDefault {
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index a16f4f2..3901d08 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -421,6 +421,12 @@ int attribute_align_arg avcodec_open2(AVCodecContext
*avctx, const AVCodec *code
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();
if (!avctx->internal->buffer_frame) {
ret = AVERROR(ENOMEM);
@@ -433,6 +439,18 @@ int attribute_align_arg avcodec_open2(AVCodecContext
*avctx, const AVCodec *code
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->ds.out_frame = av_frame_alloc();
+ if (!avctx->internal->ds.out_frame) {
+ ret = AVERROR(ENOMEM);
+ goto free_and_end;
+ }
+
avctx->internal->last_pkt_props = av_packet_alloc();
if (!avctx->internal->last_pkt_props) {
ret = AVERROR(ENOMEM);
@@ -717,9 +735,14 @@ FF_ENABLE_DEPRECATION_WARNINGS
av_freep(&avctx->priv_data);
if (avctx->internal) {
av_frame_free(&avctx->internal->to_free);
+ av_frame_free(&avctx->internal->compat_decode_frame);
av_frame_free(&avctx->internal->buffer_frame);
av_packet_free(&avctx->internal->buffer_pkt);
av_packet_free(&avctx->internal->last_pkt_props);
+
+ av_packet_free(&avctx->internal->ds.in_pkt);
+ av_frame_free(&avctx->internal->ds.out_frame);
+
av_freep(&avctx->internal->pool);
}
av_freep(&avctx->internal);
@@ -758,9 +781,14 @@ 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->compat_decode_frame);
av_frame_free(&avctx->internal->buffer_frame);
av_packet_free(&avctx->internal->buffer_pkt);
av_packet_free(&avctx->internal->last_pkt_props);
+
+ av_packet_free(&avctx->internal->ds.in_pkt);
+ av_frame_free(&avctx->internal->ds.out_frame);
+
for (i = 0; i < FF_ARRAY_ELEMS(pool->pools); i++)
av_buffer_pool_uninit(&pool->pools[i]);
av_freep(&avctx->internal->pool);
--
2.0.0
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel