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
下一篇:设计模式-工厂模式与抽象工厂模式