打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
ffmpeg+sdl2.0编写最简单的视频播放器

花了好几天的时间,终于把这东东搞出来了

sdl2相比sdl1,api有了比较大的变化,尤其是绘图方面

网上基本上找不到用sdl2编写的,只好自己不断探索尝试

ffmpeg和sdl都可以直接去官网下载,现在已经有编译好的vc库文件下载,怎么配置网上有很多,这里就不多说了


推荐几个sdl2的教程:

http://adolfans.github.io/sdltutorialcn/blog/2013/01/25/sdl-2-dot-0-tutorial-index/

http://www.sdltutorials.com/tutorials

ffmpeg的api文档可以在这里看:

http://ffmpeg.org/doxygen/2.0/index.html

需要注意的一点是,建立工程的时候最好选择 控制台应用程序,加上预编译头文件,即有stdafx.h头文件的那种


再推荐一个学习的博客,我的代码就是参考他的写出来的

http://blog.csdn.net/leixiaohua1020/article/details/8652605

还有一个很好的教程,虽然有点过时,但是基本思想是不变的,很值得参考

如何用FFmpeg编写一个简单播放器

最后你需要了解一下像素格式,可以参考:

图文详解YUV格式

在sdl的头文件SDL_Pixel.h中有各种像素格式的声明


其他不多说了,直接上代码

  1. #include "stdafx.h"  
  2.   
  3. extern "C"{  
  4. #include "libavcodec\avcodec.h"  
  5. #include "libavformat\avformat.h"  
  6. #include "libswscale\swscale.h"  
  7. }  
  8. #include "SDL.h"  
  9. #include "SDL_image.h"  
  10. #include "SDL_thread.h"  
  11.   
  12. #include <iostream>  
  13. using namespace std;  
  14.   
  15.   
  16. /* 
  17. void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame){ 
  18. FILE *pFile; 
  19. char szFilename[32]; 
  20. int y; 
  21.  
  22. sprintf(szFilename, "frame%d.ppm", iFrame); 
  23. pFile = fopen(szFilename, "wb"); 
  24. if (pFile == NULL){ 
  25. cout << "open file:" << szFilename << " error." << endl; 
  26. return; 
  27. } 
  28.  
  29. //Write header 
  30. }*/  
  31.   
  32. int _tmain(int argc, char *agrv[]){  
  33.     av_register_all();  //注册了所有的文件格式和编解码的库,它们将被自动的使用在被打开的合适格式的文件上  
  34.     AVFormatContext *pFormatCtx;  
  35.     pFormatCtx = avformat_alloc_context();  
  36.   
  37.     char filepath[] = "../../resource/test.mp4";  
  38.     //Open an input stream and read the header  
  39.     if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0){  
  40.         printf("Can't open the file\n");  
  41.         return -1;  
  42.     }  
  43.     //Retrieve stream information  
  44.     if (avformat_find_stream_info(pFormatCtx, NULL) < 0){  
  45.         printf("Couldn't find stream information.\n");  
  46.         return -1;  
  47.     }  
  48.   
  49.     int i, videoIndex;  
  50.     AVCodecContext *pCodecCtx;  
  51.     AVCodec *pCodec;  
  52.   
  53.     //Find the first video stream  
  54.     videoIndex = -1;  
  55.     for (i = 0; i < pFormatCtx->nb_streams; i++){//视音频流的个数  
  56.         if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){  
  57.             videoIndex = i;  
  58.             break;  
  59.         }  
  60.     }  
  61.     if (videoIndex == -1)  
  62.         return -1;  
  63.     //Get a pointer to the codec context for the video stream  
  64.     //流中关于编解码器的信息就是被我们叫做"codec context"(编解码器上下文)  
  65.     //的东西。这里面包含了流中所使用的关于编解码器的所有信  
  66.     pCodecCtx = pFormatCtx->streams[videoIndex]->codec;  
  67.     //Find the decoder for the video stream  
  68.     pCodec = avcodec_find_decoder(pCodecCtx->codec_id);  
  69.     if (pCodec == NULL){  
  70.         printf("Unsupported codec!\n");  
  71.         return -1;  
  72.     }  
  73.     //Open codec  
  74.     if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0){  
  75.         printf("Could not open codec.\n");  
  76.         return -1;  
  77.     }  
  78.     //allocate video frame and set its fileds to default value  
  79.     AVFrame *pFrame, *pFrameYUV;  
  80.     pFrame = av_frame_alloc();  
  81.     pFrameYUV = av_frame_alloc();  
  82.   
  83.     //即使我们申请了一帧的内存,当转换的时候,我们仍然需要一个地方来放置原始  
  84.     //的数据。我们使用avpicture_get_size 来获得我们需要的大小, 然后手工申请  
  85.     //内存空间:  
  86.     uint8_t *out_buffer;  
  87.     int numBytes;  
  88.     numBytes = avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);  
  89.     //av_malloc 是ffmpeg 的malloc,用来实现一个简单的malloc 的包装,这样来保  
  90.     //证内存地址是对齐的(4 字节对齐或者2 字节对齐)。它并不能保 护你不被内  
  91.     //存泄漏,重复释放或者其它malloc 的问题所困扰。  
  92.     out_buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t));  
  93.     //Assign appropriate parts of buffer to image planes in pFrameYUV  
  94.     //Note that pFrameYUV is an AVFrame, but AVFrame is a superset of AVPicture  
  95.     avpicture_fill((AVPicture*)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);  
  96.   
  97.   
  98.     //----------------SDL--------------------------------------//  
  99.     if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)){  
  100.         printf("Could not initialize SDL -%s\n", SDL_GetError());  
  101.         exit(1);  
  102.     }  
  103.   
  104.     SDL_Window *window = nullptr;  
  105.     window = SDL_CreateWindow("MyPlayer", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,  
  106.         pCodecCtx->width, pCodecCtx->height, SDL_WINDOW_SHOWN);  
  107.     if (!window){  
  108.         cout << SDL_GetError() << endl;  
  109.         return 1;  
  110.     }  
  111.   
  112.     SDL_Renderer *ren = nullptr;  
  113.     ren = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);  
  114.     if (ren == nullptr){  
  115.         cout << SDL_GetError() << endl;  
  116.         return -1;  
  117.     }  
  118.   
  119.     SDL_Texture *texture = nullptr;  
  120.     texture = SDL_CreateTexture(ren, SDL_PIXELFORMAT_YV12,  
  121.         SDL_TEXTUREACCESS_STREAMING, pCodecCtx->width, pCodecCtx->height);  
  122.     SDL_Rect rect;  
  123.     rect.x = 0, rect.y = 0;  
  124.     rect.w = pCodecCtx->width;  
  125.     rect.h = pCodecCtx->height;  
  126.   
  127.     //*************************************************************//  
  128.     //通过读取包来读取整个视频流,然后把它解码成帧,最后转换格式并且保存  
  129.     int frameFinished;  
  130.     //int psize = pCodecCtx->width * pCodecCtx->height;  
  131.     AVPacket packet;  
  132.     av_new_packet(&packet, numBytes);  
  133.   
  134.     //output file information  
  135.     cout << "文件信息----------------------------------" << endl;  
  136.     av_dump_format(pFormatCtx, 0, filepath, 0);  
  137.     cout << "--------------------------------------------" << endl;  
  138.   
  139.     i = 0;  
  140.     int ret;  
  141.     static struct SwsContext *img_convert_ctx;  
  142.     img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,  
  143.         pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P,  
  144.         SWS_BICUBIC, NULL, NULL, NULL);  
  145.   
  146.     //Read the next frame of a stream  
  147.     while (av_read_frame(pFormatCtx, &packet) >= 0){  
  148.         //Is this a packet from the video stream?  
  149.         if (packet.stream_index == videoIndex){  
  150.             //decode video frame of size packet.size from packet.data into picture  
  151.             ret = avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);  
  152.             //Did we get a video frame?  
  153.             if (ret >= 0){  
  154.                 //Convert the image from its native format to YUV  
  155.                 if (frameFinished){  
  156.                     sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data,  
  157.                         pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);  
  158.   
  159.                     SDL_UpdateYUVTexture(texture, &rect, pFrameYUV->data[0], pFrameYUV->linesize[0],  
  160.                         pFrameYUV->data[1], pFrameYUV->linesize[1], pFrameYUV->data[2], pFrameYUV->linesize[2]);  
  161.                       
  162.                     SDL_RenderClear(ren);  
  163.                     SDL_RenderCopy(ren, texture, &rect, &rect);  
  164.                     SDL_RenderPresent(ren);  
  165.                 }  
  166.                 SDL_Delay(50);  
  167.             }  
  168.             else{  
  169.                 cout << "decode error" << endl;  
  170.                 return -1;  
  171.             }  
  172.         }  
  173.     }  
  174.   
  175.     av_free_packet(&packet);  
  176.   
  177.     SDL_Event event;  
  178.     SDL_PollEvent(&event);  
  179.     switch (event.type){  
  180.     case SDL_QUIT:  
  181.         SDL_Quit();  
  182.         exit(0);  
  183.         break;  
  184.     default:  
  185.         break;  
  186.     }  
  187.   
  188.     SDL_DestroyTexture(texture);  
  189.   
  190.     av_frame_free(&pFrame);  
  191.     av_frame_free(&pFrameYUV);  
  192.   
  193.     avcodec_close(pCodecCtx);  
  194.   
  195.     avformat_close_input(&pFormatCtx);  
  196.   
  197.     return 0;  
  198. }  



本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
最简单的基于FFmpeg的内存读写的例子
h.264 视频解码的一点小经验(ffmpeg)
libavformat/libavcodec学习(转) - 视频开发 - 在路上........
关于ffmpeg如何提取视频的关键帧的问题
Decode mp3 audio using ffmpeg libraries | Muroa
FFmpeg学习教程
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服