[FFmpeg-devel] [PATCH 6/6] lavfi/src_movie: switch to new decoding API
Nicolas George
george at nsup.org
Mon Nov 2 21:21:46 EET 2020
Anton Khirnov (12020-11-02):
> ---
> libavfilter/src_movie.c | 170 +++++++++++++++++++---------------------
> 1 file changed, 82 insertions(+), 88 deletions(-)
Thanks for working on this. It will make switching to activate correctly
much easier too.
>
> diff --git a/libavfilter/src_movie.c b/libavfilter/src_movie.c
> index ab12c34f4a..b53f811846 100644
> --- a/libavfilter/src_movie.c
> +++ b/libavfilter/src_movie.c
> @@ -51,7 +51,6 @@
> typedef struct MovieStream {
> AVStream *st;
> AVCodecContext *codec_ctx;
> - int done;
> int64_t discontinuity_threshold;
> int64_t last_pts;
> } MovieStream;
> @@ -70,7 +69,6 @@ typedef struct MovieContext {
> int64_t ts_offset;
>
> AVFormatContext *format_ctx;
> - int eof;
> AVPacket pkt;
>
> int max_stream_index; /**< max stream # actually used for output */
> @@ -172,7 +170,6 @@ static int open_stream(AVFilterContext *ctx, MovieStream *st)
> if (ret < 0)
> return ret;
>
> - st->codec_ctx->refcounted_frames = 1;
> st->codec_ctx->thread_count = ff_filter_get_nb_threads(ctx);
>
> if ((ret = avcodec_open2(st->codec_ctx, codec, NULL)) < 0) {
> @@ -451,103 +448,70 @@ static int rewind_file(AVFilterContext *ctx)
>
> for (i = 0; i < ctx->nb_outputs; i++) {
> avcodec_flush_buffers(movie->st[i].codec_ctx);
> - movie->st[i].done = 0;
> }
> - movie->eof = 0;
> return 0;
> }
>
> +static int movie_decode_packet(AVFilterContext *ctx)
> +{
> + MovieContext *movie = ctx->priv;
> + AVPacket *pkt = &movie->pkt;
Since the new decode API does not do partial packets, the packet does
not need to reside in the context at all now, it can be just a local
variable.
> + int pkt_out_id, ret;
> +
> + /* read a new packet from input stream */
> + av_packet_unref(pkt);
> + ret = av_read_frame(movie->format_ctx, pkt);
> + if (ret == AVERROR_EOF) {
> + /* EOF -> set all decoders for flushing */
> + for (int i = 0; i < ctx->nb_outputs; i++) {
> + ret = avcodec_send_packet(movie->st[i].codec_ctx, NULL);
> + if (ret < 0 && ret != AVERROR_EOF)
> + return ret;
> + }
> +
> + return 0;
> + } else if (ret < 0)
> + return ret;
> +
> + /* send the packet to its decoder, if any */
> + pkt_out_id = pkt->stream_index > movie->max_stream_index ? -1 :
> + movie->out_index[pkt->stream_index];
> + if (pkt_out_id >= 0)
> + ret = avcodec_send_packet(movie->st[pkt_out_id].codec_ctx, pkt);
> + av_packet_unref(pkt);
> +
> + return ret;
> +}
> +
> /**
> * Try to push a frame to the requested output.
> *
> * @param ctx filter context
> * @param out_id number of output where a frame is wanted;
> - * if the frame is read from file, used to set the return value;
> - * if the codec is being flushed, flush the corresponding stream
> - * @return 1 if a frame was pushed on the requested output,
> - * 0 if another attempt is possible,
> - * <0 AVERROR code
> + * @return 0 if a frame was pushed on the requested output,
> + * AVERROR(EAGAIN) if the decoder requires more input
> + * AVERROR(EOF) if the decoder has been completely flushed
> + * <0 AVERROR code
> */
> static int movie_push_frame(AVFilterContext *ctx, unsigned out_id)
> {
> - MovieContext *movie = ctx->priv;
> - AVPacket *pkt = &movie->pkt;
> - enum AVMediaType frame_type;
> - MovieStream *st;
> - int ret, got_frame = 0, pkt_out_id;
> - AVFilterLink *outlink;
> + MovieContext *movie = ctx->priv;
> + MovieStream *st = &movie->st[out_id];
> + AVFilterLink *outlink = ctx->outputs[out_id];
> AVFrame *frame;
> -
> - if (!pkt->size) {
> - if (movie->eof) {
> - if (movie->st[out_id].done) {
> - if (movie->loop_count != 1) {
> - ret = rewind_file(ctx);
> - if (ret < 0)
> - return ret;
> - movie->loop_count -= movie->loop_count > 1;
> - av_log(ctx, AV_LOG_VERBOSE, "Stream finished, looping.\n");
> - return 0; /* retry */
> - }
> - return AVERROR_EOF;
> - }
> - pkt->stream_index = movie->st[out_id].st->index;
> - /* packet is already ready for flushing */
> - } else {
> - ret = av_read_frame(movie->format_ctx, pkt);
> - if (ret < 0) {
> - if (ret == AVERROR_EOF) {
> - movie->eof = 1;
> - return 0; /* start flushing */
> - }
> - return ret;
> - }
> - }
> - }
> -
> - pkt_out_id = pkt->stream_index > movie->max_stream_index ? -1 :
> - movie->out_index[pkt->stream_index];
> - if (pkt_out_id < 0) {
> - av_packet_unref(pkt);
> - return 0;
> - }
> - st = &movie->st[pkt_out_id];
> - outlink = ctx->outputs[pkt_out_id];
> + int ret;
>
> frame = av_frame_alloc();
> if (!frame)
> return AVERROR(ENOMEM);
>
> - frame_type = st->st->codecpar->codec_type;
> - switch (frame_type) {
> - case AVMEDIA_TYPE_VIDEO:
> - ret = avcodec_decode_video2(st->codec_ctx, frame, &got_frame, pkt);
> - break;
> - case AVMEDIA_TYPE_AUDIO:
> - ret = avcodec_decode_audio4(st->codec_ctx, frame, &got_frame, pkt);
> - break;
> - default:
> - ret = AVERROR(ENOSYS);
> - break;
> - }
> + ret = avcodec_receive_frame(st->codec_ctx, frame);
> if (ret < 0) {
> - av_log(ctx, AV_LOG_WARNING, "Decode error: %s\n", av_err2str(ret));
> - av_frame_free(&frame);
> - av_packet_unref(pkt);
> - return 0;
> - }
> - if (!ret || st->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
> - ret = pkt->size;
> -
> - pkt->data += ret;
> - pkt->size -= ret;
> - if (pkt->size <= 0)
> - av_packet_unref(pkt);
> - if (!got_frame) {
> - if (!ret)
> - st->done = 1;
> + if (ret != AVERROR_EOF && ret != AVERROR(EAGAIN))
> + av_log(ctx, AV_LOG_WARNING, "Decode error: %s\n", av_err2str(ret));
> +
> av_frame_free(&frame);
> - return 0;
> + return ret;
> }
>
> frame->pts = frame->best_effort_timestamp;
> @@ -558,7 +522,7 @@ static int movie_push_frame(AVFilterContext *ctx, unsigned out_id)
> if (st->last_pts != AV_NOPTS_VALUE) {
> int64_t diff = frame->pts - st->last_pts;
> if (diff < 0 || diff > st->discontinuity_threshold) {
> - av_log(ctx, AV_LOG_VERBOSE, "Discontinuity in stream:%d diff:%"PRId64"\n", pkt_out_id, diff);
> + av_log(ctx, AV_LOG_VERBOSE, "Discontinuity in stream:%d diff:%"PRId64"\n", out_id, diff);
> movie->ts_offset += av_rescale_q_rnd(-diff, outlink->time_base, AV_TIME_BASE_Q, AV_ROUND_UP);
> frame->pts -= diff;
> }
> @@ -567,7 +531,8 @@ static int movie_push_frame(AVFilterContext *ctx, unsigned out_id)
> st->last_pts = frame->pts;
> }
> ff_dlog(ctx, "movie_push_frame(): file:'%s' %s\n", movie->file_name,
> - describe_frame_to_str((char[1024]){0}, 1024, frame, frame_type, outlink));
> + describe_frame_to_str((char[1024]){0}, 1024, frame,
> + st->st->codecpar->codec_type, outlink));
>
> if (st->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
> if (frame->format != outlink->format) {
> @@ -583,19 +548,49 @@ static int movie_push_frame(AVFilterContext *ctx, unsigned out_id)
>
> if (ret < 0)
> return ret;
> - return pkt_out_id == out_id;
> + return 0;
> }
>
> static int movie_request_frame(AVFilterLink *outlink)
> {
> AVFilterContext *ctx = outlink->src;
> + MovieContext *movie = ctx->priv;
> unsigned out_id = FF_OUTLINK_IDX(outlink);
> - int ret;
>
> while (1) {
> - ret = movie_push_frame(ctx, out_id);
> - if (ret)
> - return FFMIN(ret, 0);
> + int got_eagain = 0, got_eof = 0;
> + int ret = 0;
> +
> + /* check all decoders for available output */
> + for (int i = 0; i < ctx->nb_outputs; i++) {
> + ret = movie_push_frame(ctx, i);
> + if (ret == AVERROR(EAGAIN))
> + got_eagain++;
> + else if (ret == AVERROR_EOF)
> + got_eof++;
> + else if (ret < 0)
> + return ret;
> + else if (i == out_id)
> + return 0;
> + }
> +
> + if (got_eagain) {
> + /* all decoders require more input -> read a new packet */
> + ret = movie_decode_packet(ctx);
> + if (ret < 0)
> + return ret;
> + } else if (got_eof) {
> + /* all decoders flushed */
> + if (movie->loop_count != 1) {
> + ret = rewind_file(ctx);
> + if (ret < 0)
> + return ret;
> + movie->loop_count -= movie->loop_count > 1;
> + av_log(ctx, AV_LOG_VERBOSE, "Stream finished, looping.\n");
> + continue;
> + }
> + return AVERROR_EOF;
> + }
> }
> }
>
> @@ -619,7 +614,6 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar
>
> for (i = 0; i < ctx->nb_outputs; i++) {
> avcodec_flush_buffers(movie->st[i].codec_ctx);
> - movie->st[i].done = 0;
> }
> return ret;
> } else if (!strcmp(cmd, "get_duration")) {
Looks good to me apart from the small comment above.
Regards,
--
Nicolas George
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20201102/a3618a75/attachment.sig>
More information about the ffmpeg-devel
mailing list