FFMpeg是跨平台的开源软件,但是由于采用C99语法,在Visual Studio中无法编译,对于想要使用ffmpeg而不想去配置MinGw和其他依赖库的同学,提供以下方案。
首先去:http://ffmpeg.zeranoe.com/builds/此网站有ffmpeg 编译好的相关文件。此处下载ffmpeg动态链接库,32-bit build(shard),其中包括了所有的动态库,同时也包括了ffmpeg.exe(可以直接做视频转化,参数很强大),ffplay.exe(直接播放音视频)。此处需要用到其中的动态库用于在应用程序中使用,同时DLL需要lib导出,也需要相应的头文件,这个需要下载32 bit build(dev),其中包含了lib,和相应的头文件,但是却没有dll文件,所以需要用到前面的shared库。
好了,准备工作都做好了,就是编码测试了,我写了个简单的测试工程。ffmpeg.c太过复杂了,4000多行代码,而且在visual studio中根本编译不过。
代码如下:
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C"
{
#include "libavutil/avutil.h"
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
}
#endif
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"swscale.lib")
#include <windows.h>
void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame);
int img_convert2(AVPicture *dst, int dst_pix_fmt,AVPicture *src, int src_pix_fmt,int src_width, int src_height);
int main(int argc, char* argv[])
{
av_register_all();
AVFormatContext *pFormatCtx = NULL;
// Open video file
AVInputFormat *pInputFormat = NULL;
if (avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0) {
return -1; // Couldn't open file
}
if(av_find_stream_info(pFormatCtx)<0) {
return -1; // Couldn't find stream information
}
int i = 0;
int videoStream=-1;
AVCodecContext *pCodecCtx = NULL;
for(i=0; i < pFormatCtx->nb_streams; i++)
{
if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
break;
}
}
if(videoStream==-1) {
return -1; // Didn't find a video stream
}
// Get a pointer to the codec context for the video stream
pCodecCtx=pFormatCtx->streams[videoStream]->codec;
AVCodec *pCodec = NULL;
// Find the decoder for the video stream
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL)
{
fprintf(stderr, "Unsupported codec!\n");
return -1; // Codec not found
}
// Open codec
if(avcodec_open(pCodecCtx, pCodec)<0) {
return -1; // Could not open codec
}
AVFrame *pFrame,*pFrameRGB;
// Allocate video frame
pFrame=avcodec_alloc_frame();
pFrameRGB=avcodec_alloc_frame();
if(pFrameRGB==NULL) {
return -1;
}
uint8_t *buffer;
int numBytes;
// Determine required buffer size and allocate buffer
numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,pCodecCtx->height);
buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,pCodecCtx->width, pCodecCtx->height);
int frameFinished;
AVPacket packet;
i=0;
while(av_read_frame(pFormatCtx, &packet) >= 0)
{
// Is this a packet from the video stream?
if(packet.stream_index==videoStream)
{
// Decode video frame
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished,&packet);
// Did we get a video frame?
if(frameFinished)
{
// Convert the image from its native format to RGB
img_convert2((AVPicture *)pFrameRGB,PIX_FMT_RGB24,(AVPicture*)pFrame, pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height);
// Save the frame to disk
if(++i<=100)
SaveFrame(pFrameRGB, pCodecCtx->width,pCodecCtx->height, i);
}
}
// Free the packet that was allocated by av_read_frame
av_free_packet(&packet);
}
// Free the RGB image
av_free(buffer);
av_free(pFrameRGB);
// Free the YUV frame
av_free(pFrame);
// Close the codec
avcodec_close(pCodecCtx);
av_close_input_file(pFormatCtx);
return 0;
}
int img_convert2(AVPicture *dst, int dst_pix_fmt,
AVPicture *src, int src_pix_fmt,
int src_width, int src_height)
{
int w;
int h;
SwsContext *pSwsCtx;
w = src_width;
h = src_height;
pSwsCtx = sws_getContext(w, h, PIX_FMT_YUV420P, w, h, PIX_FMT_RGB24,SWS_BICUBIC, NULL, NULL, NULL);
sws_scale(pSwsCtx,src->data, src->linesize,0, h, dst->data, dst->linesize);
SaveFrame((AVFrame *)dst, src_width, src_height, 0);
sws_freeContext(pSwsCtx);
return 0;
}
void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame)
{
FILE *pFile;
char szFilename[32];
int y;
// Open file
sprintf(szFilename, "frame%d.ppm", iFrame);
pFile=fopen(szFilename, "wb");
//构造文件头
BITMAPFILEHEADER bmpFileHeader;
memset(&bmpFileHeader, 0, sizeof(BITMAPFILEHEADER));
bmpFileHeader.bfType = 0x4D42;
bmpFileHeader.bfOffBits = 54;
bmpFileHeader.bfSize = 54 + width * height * 24/8;
BITMAPINFOHEADER bmpInfoHeader;
memset(&bmpInfoHeader, 0, sizeof(BITMAPINFOHEADER));
bmpInfoHeader.biCompression = BI_RGB;
bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = 24; //定死为24位图
bmpInfoHeader.biWidth = width;
bmpInfoHeader.biHeight = height;
fwrite(&bmpFileHeader, sizeof(bmpFileHeader), 1, pFile);
fwrite(&bmpInfoHeader, sizeof(bmpInfoHeader), 1, pFile);
// Write pixel data
for(y=0; y<height; y++) {
fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);
}
fclose(pFile);
}
此代码完成了视频的解码并将原始YUV数据转化为RGB存储到bmp文件中,但此处没做处理,bmp文件图像是反的。
注意一点:ffmpeg头文件需要依赖一些visual studio的头文件,我将自己的测试工程上传到资源中了。
此为完整可编译的ffmpeg vs测试工程。