看了一篇博文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,最近很难打开了