天天看點

ffmpeg解碼視訊存為BMP檔案

1. #include <windows.h>
2.  #include <stdio.h>
3. #include <stdlib.h>
4. #include <string.h>
5. #pragma once  
6.   
7.  #ifdef __cplusplus
8. extern "C"
9. #endif
10. #include <libavcodec/avcodec.h>
11. #include <libavformat/avformat.h>
12. #include <libswscale/swscale.h>
13.   
14.   
15. #ifdef __cplusplus
16. }  
17. #endif
18.   
19. //定義BMP檔案頭
20.  #ifndef _WINGDI_ 
21. #define _WINGDI_
22. typedef struct
23. WORD
24. DWORD
25. WORD
26. WORD
27. DWORD
28. } BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;   
29.    
30. typedef struct
31. DWORD
32. LONG
33. LONG
34. WORD
35. WORD
36. DWORD
37. DWORD
38. LONG
39. LONG
40. DWORD
41. DWORD
42. } BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;   
43.    
44. #endif 
45.    
46. //儲存BMP檔案的函數
47. void SaveAsBMP (AVFrame *pFrameRGB, int width, int height, int index, int
48. {   
49. char
50.     BITMAPFILEHEADER bmpheader;   
51.     BITMAPINFOHEADER bmpinfo;   
52. FILE
53.        
54. char *filename = new char[255];  
55. //檔案存放路徑,根據自己的修改
56. "%s%d.bmp","D:/My Documents/Visual Studio 2008/Projects/WriteVideo/Debug/test",index);  
57. if ( (fp=fopen(filename,"wb+")) == NULL )   
58.     {   
59. "open file failed!\n");   
60. return;   
61.     }   
62.    
63.     bmpheader.bfType = 0x4d42;   
64.     bmpheader.bfReserved1 = 0;   
65.     bmpheader.bfReserved2 = 0;   
66. sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);   
67.     bmpheader.bfSize = bmpheader.bfOffBits + width*height*bpp/8;   
68.        
69. sizeof(BITMAPINFOHEADER);   
70.     bmpinfo.biWidth = width;   
71.     bmpinfo.biHeight = height;   
72.     bmpinfo.biPlanes = 1;   
73.     bmpinfo.biBitCount = bpp;   
74.     bmpinfo.biCompression = BI_RGB;   
75.     bmpinfo.biSizeImage = (width*bpp+31)/32*4*height;   
76.     bmpinfo.biXPelsPerMeter = 100;   
77.     bmpinfo.biYPelsPerMeter = 100;   
78.     bmpinfo.biClrUsed = 0;   
79.     bmpinfo.biClrImportant = 0;   
80.        
81. sizeof(bmpheader), 1, fp);   
82. sizeof(bmpinfo), 1, fp);   
83.     fwrite (pFrameRGB->data[0], width*height*bpp/8, 1, fp);   
84.        
85.     fclose(fp);   
86. }   
87.    
88. //主函數
89. int main (void)   
90. {   
91. int
92.     AVCodecContext *pCodecCtx;   
93.     AVFormatContext *pFormatCtx;   
94.     AVCodec *pCodec;   
95.     AVFrame *pFrame, *pFrameRGB;   
96. struct
97. const char *filename = "D:/My Documents/Visual Studio 2008/Projects/WriteVideo/Debug/DELTA.MPG";   
98.     AVPacket packet;   
99. int
100. int
101.     uint8_t *buf;   
102. //注冊編解碼器
103.     av_register_all();   
104. //打開視訊檔案
105. if
106.     {   
107. "av open input file failed!\n");   
108.         exit (1);   
109.     }   
110. //擷取流資訊
111. if
112.     {   
113. "av find stream info failed!\n");   
114.         exit (1);   
115.     }   
116. //擷取視訊流
117. for
118. if
119.     {   
120.        videoStream = i;   
121. break;   
122.     }   
123.        
124. if
125.     {   
126. "find video stream failed!\n");   
127.         exit (1);   
128.     }   
129.        
130.     pCodecCtx = pFormatCtx->streams[videoStream]->codec;   
131.        
132.     pCodec = avcodec_find_decoder (pCodecCtx->codec_id);   
133.        
134. if
135.     {   
136. "avcode find decoder failed!\n");   
137.         exit (1);   
138.     }   
139. //打開解碼器
140. if
141.     {   
142. "avcode open failed!\n");   
143.         exit (1);   
144.     }   
145.        
146. //為每幀圖像配置設定記憶體
147.     pFrame = avcodec_alloc_frame();   
148.     pFrameRGB = avcodec_alloc_frame();   
149.        
150. if
151.     {   
152. "avcodec alloc frame failed!\n");   
153.         exit (1);   
154.     }   
155.        
156.     PictureSize = avpicture_get_size (PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);   
157.     buf = (uint8_t*)av_malloc(PictureSize);   
158.        
159. if
160.     {   
161. "av malloc failed!\n");   
162.         exit(1);   
163.     }   
164.     avpicture_fill ( (AVPicture *)pFrameRGB, buf, PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);   
165.        
166. //設定圖像轉換上下文
167.     pSwsCtx = sws_getContext (pCodecCtx->width,   
168.              pCodecCtx->height,   
169.              pCodecCtx->pix_fmt,   
170.              pCodecCtx->width,   
171.              pCodecCtx->height,   
172.              PIX_FMT_BGR24,   
173.              SWS_BICUBIC,   
174.              NULL, NULL, NULL);   
175.     i = 0;   
176. while(av_read_frame(pFormatCtx, &packet) >= 0)   
177.     {   
178. if(packet.stream_index==videoStream)   
179.     {   
180.        avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,  
181.      packet.data, packet.size);   
182.          
183. if(frameFinished)   
184.        {      
185. //反轉圖像 ,否則生成的圖像是上下調到的
186.             pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height - 1);   
187.             pFrame->linesize[0] *= -1;   
188.             pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height / 2 - 1);   
189.             pFrame->linesize[1] *= -1;   
190.             pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height / 2 - 1);   
191.             pFrame->linesize[2] *= -1;   
192. //轉換圖像格式,将解壓出來的YUV420P的圖像轉換為BRG24的圖像
193.             sws_scale (pSwsCtx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);   
194.      SaveAsBMP (pFrameRGB, pCodecCtx->width, pCodecCtx->height, i++, 24);   
195.        }       
196.     }   
197.     av_free_packet(&packet);   
198.     }   
199.        
200.     sws_freeContext (pSwsCtx);   
201.     av_free (pFrame);   
202.     av_free (pFrameRGB);   
203.     avcodec_close (pCodecCtx);   
204.     av_close_input_file (pFormatCtx);   
205.        
206. return
207. }   
 
#include <windows.h>
 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma once  

 #ifdef __cplusplus
extern "C" {
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>


#ifdef __cplusplus
}
#endif

//定義BMP檔案頭
 #ifndef _WINGDI_ 
#define _WINGDI_
typedef struct tagBITMAPFILEHEADER { 
        WORD    bfType; 
        DWORD   bfSize; 
        WORD    bfReserved1; 
        WORD    bfReserved2; 
        DWORD   bfOffBits; 
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER; 
 
typedef struct tagBITMAPINFOHEADER{ 
        DWORD      biSize; 
        LONG       biWidth; 
        LONG       biHeight; 
        WORD       biPlanes; 
        WORD       biBitCount; 
        DWORD      biCompression; 
        DWORD      biSizeImage; 
        LONG       biXPelsPerMeter; 
        LONG       biYPelsPerMeter; 
        DWORD      biClrUsed; 
        DWORD      biClrImportant; 
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER; 
 
#endif 
 
//儲存BMP檔案的函數
void SaveAsBMP (AVFrame *pFrameRGB, int width, int height, int index, int bpp) 
{ 
   char buf[5] = {0}; 
   BITMAPFILEHEADER bmpheader; 
   BITMAPINFOHEADER bmpinfo; 
   FILE *fp; 
    
   char *filename = new char[255];
       //檔案存放路徑,根據自己的修改
   sprintf_s(filename,255,"%s%d.bmp","D:/My Documents/Visual Studio 2008/Projects/WriteVideo/Debug/test",index);
   if ( (fp=fopen(filename,"wb+")) == NULL ) 
   { 
      printf ("open file failed!\n"); 
      return; 
   } 
 
   bmpheader.bfType = 0x4d42; 
   bmpheader.bfReserved1 = 0; 
   bmpheader.bfReserved2 = 0; 
   bmpheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); 
   bmpheader.bfSize = bmpheader.bfOffBits + width*height*bpp/8; 
    
   bmpinfo.biSize = sizeof(BITMAPINFOHEADER); 
   bmpinfo.biWidth = width; 
   bmpinfo.biHeight = height; 
   bmpinfo.biPlanes = 1; 
   bmpinfo.biBitCount = bpp; 
   bmpinfo.biCompression = BI_RGB; 
   bmpinfo.biSizeImage = (width*bpp+31)/32*4*height; 
   bmpinfo.biXPelsPerMeter = 100; 
   bmpinfo.biYPelsPerMeter = 100; 
   bmpinfo.biClrUsed = 0; 
   bmpinfo.biClrImportant = 0; 
    
   fwrite (&bmpheader, sizeof(bmpheader), 1, fp); 
   fwrite (&bmpinfo, sizeof(bmpinfo), 1, fp); 
   fwrite (pFrameRGB->data[0], width*height*bpp/8, 1, fp); 
    
   fclose(fp); 
} 
 
//主函數
int main (void) 
{ 
   unsigned int i = 0, videoStream = -1; 
   AVCodecContext *pCodecCtx; 
   AVFormatContext *pFormatCtx; 
   AVCodec *pCodec; 
   AVFrame *pFrame, *pFrameRGB; 
   struct SwsContext *pSwsCtx; 
   const char *filename = "D:/My Documents/Visual Studio 2008/Projects/WriteVideo/Debug/DELTA.MPG"; 
   AVPacket packet; 
   int frameFinished; 
   int PictureSize; 
   uint8_t *buf; 
    //注冊編解碼器
   av_register_all(); 
    //打開視訊檔案
   if ( av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL) != 0 ) 
   { 
      printf ("av open input file failed!\n"); 
      exit (1); 
   } 
    //擷取流資訊
   if ( av_find_stream_info(pFormatCtx) < 0 ) 
   { 
      printf ("av find stream info failed!\n"); 
      exit (1); 
   } 
    //擷取視訊流
   for ( i=0; i<pFormatCtx->nb_streams; i++ ) 
   if ( pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO ) 
   { 
      videoStream = i; 
      break; 
   } 
    
   if (videoStream == -1) 
   { 
      printf ("find video stream failed!\n"); 
      exit (1); 
   } 
    
   pCodecCtx = pFormatCtx->streams[videoStream]->codec; 
    
   pCodec = avcodec_find_decoder (pCodecCtx->codec_id); 
    
   if (pCodec == NULL) 
   { 
      printf ("avcode find decoder failed!\n"); 
      exit (1); 
   } 
    //打開解碼器
   if ( avcodec_open(pCodecCtx, pCodec)<0 ) 
   { 
      printf ("avcode open failed!\n"); 
      exit (1); 
   } 
    
   //為每幀圖像配置設定記憶體
   pFrame = avcodec_alloc_frame(); 
   pFrameRGB = avcodec_alloc_frame(); 
    
   if ( (pFrame==NULL)||(pFrameRGB==NULL) ) 
   { 
      printf("avcodec alloc frame failed!\n"); 
      exit (1); 
   } 
    
   PictureSize = avpicture_get_size (PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height); 
   buf = (uint8_t*)av_malloc(PictureSize); 
    
   if ( buf == NULL ) 
   { 
      printf( "av malloc failed!\n"); 
      exit(1); 
   } 
   avpicture_fill ( (AVPicture *)pFrameRGB, buf, PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height); 
    
//設定圖像轉換上下文
   pSwsCtx = sws_getContext (pCodecCtx->width, 
          pCodecCtx->height, 
          pCodecCtx->pix_fmt, 
          pCodecCtx->width, 
          pCodecCtx->height, 
          PIX_FMT_BGR24, 
          SWS_BICUBIC, 
          NULL, NULL, NULL); 
   i = 0; 
   while(av_read_frame(pFormatCtx, &packet) >= 0) 
   { 
   if(packet.stream_index==videoStream) 
   { 
      avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,
    packet.data, packet.size); 
      
      if(frameFinished) 
      {    
         //反轉圖像 ,否則生成的圖像是上下調到的
         pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height - 1); 
         pFrame->linesize[0] *= -1; 
         pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height / 2 - 1); 
         pFrame->linesize[1] *= -1; 
         pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height / 2 - 1); 
         pFrame->linesize[2] *= -1; 
    //轉換圖像格式,将解壓出來的YUV420P的圖像轉換為BRG24的圖像
         sws_scale (pSwsCtx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); 
    SaveAsBMP (pFrameRGB, pCodecCtx->width, pCodecCtx->height, i++, 24); 
      }     
   } 
   av_free_packet(&packet); 
   } 
    
   sws_freeContext (pSwsCtx); 
   av_free (pFrame); 
   av_free (pFrameRGB); 
   avcodec_close (pCodecCtx); 
   av_close_input_file (pFormatCtx); 
    
   return 0; 
}