最近工作无聊,看到网络上前辈门喊叫着FFmepg在VC上编译遇到很多问题,本人由于工作后期也有点需求用到FFmpeg的codec,所以就顺便整理了一份针对VC环境的视频播放软件,虽然第一个版本比较老了些,但是只是为了验证而已,后期会专门针对on2、VP6做一个全新的、单纯的只能够播放FLV视频的软件,因为要用到后期的Flash player上去.
其实很简单,没有想象的那么复杂,我也是只用了不到一个星期的功夫就整理出来了,写点心得给能够有这方面需求的人.
首先,我们应该清楚系统的架构,我是做系统的,所以很多软件工程的架构都大致有个了解,要明白自己要做什么,需要什么,明白自己要那些东西,对整个流程要有一定的认识,然后再去裁减,才会达到事半功倍的效果.
其次,遇到问题不要怕,这样那样的错误其实是个好事情,最可怕的是遇不到错误,你不知道程序究竟运行到那里出了问题,诸如:指针一不小心瞄准了自己.FFmpeg是个体力活,静下心来,慢慢的就明白是怎么回事情了.
最后,再实现播放后,裁减个最小的方便自己认真学习人家的编程思想.研究人家的算法理念.
遇到的错误:
① 头文件找不到
② 字节对齐
③ SDL的问题(当然我的程序最后是不用这个东西的,因为要平台化)
图片再相册里有.
int main (int argc, char *argv[])
{
AVFormatContext *pFormatCtx;
int i, videoStream,audioStream;
AVCodecContext *pCodecCtx,*pAudioCtx;
AVCodec *pCodec;
AVFrame *pFrame;
AVFrame *pFrameYUV;
AVPacket packet;
PacketQueue audioq;
int frameFinished;
int numBytes;
const char *filename = "3.flv";
SDL_Surface *screen ;
SDL_Overlay *overlay;
SDL_AudioSpec PTempCtx,spec;
static SDL_Rect rect;
argv[1] = filename;
// Register all formats and codecs
av_register_all ();
// Open video file
if (av_open_input_file (&pFormatCtx, argv[1], NULL, 0, NULL) != 0)
return -1; // Couldn't open file
// Retrieve stream information
if (av_find_stream_info (pFormatCtx) < 0)
return -1; // Couldn't find stream information
// Dump information about file onto standard error
dump_format (pFormatCtx, 0, argv[1], 0);
// Find the first video stream
videoStream = -1;
audioStream = -1;
for (i = 0; i < pFormatCtx->nb_streams; i++)
{
if (pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO )
{
videoStream = i;
// break;
}
if (pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO)
{
audioStream = i;
// break;
}
}
if (videoStream == -1)
return -1;
if (audioStream == -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;
pAudioCtx = pFormatCtx->streams[audioStream]->codec;//
/ SDL initialization
if( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER))/
{
fprintf(stderr, "Could not initialize SDL - %s/n", SDL_GetError());
exit(1);
}
screen = SDL_SetVideoMode (pCodecCtx->width, pCodecCtx->height, 0, SDL_HWSURFACE);
overlay = SDL_CreateYUVOverlay (pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, screen);
rect.x = 0;
rect.y = 0;
rect.w = pCodecCtx->width;
rect.h = pCodecCtx->height;
PTempCtx.freq = pAudioCtx->sample_rate;
PTempCtx.format = AUDIO_S16SYS;
PTempCtx.channels = pAudioCtx->channels;
PTempCtx.silence = 0;
PTempCtx.samples = SDL_AUDIO_BUFFER_SIZE;
PTempCtx.callback = sdl_audio_callback;
PTempCtx.userdata = pAudioCtx;
if(SDL_OpenAudio(&PTempCtx, &spec) < 0)
{
fprintf(stderr, "SDL_OpenAudio: %s/n", SDL_GetError());
return -1;
}
//
// Find the decoder for the video stream
pCodec = avcodec_find_decoder (pCodecCtx->codec_id);
if (pCodec == NULL)
return -1; // Codec not found
// Open codec
if (avcodec_open (pCodecCtx, pCodec) < 0)
return -1; // Could not open codec
if (avcodec_open (pAudioCtx, pCodec) < 0)
return -1;
packet_queue_init(&audioq);
SDL_PauseAudio(0);
// Allocate video frame
pFrame = avcodec_alloc_frame ();
// Allocate an AVFrame structure
pFrameYUV = avcodec_alloc_frame ();
if (pFrameYUV == NULL)
return -1;
// Set SDL events
SDL_EventState (SDL_ACTIVEEVENT, SDL_IGNORE);
SDL_EventState (SDL_MOUSEMOTION, SDL_IGNORE);
SDL_ShowCursor (SDL_DISABLE);
// Read frames
while ((av_read_frame (pFormatCtx, &packet) >= 0)
&& (SDL_PollEvent (NULL) == 0)) {
// Is this a packet from the video stream?
if (packet.stream_index == videoStream)
{
// Decode video frame
avcodec_decode_video (pCodecCtx, pFrame, &frameFinished, packet.data, packet.size);
// Did we get a video frame?
if (frameFinished)
{
// Convert the image from its native format to YUV, and display
SDL_LockYUVOverlay (overlay);
pFrameYUV->data[0] = overlay->pixels[0];
pFrameYUV->data[1] = overlay->pixels[2];
pFrameYUV->data[2] = overlay->pixels[1];
pFrameYUV->linesize[0] = overlay->pitches[0];
pFrameYUV->linesize[1] = overlay->pitches[2];
pFrameYUV->linesize[2] = overlay->pitches[1];
img_convert ((AVPicture *) pFrameYUV, PIX_FMT_YUV420P,
(AVPicture *) pFrame, pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height);
SDL_UnlockYUVOverlay (overlay);
SDL_DisplayYUVOverlay (overlay, &rect);
SDL_Delay (40);
}
}
else if (packet.stream_index == audioStream)
{
packet_queue_put(&audioq, &packet);
}
else
{
// Free the packet that was allocated by av_read_frame
av_free_packet (&packet);
}
}
// Free the RGB image
av_free (pFrameYUV);
// Free the YUV frame
av_free (pFrame);
// Close the codec
avcodec_close (pCodecCtx);
// Close the video file
av_close_input_file (pFormatCtx);
//
SDL_FreeYUVOverlay (overlay);
return 0;
}