ffmpeg 最简单的转码封装mp4文件

来源:互联网 发布:国家电网试题软件 编辑:程序博客网 时间:2024/06/01 22:45

转自:http://www.rosoo.net/a/201411/17115.html


本例简单实现了解码后的video重新编码264之后在mux成MP4文件的过程,主要是用来记录muxing的方法。
下面详细说一下细节:
大家都知道一般解码出来的数据都是播放顺序,解码器是将编码顺序的数据重新按照解码后的播放顺序输出的。而编码器是把数据根据解码需要的顺序重新排序保存的。
当然,以上情况只在有帧的情况下才有用,否则只有IP帧的话解码和编码的顺序是一样的
比如:解码后的数据是IBBP,那要将这个数据编码的话,编码后的数据保存的格式就是IPBB
这只是内部的处理,对于用ffmpeg的库的我们不用太过关心 ,但是 , 要注意,我们将数据塞给编码器的时候,要给顺序的播放加上顺序的时间标记,其实很简单只要保证你送给编码器的每一frame的pts都是顺序的就可以了, 否则编码器会报 “non-strictly-monotonic pts at frame” , 究其原因,是因为编码器需要送进来的frame时间上是递增的,为什么需要这个就得去本研究编码器了

if( pic.i_pts <= largest_pts ) { if( cli_log_level >= X264_LOG_DEBUG || pts_warning_cnt < MAX_PTS_WARNING )     x264_cli_log( "x264", X264_LOG_WARNING    , "non-strictly-monotonic pts at frame %d (%"PRId64" <= %"PRId64")\n"    , i_frame, pic.i_pts, largest_pts ); else if( pts_warning_cnt == MAX_PTS_WARNING )     x264_cli_log( "x264", X264_LOG_WARNING    , "too many nonmonotonic pts warnings, suppressing further ones\n" );     pts_warning_cnt++;     pic.i_pts = largest_pts + ticks_per_frame; } 

在将数据送到编码器后,进行编码输出得到的pkt有自己的pts和dts等数据,但是这个数据记得吗?是用我们自己送进去的pts来表示的,所以在和原来 的audio mux的时候,会出现严重的音视频不同步,现在想想这个问题,就很容易理解了,两边的pts差距很大,当然解码后做同步的时候会差很多。
其实ffmpeg在解码的时候将解码出来的顺序时间戳给了frame的pkt_pts这个成员,所以我们可以直接用这个值赋值给frame的pts,在送进编码器,这样编码出来的pkt中的时间戳就和原来的audio对上了。

ret = avcodec_decode_video2(video_dec_ctx, pFrame, &got_picture,pkt); if (ret < 0) { delete pkt; return 0; } pFrame->pts = pFrame->pkt_pts;  //赋值解码后的pts 

最后在进行mux成mp4文件就ok了
在mux的过程中,有个接口av_rescale_q_rnd,这个是用来换算pts的,因为在设定mp4输出格式的时候time_base这个值是和 原来的文件不一样的,所以要用这个来重新算分装数据的在新的mp4中的pts和dts等数据,具体原因后续会继续往里研究


直接上代码:

const char* SRC_FILE = "1.mkv"; const char* OUT_FILE = "outfile.h264"; const char* OUT_FMT_FILE = "outfmtfile.mp4"; int main() {     av_register_all();            AVFormatContext* pFormat = NULL;     if (avformat_open_input(&pFormat, SRC_FILE, NULL, NULL) < 0)     {         return 0;     }     AVCodecContext* video_dec_ctx = NULL;     AVCodec* video_dec = NULL;     if (avformat_find_stream_info(pFormat, NULL) < 0)     {         return 0;     }     av_dump_format(pFormat, 0, SRC_FILE, 0);     video_dec_ctx = pFormat->streams[0]->codec;     video_dec = avcodec_find_decoder(video_dec_ctx->codec_id);     if (avcodec_open2(video_dec_ctx, video_dec, NULL) < 0)     {         return 0;     }      AVFormatContext* pOFormat = NULL;     AVOutputFormat* ofmt = NULL;     if (avformat_alloc_output_context2(&pOFormat, NULL, NULL, OUT_FILE) < 0)     {         return 0;     }     ofmt = pOFormat->oformat;     if (avio_open(&(pOFormat->pb), OUT_FILE, AVIO_FLAG_READ_WRITE) < 0)     {         return 0;     }     AVCodecContext *video_enc_ctx = NULL;     AVCodec *video_enc = NULL;     video_enc = avcodec_find_encoder(AV_CODEC_ID_H264);     AVStream *video_st = avformat_new_stream(pOFormat, video_enc);     if (!video_st)         return 0;     video_enc_ctx = video_st->codec;     video_enc_ctx->width = video_dec_ctx->width;     video_enc_ctx->height = video_dec_ctx->height;     video_enc_ctx->pix_fmt = PIX_FMT_YUV420P;     video_enc_ctx->time_base.num = 1;     video_enc_ctx->time_base.den = 25;     video_enc_ctx->bit_rate = video_dec_ctx->bit_rate;     video_enc_ctx->gop_size = 250;     video_enc_ctx->max_b_frames = 10;     //H264     //pCodecCtx->me_range = 16;     //pCodecCtx->max_qdiff = 4;     video_enc_ctx->qmin = 10;     video_enc_ctx->qmax = 51;     if (avcodec_open2(video_enc_ctx, video_enc, NULL) < 0)     {         printf("编码器打开失败!\n");         return 0;     }     printf("Output264video Information====================\n");     av_dump_format(pOFormat, 0, OUT_FILE, 1);     printf("Output264video Information====================\n");      //mp4 file     AVFormatContext* pMp4Format = NULL;     AVOutputFormat* pMp4OFormat = NULL;     if (avformat_alloc_output_context2(&pMp4Format, NULL, NULL, OUT_FMT_FILE) < 0)     {         return 0;     }     pMp4OFormat = pMp4Format->oformat;     if (avio_open(&(pMp4Format->pb), OUT_FMT_FILE, AVIO_FLAG_READ_WRITE) < 0)     {         return 0;     }      for (int i = 0; i < pFormat->nb_streams; i++) {         AVStream *in_stream = pFormat->streams[i];         AVStream *out_stream = avformat_new_stream(pMp4Format, in_stream->codec->codec);         if (!out_stream) {             return 0;         }         int ret = 0;         ret = avcodec_copy_context(out_stream->codec, in_stream->codec);         if (ret < 0) { fprintf(stderr, "Failed to copy context from input to output stream codec context\n"); return 0;         }         out_stream->codec->codec_tag = 0;         if (pMp4Format->oformat->flags & AVFMT_GLOBALHEADER)             out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;     }       av_dump_format(pMp4Format, 0, OUT_FMT_FILE, 1);      if (avformat_write_header(pMp4Format, NULL) < 0)     {         return 0;     }     ////     av_opt_set(video_enc_ctx->priv_data, "preset", "superfast", 0);     av_opt_set(video_enc_ctx->priv_data, "tune", "zerolatency", 0);     avformat_write_header(pOFormat, NULL);     AVPacket *pkt = new AVPacket();     av_init_packet(pkt);     AVFrame *pFrame = avcodec_alloc_frame();     int ts = 0;     while (1)     {         if (av_read_frame(pFormat, pkt) < 0)         {             avio_close(pOFormat->pb);             av_write_trailer(pMp4Format);             avio_close(pMp4Format->pb);             delete pkt;             return 0;         }         if (pkt->stream_index == 0)         {                          int got_picture = 0, ret = 0;             ret = avcodec_decode_video2(video_dec_ctx, pFrame, &got_picture, pkt);             if (ret < 0)             {                 delete pkt;                 return 0;             }             pFrame->pts = pFrame->pkt_pts;//ts++;             if (got_picture)             {                 AVPacket *tmppkt = new AVPacket;                 av_init_packet(tmppkt);                 int size = video_enc_ctx->width*video_enc_ctx->height * 3 / 2;                 char* buf = new char[size];                 memset(buf, 0, size);                 tmppkt->data = (uint8_t*)buf;                 tmppkt->size = size;                 ret = avcodec_encode_video2(video_enc_ctx, tmppkt, pFrame, &got_picture);                 if (ret < 0)                 {                     avio_close(pOFormat->pb);                     delete buf;                     return 0;                 }                 if (got_picture)                 {                     //ret = av_interleaved_write_frame(pOFormat, tmppkt);                     AVStream *in_stream = pFormat->streams[pkt->stream_index];                     AVStream *out_stream = pMp4Format->streams[pkt->stream_index];      tmppkt->pts = av_rescale_q_rnd(tmppkt->pts, in_stream->time_base    , out_stream->time_base, AV_ROUND_NEAR_INF); tmppkt->dts = av_rescale_q_rnd(tmppkt->dts, in_stream->time_base    , out_stream->time_base, AV_ROUND_NEAR_INF); tmppkt->duration = av_rescale_q(tmppkt->duration, in_stream->time_base    , out_stream->time_base); tmppkt->pos = -1; ret = av_interleaved_write_frame(pMp4Format, tmppkt);                     if (ret < 0)                         return 0;                     delete tmppkt;                     delete buf;                 }             }             //avcodec_free_frame(&pFrame);         }         else if (pkt->stream_index == 1)         {             AVStream *in_stream = pFormat->streams[pkt->stream_index];             AVStream *out_stream = pMp4Format->streams[pkt->stream_index];  pkt->pts = av_rescale_q_rnd(pkt->pts, in_stream->time_base    , out_stream->time_base, AV_ROUND_NEAR_INF); pkt->dts = av_rescale_q_rnd(pkt->dts, in_stream->time_base    , out_stream->time_base, AV_ROUND_NEAR_INF); pkt->duration = av_rescale_q(pkt->duration, in_stream->time_base    , out_stream->time_base);             pkt->pos = -1;             if (av_interleaved_write_frame(pMp4Format, pkt) < 0)                 return 0;         }     }     avcodec_free_frame(&pFrame);     return 0; }  



0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 宝宝2岁半胆小怎么办 5岁宝宝超级粘人怎么办 狗狗吃饭要人喂怎么办 十个月宝宝认人怎么办 一岁宝宝粘人怎么办 9个月宝宝粘妈妈怎么办 一岁的宝宝呕吐怎么办 宝宝一岁八个月太粘人了怎么办 六个月的宝宝好粘人怎么办 两岁半宝宝说话突然结巴了怎么办 1岁宝宝突然呕吐怎么办 宝宝吃坏了呕吐怎么办 1岁宝宝吃饭爱玩怎么办 7岁儿童半夜呕吐怎么办 一个月宝宝粘人怎么办 2岁宝宝太粘人了怎么办 8个月宝宝很粘人怎么办 7个月宝宝呕吐是怎么办 一个月婴儿粘人怎么办 八个月小孩粘人怎么办 一岁的宝宝粘人怎么办 六个月宝宝粘人爱哭怎么办 摔伤结巴里面灌脓了怎么办 两周半的宝宝说话结巴怎么办 孩子两周说话结巴怎么办 名字取了生僻字考大学怎么办 淘宝客服一直不说话怎么办 淘宝客服不说话也不发货怎么办 面对不说话的客人怎么办? 卖家客服不回复怎么办 2周小孩说话结巴怎么办 微信群里只领红包不说话的人怎么办 躺在微信不说话的客户怎么办 9岁儿童说话结巴怎么办 5岁儿童说话结巴怎么办 京东客服不说话怎么办 两岁宝宝说话有点结巴怎么办 孩子不敢跟外人说话怎么办? 孩子不爱跟外人说话怎么办 别人说我不说话怎么办 衣服屁股那块变亮怎么办