ffmpeg的例子:制作屏幕錄像


  最近需要設計一個播放器,然后了解到ffmpeg這個東西,發現這東西應用還挺廣泛的。

  在這里要特別提一下CSDN的雷霄驊,關於ffmpeg的博客那是寫的真的好,而且還開源了大量的資料。只不過天妒英才啊!聽說因為過度勞累而猝死

  本篇博客主要是學習雷神推薦的:如何用FFmpeg編寫一個簡單播放器

  因為ffmpeg的版本升級,導致版本之間多少有些差異,我的FFmpeg版本為3.2.2,所以在移植第一個代碼示例的過程中,出了不少幺蛾子。關於ffmpeg的安裝網上到處都是,我就不說明了。

  下面我上我修改后的示例代碼:

  開發環境:ubuntu14  64位

  ffmpeg版本:3.2.2

  測試文件:flv格式視頻或其他格式視頻

  效果:得到5張視頻截圖

  編譯命令:gcc -g main.c -o test -I /usr/local/ffmpeg/include -L /usr/local/ffmpeg/lib -lavutil -lavformat -lavcodec -lz -lavutil -lswscale(說明:-g為加入gdb調試,/usr/local/ffmpeg為我的ffmpeg安裝目錄,具體目錄看你的安裝路徑來設置)

  1 #ifdef _cplusplus
  2 extern "C" {
  3 #endif
  4 
  5 #include<stdio.h>
  6 #include<libavcodec/avcodec.h>
  7 #include<libavformat/avformat.h>
  8 #include<libavutil/avutil.h>
  9 #include<libswscale/swscale.h>
 10 #include<libavutil/avutil.h>
 11 #include<SDL2/SDL.h>
 12 
 14 
 15 //******************函數聲明***********************************
 16 void SaveFrame(AVFrame *pFrame,int width,int height,int iFrame);
 17 
 18 int main(int argc,char **argv)
 19 {
 20     printf("~~~~~~~~design a player!\n");
 21     AVFormatContext *pFormatCtx;
 22     av_register_all();
 23     avformat_network_init();
 24      pFormatCtx = avformat_alloc_context();
 25     //打開視頻文件
 26 //    if(avformat_open_input(&pFormatCtx,"bigbuckbunny_480x272.h265",NULL,NULL)!=0)
 27      if(avformat_open_input(&pFormatCtx,"test.flv",NULL,NULL)!=0)
 28         return -1;//不能打開文件
 29     if(avformat_find_stream_info(pFormatCtx,NULL)<0){
 30             printf("Couldn't find stream information.\n");
 31             return -1;
 32         }
 33     //丟出一個信息,調試用的
 34 //    av_dump_format(pFormatCtx,0,argv[1],0);
 35     int i,videoStream;
 36     AVCodecContext *pCodecCtx;
 37     //找到第一個視頻流
 38     videoStream = -1;
 39     for(i=0;i<pFormatCtx->nb_streams;i++)
 40     {
 41         if(pFormatCtx->streams[i]->codec->codec_type ==AVMEDIA_TYPE_VIDEO)
 42         {
 43             videoStream = i;
 44             break;
 45         }
 46     }
 47     if(videoStream==-1){
 48             printf("Didn't find a video stream.\n");
 49             return -1;
 50         }
 51     //從視頻流中得到一個編解碼上下文的指針,里面包含了編解碼器的所有信息,包含了一個
 52     //指向真正的編解碼的指針
 53     pCodecCtx = pFormatCtx->streams[videoStream]->codec;
 54     AVCodec *pCodec;
 55     //在視頻流中找到這個解碼器
 56     pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
 57     if(pCodec == NULL)
 58     {
 59         fprintf(stderr,"Unsupported codec !\n");
 60         return -1;
 61     }
 62     //Open codec
 63     if(avcodec_open2(pCodecCtx,pCodec,NULL)<0){
 64         printf("cann't open the codec!\n");
 65         return -1;
 66     }
 67     //保存數據
 68     AVFrame *pFrame;
 69     //分配一個視頻幀
 70     pFrame = av_frame_alloc();
 71     //分配一幀結構體
 72     AVFrame *pFrameRGB;
 73     pFrameRGB = av_frame_alloc();
 74     if(pFrameRGB == NULL){
 75         return -1;
 76     }
 77     //我們申請了一幀的內存,當轉換的時候,我們需要用一個地方來放置原始數據,首先
 78     //我們需要使用avpicture_get_size來獲得我們需要的大小,然后手工申請內存
 79     uint8_t *buffer;
 80     int numBytes;
 81     //確定需要的內存大小並分配內存
 82     numBytes = avpicture_get_size(AV_PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);
 83     buffer = (uint8_t*)av_mallocz(numBytes*sizeof(uint8_t));
 84     //指定buffer的適宜的一部分到pFrameRGB的圖像平面
 85     //注意pFrameRGB是一個媒體幀,但是該媒體幀是AVPicture的父集
 86     avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_RGB24,
 87     pCodecCtx->width, pCodecCtx->height);
 88     //**********讀取數據*****************************************
 89     int frameFinished;
 90     AVPacket packet;
 91     struct SwsContext *pSwsCtx;
 92     i=0;
 93     pSwsCtx = sws_getContext(pCodecCtx->width,
 94             pCodecCtx->height,
 95             pCodecCtx->pix_fmt,
 96             pCodecCtx->width,
 97             pCodecCtx->height,
 98             AV_PIX_FMT_RGB24,
 99             SWS_BICUBIC,
100             NULL,NULL,NULL
101             );
102      if(pSwsCtx == NULL)
103        {
104             fprintf(stderr, "Cannot initialize the conversion context!\n");
105             return -1;
106         }
107     while(av_read_frame(pFormatCtx,&packet) >= 0)
108     {
109             //如果讀取的包來自視頻流
110             if(packet.stream_index == videoStream)
111             {
112                 //解碼幀數據
113                 avcodec_decode_video2(pCodecCtx,pFrame,&frameFinished,&packet);
114                 //我們是否得到一個視頻幀
115                 if(frameFinished){
116                     //使用RGB格式來將它轉換為圖片
117                      sws_scale(pSwsCtx,
118                                       pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
119                                       pFrameRGB->data, pFrameRGB->linesize);
120                      //保存這個幀數據到磁盤
121                      if(++i<=5)
122                          SaveFrame(pFrameRGB,pCodecCtx->width,pCodecCtx->height,i);
123                 }
124             }
125             av_free_packet(&packet);
126     }
127     //清理操作
128     av_free(buffer);
129     av_free(pFrameRGB);
130     av_free(pFrame);
131     avcodec_close(pCodecCtx);
132     avformat_close_input(&pFormatCtx);
133     return EXIT_SUCCESS;
134 }
135 
136 //*****************函數定義***********************************
137 void SaveFrame(AVFrame *pFrame,int width,int height,int iFrame)
138 {
139     FILE    *pFile;
140     char szFilename[32];
141     int y;
142 
143     //打開文件
144     sprintf(szFilename,"frame%d.ppm",iFrame);
145     pFile = fopen(szFilename,"wb");
146     if(pFile == NULL)
147         return;
148     //寫頭
149     fprintf(pFile,"P6\n%d %d\n255\n",width,height);
150 
151     //寫 pixel 數據
152     for(y=0; y<height; y++)
153         fwrite(pFrame->data[0]+y*pFrame->linesize[0], width*3, 1, pFile);
154     //關閉文件
155     fclose(pFile);
156 }
157 
158 #ifdef _cplusplus
159 }
160 #endif

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM