[Libav-user] Transcode with the some properties

Andrew Randrianasulu randrianasulu at gmail.com
Mon Nov 4 13:46:38 EET 2019


В сообщении от Monday 04 November 2019 14:22:32 Boris написал(а):
> Le lun. 4 nov. 2019 à 11:47, Andrew Randrianasulu <randrianasulu at gmail.com>
> a écrit :
> 
> > В сообщении от 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?
> >
> 
> I'm not sure but I thought it could be done. If you have things that I do
> not know, do not hesitate to share them with me,please.

Well, my thinking is extremely generic and might be incorrect.

But codecs usually analyze input video so they  can arrange keyframes and various types of macroblocs optimally (as far as their logic allow them).
So, while if two different codecs run over same uncompressed  video/set of images
should produce same bitsream - small artefacts from first (lossy) codec run will change behavior of second codec in chain, i think...

because codecs just do math over number of pixels, and while number of pixels will remain the same - their exact values will be slightly off after first encoding ...

May be things like ffv1 can be used without any real mathematical degradation of video, but then re-encoding basically lost any sense ...?

> 
> Regards
> 
> Hello
> 
> > > 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
> > >
> >
> >
> > _______________________________________________
> > Libav-user mailing list
> > Libav-user at ffmpeg.org
> > https://ffmpeg.org/mailman/listinfo/libav-user
> >
> > To unsubscribe, visit link above, or email
> > libav-user-request at ffmpeg.org with subject "unsubscribe".
> 




More information about the Libav-user mailing list