Commit 6b449a12 authored by Hendrik Leppkes's avatar Hendrik Leppkes

Merge commit 'ba7397ba'

* commit 'ba7397ba':
  avconv: factor out initializing stream parameters for encoding
Merged-by: 's avatarHendrik Leppkes <h.leppkes@gmail.com>
parents ca7cdffb ba7397ba
......@@ -2720,9 +2720,17 @@ static int get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
static int init_input_stream(int ist_index, char *error, int error_len)
{
int ret;
int i, ret;
InputStream *ist = input_streams[ist_index];
for (i = 0; i < ist->nb_filters; i++) {
ret = ifilter_parameters_from_decoder(ist->filters[i], ist->dec_ctx);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Error initializing filter input\n");
return ret;
}
}
if (ist->decoding_needed) {
AVCodec *codec = ist->dec;
if (!codec) {
......@@ -2927,6 +2935,9 @@ static int init_output_stream_streamcopy(OutputStream *ost)
// copy timebase while removing common factors
ost->st->time_base = av_add_q(av_stream_get_codec_timebase(ost->st), (AVRational){0, 1});
// copy disposition
ost->st->disposition = ist->st->disposition;
if (ist->st->nb_side_data) {
ost->st->side_data = av_realloc_array(NULL, ist->st->nb_side_data,
sizeof(*ist->st->side_data));
......@@ -3015,123 +3026,45 @@ static int init_output_stream_streamcopy(OutputStream *ost)
return 0;
}
static int init_output_stream(OutputStream *ost, char *error, int error_len)
static void set_encoder_id(OutputFile *of, OutputStream *ost)
{
int ret = 0;
AVDictionaryEntry *e;
if (ost->encoding_needed) {
AVCodec *codec = ost->enc;
AVCodecContext *dec = NULL;
InputStream *ist;
uint8_t *encoder_string;
int encoder_string_len;
int format_flags = 0;
int codec_flags = 0;
if ((ist = get_input_stream(ost)))
dec = ist->dec_ctx;
if (dec && dec->subtitle_header) {
/* ASS code assumes this buffer is null terminated so add extra byte. */
ost->enc_ctx->subtitle_header = av_mallocz(dec->subtitle_header_size + 1);
if (!ost->enc_ctx->subtitle_header)
return AVERROR(ENOMEM);
memcpy(ost->enc_ctx->subtitle_header, dec->subtitle_header, dec->subtitle_header_size);
ost->enc_ctx->subtitle_header_size = dec->subtitle_header_size;
}
if (!av_dict_get(ost->encoder_opts, "threads", NULL, 0))
av_dict_set(&ost->encoder_opts, "threads", "auto", 0);
if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
!codec->defaults &&
!av_dict_get(ost->encoder_opts, "b", NULL, 0) &&
!av_dict_get(ost->encoder_opts, "ab", NULL, 0))
av_dict_set(&ost->encoder_opts, "b", "128000", 0);
if (av_dict_get(ost->st->metadata, "encoder", NULL, 0))
return;
if (ost->filter && ost->filter->filter->inputs[0]->hw_frames_ctx) {
ost->enc_ctx->hw_frames_ctx = av_buffer_ref(ost->filter->filter->inputs[0]->hw_frames_ctx);
if (!ost->enc_ctx->hw_frames_ctx)
return AVERROR(ENOMEM);
e = av_dict_get(of->opts, "fflags", NULL, 0);
if (e) {
const AVOption *o = av_opt_find(of->ctx, "fflags", NULL, 0, 0);
if (!o)
return;
av_opt_eval_flags(of->ctx, o, e->value, &format_flags);
}
if ((ret = avcodec_open2(ost->enc_ctx, codec, &ost->encoder_opts)) < 0) {
if (ret == AVERROR_EXPERIMENTAL)
abort_codec_experimental(codec, 1);
snprintf(error, error_len,
"Error while opening encoder for output stream #%d:%d - "
"maybe incorrect parameters such as bit_rate, rate, width or height",
ost->file_index, ost->index);
return ret;
e = av_dict_get(ost->encoder_opts, "flags", NULL, 0);
if (e) {
const AVOption *o = av_opt_find(ost->enc_ctx, "flags", NULL, 0, 0);
if (!o)
return;
av_opt_eval_flags(ost->enc_ctx, o, e->value, &codec_flags);
}
if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
!(ost->enc->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE))
av_buffersink_set_frame_size(ost->filter->filter,
ost->enc_ctx->frame_size);
assert_avoptions(ost->encoder_opts);
if (ost->enc_ctx->bit_rate && ost->enc_ctx->bit_rate < 1000)
av_log(NULL, 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(NULL, AV_LOG_FATAL,
"Error initializing the output stream codec context.\n");
encoder_string_len = sizeof(LIBAVCODEC_IDENT) + strlen(ost->enc->name) + 2;
encoder_string = av_mallocz(encoder_string_len);
if (!encoder_string)
exit_program(1);
}
/*
* FIXME: ost->st->codec should't be needed here anymore.
*/
ret = avcodec_copy_context(ost->st->codec, ost->enc_ctx);
if (ret < 0)
return ret;
if (ost->enc_ctx->nb_coded_side_data) {
int i;
ost->st->side_data = av_realloc_array(NULL, ost->enc_ctx->nb_coded_side_data,
sizeof(*ost->st->side_data));
if (!ost->st->side_data)
return AVERROR(ENOMEM);
for (i = 0; i < ost->enc_ctx->nb_coded_side_data; i++) {
const AVPacketSideData *sd_src = &ost->enc_ctx->coded_side_data[i];
AVPacketSideData *sd_dst = &ost->st->side_data[i];
sd_dst->data = av_malloc(sd_src->size);
if (!sd_dst->data)
return AVERROR(ENOMEM);
memcpy(sd_dst->data, sd_src->data, sd_src->size);
sd_dst->size = sd_src->size;
sd_dst->type = sd_src->type;
ost->st->nb_side_data++;
}
}
// copy timebase while removing common factors
ost->st->time_base = av_add_q(ost->enc_ctx->time_base, (AVRational){0, 1});
ost->st->codec->codec= ost->enc_ctx->codec;
} else if (ost->stream_copy) {
ret = init_output_stream_streamcopy(ost);
if (ret < 0)
return ret;
/*
* FIXME: will the codec context used by the parser during streamcopy
* This should go away with the new parser API.
*/
ret = avcodec_parameters_to_context(ost->parser_avctx, ost->st->codecpar);
if (ret < 0)
return ret;
}
/* initialize bitstream filters for the output stream
* needs to be done here, because the codec id for streamcopy is not
* known until now */
ret = init_output_bsfs(ost);
if (ret < 0)
return ret;
ost->initialized = 1;
ret = check_init_output_file(output_files[ost->file_index], ost->file_index);
if (ret < 0)
return ret;
return ret;
if (!(format_flags & AVFMT_FLAG_BITEXACT) && !(codec_flags & AV_CODEC_FLAG_BITEXACT))
av_strlcpy(encoder_string, LIBAVCODEC_IDENT " ", encoder_string_len);
else
av_strlcpy(encoder_string, "Lavc ", encoder_string_len);
av_strlcat(encoder_string, ost->enc->name, encoder_string_len);
av_dict_set(&ost->st->metadata, "encoder", encoder_string,
AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE);
}
static void parse_forced_key_frames(char *kf, OutputStream *ost,
......@@ -3197,106 +3130,24 @@ static void parse_forced_key_frames(char *kf, OutputStream *ost,
ost->forced_kf_pts = pts;
}
static void report_new_stream(int input_index, AVPacket *pkt)
static int init_output_stream_encode(OutputStream *ost)
{
InputFile *file = input_files[input_index];
AVStream *st = file->ctx->streams[pkt->stream_index];
if (pkt->stream_index < file->nb_streams_warn)
return;
av_log(file->ctx, AV_LOG_WARNING,
"New %s stream %d:%d at pos:%"PRId64" and DTS:%ss\n",
av_get_media_type_string(st->codecpar->codec_type),
input_index, pkt->stream_index,
pkt->pos, av_ts2timestr(pkt->dts, &st->time_base));
file->nb_streams_warn = pkt->stream_index + 1;
}
static void set_encoder_id(OutputFile *of, OutputStream *ost)
{
AVDictionaryEntry *e;
uint8_t *encoder_string;
int encoder_string_len;
int format_flags = 0;
int codec_flags = 0;
if (av_dict_get(ost->st->metadata, "encoder", NULL, 0))
return;
e = av_dict_get(of->opts, "fflags", NULL, 0);
if (e) {
const AVOption *o = av_opt_find(of->ctx, "fflags", NULL, 0, 0);
if (!o)
return;
av_opt_eval_flags(of->ctx, o, e->value, &format_flags);
}
e = av_dict_get(ost->encoder_opts, "flags", NULL, 0);
if (e) {
const AVOption *o = av_opt_find(ost->enc_ctx, "flags", NULL, 0, 0);
if (!o)
return;
av_opt_eval_flags(ost->enc_ctx, o, e->value, &codec_flags);
}
encoder_string_len = sizeof(LIBAVCODEC_IDENT) + strlen(ost->enc->name) + 2;
encoder_string = av_mallocz(encoder_string_len);
if (!encoder_string)
exit_program(1);
if (!(format_flags & AVFMT_FLAG_BITEXACT) && !(codec_flags & AV_CODEC_FLAG_BITEXACT))
av_strlcpy(encoder_string, LIBAVCODEC_IDENT " ", encoder_string_len);
else
av_strlcpy(encoder_string, "Lavc ", encoder_string_len);
av_strlcat(encoder_string, ost->enc->name, encoder_string_len);
av_dict_set(&ost->st->metadata, "encoder", encoder_string,
AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE);
}
static int transcode_init(void)
{
int ret = 0, i, j, k;
AVFormatContext *oc;
OutputStream *ost;
InputStream *ist;
char error[1024] = {0};
for (i = 0; i < nb_filtergraphs; i++) {
FilterGraph *fg = filtergraphs[i];
for (j = 0; j < fg->nb_outputs; j++) {
OutputFilter *ofilter = fg->outputs[j];
if (!ofilter->ost || ofilter->ost->source_index >= 0)
continue;
if (fg->nb_inputs != 1)
continue;
for (k = nb_input_streams-1; k >= 0 ; k--)
if (fg->inputs[0]->ist == input_streams[k])
break;
ofilter->ost->source_index = k;
}
}
/* init framerate emulation */
for (i = 0; i < nb_input_files; i++) {
InputFile *ifile = input_files[i];
if (ifile->rate_emu)
for (j = 0; j < ifile->nb_streams; j++)
input_streams[j + ifile->ist_index]->start = av_gettime_relative();
}
/* for each output stream, we compute the right encoding parameters */
for (i = 0; i < nb_output_streams; i++) {
ost = output_streams[i];
oc = output_files[ost->file_index]->ctx;
ist = get_input_stream(ost);
InputStream *ist = get_input_stream(ost);
AVCodecContext *enc_ctx = ost->enc_ctx;
AVCodecContext *dec_ctx = NULL;
AVFormatContext *oc = output_files[ost->file_index]->ctx;
int j, ret;
if (ost->attachment_filename)
continue;
set_encoder_id(output_files[ost->file_index], ost);
if (ist) {
ost->st->disposition = ist->st->disposition;
dec_ctx = ist->dec_ctx;
enc_ctx->chroma_sample_location = dec_ctx->chroma_sample_location;
} else {
for (j=0; j<oc->nb_streams; j++) {
for (j = 0; j < oc->nb_streams; j++) {
AVStream *st = oc->streams[j];
if (st != ost->st && st->codecpar->codec_type == ost->st->codecpar->codec_type)
break;
......@@ -3307,42 +3158,11 @@ static int transcode_init(void)
ost->st->disposition = AV_DISPOSITION_DEFAULT;
}
if (!ost->stream_copy) {
AVCodecContext *enc_ctx = ost->enc_ctx;
AVCodecContext *dec_ctx = NULL;
set_encoder_id(output_files[ost->file_index], ost);
if (ist) {
dec_ctx = ist->dec_ctx;
enc_ctx->chroma_sample_location = dec_ctx->chroma_sample_location;
}
#if CONFIG_LIBMFX
if (qsv_transcode_init(ost))
exit_program(1);
#endif
#if CONFIG_CUVID
if (cuvid_transcode_init(ost))
exit_program(1);
#endif
if ((enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
enc_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&
filtergraph_is_simple(ost->filter->graph)) {
FilterGraph *fg = ost->filter->graph;
if (dec_ctx) {
ret = ifilter_parameters_from_decoder(fg->inputs[0],
dec_ctx);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Error initializing filter input\n");
exit_program(1);
}
}
if (configure_filtergraph(fg)) {
av_log(NULL, AV_LOG_FATAL, "Error opening filters!\n");
exit_program(1);
......@@ -3470,8 +3290,118 @@ static int transcode_init(void)
abort();
break;
}
return 0;
}
static int init_output_stream(OutputStream *ost, char *error, int error_len)
{
int ret = 0;
if (ost->encoding_needed) {
AVCodec *codec = ost->enc;
AVCodecContext *dec = NULL;
InputStream *ist;
ret = init_output_stream_encode(ost);
if (ret < 0)
return ret;
if ((ist = get_input_stream(ost)))
dec = ist->dec_ctx;
if (dec && dec->subtitle_header) {
/* ASS code assumes this buffer is null terminated so add extra byte. */
ost->enc_ctx->subtitle_header = av_mallocz(dec->subtitle_header_size + 1);
if (!ost->enc_ctx->subtitle_header)
return AVERROR(ENOMEM);
memcpy(ost->enc_ctx->subtitle_header, dec->subtitle_header, dec->subtitle_header_size);
ost->enc_ctx->subtitle_header_size = dec->subtitle_header_size;
}
if (!av_dict_get(ost->encoder_opts, "threads", NULL, 0))
av_dict_set(&ost->encoder_opts, "threads", "auto", 0);
if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
!codec->defaults &&
!av_dict_get(ost->encoder_opts, "b", NULL, 0) &&
!av_dict_get(ost->encoder_opts, "ab", NULL, 0))
av_dict_set(&ost->encoder_opts, "b", "128000", 0);
if (ost->filter && ost->filter->filter->inputs[0]->hw_frames_ctx) {
ost->enc_ctx->hw_frames_ctx = av_buffer_ref(ost->filter->filter->inputs[0]->hw_frames_ctx);
if (!ost->enc_ctx->hw_frames_ctx)
return AVERROR(ENOMEM);
}
if ((ret = avcodec_open2(ost->enc_ctx, codec, &ost->encoder_opts)) < 0) {
if (ret == AVERROR_EXPERIMENTAL)
abort_codec_experimental(codec, 1);
snprintf(error, error_len,
"Error while opening encoder for output stream #%d:%d - "
"maybe incorrect parameters such as bit_rate, rate, width or height",
ost->file_index, ost->index);
return ret;
}
if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
!(ost->enc->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE))
av_buffersink_set_frame_size(ost->filter->filter,
ost->enc_ctx->frame_size);
assert_avoptions(ost->encoder_opts);
if (ost->enc_ctx->bit_rate && ost->enc_ctx->bit_rate < 1000)
av_log(NULL, 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(NULL, AV_LOG_FATAL,
"Error initializing the output stream codec context.\n");
exit_program(1);
}
/*
* FIXME: ost->st->codec should't be needed here anymore.
*/
ret = avcodec_copy_context(ost->st->codec, ost->enc_ctx);
if (ret < 0)
return ret;
if (ost->enc_ctx->nb_coded_side_data) {
int i;
ost->st->side_data = av_realloc_array(NULL, ost->enc_ctx->nb_coded_side_data,
sizeof(*ost->st->side_data));
if (!ost->st->side_data)
return AVERROR(ENOMEM);
for (i = 0; i < ost->enc_ctx->nb_coded_side_data; i++) {
const AVPacketSideData *sd_src = &ost->enc_ctx->coded_side_data[i];
AVPacketSideData *sd_dst = &ost->st->side_data[i];
sd_dst->data = av_malloc(sd_src->size);
if (!sd_dst->data)
return AVERROR(ENOMEM);
memcpy(sd_dst->data, sd_src->data, sd_src->size);
sd_dst->size = sd_src->size;
sd_dst->type = sd_src->type;
ost->st->nb_side_data++;
}
}
// copy timebase while removing common factors
ost->st->time_base = av_add_q(ost->enc_ctx->time_base, (AVRational){0, 1});
ost->st->codec->codec= ost->enc_ctx->codec;
} else if (ost->stream_copy) {
ret = init_output_stream_streamcopy(ost);
if (ret < 0)
return ret;
/*
* FIXME: will the codec context used by the parser during streamcopy
* This should go away with the new parser API.
*/
ret = avcodec_parameters_to_context(ost->parser_avctx, ost->st->codecpar);
if (ret < 0)
return ret;
}
// parse user provided disposition, and update stream values
if (ost->disposition) {
static const AVOption opts[] = {
{ "disposition" , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, INT64_MAX, .unit = "flags" },
......@@ -3500,7 +3430,85 @@ static int transcode_init(void)
ret = av_opt_eval_flags(&pclass, &opts[0], ost->disposition, &ost->st->disposition);
if (ret < 0)
goto dump_format;
return ret;
}
/* initialize bitstream filters for the output stream
* needs to be done here, because the codec id for streamcopy is not
* known until now */
ret = init_output_bsfs(ost);
if (ret < 0)
return ret;
ost->initialized = 1;
ret = check_init_output_file(output_files[ost->file_index], ost->file_index);
if (ret < 0)
return ret;
return ret;
}
static void report_new_stream(int input_index, AVPacket *pkt)
{
InputFile *file = input_files[input_index];
AVStream *st = file->ctx->streams[pkt->stream_index];
if (pkt->stream_index < file->nb_streams_warn)
return;
av_log(file->ctx, AV_LOG_WARNING,
"New %s stream %d:%d at pos:%"PRId64" and DTS:%ss\n",
av_get_media_type_string(st->codecpar->codec_type),
input_index, pkt->stream_index,
pkt->pos, av_ts2timestr(pkt->dts, &st->time_base));
file->nb_streams_warn = pkt->stream_index + 1;
}
static int transcode_init(void)
{
int ret = 0, i, j, k;
AVFormatContext *oc;
OutputStream *ost;
InputStream *ist;
char error[1024] = {0};
for (i = 0; i < nb_filtergraphs; i++) {
FilterGraph *fg = filtergraphs[i];
for (j = 0; j < fg->nb_outputs; j++) {
OutputFilter *ofilter = fg->outputs[j];
if (!ofilter->ost || ofilter->ost->source_index >= 0)
continue;
if (fg->nb_inputs != 1)
continue;
for (k = nb_input_streams-1; k >= 0 ; k--)
if (fg->inputs[0]->ist == input_streams[k])
break;
ofilter->ost->source_index = k;
}
}
/* init framerate emulation */
for (i = 0; i < nb_input_files; i++) {
InputFile *ifile = input_files[i];
if (ifile->rate_emu)
for (j = 0; j < ifile->nb_streams; j++)
input_streams[j + ifile->ist_index]->start = av_gettime_relative();
}
/* hwaccel transcoding */
for (i = 0; i < nb_output_streams; i++) {
ost = output_streams[i];
if (!ost->stream_copy) {
#if CONFIG_LIBMFX
if (qsv_transcode_init(ost))
exit_program(1);
#endif
#if CONFIG_CUVID
if (cuvid_transcode_init(ost))
exit_program(1);
#endif
}
}
......
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