diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 6e1ed74e08..1827711b50 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -3217,20 +3217,22 @@ 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 + * 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). + * - if AV_CODEC_CAP_DELAY is not set, drain frames are never sent, + * - only one drain frame is ever passed down, */ 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); + + /** + * 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. * Will be called when seeking diff --git a/libavcodec/decode.c b/libavcodec/decode.c index b02278d3a6..a1908ecf4b 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" @@ -31,6 +32,7 @@ #include "avcodec.h" #include "bytestream.h" +#include "decode.h" #include "internal.h" #include "thread.h" @@ -152,70 +154,158 @@ static int unrefcount_frame(AVCodecInternal *avci, AVFrame *frame) return 0; } -static int do_decode(AVCodecContext *avctx, AVPacket *pkt) +int ff_decode_get_packet(AVCodecContext *avctx, AVPacket *pkt) { + AVCodecInternal *avci = avctx->internal; + int ret; + + if (avci->draining) + return AVERROR_EOF; + + if (!avci->buffer_pkt->data && !avci->buffer_pkt->side_data_elems) + return AVERROR(EAGAIN); + + av_packet_move_ref(pkt, avci->buffer_pkt); + + ret = extract_packet_props(avctx->internal, pkt); + if (ret < 0) + goto finish; + + ret = apply_param_change(avctx, pkt); + if (ret < 0) + goto finish; + + if (avctx->codec->receive_frame) + avci->compat_decode_consumed += pkt->size; + + return 0; +finish: + av_packet_unref(pkt); + return ret; +} + +/* + * The core of the receive_frame_wrapper for the decoders implementing + * the simple API. Certain decoders might consume partial packets without + * returning any output, so this function needs to be called in a loop until it + * returns EAGAIN. + **/ +static int decode_simple_internal(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; + if (!pkt->data && !avci->draining) { + av_packet_unref(pkt); + ret = ff_decode_get_packet(avctx, pkt); + if (ret < 0 && ret != AVERROR_EOF) + return ret; + } // 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 && + !(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; - if (ret >= pkt->size) { - av_packet_unref(avctx->internal->buffer_pkt); + avci->compat_decode_consumed += ret; + + 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 ret < 0 ? ret : 0; +} + +static int decode_simple_receive_frame(AVCodecContext *avctx, AVFrame *frame) +{ + int ret; + + while (!frame->buf[0]) { + ret = decode_simple_internal(avctx, frame); + if (ret < 0) + return ret; + } return 0; } +static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) +{ + AVCodecInternal *avci = avctx->internal; + int ret; + + av_assert0(!frame->buf[0]); + + 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_send_packet(AVCodecContext *avctx, const AVPacket *avpkt) { - int ret; + AVCodecInternal *avci = avctx->internal; + int ret = 0; if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec)) return AVERROR(EINVAL); @@ -223,38 +313,29 @@ int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacke 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) { - if (avpkt) { - 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]) + if (avci->buffer_pkt->data || avci->buffer_pkt->side_data_elems) 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); + if (!avpkt || !avpkt->size) { + avctx->internal->draining = 1; + } else { + ret = av_packet_ref(avci->buffer_pkt, avpkt); + if (ret < 0) + return ret; + } + + if (!avci->buffer_frame->buf[0]) { + ret = decode_receive_frame_internal(avctx, avci->buffer_frame); + if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) + return ret; + } + + return 0; } int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame) { + AVCodecInternal *avci = avctx->internal; int ret; av_frame_unref(frame); @@ -262,106 +343,96 @@ int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *fr 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); + if (avci->buffer_frame->buf[0]) { + av_frame_move_ref(frame, avci->buffer_frame); + } else { + ret = decode_receive_frame_internal(avctx, frame); + if (ret < 0) + return ret; } - // Emulation via old API. + avctx->frame_number++; - if (!avctx->internal->buffer_frame->buf[0]) { - if (!avctx->internal->buffer_pkt->size && !avctx->internal->draining) - return AVERROR(EAGAIN); - - 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; - } - } - - 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 compat_decode(AVCodecContext *avctx, AVFrame *frame, + int *got_frame, AVPacket *pkt) +{ + AVCodecInternal *avci = avctx->internal; + int ret; + + av_assert0(avci->compat_decode_consumed == 0); + + *got_frame = 0; + avci->compat_decode = 1; + + 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; + } + + 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; + } + + 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) { + ret = unrefcount_frame(avci, frame); + if (ret < 0) + goto finish; + } + + *got_frame = 1; + frame = avci->compat_decode_frame; + } else { + 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) { - AVCodecInternal *avci = avctx->internal; - int ret; - - *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 (!avctx->codec->decode) { - av_log(avctx, AV_LOG_ERROR, "This decoder requires using the avcodec_send_packet() API.\n"); - return AVERROR(ENOSYS); - } - - ret = extract_packet_props(avci, avpkt); - if (ret < 0) - return ret; - - ret = apply_param_change(avctx, avpkt); - if (ret < 0) - return ret; - - 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; - } - } - - emms_c(); //needed to avoid an emms_c() call before every return; - - if (*got_picture_ptr) { - if (!avctx->refcounted_frames) { - int err = unrefcount_frame(avci, picture); - if (err < 0) - return err; - } - - avctx->frame_number++; - } else - av_frame_unref(picture); - } else - ret = 0; - -#if FF_API_AVCTX_TIMEBASE - if (avctx->framerate.num > 0 && avctx->framerate.den > 0) - avctx->time_base = av_inv_q(avctx->framerate); -#endif - - return ret; + return compat_decode(avctx, picture, got_picture_ptr, avpkt); } int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx, @@ -369,50 +440,7 @@ int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx, int *got_frame_ptr, AVPacket *avpkt) { - AVCodecInternal *avci = avctx->internal; - int ret = 0; - - *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); - } - - ret = extract_packet_props(avci, avpkt); - if (ret < 0) - return ret; - - if (!avpkt->data && avpkt->size) { - av_log(avctx, AV_LOG_ERROR, "invalid packet: NULL data, size != 0\n"); - return AVERROR(EINVAL); - } - - ret = apply_param_change(avctx, avpkt); - if (ret < 0) - return ret; - - av_frame_unref(frame); - - 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; - - if (!avctx->refcounted_frames) { - int err = unrefcount_frame(avci, frame); - if (err < 0) - return err; - } - } else - av_frame_unref(frame); - } - - - return ret; + return compat_decode(avctx, frame, got_frame_ptr, avpkt); } int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, @@ -919,9 +947,12 @@ 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); + if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME) ff_thread_flush(avctx); else if (avctx->codec->flush) diff --git a/libavcodec/decode.h b/libavcodec/decode.h new file mode 100644 index 0000000000..21c7c3e07a --- /dev/null +++ b/libavcodec/decode.h @@ -0,0 +1,35 @@ +/* + * 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 */ diff --git a/libavcodec/internal.h b/libavcodec/internal.h index 2ca7a45e81..dc24e8f764 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 b569b48f7a..8a422d7669 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -100,7 +100,7 @@ int av_codec_is_encoder(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) @@ -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,12 @@ 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->last_pkt_props = av_packet_alloc(); if (!avctx->internal->last_pkt_props) { ret = AVERROR(ENOMEM); @@ -717,9 +729,13 @@ 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_freep(&avctx->internal->pool); } av_freep(&avctx->internal); @@ -758,9 +774,13 @@ 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); + for (i = 0; i < FF_ARRAY_ELEMS(pool->pools); i++) av_buffer_pool_uninit(&pool->pools[i]); av_freep(&avctx->internal->pool);