77范文网 - 专业文章范例文档资料分享平台

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

来源:网络收集 时间:2020-06-17 下载这篇文档 手机版
说明:文章内容仅供预览,部分内容可能不全,需要完整文档或者需要复制内容,请下载word后使用。下载word有问题请添加微信号:或QQ: 处理(尽可能给您提供完整文档),感谢您的支持与谅解。点击这里给我发消息

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

分类: C/C++

本例简单实现了解码后的video重新编码264之后在mux成MP4文件的过程,主要是用来记录muxing的方法。 下面详细说一下细节:

大家都知道一般解码出来的数据都是播放顺序,解码器是将编码顺序的数据重新按照解码后的播放顺序输出的。而编码器是把数据根据解码需要的顺序重新排序保存的。

当然,以上情况只在有帧的情况下才有用,否则只有IP帧的话解码和编码的顺序是一样的

比如:解码后的数据是IBBP,那要将这个数据编码的话,编码后的数据保存的格式就是IPBB

这只是内部的处理,对于用ffmpeg的库的我们不用太过关心 ,但是 , 要注意,我们将数据塞给编码器的时候,要给顺序的播放加上顺序的时间标记,其实很简单只要保证你送给编码器的每一frame的pts都是顺序的就可以了,否则编码器会报 “non-strictly-monotonic pts at frame” , 究其原因,是因为编码器需要送进来的frame时间上是递增的,为什么需要这个就得去本研究编码器了

点击(此处)折叠或打开 1. 2. 3. if( pic.i_pts <= largest_pts ) { if( cli_log_level >= X264_LOG_DEBUG || pts_warning_cnt < MAX_PTS_WARNING ) 4. x264_cli_log( \, X264_LOG_WARNING, \tonic pts at frame %d (%\PRId64\PRId64\, 5. i_frame, pic.i_pts, largest_pts ); 6. else if( pts_warning_cnt == MAX_PTS_WARNING ) 7. x264_cli_log( \, X264_LOG_WARNING, \onic 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. 2. 3. 4. 5. 6. 7. 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等数据,具体原因后续会继续往里研究

直接上代码:

点击(此处)折叠或打开 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 0) 32. 33. 34. 35. 36. { return 0; } ofmt = pOFormat->oformat; if (avio_open(&(pOFormat->pb), OUT_FILE, AVIO_FLAG_READ_WRITE) < 0) const char* SRC_FILE = \; const char* OUT_FILE = \; const char* OUT_FMT_FILE = \; 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) < 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. { 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(\); av_dump_format(pOFormat, 0, OUT_FILE, 1); printf(\); //mp4 file AVFormatContext* pMp4Format = NULL; AVOutputFormat* pMp4OFormat = NULL; if (avformat_alloc_output_context2(&pMp4Format, NULL, NULL, OUT_FMT_FILE) < 0) 73. { 74. return 0; 75. } 76. pMp4OFormat = pMp4Format->oformat; 77. if (avio_open(&(pMp4Format->pb), OUT_FMT_FILE, AVIO_FLAG_READ_WRITE) < 0) 78. { 79. return 0; 80. } 81. 82. for (int i = 0; i < pFormat->nb_streams; i++) { 83. AVStream *in_stream = pFormat->streams[i]; 84. AVStream *out_stream = avformat_new_stream(pMp4Format, in_stream->codec->codec); 85. if (!out_stream) { 86. return 0; 87. } 88. int ret = 0; 89. ret = avcodec_copy_context(out_stream->codec, in_stream->codec); 90. if (ret < 0) { 91. fprintf(stderr, \tream codec context\\n\); 92. return 0; 93. } 94. out_stream->codec->codec_tag = 0; 95. if (pMp4Format->oformat->flags & AVFMT_GLOBALHEADER) 96. out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; 97. } 98. 99. 100. av_dump_format(pMp4Format, 0, OUT_FMT_FILE, 1); 101. 102. if (avformat_write_header(pMp4Format, NULL) < 0) 103. { 104. return 0; 105. } 106. 107. 108. //// 109. 110. 111. 112. av_opt_set(video_enc_ctx->priv_data, \, \, 0); 113. av_opt_set(video_enc_ctx->priv_data, \, \, 0); 114. avformat_write_header(pOFormat, NULL); 115. AVPacket *pkt = new AVPacket(); 116. av_init_packet(pkt); 117. AVFrame *pFrame = avcodec_alloc_frame(); 118. int ts = 0; 119. while (1) 120. { 121. if (av_read_frame(pFormat, pkt) < 0) 122. { 123. avio_close(pOFormat->pb); 124. av_write_trailer(pMp4Format); 125. avio_close(pMp4Format->pb); 126. delete pkt; 127. return 0; 128. } 129. if (pkt->stream_index == 0) 130. { 131. 132. int got_picture = 0, ret = 0; 133. ret = avcodec_decode_video2(video_dec_ctx, pFrame, &got_picture, pkt); 134. if (ret < 0) 135. { 136. delete pkt; 137. return 0; 138. } 139. pFrame->pts = pFrame->pkt_pts;//ts++; 140. if (got_picture) 141. { 142. AVPacket *tmppkt = new AVPacket; 143. av_init_packet(tmppkt); 144. int size = video_enc_ctx->width*video_enc_ctx->height * 3 / 2; 145. char* buf = new char[size]; 146. memset(buf, 0, size); 147. tmppkt->data = (uint8_t*)buf; 148. tmppkt->size = size; 149. ret = avcodec_encode_video2(video_enc_ctx, tmppkt, pFrame, &got_picture); 150. if (ret < 0) 151. { 152. avio_close(pOFormat->pb); 153. delete buf; 154. return 0; 155. } 156. if (got_picture) 157. { 158. //ret = av_interleaved_write_frame(pOFormat, tmppkt); 159. AVStream *in_stream = pFormat->streams[pkt->stream_index]; 160. AVStream *out_stream = pMp4Format->streams[pkt->stream_index]; 161. 162. tmppkt->pts = av_rescale_q_rnd(tmppkt->pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF); 163. tmppkt->dts = av_rescale_q_rnd(tmppkt->dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF); 164. tmppkt->duration = av_rescale_q(tmppkt->duration, in_stream->time_base, out_stream->time_base); 165. tmppkt->pos = -1; 166. ret = av_interleaved_write_frame(pMp4Format, tmppkt); 167. if (ret < 0) 168. return 0; 169. delete tmppkt; 170. delete buf; 171. } 172. } 173. //avcodec_free_frame(&pFrame); 174. } 175. else if (pkt->stream_index == 1) 176. { 177. AVStream *in_stream = pFormat->streams[pkt->stream_index]; 178. AVStream *out_stream = pMp4Format->streams[pkt->stream_index]; 179. 180. pkt->pts = av_rescale_q_rnd(pkt->pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF); 181. pkt->dts = av_rescale_q_rnd(pkt->dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF); 182. pkt->duration = av_rescale_q(pkt->duration, in_stream->time_base, out_stream->time_base); 183. pkt->pos = -1; 184. if (av_interleaved_write_frame(pMp4Format, pkt) < 0) 185. return 0; 186. } 187. } 188. avcodec_free_frame(&pFrame); 189. return 0; 190. }

阅读(4898) | 评论(0) | 转发(0) |

0

上一篇:ffmpeg 最简单的编码264

下一篇:设计模式-工厂模式与抽象工厂模式

百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库ffmpeg 最简单的转码封装mp4文件在线全文阅读。

ffmpeg 最简单的转码封装mp4文件.doc 将本文的Word文档下载到电脑,方便复制、编辑、收藏和打印 下载失败或者文档不完整,请联系客服人员解决!
本文链接:https://www.77cn.com.cn/wenku/zonghe/1105491.html(转载请注明文章来源)
Copyright © 2008-2022 免费范文网 版权所有
声明 :本网站尊重并保护知识产权,根据《信息网络传播权保护条例》,如果我们转载的作品侵犯了您的权利,请在一个月内通知我们,我们会及时删除。
客服QQ: 邮箱:tiandhx2@hotmail.com
苏ICP备16052595号-18
× 注册会员免费下载(下载后可以自由复制和排版)
注册会员下载
全站内容免费自由复制
注册会员下载
全站内容免费自由复制
注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: