Commit bddb2343 authored by James Almer's avatar James Almer

Merge commit '061a0c14'

* commit '061a0c14':
  decode: restructure the core decoding code

CUVID decoder adapted by wm4.
Merged-by: 's avatarJames Almer <jamrial@gmail.com>
parents 1fd76277 061a0c14
......@@ -3764,20 +3764,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
......
......@@ -31,6 +31,7 @@
#include "libavutil/pixdesc.h"
#include "avcodec.h"
#include "decode.h"
#include "internal.h"
typedef struct CuvidContext
......@@ -357,6 +358,13 @@ static int CUDAAPI cuvid_handle_picture_display(void *opaque, CUVIDPARSERDISPINF
return 1;
}
static int cuvid_is_buffer_full(AVCodecContext *avctx)
{
CuvidContext *ctx = avctx->priv_data;
return (av_fifo_size(ctx->frame_queue) / sizeof(CuvidParsedFrame)) + 2 > ctx->nb_surfaces;
}
static int cuvid_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt)
{
CuvidContext *ctx = avctx->priv_data;
......@@ -373,7 +381,7 @@ static int cuvid_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt)
if (is_flush && avpkt && avpkt->size)
return AVERROR_EOF;
if ((av_fifo_size(ctx->frame_queue) / sizeof(CuvidParsedFrame)) + 2 > ctx->nb_surfaces && avpkt && avpkt->size)
if (cuvid_is_buffer_full(avctx) && avpkt && avpkt->size)
return AVERROR(EAGAIN);
if (ctx->bsf && avpkt && avpkt->size) {
......@@ -464,6 +472,20 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame)
return ret;
}
if (!cuvid_is_buffer_full(avctx)) {
AVPacket pkt = {0};
ret = ff_decode_get_packet(avctx, &pkt);
if (ret < 0 && ret != AVERROR_EOF)
return ret;
ret = cuvid_decode_packet(avctx, &pkt);
av_packet_unref(&pkt);
// cuvid_is_buffer_full() should avoid this.
if (ret == AVERROR(EAGAIN))
ret = AVERROR_EXTERNAL;
if (ret < 0 && ret != AVERROR_EOF)
return ret;
}
ret = CHECK_CU(ctx->cudl->cuCtxPushCurrent(cuda_ctx));
if (ret < 0)
return ret;
......@@ -1026,7 +1048,6 @@ static const AVOption options[] = {
.init = cuvid_decode_init, \
.close = cuvid_decode_end, \
.decode = cuvid_decode_frame, \
.send_packet = cuvid_decode_packet, \
.receive_frame = cuvid_output_frame, \
.flush = cuvid_flush, \
.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \
......
This diff is collapsed.
/*
* generic decoding-related code
*
* This file is part of FFmpeg.
*
* FFmpeg 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.
*
* FFmpeg 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 FFmpeg; 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 */
......@@ -101,6 +101,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
......@@ -137,6 +142,8 @@ typedef struct AVCodecInternal {
void *thread_ctx;
DecodeSimpleContext ds;
/**
* Properties (timestamps+side data) extracted from the last packet passed
* for decoding.
......@@ -173,6 +180,17 @@ 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;
int showed_multi_packet_warning;
int skip_samples_multiplier;
......
......@@ -172,7 +172,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)
......@@ -672,6 +672,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);
......@@ -684,6 +690,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);
......@@ -1114,9 +1126,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);
......@@ -1163,9 +1179,13 @@ av_cold int avcodec_close(AVCodecContext *avctx)
avctx->internal->byte_buffer_size = 0;
av_freep(&avctx->internal->byte_buffer);
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);
......
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