Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: Anton Khirnov <anton@khirnov.net>
To: ffmpeg-devel@ffmpeg.org
Subject: [FFmpeg-devel] [PATCH 14/23] fftools/ffmpeg: move initializing encoders to a new file
Date: Sat, 25 Mar 2023 20:15:20 +0100
Message-ID: <20230325191529.10578-14-anton@khirnov.net> (raw)
In-Reply-To: <20230325191529.10578-1-anton@khirnov.net>

This file will contain more encoding-related code in the future.
---
 fftools/Makefile     |   1 +
 fftools/ffmpeg.c     | 306 +-------------------------------------
 fftools/ffmpeg.h     |   2 +
 fftools/ffmpeg_enc.c | 342 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 346 insertions(+), 305 deletions(-)
 create mode 100644 fftools/ffmpeg_enc.c

diff --git a/fftools/Makefile b/fftools/Makefile
index 8ac38e75d2..9939c7095c 100644
--- a/fftools/Makefile
+++ b/fftools/Makefile
@@ -11,6 +11,7 @@ ALLAVPROGS_G = $(AVBASENAMES:%=%$(PROGSSUF)_g$(EXESUF))
 
 OBJS-ffmpeg +=                  \
     fftools/ffmpeg_demux.o      \
+    fftools/ffmpeg_enc.o        \
     fftools/ffmpeg_filter.o     \
     fftools/ffmpeg_hw.o         \
     fftools/ffmpeg_mux.o        \
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 5bfe465e97..03e5391970 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -2967,316 +2967,12 @@ static int init_output_stream_streamcopy(OutputStream *ost)
     return 0;
 }
 
-static void set_encoder_id(OutputFile *of, OutputStream *ost)
-{
-    const char *cname = ost->enc_ctx->codec->name;
-    uint8_t *encoder_string;
-    int encoder_string_len;
-
-    if (av_dict_get(ost->st->metadata, "encoder",  NULL, 0))
-        return;
-
-    encoder_string_len = sizeof(LIBAVCODEC_IDENT) + strlen(cname) + 2;
-    encoder_string     = av_mallocz(encoder_string_len);
-    if (!encoder_string)
-        report_and_exit(AVERROR(ENOMEM));
-
-    if (!of->bitexact && !ost->bitexact)
-        av_strlcpy(encoder_string, LIBAVCODEC_IDENT " ", encoder_string_len);
-    else
-        av_strlcpy(encoder_string, "Lavc ", encoder_string_len);
-    av_strlcat(encoder_string, cname, encoder_string_len);
-    av_dict_set(&ost->st->metadata, "encoder",  encoder_string,
-                AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE);
-}
-
-static void init_encoder_time_base(OutputStream *ost, AVRational default_time_base)
-{
-    InputStream *ist = ost->ist;
-    AVCodecContext *enc_ctx = ost->enc_ctx;
-
-    if (ost->enc_timebase.num > 0) {
-        enc_ctx->time_base = ost->enc_timebase;
-        return;
-    }
-
-    if (ost->enc_timebase.num < 0) {
-        if (ist) {
-            enc_ctx->time_base = ist->st->time_base;
-            return;
-        }
-
-        av_log(ost, AV_LOG_WARNING,
-               "Input stream data not available, using default time base\n");
-    }
-
-    enc_ctx->time_base = default_time_base;
-}
-
-static int init_output_stream_encode(OutputStream *ost, AVFrame *frame)
-{
-    InputStream *ist = ost->ist;
-    AVCodecContext *enc_ctx = ost->enc_ctx;
-    AVCodecContext *dec_ctx = NULL;
-    const AVCodec      *enc = enc_ctx->codec;
-    OutputFile      *of = output_files[ost->file_index];
-    int ret;
-
-    set_encoder_id(output_files[ost->file_index], ost);
-
-    if (ist) {
-        dec_ctx = ist->dec_ctx;
-    }
-
-    if (enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
-        if (!ost->frame_rate.num)
-            ost->frame_rate = av_buffersink_get_frame_rate(ost->filter->filter);
-        if (!ost->frame_rate.num && !ost->max_frame_rate.num) {
-            ost->frame_rate = (AVRational){25, 1};
-            av_log(ost, AV_LOG_WARNING,
-                   "No information "
-                   "about the input framerate is available. Falling "
-                   "back to a default value of 25fps. Use the -r option "
-                   "if you want a different framerate.\n");
-        }
-
-        if (ost->max_frame_rate.num &&
-            (av_q2d(ost->frame_rate) > av_q2d(ost->max_frame_rate) ||
-            !ost->frame_rate.den))
-            ost->frame_rate = ost->max_frame_rate;
-
-        if (enc->supported_framerates && !ost->force_fps) {
-            int idx = av_find_nearest_q_idx(ost->frame_rate, enc->supported_framerates);
-            ost->frame_rate = enc->supported_framerates[idx];
-        }
-        // reduce frame rate for mpeg4 to be within the spec limits
-        if (enc_ctx->codec_id == AV_CODEC_ID_MPEG4) {
-            av_reduce(&ost->frame_rate.num, &ost->frame_rate.den,
-                      ost->frame_rate.num, ost->frame_rate.den, 65535);
-        }
-    }
-
-    switch (enc_ctx->codec_type) {
-    case AVMEDIA_TYPE_AUDIO:
-        enc_ctx->sample_fmt     = av_buffersink_get_format(ost->filter->filter);
-        enc_ctx->sample_rate    = av_buffersink_get_sample_rate(ost->filter->filter);
-        ret = av_buffersink_get_ch_layout(ost->filter->filter, &enc_ctx->ch_layout);
-        if (ret < 0)
-            return ret;
-
-        if (ost->bits_per_raw_sample)
-            enc_ctx->bits_per_raw_sample = ost->bits_per_raw_sample;
-        else if (dec_ctx && ost->filter->graph->is_meta)
-            enc_ctx->bits_per_raw_sample = FFMIN(dec_ctx->bits_per_raw_sample,
-                                                 av_get_bytes_per_sample(enc_ctx->sample_fmt) << 3);
-
-        init_encoder_time_base(ost, av_make_q(1, enc_ctx->sample_rate));
-        break;
-
-    case AVMEDIA_TYPE_VIDEO:
-        init_encoder_time_base(ost, av_inv_q(ost->frame_rate));
-
-        if (!(enc_ctx->time_base.num && enc_ctx->time_base.den))
-            enc_ctx->time_base = av_buffersink_get_time_base(ost->filter->filter);
-        if (   av_q2d(enc_ctx->time_base) < 0.001 && ost->vsync_method != VSYNC_PASSTHROUGH
-           && (ost->vsync_method == VSYNC_CFR || ost->vsync_method == VSYNC_VSCFR ||
-               (ost->vsync_method == VSYNC_AUTO && !(of->format->flags & AVFMT_VARIABLE_FPS)))){
-            av_log(ost, AV_LOG_WARNING, "Frame rate very high for a muxer not efficiently supporting it.\n"
-                                        "Please consider specifying a lower framerate, a different muxer or "
-                                        "setting vsync/fps_mode to vfr\n");
-        }
-
-        enc_ctx->width  = av_buffersink_get_w(ost->filter->filter);
-        enc_ctx->height = av_buffersink_get_h(ost->filter->filter);
-        enc_ctx->sample_aspect_ratio = ost->st->sample_aspect_ratio =
-            ost->frame_aspect_ratio.num ? // overridden by the -aspect cli option
-            av_mul_q(ost->frame_aspect_ratio, (AVRational){ enc_ctx->height, enc_ctx->width }) :
-            av_buffersink_get_sample_aspect_ratio(ost->filter->filter);
-
-        enc_ctx->pix_fmt = av_buffersink_get_format(ost->filter->filter);
-
-        if (ost->bits_per_raw_sample)
-            enc_ctx->bits_per_raw_sample = ost->bits_per_raw_sample;
-        else if (dec_ctx && ost->filter->graph->is_meta)
-            enc_ctx->bits_per_raw_sample = FFMIN(dec_ctx->bits_per_raw_sample,
-                                                 av_pix_fmt_desc_get(enc_ctx->pix_fmt)->comp[0].depth);
-
-        if (frame) {
-            enc_ctx->color_range            = frame->color_range;
-            enc_ctx->color_primaries        = frame->color_primaries;
-            enc_ctx->color_trc              = frame->color_trc;
-            enc_ctx->colorspace             = frame->colorspace;
-            enc_ctx->chroma_sample_location = frame->chroma_location;
-        }
-
-        enc_ctx->framerate = ost->frame_rate;
-
-        ost->st->avg_frame_rate = ost->frame_rate;
-
-        // Field order: autodetection
-        if (frame) {
-            if (enc_ctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME) &&
-                ost->top_field_first >= 0)
-                frame->top_field_first = !!ost->top_field_first;
-
-            if (frame->interlaced_frame) {
-                if (enc->id == AV_CODEC_ID_MJPEG)
-                    enc_ctx->field_order = frame->top_field_first ? AV_FIELD_TT:AV_FIELD_BB;
-                else
-                    enc_ctx->field_order = frame->top_field_first ? AV_FIELD_TB:AV_FIELD_BT;
-            } else
-                enc_ctx->field_order = AV_FIELD_PROGRESSIVE;
-        }
-
-        // Field order: override
-        if (ost->top_field_first == 0) {
-            enc_ctx->field_order = AV_FIELD_BB;
-        } else if (ost->top_field_first == 1) {
-            enc_ctx->field_order = AV_FIELD_TT;
-        }
-
-        break;
-    case AVMEDIA_TYPE_SUBTITLE:
-        enc_ctx->time_base = AV_TIME_BASE_Q;
-        if (!enc_ctx->width) {
-            enc_ctx->width     = ost->ist->par->width;
-            enc_ctx->height    = ost->ist->par->height;
-        }
-        if (dec_ctx && dec_ctx->subtitle_header) {
-            /* ASS code assumes this buffer is null terminated so add extra byte. */
-            enc_ctx->subtitle_header = av_mallocz(dec_ctx->subtitle_header_size + 1);
-            if (!enc_ctx->subtitle_header)
-                return AVERROR(ENOMEM);
-            memcpy(enc_ctx->subtitle_header, dec_ctx->subtitle_header,
-                   dec_ctx->subtitle_header_size);
-            enc_ctx->subtitle_header_size = dec_ctx->subtitle_header_size;
-        }
-        if (ist && ist->dec->type == AVMEDIA_TYPE_SUBTITLE &&
-            enc_ctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {
-            int input_props = 0, output_props = 0;
-            AVCodecDescriptor const *input_descriptor =
-                avcodec_descriptor_get(ist->dec->id);
-            AVCodecDescriptor const *output_descriptor =
-                avcodec_descriptor_get(enc_ctx->codec_id);
-            if (input_descriptor)
-                input_props = input_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);
-            if (output_descriptor)
-                output_props = output_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);
-            if (input_props && output_props && input_props != output_props) {
-                av_log(ost, AV_LOG_ERROR,
-                       "Subtitle encoding currently only possible from text to text "
-                       "or bitmap to bitmap");
-                return AVERROR_INVALIDDATA;
-            }
-        }
-
-        break;
-    default:
-        abort();
-        break;
-    }
-
-    if (ost->bitexact)
-        enc_ctx->flags |= AV_CODEC_FLAG_BITEXACT;
-
-    if (!av_dict_get(ost->encoder_opts, "threads", NULL, 0))
-        av_dict_set(&ost->encoder_opts, "threads", "auto", 0);
-
-    if (enc->capabilities & AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE) {
-        ret = av_dict_set(&ost->encoder_opts, "flags", "+copy_opaque", AV_DICT_MULTIKEY);
-        if (ret < 0)
-            return ret;
-    }
-
-    ret = hw_device_setup_for_encode(ost);
-    if (ret < 0) {
-        av_log(ost, AV_LOG_ERROR,
-               "Encoding hardware device setup failed: %s\n", av_err2str(ret));
-        return ret;
-    }
-
-    if ((ret = avcodec_open2(ost->enc_ctx, enc, &ost->encoder_opts)) < 0) {
-        if (ret == AVERROR_EXPERIMENTAL)
-            abort_codec_experimental(enc, 1);
-        av_log(ost, AV_LOG_ERROR, "Error while opening encoder - maybe "
-               "incorrect parameters such as bit_rate, rate, width or height.\n");
-        return ret;
-    }
-
-    if (ost->enc_ctx->frame_size) {
-        av_assert0(ost->sq_idx_encode >= 0);
-        sq_frame_samples(output_files[ost->file_index]->sq_encode,
-                         ost->sq_idx_encode, ost->enc_ctx->frame_size);
-    }
-
-    assert_avoptions(ost->encoder_opts);
-    if (ost->enc_ctx->bit_rate && ost->enc_ctx->bit_rate < 1000 &&
-        ost->enc_ctx->codec_id != AV_CODEC_ID_CODEC2 /* don't complain about 700 bit/s modes */)
-        av_log(ost, AV_LOG_WARNING, "The bitrate parameter is set too low."
-                                    " It takes bits/s as argument, not kbits/s\n");
-
-    ret = avcodec_parameters_from_context(ost->st->codecpar, ost->enc_ctx);
-    if (ret < 0) {
-        av_log(ost, AV_LOG_FATAL,
-               "Error initializing the output stream codec context.\n");
-        exit_program(1);
-    }
-
-    if (ost->enc_ctx->nb_coded_side_data) {
-        int i;
-
-        for (i = 0; i < ost->enc_ctx->nb_coded_side_data; i++) {
-            const AVPacketSideData *sd_src = &ost->enc_ctx->coded_side_data[i];
-            uint8_t *dst_data;
-
-            dst_data = av_stream_new_side_data(ost->st, sd_src->type, sd_src->size);
-            if (!dst_data)
-                return AVERROR(ENOMEM);
-            memcpy(dst_data, sd_src->data, sd_src->size);
-        }
-    }
-
-    /*
-     * Add global input side data. For now this is naive, and copies it
-     * from the input stream's global side data. All side data should
-     * really be funneled over AVFrame and libavfilter, then added back to
-     * packet side data, and then potentially using the first packet for
-     * global side data.
-     */
-    if (ist) {
-        int i;
-        for (i = 0; i < ist->st->nb_side_data; i++) {
-            AVPacketSideData *sd = &ist->st->side_data[i];
-            if (sd->type != AV_PKT_DATA_CPB_PROPERTIES) {
-                uint8_t *dst = av_stream_new_side_data(ost->st, sd->type, sd->size);
-                if (!dst)
-                    return AVERROR(ENOMEM);
-                memcpy(dst, sd->data, sd->size);
-                if (ist->autorotate && sd->type == AV_PKT_DATA_DISPLAYMATRIX)
-                    av_display_rotation_set((int32_t *)dst, 0);
-            }
-        }
-    }
-
-    // copy timebase while removing common factors
-    if (ost->st->time_base.num <= 0 || ost->st->time_base.den <= 0)
-        ost->st->time_base = av_add_q(ost->enc_ctx->time_base, (AVRational){0, 1});
-
-    // copy estimated duration as a hint to the muxer
-    if (ost->st->duration <= 0 && ist && ist->st->duration > 0)
-        ost->st->duration = av_rescale_q(ist->st->duration, ist->st->time_base, ost->st->time_base);
-
-    ost->mux_timebase = enc_ctx->time_base;
-
-    return 0;
-}
-
 static int init_output_stream(OutputStream *ost, AVFrame *frame)
 {
     int ret = 0;
 
     if (ost->enc_ctx) {
-        ret = init_output_stream_encode(ost, frame);
+        ret = enc_open(ost, frame);
         if (ret < 0)
             return ret;
     } else if (ost->ist) {
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 791deedc07..c1e2bbc300 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -810,6 +810,8 @@ AVBufferRef *hw_device_for_filter(void);
 
 int hwaccel_decode_init(AVCodecContext *avctx);
 
+int enc_open(OutputStream *ost, AVFrame *frame);
+
 /*
  * Initialize muxing state for the given stream, should be called
  * after the codec/streamcopy setup has been done.
diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
new file mode 100644
index 0000000000..9db2ff5ef3
--- /dev/null
+++ b/fftools/ffmpeg_enc.c
@@ -0,0 +1,342 @@
+/*
+ * 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
+ */
+
+#include <math.h>
+#include <stdint.h>
+
+#include "ffmpeg.h"
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/avutil.h"
+#include "libavutil/dict.h"
+#include "libavutil/display.h"
+#include "libavutil/eval.h"
+#include "libavutil/frame.h"
+#include "libavutil/log.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/rational.h"
+
+#include "libavfilter/buffersink.h"
+
+#include "libavcodec/avcodec.h"
+
+#include "libavformat/avformat.h"
+
+static void set_encoder_id(OutputFile *of, OutputStream *ost)
+{
+    const char *cname = ost->enc_ctx->codec->name;
+    uint8_t *encoder_string;
+    int encoder_string_len;
+
+    if (av_dict_get(ost->st->metadata, "encoder",  NULL, 0))
+        return;
+
+    encoder_string_len = sizeof(LIBAVCODEC_IDENT) + strlen(cname) + 2;
+    encoder_string     = av_mallocz(encoder_string_len);
+    if (!encoder_string)
+        report_and_exit(AVERROR(ENOMEM));
+
+    if (!of->bitexact && !ost->bitexact)
+        av_strlcpy(encoder_string, LIBAVCODEC_IDENT " ", encoder_string_len);
+    else
+        av_strlcpy(encoder_string, "Lavc ", encoder_string_len);
+    av_strlcat(encoder_string, cname, encoder_string_len);
+    av_dict_set(&ost->st->metadata, "encoder",  encoder_string,
+                AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE);
+}
+
+static void init_encoder_time_base(OutputStream *ost, AVRational default_time_base)
+{
+    InputStream *ist = ost->ist;
+    AVCodecContext *enc_ctx = ost->enc_ctx;
+
+    if (ost->enc_timebase.num > 0) {
+        enc_ctx->time_base = ost->enc_timebase;
+        return;
+    }
+
+    if (ost->enc_timebase.num < 0) {
+        if (ist) {
+            enc_ctx->time_base = ist->st->time_base;
+            return;
+        }
+
+        av_log(ost, AV_LOG_WARNING,
+               "Input stream data not available, using default time base\n");
+    }
+
+    enc_ctx->time_base = default_time_base;
+}
+
+int enc_open(OutputStream *ost, AVFrame *frame)
+{
+    InputStream *ist = ost->ist;
+    AVCodecContext *enc_ctx = ost->enc_ctx;
+    AVCodecContext *dec_ctx = NULL;
+    const AVCodec      *enc = enc_ctx->codec;
+    OutputFile      *of = output_files[ost->file_index];
+    int ret;
+
+    set_encoder_id(output_files[ost->file_index], ost);
+
+    if (ist) {
+        dec_ctx = ist->dec_ctx;
+    }
+
+    if (enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+        if (!ost->frame_rate.num)
+            ost->frame_rate = av_buffersink_get_frame_rate(ost->filter->filter);
+        if (!ost->frame_rate.num && !ost->max_frame_rate.num) {
+            ost->frame_rate = (AVRational){25, 1};
+            av_log(ost, AV_LOG_WARNING,
+                   "No information "
+                   "about the input framerate is available. Falling "
+                   "back to a default value of 25fps. Use the -r option "
+                   "if you want a different framerate.\n");
+        }
+
+        if (ost->max_frame_rate.num &&
+            (av_q2d(ost->frame_rate) > av_q2d(ost->max_frame_rate) ||
+            !ost->frame_rate.den))
+            ost->frame_rate = ost->max_frame_rate;
+
+        if (enc->supported_framerates && !ost->force_fps) {
+            int idx = av_find_nearest_q_idx(ost->frame_rate, enc->supported_framerates);
+            ost->frame_rate = enc->supported_framerates[idx];
+        }
+        // reduce frame rate for mpeg4 to be within the spec limits
+        if (enc_ctx->codec_id == AV_CODEC_ID_MPEG4) {
+            av_reduce(&ost->frame_rate.num, &ost->frame_rate.den,
+                      ost->frame_rate.num, ost->frame_rate.den, 65535);
+        }
+    }
+
+    switch (enc_ctx->codec_type) {
+    case AVMEDIA_TYPE_AUDIO:
+        enc_ctx->sample_fmt     = av_buffersink_get_format(ost->filter->filter);
+        enc_ctx->sample_rate    = av_buffersink_get_sample_rate(ost->filter->filter);
+        ret = av_buffersink_get_ch_layout(ost->filter->filter, &enc_ctx->ch_layout);
+        if (ret < 0)
+            return ret;
+
+        if (ost->bits_per_raw_sample)
+            enc_ctx->bits_per_raw_sample = ost->bits_per_raw_sample;
+        else if (dec_ctx && ost->filter->graph->is_meta)
+            enc_ctx->bits_per_raw_sample = FFMIN(dec_ctx->bits_per_raw_sample,
+                                                 av_get_bytes_per_sample(enc_ctx->sample_fmt) << 3);
+
+        init_encoder_time_base(ost, av_make_q(1, enc_ctx->sample_rate));
+        break;
+
+    case AVMEDIA_TYPE_VIDEO:
+        init_encoder_time_base(ost, av_inv_q(ost->frame_rate));
+
+        if (!(enc_ctx->time_base.num && enc_ctx->time_base.den))
+            enc_ctx->time_base = av_buffersink_get_time_base(ost->filter->filter);
+        if (   av_q2d(enc_ctx->time_base) < 0.001 && ost->vsync_method != VSYNC_PASSTHROUGH
+           && (ost->vsync_method == VSYNC_CFR || ost->vsync_method == VSYNC_VSCFR ||
+               (ost->vsync_method == VSYNC_AUTO && !(of->format->flags & AVFMT_VARIABLE_FPS)))){
+            av_log(ost, AV_LOG_WARNING, "Frame rate very high for a muxer not efficiently supporting it.\n"
+                                        "Please consider specifying a lower framerate, a different muxer or "
+                                        "setting vsync/fps_mode to vfr\n");
+        }
+
+        enc_ctx->width  = av_buffersink_get_w(ost->filter->filter);
+        enc_ctx->height = av_buffersink_get_h(ost->filter->filter);
+        enc_ctx->sample_aspect_ratio = ost->st->sample_aspect_ratio =
+            ost->frame_aspect_ratio.num ? // overridden by the -aspect cli option
+            av_mul_q(ost->frame_aspect_ratio, (AVRational){ enc_ctx->height, enc_ctx->width }) :
+            av_buffersink_get_sample_aspect_ratio(ost->filter->filter);
+
+        enc_ctx->pix_fmt = av_buffersink_get_format(ost->filter->filter);
+
+        if (ost->bits_per_raw_sample)
+            enc_ctx->bits_per_raw_sample = ost->bits_per_raw_sample;
+        else if (dec_ctx && ost->filter->graph->is_meta)
+            enc_ctx->bits_per_raw_sample = FFMIN(dec_ctx->bits_per_raw_sample,
+                                                 av_pix_fmt_desc_get(enc_ctx->pix_fmt)->comp[0].depth);
+
+        if (frame) {
+            enc_ctx->color_range            = frame->color_range;
+            enc_ctx->color_primaries        = frame->color_primaries;
+            enc_ctx->color_trc              = frame->color_trc;
+            enc_ctx->colorspace             = frame->colorspace;
+            enc_ctx->chroma_sample_location = frame->chroma_location;
+        }
+
+        enc_ctx->framerate = ost->frame_rate;
+
+        ost->st->avg_frame_rate = ost->frame_rate;
+
+        // Field order: autodetection
+        if (frame) {
+            if (enc_ctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME) &&
+                ost->top_field_first >= 0)
+                frame->top_field_first = !!ost->top_field_first;
+
+            if (frame->interlaced_frame) {
+                if (enc->id == AV_CODEC_ID_MJPEG)
+                    enc_ctx->field_order = frame->top_field_first ? AV_FIELD_TT:AV_FIELD_BB;
+                else
+                    enc_ctx->field_order = frame->top_field_first ? AV_FIELD_TB:AV_FIELD_BT;
+            } else
+                enc_ctx->field_order = AV_FIELD_PROGRESSIVE;
+        }
+
+        // Field order: override
+        if (ost->top_field_first == 0) {
+            enc_ctx->field_order = AV_FIELD_BB;
+        } else if (ost->top_field_first == 1) {
+            enc_ctx->field_order = AV_FIELD_TT;
+        }
+
+        break;
+    case AVMEDIA_TYPE_SUBTITLE:
+        enc_ctx->time_base = AV_TIME_BASE_Q;
+        if (!enc_ctx->width) {
+            enc_ctx->width     = ost->ist->par->width;
+            enc_ctx->height    = ost->ist->par->height;
+        }
+        if (dec_ctx && dec_ctx->subtitle_header) {
+            /* ASS code assumes this buffer is null terminated so add extra byte. */
+            enc_ctx->subtitle_header = av_mallocz(dec_ctx->subtitle_header_size + 1);
+            if (!enc_ctx->subtitle_header)
+                return AVERROR(ENOMEM);
+            memcpy(enc_ctx->subtitle_header, dec_ctx->subtitle_header,
+                   dec_ctx->subtitle_header_size);
+            enc_ctx->subtitle_header_size = dec_ctx->subtitle_header_size;
+        }
+        if (ist && ist->dec->type == AVMEDIA_TYPE_SUBTITLE &&
+            enc_ctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {
+            int input_props = 0, output_props = 0;
+            AVCodecDescriptor const *input_descriptor =
+                avcodec_descriptor_get(ist->dec->id);
+            AVCodecDescriptor const *output_descriptor =
+                avcodec_descriptor_get(enc_ctx->codec_id);
+            if (input_descriptor)
+                input_props = input_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);
+            if (output_descriptor)
+                output_props = output_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);
+            if (input_props && output_props && input_props != output_props) {
+                av_log(ost, AV_LOG_ERROR,
+                       "Subtitle encoding currently only possible from text to text "
+                       "or bitmap to bitmap");
+                return AVERROR_INVALIDDATA;
+            }
+        }
+
+        break;
+    default:
+        abort();
+        break;
+    }
+
+    if (ost->bitexact)
+        enc_ctx->flags |= AV_CODEC_FLAG_BITEXACT;
+
+    if (!av_dict_get(ost->encoder_opts, "threads", NULL, 0))
+        av_dict_set(&ost->encoder_opts, "threads", "auto", 0);
+
+    if (enc->capabilities & AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE) {
+        ret = av_dict_set(&ost->encoder_opts, "flags", "+copy_opaque", AV_DICT_MULTIKEY);
+        if (ret < 0)
+            return ret;
+    }
+
+    ret = hw_device_setup_for_encode(ost);
+    if (ret < 0) {
+        av_log(ost, AV_LOG_ERROR,
+               "Encoding hardware device setup failed: %s\n", av_err2str(ret));
+        return ret;
+    }
+
+    if ((ret = avcodec_open2(ost->enc_ctx, enc, &ost->encoder_opts)) < 0) {
+        if (ret != AVERROR_EXPERIMENTAL)
+            av_log(ost, AV_LOG_ERROR, "Error while opening encoder - maybe "
+                   "incorrect parameters such as bit_rate, rate, width or height.\n");
+        return ret;
+    }
+
+    if (ost->enc_ctx->frame_size) {
+        av_assert0(ost->sq_idx_encode >= 0);
+        sq_frame_samples(output_files[ost->file_index]->sq_encode,
+                         ost->sq_idx_encode, ost->enc_ctx->frame_size);
+    }
+
+    assert_avoptions(ost->encoder_opts);
+    if (ost->enc_ctx->bit_rate && ost->enc_ctx->bit_rate < 1000 &&
+        ost->enc_ctx->codec_id != AV_CODEC_ID_CODEC2 /* don't complain about 700 bit/s modes */)
+        av_log(ost, AV_LOG_WARNING, "The bitrate parameter is set too low."
+                                    " It takes bits/s as argument, not kbits/s\n");
+
+    ret = avcodec_parameters_from_context(ost->st->codecpar, ost->enc_ctx);
+    if (ret < 0) {
+        av_log(ost, AV_LOG_FATAL,
+               "Error initializing the output stream codec context.\n");
+        exit_program(1);
+    }
+
+    if (ost->enc_ctx->nb_coded_side_data) {
+        int i;
+
+        for (i = 0; i < ost->enc_ctx->nb_coded_side_data; i++) {
+            const AVPacketSideData *sd_src = &ost->enc_ctx->coded_side_data[i];
+            uint8_t *dst_data;
+
+            dst_data = av_stream_new_side_data(ost->st, sd_src->type, sd_src->size);
+            if (!dst_data)
+                return AVERROR(ENOMEM);
+            memcpy(dst_data, sd_src->data, sd_src->size);
+        }
+    }
+
+    /*
+     * Add global input side data. For now this is naive, and copies it
+     * from the input stream's global side data. All side data should
+     * really be funneled over AVFrame and libavfilter, then added back to
+     * packet side data, and then potentially using the first packet for
+     * global side data.
+     */
+    if (ist) {
+        int i;
+        for (i = 0; i < ist->st->nb_side_data; i++) {
+            AVPacketSideData *sd = &ist->st->side_data[i];
+            if (sd->type != AV_PKT_DATA_CPB_PROPERTIES) {
+                uint8_t *dst = av_stream_new_side_data(ost->st, sd->type, sd->size);
+                if (!dst)
+                    return AVERROR(ENOMEM);
+                memcpy(dst, sd->data, sd->size);
+                if (ist->autorotate && sd->type == AV_PKT_DATA_DISPLAYMATRIX)
+                    av_display_rotation_set((int32_t *)dst, 0);
+            }
+        }
+    }
+
+    // copy timebase while removing common factors
+    if (ost->st->time_base.num <= 0 || ost->st->time_base.den <= 0)
+        ost->st->time_base = av_add_q(ost->enc_ctx->time_base, (AVRational){0, 1});
+
+    // copy estimated duration as a hint to the muxer
+    if (ost->st->duration <= 0 && ist && ist->st->duration > 0)
+        ost->st->duration = av_rescale_q(ist->st->duration, ist->st->time_base, ost->st->time_base);
+
+    ost->mux_timebase = enc_ctx->time_base;
+
+    return 0;
+}
-- 
2.39.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

  parent reply	other threads:[~2023-03-25 19:18 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-03-25 19:15 [FFmpeg-devel] [PATCH 01/23] fftools/ffmpeg: drop InputStream.processing_needed Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 02/23] fftools/ffmpeg: move initializing next_[pd]ts to add_input_streams() Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 03/23] fftools/sync_queue: use timebase from input frames/packets Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 04/23] fftools/sync_queue: document overall design Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 05/23] fftools/sync_queue: support operation with no limiting streams Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 06/23] fftools/sync_queue: make sure audio duration matches sample count Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 07/23] fftools/sync_queue: allow requesting a specific number of audio samples Anton Khirnov
2023-03-29 23:41   ` James Almer
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 08/23] fftools/ffmpeg: use sync queues for enforcing audio frame size Anton Khirnov
2023-03-25 21:43   ` Michael Niedermayer
2023-03-27  5:15     ` [FFmpeg-devel] [PATCH] fftools/ffmpeg: do not return finished streams from choose_output() Anton Khirnov
2023-03-29 17:59       ` Michael Niedermayer
2023-03-30  8:48         ` Anton Khirnov
2023-04-02 15:58           ` Michael Niedermayer
2023-04-03 10:09             ` [FFmpeg-devel] [PATCH] fftools/ffmpeg: make sure non-lavfi streams are closed on input EOF Anton Khirnov
2023-04-05 22:33               ` Michael Niedermayer
2023-04-06  7:27                 ` Anton Khirnov
2023-03-29 18:08     ` [FFmpeg-devel] [PATCH 08/23] fftools/ffmpeg: use sync queues for enforcing audio frame size Michael Niedermayer
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 09/23] fftools/ffmpeg: stop handling AVMEDIA_TYPE_DATA in init_output_stream_encode() Anton Khirnov
2023-03-25 19:43   ` James Almer
2023-03-26  9:20     ` Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 10/23] fftools/ffmpeg: drop unnecessarily indirection Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 11/23] fftools/ffmpeg: use stack variables to shorten code Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 12/23] fftools/ffmpeg: move encoder initialization to init_output_stream_encode Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 13/23] fftools/ffmpeg: reindent after previous commit Anton Khirnov
2023-03-28 22:42   ` Michael Niedermayer
2023-03-29  0:16     ` Anton Khirnov
2023-03-25 19:15 ` Anton Khirnov [this message]
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 15/23] fftools/ffmpeg: simplify output stream initialization call graph Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 16/23] fftools/ffmpeg: replace ff_dlog() with av_log() Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 17/23] fftools/ffmpeg: move subtitle encoding to ffmpeg_enc.c Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 18/23] fftools/ffmpeg: move audio/video encoding code " Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 19/23] fftools/ffmpeg: add encoder private data Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 20/23] fftools/ffmpeg: stop including os_support.h Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 21/23] fftools/ffmpeg: clean up system header includes Anton Khirnov
2023-03-27  5:35   ` Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 22/23] fftools/ffmpeg: clean up local includes Anton Khirnov
2023-03-25 19:15 ` [FFmpeg-devel] [PATCH 23/23] fftools/ffmpeg_enc: factorize calling enc_init() Anton Khirnov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230325191529.10578-14-anton@khirnov.net \
    --to=anton@khirnov.net \
    --cc=ffmpeg-devel@ffmpeg.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git