当前位置:   article > 正文

使用FFMPEG库封装264视频和acc音频数据到MP4文件中_ffmpeg 将aac 和 h264合并成mp4

ffmpeg 将aac 和 h264合并成mp4

准备

ffmepeg 4.4

一段H264的视频文件

一段acc格式的音频文件

封装流程

1.使用avformat_open_input分别打开视频和音频文件,初始化其AVFormatContext,使用avformat_find_stream_info获取编码器基本信息

2.使用avformat_alloc_output_context2初始化输出的AVFormatContext结构

3.使用函数avformat_new_stream给输出的AVFormatContext结构创建音频和视频流,使用avcodec_parameters_copy方法将音视频的编码参数拷贝到新创建的对应的流的codecpar结构中

4.使用avio_open打开输出文件,初始化输出AVFormatContext结构中的IO上下文结构

5.使用avformat_write_header写入流的头信息到输出文件中

6.根据时间戳同步原则交错写入音视频数据,并对时间戳信息进行设置和校准

7.写入流预告信息到输出文件中(moov)

8.释放空间,关闭文件

 

源码

  1. #include <stdio.h>
  2. #define __STDC_CONSTANT_MACROS
  3. #ifdef _WIN32
  4. //Windows
  5. extern "C"
  6. {
  7. #include "libavformat/avformat.h"
  8. };
  9. #else
  10. //Linux...
  11. #ifdef __cplusplus
  12. extern "C"
  13. {
  14. #endif
  15. #include <libavformat/avformat.h>
  16. #ifdef __cplusplus
  17. };
  18. #endif
  19. #endif
  20. int main(int argc, char* argv[]) {
  21. AVOutputFormat* ofmt = NULL;
  22. //Input AVFormatContext and Output AVFormatContext
  23. AVFormatContext* ifmt_ctx_v = NULL, * ifmt_ctx_a = NULL, * ofmt_ctx = NULL;
  24. AVPacket pkt;
  25. int ret, i;
  26. int videoindex_v = -1, videoindex_out = -1;
  27. int audioindex_a = -1, audioindex_out = -1;
  28. int frame_index = 0;
  29. int64_t cur_pts_v = 0, cur_pts_a = 0;
  30. int writing_v = 1, writing_a = 1;
  31. const char* in_filename_v = "D:/测试工程/sound/ffmpeg_demo.h264";
  32. const char* in_filename_a = "D:/测试工程/sound/ffmpeg_demo.aac";
  33. const char* out_filename = "D:/测试工程/sound/muxing.mp4";//Output file URL
  34. if ((ret = avformat_open_input(&ifmt_ctx_v, in_filename_v, 0, 0)) < 0) {
  35. printf("Could not open input file.");
  36. goto end;
  37. }
  38. if ((ret = avformat_find_stream_info(ifmt_ctx_v, 0)) < 0) {
  39. printf("Failed to retrieve input stream information");
  40. goto end;
  41. }
  42. if ((ret = avformat_open_input(&ifmt_ctx_a, in_filename_a, 0, 0)) < 0) {
  43. printf("Could not open input file.");
  44. goto end;
  45. }
  46. if ((ret = avformat_find_stream_info(ifmt_ctx_a, 0)) < 0) {
  47. printf("Failed to retrieve input stream information");
  48. goto end;
  49. }
  50. //Output
  51. avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
  52. if (!ofmt_ctx) {
  53. printf("Could not create output context\n");
  54. ret = AVERROR_UNKNOWN;
  55. goto end;
  56. }
  57. ofmt = ofmt_ctx->oformat;
  58. for (i = 0; i < ifmt_ctx_v->nb_streams; i++) {
  59. //Create output AVStream according to input AVStream
  60. if (ifmt_ctx_v->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
  61. AVStream* out_stream = avformat_new_stream(ofmt_ctx, nullptr);
  62. videoindex_v = i;
  63. if (!out_stream) {
  64. printf("Failed allocating output stream\n");
  65. ret = AVERROR_UNKNOWN;
  66. goto end;
  67. }
  68. videoindex_out = out_stream->index;
  69. //Copy the settings of AVCodecContext
  70. if (avcodec_parameters_copy(out_stream->codecpar, ifmt_ctx_v->streams[i]->codecpar) < 0) {
  71. printf("Failed to copy context from input to output stream codec context\n");
  72. goto end;
  73. }
  74. break;
  75. }
  76. }
  77. for (i = 0; i < ifmt_ctx_a->nb_streams; i++) {
  78. //Create output AVStream according to input AVStream
  79. if (ifmt_ctx_a->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
  80. AVStream* out_stream = avformat_new_stream(ofmt_ctx, nullptr);
  81. audioindex_a = i;
  82. if (!out_stream) {
  83. printf("Failed allocating output stream\n");
  84. ret = AVERROR_UNKNOWN;
  85. goto end;
  86. }
  87. audioindex_out = out_stream->index;
  88. //Copy the settings of AVCodecContext
  89. if (avcodec_parameters_copy(out_stream->codecpar, ifmt_ctx_a->streams[i]->codecpar) < 0) {
  90. printf("Failed to copy context from input to output stream codec context\n");
  91. goto end;
  92. }
  93. out_stream->codecpar->codec_tag = 0;
  94. if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
  95. ofmt_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
  96. break;
  97. }
  98. }
  99. /* open the output file, if needed */
  100. if (!(ofmt->flags & AVFMT_NOFILE)) {
  101. if (avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE)) {
  102. fprintf(stderr, "Could not open '%s': %d\n", out_filename,
  103. ret);
  104. goto end;
  105. }
  106. }
  107. //Write file header
  108. if (avformat_write_header(ofmt_ctx, NULL) < 0) {
  109. fprintf(stderr, "Error occurred when opening output file: %d\n",
  110. ret);
  111. goto end;
  112. }
  113. //写入数据
  114. while (writing_v || writing_a)
  115. {
  116. AVFormatContext* ifmt_ctx;
  117. int stream_index = 0;
  118. AVStream* in_stream, * out_stream;
  119. if (writing_v &&
  120. (!writing_a || av_compare_ts(cur_pts_v, ifmt_ctx_v->streams[videoindex_v]->time_base,
  121. cur_pts_a, ifmt_ctx_a->streams[audioindex_a]->time_base) <= 0))
  122. {
  123. ifmt_ctx = ifmt_ctx_v;
  124. stream_index = videoindex_out;
  125. if (av_read_frame(ifmt_ctx, &pkt) >= 0)
  126. {
  127. do {
  128. in_stream = ifmt_ctx->streams[pkt.stream_index];
  129. out_stream = ofmt_ctx->streams[stream_index];
  130. if (pkt.stream_index == videoindex_v)
  131. {
  132. //FIX:No PTS (Example: Raw H.264)
  133. //Simple Write PTS
  134. if (pkt.pts == AV_NOPTS_VALUE)
  135. {
  136. //Write PTS
  137. AVRational time_base1 = in_stream->time_base;
  138. //Duration between 2 frames (us)
  139. int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
  140. //Parameters
  141. pkt.pts = (double)(frame_index * calc_duration) / (double)(av_q2d(time_base1) * AV_TIME_BASE);
  142. pkt.dts = pkt.pts;
  143. pkt.duration = (double)calc_duration / (double)(av_q2d(time_base1) * AV_TIME_BASE);
  144. frame_index++;
  145. printf("frame_index: %d\n ", frame_index);
  146. }
  147. cur_pts_v = pkt.pts;
  148. break;
  149. }
  150. } while
  151. (av_read_frame(ifmt_ctx, &pkt) >= 0);
  152. }
  153. else
  154. {
  155. writing_v = 0;
  156. continue;
  157. }
  158. }
  159. else
  160. {
  161. ifmt_ctx = ifmt_ctx_a;
  162. stream_index = audioindex_out;
  163. if (av_read_frame(ifmt_ctx, &pkt) >= 0)
  164. {
  165. do {
  166. in_stream = ifmt_ctx->streams[pkt.stream_index];
  167. out_stream = ofmt_ctx->streams[stream_index];
  168. if (pkt.stream_index == audioindex_a)
  169. {
  170. //FIX:No PTS
  171. //Simple Write PTS
  172. if (pkt.pts == AV_NOPTS_VALUE)
  173. {
  174. //Write PTS
  175. AVRational time_base1 = in_stream->time_base;
  176. //Duration between 2 frames (us)
  177. int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
  178. //Parameters
  179. pkt.pts = (double)(frame_index * calc_duration) /
  180. (double)(av_q2d(time_base1) * AV_TIME_BASE);
  181. pkt.dts = pkt.pts;
  182. pkt.duration = (double)calc_duration / (double)(av_q2d(time_base1) * AV_TIME_BASE);
  183. frame_index++;
  184. }
  185. cur_pts_a = pkt.pts;
  186. break;
  187. }
  188. } while (av_read_frame(ifmt_ctx, &pkt) >= 0);
  189. }
  190. else
  191. {
  192. writing_a = 0;
  193. continue;
  194. }
  195. }
  196. //Convert PTS/DTS
  197. pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base,
  198. (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
  199. pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base,
  200. (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
  201. pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
  202. pkt.pos = -1;
  203. pkt.stream_index = stream_index;
  204. printf("Write 1 Packet. size:%5d\tpts:%lld\n", pkt.size, pkt.pts);
  205. //Write
  206. if (av_interleaved_write_frame(ofmt_ctx, &pkt) < 0) {
  207. printf("Error muxing packet\n");
  208. break;
  209. }
  210. av_packet_unref(&pkt);
  211. }
  212. printf("Write file trailer.\n");
  213. //Write file trailer
  214. av_write_trailer(ofmt_ctx);
  215. end:
  216. avformat_close_input(&ifmt_ctx_v);
  217. avformat_close_input(&ifmt_ctx_a);
  218. /* close output */
  219. if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
  220. avio_close(ofmt_ctx->pb);
  221. avformat_free_context(ofmt_ctx);
  222. if (ret < 0 && ret != AVERROR_EOF) {
  223. printf("Error occurred.\n");
  224. return -1;
  225. }
  226. return 0;
  227. }

小结

这里需要几个概念简单说明下:

tbr  表示每秒帧数

tbn 表示数据流的实际真实帧率的倒数

如:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/491196
推荐阅读
相关标签
  

闽ICP备14008679号