经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
FFmpeg4.0笔记:本地媒体文件解码
来源:cnblogs  作者:gongluck  时间:2019/5/8 9:32:22  对本文有异议

Github

https://github.com/gongluck/FFmpeg4.0-study/blob/master/official%20example/my_example.cpp

  1. #include <iostream>
  2. #include <fstream>
  3. //#define NOVIDEO
  4. //#define NOAUDIO
  5. #ifdef __cplusplus
  6. extern "C"
  7. {
  8. #endif
  9. // FFmpeg 头文件
  10. #include "libavformat/avformat.h"
  11. #ifdef __cplusplus
  12. }
  13. // C++中使用av_err2str宏
  14. char av_error[AV_ERROR_MAX_STRING_SIZE] = { 0 };
  15. #define av_err2str(errnum) av_make_error_string(av_error, AV_ERROR_MAX_STRING_SIZE, errnum)
  16. #endif
  17. int main(int argc, char* argv[])
  18. {
  19. AVFormatContext* fmt_ctx = nullptr;
  20. AVCodecContext *vcodectx = nullptr, *acodectx = nullptr;
  21. AVCodecParameters *vcodecpar = nullptr, *acodecpar = nullptr;
  22. AVCodec *vcodec = nullptr, *acodec = nullptr;
  23. AVPacket* pkt = nullptr;
  24. AVFrame* frame = nullptr;
  25. std::ofstream out_yuv, out_pcm;
  26. const char* in = "in.flv";
  27. int vindex = -1, aindex = -1;
  28. int ret = 0;
  29. out_yuv.open("out.yuv", std::ios::binary | std::ios::trunc);
  30. out_pcm.open("out.pcm", std::ios::binary | std::ios::trunc);
  31. if (!out_yuv.is_open() || !out_pcm.is_open())
  32. {
  33. std::cerr << "创建/打开输出文件失败" << std::endl;
  34. goto END;
  35. }
  36. // 日志
  37. av_log_set_level(AV_LOG_ERROR);
  38. // 打开输入
  39. ret = avformat_open_input(&fmt_ctx, in, nullptr, nullptr);
  40. if (ret < 0)
  41. {
  42. std::cerr << "avformat_open_input err : " << av_err2str(ret) << std::endl;
  43. goto END;
  44. }
  45. // 查找流信息,对输入进行预处理
  46. ret = avformat_find_stream_info(fmt_ctx, nullptr);
  47. if (ret < 0)
  48. {
  49. std::cerr << "avformat_find_stream_info err : " << av_err2str(ret) << std::endl;
  50. goto END;
  51. }
  52. // 打印输入信息
  53. av_dump_format(fmt_ctx, 0, fmt_ctx->url, 0);
  54. //查找流
  55. for (int i = 0; i < fmt_ctx->nb_streams; ++i)
  56. {
  57. if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
  58. {
  59. vindex = i;
  60. }
  61. else if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
  62. {
  63. aindex = i;
  64. }
  65. }
  66. if (vindex == -1)
  67. {
  68. std::cerr << "找不到视频流" << std::endl;
  69. }
  70. if (aindex == -1)
  71. {
  72. std::cerr << "找不到音频流" << std::endl;
  73. }
  74. //查找解码器
  75. vcodecpar = fmt_ctx->streams[vindex]->codecpar;
  76. vcodec = avcodec_find_decoder(vcodecpar->codec_id);
  77. if (vcodec == nullptr)
  78. {
  79. std::cerr << "avcodec_find_decoder err : " << av_err2str(ret) << std::endl;
  80. goto END;
  81. }
  82. acodecpar = fmt_ctx->streams[aindex]->codecpar;
  83. acodec = avcodec_find_decoder(acodecpar->codec_id);
  84. if (acodec == nullptr)
  85. {
  86. std::cerr << "avcodec_find_decoder err : " << av_err2str(ret) << std::endl;
  87. goto END;
  88. }
  89. //打开解码器
  90. vcodectx = avcodec_alloc_context3(vcodec);
  91. ret = avcodec_parameters_to_context(vcodectx, vcodecpar);// 参数拷贝
  92. if (ret < 0)
  93. {
  94. std::cerr << "avcodec_parameters_to_context err : " << av_err2str(ret) << std::endl;
  95. goto END;
  96. }
  97. ret = avcodec_open2(vcodectx, vcodec, nullptr);
  98. if (ret < 0)
  99. {
  100. std::cerr << "avcodec_open2 err : " << av_err2str(ret) << std::endl;
  101. goto END;
  102. }
  103. acodectx = avcodec_alloc_context3(acodec);
  104. ret = avcodec_parameters_to_context(acodectx, acodecpar);// 参数拷贝
  105. if (ret < 0)
  106. {
  107. std::cerr << "avcodec_parameters_to_context err : " << av_err2str(ret) << std::endl;
  108. goto END;
  109. }
  110. ret = avcodec_open2(acodectx, acodec, nullptr);
  111. if (ret < 0)
  112. {
  113. std::cerr << "avcodec_open2 err : " << av_err2str(ret) << std::endl;
  114. goto END;
  115. }
  116. // 创建AVPacket
  117. pkt = av_packet_alloc();
  118. if (pkt == nullptr)
  119. {
  120. std::cerr << "av_packet_alloc err : " << std::endl;
  121. goto END;
  122. }
  123. av_init_packet(pkt);
  124. // 创建AVFrame
  125. frame = av_frame_alloc();
  126. if (frame == nullptr)
  127. {
  128. std::cerr << "av_frame_alloc err : " << std::endl;
  129. goto END;
  130. }
  131. // 从输入读取数据
  132. while (av_read_frame(fmt_ctx, pkt) >= 0)
  133. {
  134. if (pkt->stream_index == vindex)
  135. {
  136. #ifndef NOVIDEO
  137. // 解码视频帧
  138. ret = avcodec_send_packet(vcodectx, pkt);
  139. if (ret < 0)
  140. {
  141. std::cerr << "avcodec_send_packet err : " << av_err2str(ret) << std::endl;
  142. break;
  143. }
  144. while (ret >= 0)
  145. {
  146. ret = avcodec_receive_frame(vcodectx, frame);
  147. if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
  148. {
  149. break;
  150. }
  151. else if (ret < 0)
  152. {
  153. std::cerr << "avcodec_receive_frame err : " << av_err2str(ret) << std::endl;
  154. break;
  155. }
  156. else
  157. {
  158. // 得到解码数据
  159. if (frame->format == AV_PIX_FMT_YUV420P)
  160. {
  161. out_yuv.write(reinterpret_cast<const char*>(frame->data[0]), frame->linesize[0] * frame->height);
  162. out_yuv.write(reinterpret_cast<const char*>(frame->data[1]), frame->linesize[1] * frame->height / 2);
  163. out_yuv.write(reinterpret_cast<const char*>(frame->data[2]), frame->linesize[2] * frame->height / 2);
  164. }
  165. }
  166. }
  167. #endif // NOVIDEO
  168. }
  169. else if (pkt->stream_index == aindex)
  170. {
  171. #ifndef NOAUDIO
  172. // 解码音频帧
  173. ret = avcodec_send_packet(acodectx, pkt);
  174. if (ret < 0)
  175. {
  176. std::cerr << "avcodec_send_packet err : " << av_err2str(ret) << std::endl;
  177. break;
  178. }
  179. while (ret >= 0)
  180. {
  181. ret = avcodec_receive_frame(acodectx, frame);
  182. if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
  183. {
  184. break;
  185. }
  186. else if (ret < 0)
  187. {
  188. std::cerr << "avcodec_receive_frame err : " << av_err2str(ret) << std::endl;
  189. break;
  190. }
  191. else
  192. {
  193. // 得到解码数据
  194. if (frame->format == AV_SAMPLE_FMT_FLTP)
  195. {
  196. /// 参考了https://www.cnblogs.com/my_life/articles/6841859.html
  197. // 计算一个planar的有效大小,很关键!
  198. auto size = av_get_bytes_per_sample(static_cast<AVSampleFormat>(frame->format)) * frame->nb_samples;
  199. for (int i = 0; i < size; i += 4)
  200. {
  201. for (int j = 0; j < frame->channels; ++j)
  202. {
  203. out_pcm.write(reinterpret_cast<const char*>(frame->data[j] + i), 4);
  204. }
  205. }
  206. }
  207. }
  208. }
  209. #endif // NOAUDIO
  210. }
  211. // 复位data和size
  212. av_packet_unref(pkt);
  213. }
  214. END:
  215. std::cerr << "end..." << std::endl;
  216. std::cin.get();
  217. out_yuv.close();
  218. out_pcm.close();
  219. av_frame_free(&frame);
  220. av_packet_free(&pkt);
  221. avcodec_free_context(&vcodectx);
  222. avcodec_free_context(&acodectx);
  223. avformat_close_input(&fmt_ctx);
  224. return 0;
  225. }

原文链接:http://www.cnblogs.com/gongluck/p/10827950.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号