aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2023-03-25 04:36:28 +0100
committerAnton Khirnov <anton@khirnov.net>2023-04-09 15:47:45 +0200
commitd96f2fbf76fd2587d8f9aa984591439cf38bfb0b (patch)
tree5ce781a682b69fd0c08fcbc98ee757b24360e359
parent1dabd4851928b868e62ae8a0b006eb2568dda62e (diff)
downloadffmpeg-d96f2fbf76fd2587d8f9aa984591439cf38bfb0b.tar.gz
fftools/ffmpeg: move initializing encoders to a new file
This file will contain more encoding-related code in the future.
-rw-r--r--fftools/Makefile1
-rw-r--r--fftools/ffmpeg.c306
-rw-r--r--fftools/ffmpeg.h2
-rw-r--r--fftools/ffmpeg_enc.c342
4 files changed, 346 insertions, 305 deletions
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 42b2735fb4..c439f94de1 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;
+}