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

点击(此处)折叠或打开

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

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

点击(此处)折叠或打开

  1. ret = avcodec_decode_video2(video_dec_ctx, pFrame, &got_picture, pkt);
  2. if (ret < 0)
  3. {
  4. delete pkt;
  5. return 0;
  6. }
  7. pFrame->pts = pFrame->pkt_pts;  //赋值解码后的pts

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

点击(此处)折叠或打开

  1. const char* SRC_FILE = "1.mkv";
  2. const char* OUT_FILE = "outfile.h264";
  3. const char* OUT_FMT_FILE = "outfmtfile.mp4";
  4. int main()
  5. {
  6. av_register_all();
  7. AVFormatContext* pFormat = NULL;
  8. if (avformat_open_input(&pFormat, SRC_FILE, NULL, NULL) < 0)
  9. {
  10. return 0;
  11. }
  12. AVCodecContext* video_dec_ctx = NULL;
  13. AVCodec* video_dec = NULL;
  14. if (avformat_find_stream_info(pFormat, NULL) < 0)
  15. {
  16. return 0;
  17. }
  18. av_dump_format(pFormat, 0, SRC_FILE, 0);
  19. video_dec_ctx = pFormat->streams[0]->codec;
  20. video_dec = avcodec_find_decoder(video_dec_ctx->codec_id);
  21. if (avcodec_open2(video_dec_ctx, video_dec, NULL) < 0)
  22. {
  23. return 0;
  24. }
  25. AVFormatContext* pOFormat = NULL;
  26. AVOutputFormat* ofmt = NULL;
  27. if (avformat_alloc_output_context2(&pOFormat, NULL, NULL, OUT_FILE) < 0)
  28. {
  29. return 0;
  30. }
  31. ofmt = pOFormat->oformat;
  32. if (avio_open(&(pOFormat->pb), OUT_FILE, AVIO_FLAG_READ_WRITE) < 0)
  33. {
  34. return 0;
  35. }
  36. AVCodecContext *video_enc_ctx = NULL;
  37. AVCodec *video_enc = NULL;
  38. video_enc = avcodec_find_encoder(AV_CODEC_ID_H264);
  39. AVStream *video_st = avformat_new_stream(pOFormat, video_enc);
  40. if (!video_st)
  41. return 0;
  42. video_enc_ctx = video_st->codec;
  43. video_enc_ctx->width = video_dec_ctx->width;
  44. video_enc_ctx->height = video_dec_ctx->height;
  45. video_enc_ctx->pix_fmt = PIX_FMT_YUV420P;
  46. video_enc_ctx->time_base.num = 1;
  47. video_enc_ctx->time_base.den = 25;
  48. video_enc_ctx->bit_rate = video_dec_ctx->bit_rate;
  49. video_enc_ctx->gop_size = 250;
  50. video_enc_ctx->max_b_frames = 10;
  51. //H264
  52. //pCodecCtx->me_range = 16;
  53. //pCodecCtx->max_qdiff = 4;
  54. video_enc_ctx->qmin = 10;
  55. video_enc_ctx->qmax = 51;
  56. if (avcodec_open2(video_enc_ctx, video_enc, NULL) < 0)
  57. {
  58. printf("编码器打开失败!\n");
  59. return 0;
  60. }
  61. printf("Output264video Information====================\n");
  62. av_dump_format(pOFormat, 0, OUT_FILE, 1);
  63. printf("Output264video Information====================\n");
  64. //mp4 file
  65. AVFormatContext* pMp4Format = NULL;
  66. AVOutputFormat* pMp4OFormat = NULL;
  67. if (avformat_alloc_output_context2(&pMp4Format, NULL, NULL, OUT_FMT_FILE) < 0)
  68. {
  69. return 0;
  70. }
  71. pMp4OFormat = pMp4Format->oformat;
  72. if (avio_open(&(pMp4Format->pb), OUT_FMT_FILE, AVIO_FLAG_READ_WRITE) < 0)
  73. {
  74. return 0;
  75. }
  76. for (int i = 0; i < pFormat->nb_streams; i++) {
  77. AVStream *in_stream = pFormat->streams[i];
  78. AVStream *out_stream = avformat_new_stream(pMp4Format, in_stream->codec->codec);
  79. if (!out_stream) {
  80. return 0;
  81. }
  82. int ret = 0;
  83. ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
  84. if (ret < 0) {
  85. fprintf(stderr, "Failed to copy context from input to output stream codec context\n");
  86. return 0;
  87. }
  88. out_stream->codec->codec_tag = 0;
  89. if (pMp4Format->oformat->flags & AVFMT_GLOBALHEADER)
  90. out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
  91. }
  92. av_dump_format(pMp4Format, 0, OUT_FMT_FILE, 1);
  93. if (avformat_write_header(pMp4Format, NULL) < 0)
  94. {
  95. return 0;
  96. }
  97. ////
  98. av_opt_set(video_enc_ctx->priv_data, "preset", "superfast", 0);
  99. av_opt_set(video_enc_ctx->priv_data, "tune", "zerolatency", 0);
  100. avformat_write_header(pOFormat, NULL);
  101. AVPacket *pkt = new AVPacket();
  102. av_init_packet(pkt);
  103. AVFrame *pFrame = avcodec_alloc_frame();
  104. int ts = 0;
  105. while (1)
  106. {
  107. if (av_read_frame(pFormat, pkt) < 0)
  108. {
  109. avio_close(pOFormat->pb);
  110. av_write_trailer(pMp4Format);
  111. avio_close(pMp4Format->pb);
  112. delete pkt;
  113. return 0;
  114. }
  115. if (pkt->stream_index == 0)
  116. {
  117. int got_picture = 0, ret = 0;
  118. ret = avcodec_decode_video2(video_dec_ctx, pFrame, &got_picture, pkt);
  119. if (ret < 0)
  120. {
  121. delete pkt;
  122. return 0;
  123. }
  124. pFrame->pts = pFrame->pkt_pts;//ts++;
  125. if (got_picture)
  126. {
  127. AVPacket *tmppkt = new AVPacket;
  128. av_init_packet(tmppkt);
  129. int size = video_enc_ctx->width*video_enc_ctx->height * 3 / 2;
  130. char* buf = new char[size];
  131. memset(buf, 0, size);
  132. tmppkt->data = (uint8_t*)buf;
  133. tmppkt->size = size;
  134. ret = avcodec_encode_video2(video_enc_ctx, tmppkt, pFrame, &got_picture);
  135. if (ret < 0)
  136. {
  137. avio_close(pOFormat->pb);
  138. delete buf;
  139. return 0;
  140. }
  141. if (got_picture)
  142. {
  143. //ret = av_interleaved_write_frame(pOFormat, tmppkt);
  144. AVStream *in_stream = pFormat->streams[pkt->stream_index];
  145. AVStream *out_stream = pMp4Format->streams[pkt->stream_index];
  146. tmppkt->pts = av_rescale_q_rnd(tmppkt->pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF);
  147. tmppkt->dts = av_rescale_q_rnd(tmppkt->dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF);
  148. tmppkt->duration = av_rescale_q(tmppkt->duration, in_stream->time_base, out_stream->time_base);
  149. tmppkt->pos = -1;
  150. ret = av_interleaved_write_frame(pMp4Format, tmppkt);
  151. if (ret < 0)
  152. return 0;
  153. delete tmppkt;
  154. delete buf;
  155. }
  156. }
  157. //avcodec_free_frame(&pFrame);
  158. }
  159. else if (pkt->stream_index == 1)
  160. {
  161. AVStream *in_stream = pFormat->streams[pkt->stream_index];
  162. AVStream *out_stream = pMp4Format->streams[pkt->stream_index];
  163. pkt->pts = av_rescale_q_rnd(pkt->pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF);
  164. pkt->dts = av_rescale_q_rnd(pkt->dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF);
  165. pkt->duration = av_rescale_q(pkt->duration, in_stream->time_base, out_stream->time_base);
  166. pkt->pos = -1;
  167. if (av_interleaved_write_frame(pMp4Format, pkt) < 0)
  168. return 0;
  169. }
  170. }
  171. avcodec_free_frame(&pFrame);
  172. return 0;
  173. }

ffmpeg 最简单的转码封装mp4文件相关推荐

  1. 转: FFMpeg 封装MP4 文件

    FFmpeg 封装MP4文件的一个例子    项目中用到FFmpeg 将IP摄像头的视频流的保存MP4文件的.之前的大哥将它先存成了H264文件,然后又调用FFMpeg的命令行去实现转码为MP4.感觉 ...

  2. 利用FFmpeg转码生成MP4文件

    利用FFmpeg转码生成MP4文件 2017年06月24日 14:42:53 阅读数:2401 项目中,需要把一路音频流及一路视频流分别转码,生成指定格式(MP4)文件.在使用ffmpeg转码生成mp ...

  3. 使用 MediaExtractor 和 MediaMuxer API 解析和封装 mp4 文件

    一个音视频文件是由音频和视频组成的,我们可以通过MediaExtractor.MediaMuxer把音频或视频给单独抽取出来,抽取出来的音频和视频能单独播放: 一.MediaExtractor API ...

  4. ffmpeg基础三:H264,从MP4文件获取(av_bsf_get_by_name(“h264_mp4toannexb“))和从TS流获取保存H264

    参考:零声学院 1.流媒体编解码流程 2.编码原理 在⾳视频传输过程中,视频⽂件的传输是⼀个极⼤的问题:⼀段分辨率为19201080,每个像 素点为RGB占⽤3个字节,帧率是25的视频,对于传输带宽的 ...

  5. H264文件封装MP4文件

    推荐一篇优秀的博文.对于MP4的初学者很有用:MP4文件格式解析_chenchong_219的博客-CSDN博客_mp4格式 对于这篇博文最后 Sample Table Box部分我想做一些补充,如有 ...

  6. 批处理ffmpeg将avi视频格式转换成mp4文件同时生成m3u8文件

    需求说明 本人在制作全栈开发的视频录制过程中,使用的是CameraStudio,录制生成在vv目录下的若干个avi视频,其中特别注意的是,生成的这些文件以及目录路径只能是字母或数字.需要将其转化成mp ...

  7. 利用WIN10自带ACG播放器完成.flv视频文件转码为mp4文件

    1.双击视频,利用ACG播放器打开  2.点击更多-工具箱 3.进行视频转码 4.压制完的视频会放在其列出的视频文件夹下:

  8. ffmpeg + opencv 把摄像头画面保存为mp4文件

    根据 https://stackoverflow.com/questions/46444474/c-ffmpeg-create-mp4-file 修改 运行环境为Ubuntu 20.10 #inclu ...

  9. linux 视频编辑 ffmpeg,ffmpeg转码视频真的好用!(ffmpeg的简单使用方法)

    说明 转码和编辑视频 今天用Android Studio(后面简称AS)里的模拟器给系统录屏,用来展示OpenGL可视化的东西,打算上传B站,后来发现AS只能保存webm格式和GIF格式的视频,并且文 ...

  10. ffmpeg转码视频真的好用!(ffmpeg的简单使用方法)

    说明 笔者个人博客网站:https://hk-shao.github.io/ 最新文章和更新都会在这里 转码和编辑视频 今天用Android Studio(后面简称AS)里的模拟器给系统录屏,用来展示 ...

最新文章

  1. Java数据库连接(JDBC)之二:Statement对象和PreparedStatement对象的使用
  2. ajax post 表单和 json 字符串
  3. linux udp端口大数据包,Linux协议栈中UDP数据报从网卡到用户空间流程总结
  4. java ews_Java---使用EWS 写个ExchangeMailUtil
  5. python版本切换_怎么切换python版本
  6. VirtualBox中使用双网卡实现CentOS既能上网(校园网)也能使用SSHclient
  7. pytorch torch.unsqueeze
  8. MVVM js 库JsRender/JsViews和knockoutjs介绍
  9. 一个虚拟服务器装多个网站,一台虚拟主机 如何放多个网站
  10. matlab拉格朗日曲线_数学中高耸的金字塔——拉格朗日
  11. Java 中与()短路与()以及 或(|)短路或(||)的关系
  12. 你了解实时3D渲染吗?实时渲染软件和应用场景科普来了
  13. Java基础案例教程_Java基础案例教程答案
  14. Latex入门_第3章:文档元素
  15. FastDFS构成、特性、Linux下安装以及Java如何访问
  16. Koa2仿知乎服务端项目:Webpack配置
  17. 前端实现语音播报功能
  18. 崭新朕亨公益公司 Kickstarter在创业公司中走出全新一条路
  19. 物联网平台独孤九剑(1)| 超强物联网架构解读
  20. 返回值被忽略_聊聊如今智能手机中一项容易被忽略的参数信息--闭环马达

热门文章

  1. XML可扩展语言的发展
  2. 服务器上装的hadoop系统,在Ubuntu Server 18.04.1中安装Hadoop系统环境
  3. 使用数据库引擎优化顾问添加建议索引
  4. Linux---文件权限的控制
  5. MySQL类型float double decimal的区别
  6. 英特尔逆天原型机:在 Android 上跑 Debian
  7. 《智能家居产品 从设计到运营》——2.2 智能设备的触角:传感器
  8. 进程cpu使用率的计算
  9. Triangular Pastures
  10. PHP oop之大讨论 --- 你究竟有无在用OOP