[Libav-user] Transcode with the some properties
Andrew Randrianasulu
randrianasulu at gmail.com
Mon Nov 4 12:39:24 EET 2019
В сообщении от Monday 04 November 2019 12:29:10 Boris написал(а):
> Hello,
> I want to transcode video with exactly the same properties of the input
> video in the output video.
> I use the transcoding.cc code. In the static int open_output_file(const
> char *filename) function, I set encoder parameters like this :
>
> if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO)
> {
> enc_ctx->height = dec_ctx->height;
> enc_ctx->width = dec_ctx->width;
> enc_ctx->sample_aspect_ratio =
> dec_ctx->sample_aspect_ratio;
>
> enc_ctx->global_quality=dec_ctx->global_quality;
> enc_ctx->gop_size=dec_ctx->gop_size;
> enc_ctx->bit_rate=dec_ctx->bit_rate;
> enc_ctx->time_base=dec_ctx->time_base;
> enc_ctx->delay=dec_ctx->delay;
>
> //**********************************************
> enc_ctx->rc_max_rate=dec_ctx->rc_max_rate;
> enc_ctx->rc_min_rate=dec_ctx->rc_min_rate;
> /* take first format from list of supported
> formats */
> if (encoder->pix_fmts)
> {
> enc_ctx->pix_fmt =
> encoder->pix_fmts[0];
> }
> else
> {
> enc_ctx->pix_fmt = dec_ctx->pix_fmt;
> }
> // video time_base can be set to whatever
> is handy and supported by encoder
> // enc_ctx->time_base =
> av_inv_q(dec_ctx->framerate);
> }
> else
> {
> enc_ctx->sample_rate = dec_ctx->sample_rate;
> enc_ctx->channel_layout =
> dec_ctx->channel_layout;
> enc_ctx->channels =
> av_get_channel_layout_nb_channels(enc_ctx->channel_layout);
> /* take first format from list of supported
> formats */
> enc_ctx->sample_fmt =
> encoder->sample_fmts[0];
> enc_ctx->time_base = (AVRational){1,
> enc_ctx->sample_rate};
> }
> /* Third parameter can be used to pass settings to
> encoder */
> ret = avcodec_open2(enc_ctx, encoder, NULL);
> if (ret < 0)
> {
> av_log(NULL, AV_LOG_ERROR, "Cannot open
> video encoder for stream #%u\n", i);
> return ret;
> }
> ret =
> avcodec_parameters_from_context(out_stream->codecpar, enc_ctx);
> if (ret < 0)
> {
> av_log(NULL, AV_LOG_ERROR, "Failed to copy
> encoder parameters to output stream #%u\n", i);
> return ret;
> }
> if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
> enc_ctx->flags |=
> AV_CODEC_FLAG_GLOBAL_HEADER;
>
> out_stream->time_base = enc_ctx->time_base;
>
>
> But when I run exiftool on output video and on input video, some values
> like video duration, encoder, bit rate, are differente.
Hm, video duration chnage sounds like most unwelcome one ...
But are codec parameters even supposed to be the same after different encoder run over output of another encoder?
I recall term 'bit exact', but is this applicable to re-encoding with lossy codecs?
> Can someone tells me how can I do to keep the same parameters (metada) of
> the input video in the output video, please?
>
> The entire open_output_file function is the following :
>
> static int open_output_file(const char *filename)
> {
> AVStream *out_stream;
> AVStream *in_stream;
> AVCodecContext *dec_ctx, *enc_ctx;
> AVCodec *encoder;
> int ret;
> unsigned int i;
> ofmt_ctx = NULL;
> avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, filename);
> if (!ofmt_ctx)
> {
> av_log(NULL, AV_LOG_ERROR, "Could not create output
> context\n");
> return AVERROR_UNKNOWN;
> }
>
> for (i = 0; i < ifmt_ctx->nb_streams; i++)
> {
> out_stream = avformat_new_stream(ofmt_ctx, NULL);
> if (!out_stream)
> {
> av_log(NULL, AV_LOG_ERROR, "Failed allocating
> output stream\n");
> return AVERROR_UNKNOWN;
> }
>
> in_stream = ifmt_ctx->streams[i];
> dec_ctx = stream_ctx[i].dec_ctx;
>
> if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
> dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO)
> {
> //AVCodecID codec_id = dec_ctx->codec_type ==
> AVMEDIA_TYPE_VIDEO ? AV_CODEC_ID_MPEG4:dec_ctx->codec_id;
> /* in this example, we choose transcoding to same
> codec */
> //encoder = dec_ctx->codec_type ==
> AVMEDIA_TYPE_VIDEO ?
> avcodec_find_encoder(AV_CODEC_ID_H264):avcodec_find_encoder(dec_ctx->codec_id);//(AV_CODEC_ID_MPEG4):avcodec_find_encoder(dec_ctx->codec_id);
> encoder = dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO
> ?
> avcodec_find_encoder(AV_CODEC_ID_MPEG4):avcodec_find_encoder(dec_ctx->codec_id);
> // if(dec_ctx->codec_type ==
> AVMEDIA_TYPE_VIDEO){encoder=avcodec_find_encoder(AV_CODEC_ID_MPEG4);}else{encoder=avcodec_find_encoder(dec_ctx->codec_id);}
> //encoder = avcodec_find_encoder(dec_ctx->codec_id);
> if (!encoder)
> {
> av_log(NULL, AV_LOG_FATAL, "Necessary
> encoder not found\n");
> return AVERROR_INVALIDDATA;
> }
> enc_ctx = avcodec_alloc_context3(encoder);
> if (!enc_ctx)
> {
> av_log(NULL, AV_LOG_FATAL, "Failed to
> allocate the encoder context\n");
> return AVERROR(ENOMEM);
> }
>
> /* In this example, we transcode to same properties
> (picture size,
> * sample rate etc.). These properties can be
> changed for output
> * streams easily using filters */
> if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO)
> {
> enc_ctx->height = dec_ctx->height;
> enc_ctx->width = dec_ctx->width;
> enc_ctx->sample_aspect_ratio =
> dec_ctx->sample_aspect_ratio;
>
> enc_ctx->global_quality=dec_ctx->global_quality;
> enc_ctx->gop_size=dec_ctx->gop_size;
> enc_ctx->bit_rate=dec_ctx->bit_rate;
> enc_ctx->time_base=dec_ctx->time_base;
> enc_ctx->delay=dec_ctx->delay;
>
> //**********************************************
> enc_ctx->rc_max_rate=dec_ctx->rc_max_rate;
> enc_ctx->rc_min_rate=dec_ctx->rc_min_rate;
> /* take first format from list of supported
> formats */
> if (encoder->pix_fmts)
> {
> enc_ctx->pix_fmt =
> encoder->pix_fmts[0];
> }
> else
> {
> enc_ctx->pix_fmt = dec_ctx->pix_fmt;
> }
> // video time_base can be set to whatever
> is handy and supported by encoder
> // enc_ctx->time_base =
> av_inv_q(dec_ctx->framerate);
> }
> else
> {
> enc_ctx->sample_rate = dec_ctx->sample_rate;
> enc_ctx->channel_layout =
> dec_ctx->channel_layout;
> enc_ctx->channels =
> av_get_channel_layout_nb_channels(enc_ctx->channel_layout);
> /* take first format from list of supported
> formats */
> enc_ctx->sample_fmt =
> encoder->sample_fmts[0];
> enc_ctx->time_base = (AVRational){1,
> enc_ctx->sample_rate};
> }
> /* Third parameter can be used to pass settings to
> encoder */
> ret = avcodec_open2(enc_ctx, encoder, NULL);
> if (ret < 0)
> {
> av_log(NULL, AV_LOG_ERROR, "Cannot open
> video encoder for stream #%u\n", i);
> return ret;
> }
> ret =
> avcodec_parameters_from_context(out_stream->codecpar, enc_ctx);
> if (ret < 0)
> {
> av_log(NULL, AV_LOG_ERROR, "Failed to copy
> encoder parameters to output stream #%u\n", i);
> return ret;
> }
> if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
> enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
>
> out_stream->time_base = enc_ctx->time_base;
> stream_ctx[i].enc_ctx = enc_ctx;
> }
> else if (dec_ctx->codec_type == AVMEDIA_TYPE_UNKNOWN)
> {
> av_log(NULL, AV_LOG_FATAL, "Elementary stream #%d
> is of unknown type, cannot proceed\n", i);
> return AVERROR_INVALIDDATA;
> }
> else
> {
> // if this stream must be remuxed
> ret = avcodec_parameters_copy(out_stream->codecpar,
> in_stream->codecpar);
> //ifmt_ctx->streams[i]->codec);
> if (ret < 0)
> {
> av_log(NULL, AV_LOG_ERROR, "Copying
> parameters for stream #%u failed\n", i);
> return ret;
> }
> out_stream->time_base = in_stream->time_base;
> }
>
> }
> av_dump_format(ofmt_ctx, 0, filename, 1);
>
> if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE))
> {
> ret = avio_open(&ofmt_ctx->pb, filename, AVIO_FLAG_WRITE);
> if (ret < 0)
> {
> av_log(NULL, AV_LOG_ERROR, "Could not open output
> file '%s'", filename);
> return ret;
> }
> }
>
> /* init muxer, write output file header */
> ret = avformat_write_header(ofmt_ctx, NULL);
> if (ret < 0)
> {
> av_log(NULL, AV_LOG_ERROR, "Error occurred when opening
> output file\n");
> return ret;
> }
> return 0;
> }
>
> Rgards
>
More information about the Libav-user
mailing list