[FFmpeg-devel] [PATCH 4/6] doc/examples/transcoding: stop constantly allocating AVFrames

Anton Khirnov anton at khirnov.net
Mon Nov 2 15:17:15 EET 2020


Allocate just one and reuse it.
---
 doc/examples/transcoding.c | 60 ++++++++++++++++++++------------------
 1 file changed, 31 insertions(+), 29 deletions(-)

diff --git a/doc/examples/transcoding.c b/doc/examples/transcoding.c
index e48837cbd2..4a45717bea 100644
--- a/doc/examples/transcoding.c
+++ b/doc/examples/transcoding.c
@@ -41,12 +41,16 @@ typedef struct FilteringContext {
     AVFilterContext *buffersink_ctx;
     AVFilterContext *buffersrc_ctx;
     AVFilterGraph *filter_graph;
+
+    AVFrame *filtered_frame;
 } FilteringContext;
 static FilteringContext *filter_ctx;
 
 typedef struct StreamContext {
     AVCodecContext *dec_ctx;
     AVCodecContext *enc_ctx;
+
+    AVFrame *dec_frame;
 } StreamContext;
 static StreamContext *stream_ctx;
 
@@ -102,6 +106,10 @@ static int open_input_file(const char *filename)
             }
         }
         stream_ctx[i].dec_ctx = codec_ctx;
+
+        stream_ctx[i].dec_frame = av_frame_alloc();
+        if (!stream_ctx[i].dec_frame)
+            return AVERROR(ENOMEM);
     }
 
     av_dump_format(ifmt_ctx, 0, filename, 0);
@@ -398,6 +406,10 @@ static int init_filters(void)
                 stream_ctx[i].enc_ctx, filter_spec);
         if (ret)
             return ret;
+
+        filter_ctx[i].filtered_frame = av_frame_alloc();
+        if (!filter_ctx[i].filtered_frame)
+            return AVERROR(ENOMEM);
     }
     return 0;
 }
@@ -420,7 +432,6 @@ static int encode_write_frame(AVFrame *filt_frame, unsigned int stream_index, in
     av_init_packet(&enc_pkt);
     ret = enc_func(stream_ctx[stream_index].enc_ctx, &enc_pkt,
             filt_frame, got_frame);
-    av_frame_free(&filt_frame);
     if (ret < 0)
         return ret;
     if (!(*got_frame))
@@ -440,12 +451,12 @@ static int encode_write_frame(AVFrame *filt_frame, unsigned int stream_index, in
 
 static int filter_encode_write_frame(AVFrame *frame, unsigned int stream_index)
 {
+    FilteringContext *filter = &filter_ctx[stream_index];
     int ret;
-    AVFrame *filt_frame;
 
     av_log(NULL, AV_LOG_INFO, "Pushing decoded frame to filters\n");
     /* push the decoded frame into the filtergraph */
-    ret = av_buffersrc_add_frame_flags(filter_ctx[stream_index].buffersrc_ctx,
+    ret = av_buffersrc_add_frame_flags(filter->buffersrc_ctx,
             frame, 0);
     if (ret < 0) {
         av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraph\n");
@@ -454,14 +465,9 @@ static int filter_encode_write_frame(AVFrame *frame, unsigned int stream_index)
 
     /* pull filtered frames from the filtergraph */
     while (1) {
-        filt_frame = av_frame_alloc();
-        if (!filt_frame) {
-            ret = AVERROR(ENOMEM);
-            break;
-        }
         av_log(NULL, AV_LOG_INFO, "Pulling filtered frame from filters\n");
-        ret = av_buffersink_get_frame(filter_ctx[stream_index].buffersink_ctx,
-                filt_frame);
+        ret = av_buffersink_get_frame(filter->buffersink_ctx,
+                                      filter->filtered_frame);
         if (ret < 0) {
             /* if no more frames for output - returns AVERROR(EAGAIN)
              * if flushed and no more frames for output - returns AVERROR_EOF
@@ -469,12 +475,12 @@ static int filter_encode_write_frame(AVFrame *frame, unsigned int stream_index)
              */
             if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
                 ret = 0;
-            av_frame_free(&filt_frame);
             break;
         }
 
-        filt_frame->pict_type = AV_PICTURE_TYPE_NONE;
-        ret = encode_write_frame(filt_frame, stream_index, NULL);
+        filter->filtered_frame->pict_type = AV_PICTURE_TYPE_NONE;
+        ret = encode_write_frame(filter->filtered_frame, stream_index, NULL);
+        av_frame_unref(filter->filtered_frame);
         if (ret < 0)
             break;
     }
@@ -506,7 +512,6 @@ int main(int argc, char **argv)
 {
     int ret;
     AVPacket packet = { .data = NULL, .size = 0 };
-    AVFrame *frame = NULL;
     enum AVMediaType type;
     unsigned int stream_index;
     unsigned int i;
@@ -535,33 +540,27 @@ int main(int argc, char **argv)
                 stream_index);
 
         if (filter_ctx[stream_index].filter_graph) {
+            StreamContext *stream = &stream_ctx[stream_index];
+
             av_log(NULL, AV_LOG_DEBUG, "Going to reencode&filter the frame\n");
-            frame = av_frame_alloc();
-            if (!frame) {
-                ret = AVERROR(ENOMEM);
-                break;
-            }
+
             av_packet_rescale_ts(&packet,
                                  ifmt_ctx->streams[stream_index]->time_base,
-                                 stream_ctx[stream_index].dec_ctx->time_base);
+                                 stream->dec_ctx->time_base);
             dec_func = (type == AVMEDIA_TYPE_VIDEO) ? avcodec_decode_video2 :
                 avcodec_decode_audio4;
-            ret = dec_func(stream_ctx[stream_index].dec_ctx, frame,
+            ret = dec_func(stream->dec_ctx, stream->dec_frame,
                     &got_frame, &packet);
             if (ret < 0) {
-                av_frame_free(&frame);
                 av_log(NULL, AV_LOG_ERROR, "Decoding failed\n");
                 break;
             }
 
             if (got_frame) {
-                frame->pts = frame->best_effort_timestamp;
-                ret = filter_encode_write_frame(frame, stream_index);
-                av_frame_free(&frame);
+                stream->dec_frame->pts = stream->dec_frame->best_effort_timestamp;
+                ret = filter_encode_write_frame(stream->dec_frame, stream_index);
                 if (ret < 0)
                     goto end;
-            } else {
-                av_frame_free(&frame);
             }
         } else {
             /* remux this frame without reencoding */
@@ -598,13 +597,16 @@ int main(int argc, char **argv)
     av_write_trailer(ofmt_ctx);
 end:
     av_packet_unref(&packet);
-    av_frame_free(&frame);
     for (i = 0; i < ifmt_ctx->nb_streams; i++) {
         avcodec_free_context(&stream_ctx[i].dec_ctx);
         if (ofmt_ctx && ofmt_ctx->nb_streams > i && ofmt_ctx->streams[i] && stream_ctx[i].enc_ctx)
             avcodec_free_context(&stream_ctx[i].enc_ctx);
-        if (filter_ctx && filter_ctx[i].filter_graph)
+        if (filter_ctx && filter_ctx[i].filter_graph) {
             avfilter_graph_free(&filter_ctx[i].filter_graph);
+            av_frame_free(&filter_ctx[i].filtered_frame);
+        }
+
+        av_frame_free(&stream_ctx[i].dec_frame);
     }
     av_free(filter_ctx);
     av_free(stream_ctx);
-- 
2.28.0



More information about the ffmpeg-devel mailing list