看了一篇博文100行代码实现最简单的基于ffmpeg+sdl的视频播放器,地址:http://blog.csdn.net/leixiaohua1020/article/details/8652605,于是乎前面学习了一哈SDL2.0,前两天看了一下ffdoc,感觉API变化了好多,现将新的代码附上:只有最基本的功能,
环境:windows XP
IDE:codeblocks13.12
SDL版本:SDL2.0
ffmpeg版本:ffmpeg2.3
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavutil/file.h>
#include <libavutil/mem.h>
#include <libswscale/swscale.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_thread.h>
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
#define rmask 0xff000000
#define gmask 0x00ff0000
#define bmask 0x0000ff00
#define amask 0x000000ff
#else
#define rmask 0x000000ff
#define gmask 0x0000ff00
#define bmask 0x00ff0000
#define amask 0xff000000
#endif
void SaveFrame(AVFrame *pFrame, int width, int height)
{
FILE *pFile;
char szFilename[32];
int y;
static int iFrame = 0;
sprintf(szFilename,"frame%d.ppm",iFrame);
pFile = fopen(szFilename,"wb");
if(pFile == NULL)
{
return;
}
//write header
fprintf(pFile, "P6\n%d %d\n255\n",width,height);
//write pixel data
for(y = 0; y < height;y++)
fwrite(pFrame->data[0] + y*pFrame->linesize[0],1,width*3,pFile);//写入一行数据
fclose(pFile);
iFrame++;
}
int main(int argc, char* args[])
{
av_register_all();
AVFormatContext* pFormatCtx;
if(SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("SDL init failed error:%s\n",SDL_GetError());
return -1;
}
pFormatCtx = avformat_alloc_context();
if(pFormatCtx == NULL)
{
printf("couldn't alloc a avformatcontext\n");
return -1;
}
if(avformat_open_input(&pFormatCtx,"123.flv",NULL, NULL) != 0)
{
printf("couldn't open file!\n");
return -1;
}
if(avformat_find_stream_info(pFormatCtx,NULL) != 0)
{
printf("couldn't find stream information!\n");
return -1;
}
printf("nb_streams:%d\n",pFormatCtx->nb_streams);
int i = 0,videoStream = -1;
AVCodecContext* pCodecCtx;
//一个文件一般有两种流:一个音频流、一个视频流
for(i = 0; i < pFormatCtx->nb_streams;i++)
if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
break;
}
if(videoStream == -1)
{
printf("couldn't find a video stream!\n");
return -1;
}
//here we find a video stream
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
AVCodec* pCodec;
//find the decoder for the video stream
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec == NULL)
{
printf("unsupported codec!\n");
return -1;
}
if(avcodec_open2(pCodecCtx,pCodec,NULL) < 0)
{
printf("open the codec failed!\n");
return -1;
}
SDL_Surface *screen = NULL;
SDL_Window* gWindow = NULL;
SDL_Surface*surface = NULL;
gWindow = SDL_CreateWindow( "FFmpeg", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, pCodecCtx->width, pCodecCtx->height, SDL_WINDOW_SHOWN );
if(gWindow == NULL)
{
printf("create window failed:%s",SDL_GetError());
return -1;
}
screen = SDL_GetWindowSurface(gWindow);
if(screen == NULL)
{
printf("create surface failed:%s",SDL_GetError());
return -1;
}
SDL_FillRect(screen,NULL,SDL_MapRGB(screen->format,0xff,0xff,0xff));
AVFrame* pFrame,*pFrameRGB;//用于保存一个帧(保存成24位RGB色的PPM文件,需要格式转换,将原始的帧切换成特定格式的帧)
pFrame = av_frame_alloc();//为帧申请一块内存
pFrameRGB = av_frame_alloc();//为帧申请一块内存
if(pFrameRGB == NULL)
{
printf("alloc rgb frame failed!\n");
return -1;
}
uint8_t *buffer;
int numBytes;
numBytes = avpicture_get_size(AV_PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);//转成rgb24需要的帧大小
buffer = (uint8_t*)av_malloc(numBytes*sizeof(uint8_t));//为rgb24帧申请空间,buffer为起始地址
avpicture_fill((AVPicture*)pFrameRGB,buffer,AV_PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);
//把申请的内存和rgb24帧结合起来,准备读取数据
int frameFinished,ret;
AVPacket packet;
struct SwsContext *pSwsCtx;
pSwsCtx = sws_getCachedContext(NULL,pCodecCtx->width, pCodecCtx->height,pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,
AV_PIX_FMT_RGB24,SWS_BILINEAR,NULL,NULL,NULL);
if(pSwsCtx == NULL)
{
printf("get sws context failed!\n");
return -1;
}
while(av_read_frame(pFormatCtx, &packet)>=0) //读取一个包并保存到packet中
{
// Is this a packet from the video stream?
if(packet.stream_index==videoStream)
{
// Decode video frame
ret = avcodec_decode_video2(pCodecCtx, pFrame,&frameFinished, &packet);
if(ret < 0)
{
printf("Decode failed!\n");
return -1;
}
// Did we get a video frame?
if(frameFinished)
{
sws_scale(pSwsCtx,
(const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
pFrameRGB->data, pFrameRGB->linesize);
//Save the frame to disk
surface = SDL_CreateRGBSurfaceFrom(pFrameRGB->data[0],pCodecCtx->width,pCodecCtx->height,24,pCodecCtx->width*3,
rmask,gmask,bmask,amask);
SDL_BlitSurface(surface,NULL,screen,NULL);
SDL_UpdateWindowSurface(gWindow);
SDL_Delay(50);
//SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height);
}
}
// Free the packet that was allocated by av_read_frame
av_free_packet(&packet);
}
// Free the RGB image
av_free(buffer);
av_free(pFrameRGB);
sws_freeContext(pSwsCtx);
SDL_FreeSurface(surface);
surface = NULL;
SDL_DestroyWindow(gWindow);
gWindow = NULL;
SDL_Quit();
// Free the YUV frame
av_free(pFrame);
// Close the codec
avcodec_close(pCodecCtx);
// Close the video file
avformat_close_input(&pFormatCtx);
return 0;
}
结果:
SDL教程:http://lazyfoo.net/tutorials/SDL/index.php,最近很难打开了