windows下使用MinGW+msys编译ffmpeg
http://blog.chinaunix.net/uid-20718335-id-2980793.html
实际上我按照这个流程编译了一遍,有些库不全,虽然编译通过了,最终似乎无法使用。
只好引用了ffmpeg项目组的
FFMPEG SDK,我下载的是当前最新的3.2版本。
此外还有一份参考资料:
英文版:An_ffmpeg_and_SDL_Tutorial
下面大致列举一下我遇到的问题,我的操作系统是Windows 7,,64位旗舰版。
其中第八项faad2、第九项faac、第11、12项目amr-nb和amr-wb编译出了一些问题
直接忽视,最后在编译ffmpeg的时候去掉对应项的enable指令就好了。
之后是集成ffmpeg的功能到自己的播放器上,我是基于MFC的对话框做了一个小小的播放器。
这里记录一点点流程,需要全部工程源码的可以私信我。
引用头文件的方法是这样子,不然最后链接的时候会提示出错
[cpp] view plaincopy
- extern "C" {
- #ifndef INT64_C
- #define INT64_C
- #define UINT64_C
- #endif
- #include "avcodec.h"
- #include "avdevice.h"
- #include "avfilter.h"
- #include "avformat.h"
- #include "avutil.h"
- #include "swscale.h"
- }
这里我把上面步骤里面最后导出的头文件其实是直接放到了一个目录下面,
大家也可以直接在VS的项目属性(配置属性-> VC++目录->包含目录和库目录)里面增加对应的头文件所在目录,
就可以这么直接包含头文件了。
然后是添加静态库lib文件,方法比较多,我是在.cpp文件里面这么弄:
[cpp] view plaincopy
1. #pragma comment(lib, "avcodec.lib")
2. #pragma comment(lib, "avdevice.lib")
3. #pragma comment(lib, "avfilter.lib")
4. #pragma comment(lib, "avformat.lib")
5. #pragma comment(lib, "swscale.lib")
6. #pragma comment(lib, "avutil.lib")
7. #pragma comment(lib, "postproc.lib")
8. #pragma comment(lib, "swresample.lib")
然后是对应的bin文件,也就是导出到 local/bin目录下的一些文件,这里我直接拷贝到了项目exe生成目录里面。
给大家看看我的目录结构,如下图:其中FFmpeg-full-sdk-3.2是最开始的那个SDK解压直接得到的。
以下的话我直接对ffmpeg的内容进行了封装,生成了一个类CNcMCodec,类的头文件内容如下:
[cpp] view plaincopy
1. #ifndef _NC_MEDIA_DECODER_H_
2. #define _NC_MEDIA_DECODER_H_
3.
4. extern "C" {
5. #if 0
6. #ifndef INT64_C
7. #define INT64_C
8. #define UINT64_C
9. #endif
10. #include "libavcodec/avcodec.h"
11. #include "libavdevice/avdevice.h"
12. #include "libavfilter/avfilter.h"
13. #include "libavformat/avformat.h"
14. #include "libavutil/avutil.h"
15. #include "libswscale/swscale.h"
16. #else
17. #include "avcodec.h"
18. #include "avdevice.h"
19. #include "avfilter.h"
20. #include "avformat.h"
21. #include "avutil.h"
22. #include "swscale.h"
23. #endif
24. }
25.
26.
27. class CNcMCodec
28. {
29. protected:
30. AVFormatContext *pFormatCtx;
31. AVCodecContext *pCodecCtx;
32. AVCodec *pCodec;
33. int videoStream;
34. AVFrame *pFrame, *pFrameRGB;
35. uint8_t *buffer;
36. DWORD bmfHeaderLen;
37.
38. public:
39. void);
40. virtual ~CNcMCodec(void);
41. bool OpenFile(LPCTSTR lpFilePath, BITMAPINFO &bmpInfo);
42. AVPicture * GetNextFrame();
43. };
44.
45. #endif // _NC_MEDIA_DECODER_H_
下面是.cpp的内容。
[cpp] view plaincopy
1. #include "stdafx.h"
2. #include "NcMCodec.h"
3. // 用于不同类型字符串的转换,宏T2A、A2T等
4. #include <atlconv.h>
5.
6. #pragma comment(lib, "avcodec.lib")
7. #pragma comment(lib, "avdevice.lib")
8. #pragma comment(lib, "avfilter.lib")
9. #pragma comment(lib, "avformat.lib")
10. #pragma comment(lib, "swscale.lib")
11. #pragma comment(lib, "avutil.lib")
12. #pragma comment(lib, "postproc.lib")
13. #pragma comment(lib, "swresample.lib")
14.
15.
16. static void CodecInit(void)
17. {
18. static bool bInitialed(false);
19. if ( true == bInitialed )
20. return;
21. av_register_all();
22. }
23.
24.
25. CNcMCodec::CNcMCodec(void)
26. {
27. pFormatCtx = NULL;
28. pCodecCtx = NULL;
29. CodecInit();
30. }
31.
32.
33. CNcMCodec::~CNcMCodec(void)
34. {
35. }
36.
37.
38. bool CNcMCodec::OpenFile(LPCTSTR lpFilePath, BITMAPINFO &bmpInfo)
39. {
40. char path[MAX_PATH];
41. #ifdef _UNICODE
42. USES_CONVERSION;
43. strcpy_s<MAX_PATH>( path, T2A(lpFilePath) );
44. #else
45. strcpy_s<MAX_PATH>( path, lpFilePath );
46. #endif
47. if ( av_open_input_file( &pFormatCtx, path, NULL, 0, NULL ) )
48. return false; // 文件打开失败
49. if ( av_find_stream_info(pFormatCtx) < 0 )
50. return 0; // 无法找到流信息
51. dump_format( pFormatCtx, 0, path, 0 );
52. size_t i = 0;
53. videoStream = -1;
54. for ( i = 0; i < pFormatCtx->nb_streams; i++ )
55. {
56. if ( pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO )
57. {
58. videoStream = i;
59. break;
60. }
61. }
62. if ( -1 == videoStream )
63. return false;
64. pCodecCtx = pFormatCtx->streams[videoStream]->codec;
65. pCodec = avcodec_find_decoder( pCodecCtx->codec_id );
66. if ( NULL == pCodec )
67. return false;
68. if ( avcodec_open(pCodecCtx, pCodec) < 0 )
69. return false; // 无法打开解码器
70. pFrame = avcodec_alloc_frame();
71. pFrameRGB = avcodec_alloc_frame();
72. if ( NULL == pFrame )
73. return false;
74. int bytes = avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
75. sizeof(uint8_t));
76. avpicture_fill( (AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height );
77. // 设置位图信息头数据
78. BITMAPINFOHEADER &infoHeader(bmpInfo.bmiHeader);
79. infoHeader.biBitCount = 24;
80. infoHeader.biClrImportant = 0;
81. infoHeader.biClrUsed = 0;
82. infoHeader.biCompression = 0;
83. // 这里要是负数,否则在MFC下面使用stretchBlt显示的图像是倒着的
84. infoHeader.biWidth = pCodecCtx->width;
85. infoHeader.biPlanes = 1;
86. infoHeader.biSize = 40;
87. infoHeader.biSizeImage = 0;
88. infoHeader.biXPelsPerMeter = 0;
89. infoHeader.biYPelsPerMeter = 0;
90. return true;
91. }
92.
93.
94. AVPicture * CNcMCodec::GetNextFrame()
95. {
96. AVPacket packet;
97. int frameFinished = 0;
98. // Convert the image from its native format to RGB
99.
100. while ( av_read_frame( pFormatCtx, &packet ) >= 0 )
101. {
102. if ( videoStream == packet.stream_index )
103. {
104. avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, packet.data, packet.size);
105. }
106. if ( frameFinished )
107. {
108. // img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24, (AVPicture *)pFrame, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height );
109. // 这里不能用那个 turial上的函数,目前的版本上已经没有了这个img_convert函数,需要用下面的三句话来替换
110.
111. static struct SwsContext *img_convert_ctx;
112. img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
113. // other codes
114. // Convert the image from its native format to RGB
115. sws_scale(img_convert_ctx, (uint8_t **)pFrame->data, pFrame->linesize,
116. 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
117. return (AVPicture *)pFrameRGB;
118. }
119. }
120. return NULL;
121. }
122. // NcMCodec.cpp至此已经结束
123. // 至于如何把这个AVPicture结构转换成HBITMAP,用于MFC的显示,
124. // 我的方法如下,其中dec是上述的一个解码器类对象,使用之前应该先进行dec.OpenFile操作:
125. HBITMAP CNcMPlayerDlg::GetNextFrame(CDC *pDC, HBITMAP &hBitmap)
126. {
127. AVPicture *pFrame = dec.GetNextFrame();
128. if ( NULL == pFrame )
129. {
130. hBitmap = NULL;
131. return NULL;
132. }
133. LPVOID lpDIBBits = (LPVOID)pFrame->data[0];/*(lpBuffer)+((BITMAPFILEHEADER *)lpBuffer)->bfOffBits*/ // 像素的数值
134. hBitmap = CreateDIBitmap(pDC->m_hDC, &bmpInfo.bmiHeader , CBM_INIT,lpDIBBits, &bmpInfo, DIB_RGB_COLORS);
135. return hBitmap;
136. }
这个代码只有一个很基本的框架,还有一点BUG(设置读取指定位置会出错),
我自己没弄明白是怎么回事。
如果你解决了或者对代码做了优化,希望能够分享给我。