当前位置:   article > 正文

[FFmpeg学习]初级的SDL播放mp4测试

[FFmpeg学习]初级的SDL播放mp4测试

在之前的学习中,通过AVFrame来保存为图片来认识了AVFrame,

[FFmpeg学习]从视频中获取图片_ffmpeg 获取图片-CSDN博客

在获取到AVFrame时,还可以调用SDL方法来进行展现,实现播放效果。

参考资料

SDL,ffmpeg实现简单视频播放器_ffmpeg sdl 播放器-CSDN博客

SDL2 简单介绍以及Windows开发环境搭建-CSDN博客

这里只显示了视频,没有处理声音,

  1. // ffmpegTest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
  2. //
  3. #include <iostream>
  4. /*
  5. int main()
  6. {
  7. std::cout << "Hello World!\n";
  8. }*/
  9. extern "C" {
  10. #include "libavcodec/avcodec.h"
  11. #include "libavformat/avformat.h"
  12. #include <libavutil/log.h>
  13. #include <libavformat/avformat.h>
  14. }
  15. using namespace std;
  16. //要使用FFmpeg库从MP4文件中提取一张图片,你需要使用FFmpeg的解码器来读取视频帧,并将其保存为图片。以下是一个简单的示例程序,演示如何使用FFmpeg库从MP4文件中提取一张图片:
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include "SDL.h"
  21. int savePicture(AVFrame* pFrame, char* out_name) {//编码保存图片
  22. int width = pFrame->width;
  23. int height = pFrame->height;
  24. AVCodecContext* pCodeCtx = NULL;
  25. AVFormatContext* pFormatCtx = avformat_alloc_context();
  26. // 设置输出文件格式
  27. pFormatCtx->oformat = av_guess_format("mjpeg", NULL, NULL);
  28. // 创建并初始化输出AVIOContext
  29. if (avio_open(&pFormatCtx->pb, out_name, AVIO_FLAG_READ_WRITE) < 0) {
  30. printf("Couldn't open output file.");
  31. return -1;
  32. }
  33. // 构建一个新stream
  34. AVStream* pAVStream = avformat_new_stream(pFormatCtx, 0);
  35. if (pAVStream == NULL) {
  36. return -1;
  37. }
  38. AVCodecParameters* parameters = pAVStream->codecpar;
  39. parameters->codec_id = pFormatCtx->oformat->video_codec;
  40. parameters->codec_type = AVMEDIA_TYPE_VIDEO;
  41. parameters->format = AV_PIX_FMT_YUVJ420P;
  42. parameters->width = pFrame->width;
  43. parameters->height = pFrame->height;
  44. const AVCodec* pCodec = avcodec_find_encoder(pAVStream->codecpar->codec_id); //查找编码器
  45. if (!pCodec) {
  46. printf("Could not find encoder\n");
  47. return -1;
  48. }
  49. pCodeCtx = avcodec_alloc_context3(pCodec); //为AVCodecContext分配内存
  50. if (!pCodeCtx) {
  51. fprintf(stderr, "Could not allocate video codec context\n");
  52. exit(1);
  53. }
  54. if ((avcodec_parameters_to_context(pCodeCtx, pAVStream->codecpar)) < 0) {
  55. fprintf(stderr, "Failed to copy %s codec parameters to decoder context\n",
  56. av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
  57. return -1;
  58. }
  59. // AVRational tmp = { 1, 25 };
  60. pCodeCtx->time_base = { 1, 25 };
  61. if (avcodec_open2(pCodeCtx, pCodec, NULL) < 0) { //打开编码器
  62. printf("Could not open codec.");
  63. return -1;
  64. }
  65. int ret = avformat_write_header(pFormatCtx, NULL);
  66. if (ret < 0) {
  67. printf("write_header fail\n");
  68. return -1;
  69. }
  70. int y_size = width * height;
  71. //Encode
  72. // 给AVPacket分配足够大的空间
  73. AVPacket pkt;
  74. av_new_packet(&pkt, y_size * 3);
  75. // 编码数据
  76. ret = avcodec_send_frame(pCodeCtx, pFrame);
  77. if (ret < 0) {
  78. printf("Could not avcodec_send_frame.");
  79. return -1;
  80. }
  81. // 得到编码后数据
  82. ret = avcodec_receive_packet(pCodeCtx, &pkt);
  83. if (ret < 0) {
  84. printf("Could not avcodec_receive_packet");
  85. return -1;
  86. }
  87. ret = av_write_frame(pFormatCtx, &pkt);
  88. if (ret < 0) {
  89. printf("Could not av_write_frame");
  90. return -1;
  91. }
  92. av_packet_unref(&pkt);
  93. //Write Trailer
  94. av_write_trailer(pFormatCtx);
  95. avcodec_close(pCodeCtx);
  96. avio_close(pFormatCtx->pb);
  97. avformat_free_context(pFormatCtx);
  98. return 0;
  99. }
  100. class SDLHandle
  101. {
  102. public:
  103. SDLHandle(int w, int h)
  104. {
  105. m_rect.x = 0;
  106. m_rect.y = 0;
  107. m_rect.w = w;
  108. m_rect.h = h;
  109. SdlInit();
  110. }
  111. ~SDLHandle()
  112. {
  113. if (m_pTexture)
  114. {
  115. SDL_DestroyTexture(m_pTexture);
  116. }
  117. if (m_pRender)
  118. {
  119. SDL_DestroyRenderer(m_pRender);
  120. }
  121. if (m_pWnd)
  122. {
  123. SDL_DestroyWindow(m_pWnd);
  124. }
  125. SDL_Quit();
  126. }
  127. bool CreateSDLWindow(const char* title, Uint32 flag)
  128. {
  129. m_pWnd = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, m_rect.w, m_rect.h, flag);
  130. if (!m_pWnd)
  131. {
  132. printf("CreateWindows error:%s.\n", SDL_GetError());
  133. return false;
  134. }
  135. m_pRender = SDL_CreateRenderer(m_pWnd, -1, 0);
  136. if (!m_pRender)
  137. {
  138. return false;
  139. }
  140. m_pTexture = SDL_CreateTexture(m_pRender, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, m_rect.w, m_rect.h);
  141. if (!m_pTexture)
  142. {
  143. return false;
  144. }
  145. return true;
  146. }
  147. void UpdateTexture(AVFrame* pFrame)
  148. {
  149. if (!pFrame)
  150. {
  151. return;
  152. }
  153. //SDL_UpdateTexture(m_pTexture, &m_rect, pFrame->data[0], pFrame->linesize[0]);
  154. SDL_UpdateYUVTexture(m_pTexture, &m_rect, pFrame->data[0], pFrame->linesize[0], pFrame->data[1], pFrame->linesize[1], pFrame->data[2], pFrame->linesize[2]);
  155. SDL_RenderClear(m_pRender);
  156. SDL_RenderCopy(m_pRender, m_pTexture, nullptr, &m_rect);
  157. SDL_RenderPresent(m_pRender);
  158. SDL_Delay(40);
  159. }
  160. private:
  161. bool SdlInit()
  162. {
  163. if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
  164. {
  165. printf("sdl_init error:%s\n", SDL_GetError());
  166. return false;
  167. }
  168. return true;
  169. }
  170. private:
  171. SDL_Renderer* m_pRender = nullptr;
  172. SDL_Window* m_pWnd = nullptr;
  173. SDL_Texture* m_pTexture = nullptr;
  174. SDL_Rect m_rect;
  175. };
  176. int getpic4() {
  177. std::string filename = "test.mp4"; // 输入MP4文件名
  178. std::string outputFilename = "output4.jpg"; // 输出图片文件名
  179. SDL_Window* pScreen = nullptr; // 播放窗口
  180. SDL_Renderer* pRender = nullptr; // 渲染器
  181. SDL_Texture* pSDLTexture = nullptr; // 纹理
  182. SDLHandle* m_pSDlHandle = nullptr;
  183. AVFormatContext* formatContext = nullptr;
  184. if (avformat_open_input(&formatContext, filename.c_str(), nullptr, nullptr) != 0) {
  185. std::cerr << "Error opening input file" << std::endl;
  186. return -1;
  187. }
  188. if (avformat_find_stream_info(formatContext, nullptr) < 0) {
  189. std::cerr << "Error finding stream information" << std::endl;
  190. avformat_close_input(&formatContext);
  191. return -1;
  192. }
  193. const AVCodec* codec = nullptr;
  194. int videoStreamIndex = -1;
  195. for (unsigned int i = 0; i < formatContext->nb_streams; i++) {
  196. if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
  197. videoStreamIndex = i;
  198. codec = avcodec_find_decoder(formatContext->streams[i]->codecpar->codec_id);
  199. break;
  200. }
  201. }
  202. if (videoStreamIndex == -1 || codec == nullptr) {
  203. std::cerr << "Error finding video stream or decoder" << std::endl;
  204. avformat_close_input(&formatContext);
  205. return -1;
  206. }
  207. AVCodecContext* codecContext = avcodec_alloc_context3(codec);
  208. if (codecContext == nullptr) {
  209. std::cerr << "Error allocating codec context" << std::endl;
  210. avformat_close_input(&formatContext);
  211. return -1;
  212. }
  213. if (avcodec_parameters_to_context(codecContext, formatContext->streams[videoStreamIndex]->codecpar) < 0) {
  214. std::cerr << "Error setting codec parameters" << std::endl;
  215. avcodec_free_context(&codecContext);
  216. avformat_close_input(&formatContext);
  217. return -1;
  218. }
  219. if (avcodec_open2(codecContext, codec, nullptr) < 0) {
  220. std::cerr << "Error opening codec" << std::endl;
  221. avcodec_free_context(&codecContext);
  222. avformat_close_input(&formatContext);
  223. return -1;
  224. }
  225. m_pSDlHandle = new SDLHandle(codecContext->width, codecContext->height);
  226. if (!m_pSDlHandle->CreateSDLWindow("SDL_TEXT", SDL_WINDOW_OPENGL))
  227. {
  228. printf("CreateSDLWindow error:%s\n", SDL_GetError());
  229. return -1;
  230. }
  231. AVPacket packet;
  232. av_init_packet(&packet);
  233. // 查找目标时间戳所对应的帧
  234. AVFrame* frame = av_frame_alloc();
  235. bool foundTargetFrame = false;
  236. int count = 0;
  237. while (av_read_frame(formatContext, &packet) >= 0) {
  238. if (packet.stream_index == videoStreamIndex) {
  239. int response = avcodec_send_packet(codecContext, &packet);
  240. if (response < 0) {
  241. std::cerr << "Error sending packet to decoder" << std::endl;
  242. break;
  243. }
  244. count++;
  245. response = avcodec_receive_frame(codecContext, frame);
  246. if (response == AVERROR(EAGAIN) || response == AVERROR_EOF) {
  247. continue;
  248. }
  249. else if (response < 0) {
  250. std::cerr << "Error receiving frame from decoder" << std::endl;
  251. break;
  252. }
  253. m_pSDlHandle->UpdateTexture(frame);
  254. }
  255. av_packet_unref(&packet);
  256. }
  257. if (!foundTargetFrame) {
  258. std::cerr << "Target frame not found" << std::endl;
  259. av_frame_free(&frame);
  260. avcodec_free_context(&codecContext);
  261. avformat_close_input(&formatContext);
  262. return -1;
  263. }
  264. // 清理资源
  265. av_frame_free(&frame);
  266. av_packet_unref(&packet);
  267. avcodec_free_context(&codecContext);
  268. return 1;
  269. }
  270. #undef main
  271. int main(int argc, char* argv[]) {
  272. av_log(NULL, AV_LOG_INFO, "...Hello world\n");
  273. getpic4();
  274. return 0;
  275. }

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

闽ICP备14008679号