开发环境:
VS2012 + ffmpeg + SDL
配置步骤:
- 将ffmpeg 中的.h文件、.lib文件、.dll文件拷贝到工程目录下,如下图所示:
- 在_mingw.h文件的结尾处(在#endif 一行之前)添加了一行:#define restrict
- 把所有long long改成了__int64。
- 源文件:
#include "stdafx.h"
#include <stdio.h>
extern "C"
{
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "sdl/SDL.h"
#include "sdl/SDL_thread.h"
};
#pragma comment(lib,"lib/avcodec.lib")
#pragma comment(lib,"lib/avformat.lib")
#pragma comment(lib,"lib/avutil")
//#pragma comment(lib,"lib/SDLmain.lib")
#pragma comment(lib,"lib/avdevice.lib")
#pragma comment(lib,"lib/avfilter.lib")
#pragma comment(lib,"lib/postproc.lib")
#pragma comment(lib,"lib/SDL.lib")
#pragma comment(lib,"lib/swresample.lib")
#pragma comment(lib,"lib/swscale.lib")
int _tmain(int argc, _TCHAR* argv[])
{
AVFormatContext * pFormatCtx; //包含输入文件的很多信息,流个数,编解码器
AVCodecContext * pCodecCtx; //编解码器上下文
AVCodec * pCodec; //真正的编解码器
AVFrame * pFrame; //保存刚解码出来的原始数据帧
AVFrame * pFrameYUV; //保存真正解码出来的帧,要显示的帧
char fileName[]="cuc_ieschool.flv";
av_register_all(); //注册所有的编解码器和文件格式
pFormatCtx=avformat_alloc_context();
if(avformat_open_input(&pFormatCtx,fileName,NULL,NULL)!=0)
{
printf("打开输入流失败\n");
return -1;
}
if(avformat_find_stream_info(pFormatCtx,NULL)<0)
{
printf("查找输入流失败\n");
return -1;
}
//寻找视频流
int videoStream=-1;
for(int 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;
pCodecCtx=pFormatCtx->streams[videoStream]->codec; //获得对应流的编解码器信息
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL)
{
printf("没有找到对应流的解码器\n");
return -1;
}
if(avcodec_open2(pCodecCtx,pCodec,NULL)<0)
{
printf("无法打开解码器\n");
return -1;
}
pFrame=avcodec_alloc_frame();
pFrameYUV=avcodec_alloc_frame();
int numBytes;
uint8_t * buffer; //这个buffer与pFrameYUV关联在一起,
//用buffer的数据填充帧pFrameYUV
AVPacket * pPacket; //存储视频数据包
SwsContext * img_convert_ctx; //源格式信息、宽高,目标格式、宽高
SDL_Overlay * bmp; //相当于一幅图片
SDL_Surface * screen;
SDL_Rect myRect;
SDL_Rect * rect=&myRect;
screen=SDL_SetVideoMode(pCodecCtx->width,pCodecCtx->height,0,0);
bmp=SDL_CreateYUVOverlay(pCodecCtx->width,pCodecCtx->height,
SDL_YV12_OVERLAY,screen); //显示格式信息
img_convert_ctx=sws_getContext(pCodecCtx->width,pCodecCtx->height,
pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,
PIX_FMT_YUV420P,SWS_BICUBIC,NULL,NULL,NULL);
numBytes=avpicture_get_size(PIX_FMT_YUV420P,pCodecCtx->width,
pCodecCtx->height);
buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
avpicture_fill((AVPicture *)pFrameYUV,buffer,PIX_FMT_YUV420P,
pCodecCtx->width,pCodecCtx->height);
pPacket=(AVPacket *)av_malloc(sizeof(AVPacket));
rect->x=0;
rect->y=0;
rect->w=pCodecCtx->width;
rect->h=pCodecCtx->height;
//开始视频解码
int frameFinished;
while (av_read_frame(pFormatCtx,pPacket)>=0)
{
if(pPacket->stream_index==videoStream)
{
avcodec_decode_video2(pCodecCtx,pFrame,&frameFinished,pPacket);
if(frameFinished)
{
sws_scale(img_convert_ctx,pFrame->data,pFrame->linesize,
0,pCodecCtx->height,pFrameYUV->data,pFrameYUV->linesize);
SDL_LockYUVOverlay(bmp);
bmp->pixels[0]=pFrameYUV->data[0];
bmp->pixels[2]=pFrameYUV->data[1];
bmp->pixels[1]=pFrameYUV->data[2];
bmp->pitches[0]=pFrameYUV->linesize[0];
bmp->pitches[2]=pFrameYUV->linesize[1];
bmp->pitches[1]=pFrameYUV->linesize[2];
SDL_UnlockYUVOverlay(bmp);
SDL_DisplayYUVOverlay(bmp,rect);
}
}
av_free_packet(pPacket);
}
sws_freeContext(img_convert_ctx);
SDL_Quit();
av_free(buffer);
av_free(pFrameYUV);
av_free(pFrame);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
return 0;
}
遇到的问题:
上述配置完成后,即可播放视频。但可能会出现如下现象:程序可以直接执行,但在程序中设置断点调试时,会出现如下问题:
解决方法:
将avcodec-56.dll、avdevice-56.dll、avfilter-5.dll、avformat-56.dll、avutil-54.dll、postproc-53.dll、SDL.dll、swresample-1.dll、swscale-3.dll拷贝到Debug目录下,如下图所示:
这样即可解决上述问题。
参考资料:
从http://ffmpeg.zeranoe.com/builds/网站上
1.下载Dev版本,里面包含了ffmpeg的xxx.h头文件以及xxx.lib库文件。
2.下载Shared版本,里面包含了ffmpeg的dll文件。
注:可能会出现问题,参见:FFMPEG 库移植到 VC 需要的步骤
http://blog.csdn.net/leixiaohua1020/article/details/12747899