FFMPEG教程2_解码后在屏幕显示(使用2014年新SDK重新整理编译通过)
2014-09-30 13:24
459 查看
#include "stdafx.h" #include <Windows.h> #pragma warning( disable : 4312 ) #pragma warning( disable : 4244 ) #pragma warning( disable : 4311 ) #ifdef __cplusplus extern "C" { #endif #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavutil/avutil.h> #include <libswscale/swscale.h> #include <SDL/SDL.h> #include <SDL/SDL_video.h> // SDL #include <SDL/SDL_thread.h> // SDL #ifdef __cplusplus } #endif #pragma comment( lib, "libgcc.a") #pragma comment( lib, "libmingwex.a") #pragma comment( lib, "libcoldname.a") #pragma comment( lib, "libavcodec.a") #pragma comment( lib, "libavformat.a") #pragma comment( lib, "libavutil.a") #pragma comment( lib, "libswscale.a") #pragma comment( lib, "libz.a") #pragma comment( lib, "libfaac.a") #pragma comment( lib, "libgsm.a") #pragma comment( lib, "libmp3lame.a") #pragma comment( lib, "libogg.a") #pragma comment( lib, "libspeex.a") #pragma comment( lib, "libtheora.a") #pragma comment( lib, "libvorbis.a") #pragma comment( lib, "libvorbisenc.a") #pragma comment( lib, "libx264.a") #pragma comment( lib, "xvidcore.a") #pragma comment( lib, "wsock32.lib") #pragma comment( lib, "vfw32.lib") #pragma comment( lib, "sdl2main.lib") #pragma comment( lib, "sdl2.lib") #pragma comment(lib, "winmm.lib ") #pragma comment(lib,"Version.lib") #pragma comment(lib,"imm32.lib") #define SFM_REFRESH_EVENT (SDL_USEREVENT + 1) int thread_exit=0; int sfp_refresh_thread(void *opaque) { while (thread_exit==0) { SDL_Event event; event.type = SFM_REFRESH_EVENT; SDL_PushEvent(&event); SDL_Delay(40); } return 0; } int _tmain(int argc, char *argv[]) { //下面这个千万要注意,原来老代码不需要=NULL, //但是新SDK如果不初始化会在avformat_open_input非法退出 //因此,将指针初始化为NULL是个好习惯! AVFormatContext *pFormatCtx = NULL; int i, videoStream; AVCodecContext *pCodecCtx = NULL; AVCodec *pCodec = NULL; AVFrame *pFrame = NULL; AVFrame *pFrameRGB = NULL; AVPacket packet; int frameFinished; int numBytes; uint8_t *buffer; struct SwsContext *sws_ctx = NULL; SDL_Texture *bmp = NULL; SDL_Window *screen = NULL; SDL_Rect rect; SDL_Event event; if(argc < 2) { printf("带参数执行,后面跟视频文件\n"); return -1; } // 注册所有的解码格式 av_register_all(); avformat_network_init(); pFormatCtx = avformat_alloc_context(); if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) { fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError()); exit(1); } printf_s("打开视频文件:%s成功\n",argv[1]); //打开视频 printf_s("打开视频文件:%s成功\n",argv[1]); if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0) return -1; // 打开视频文件失败 printf_s("打开视频文件:%s成功\n",argv[1]); // 检索流信息 if(av_find_stream_info(pFormatCtx)<0) return -1; // 不能发现流信息资料 //打印标准的转储信息 av_dump_format(pFormatCtx, 0, argv[1], 0); // 找到第一个视频 videoStream=-1; for(i=0; i<(int)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) { fprintf(stderr, "Unsupported codec!\n"); return -1; //视频解码未发现 } // 开放的编解码器 if(avcodec_open(pCodecCtx, pCodec)<0)return -1; // 视频解码未发现 //分配视频帧 pFrame=avcodec_alloc_frame(); // 分配一个AVFrame结构 pFrameRGB=avcodec_alloc_frame(); if(pFrameRGB==NULL)return -1; int screen_w = pCodecCtx->width; int screen_h = pCodecCtx->height; screen = SDL_CreateWindow("Simplest ffmpeg player's Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_w, screen_h,SDL_WINDOW_OPENGL); //screen = SDL_CreateWindow("My Game Window",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,pCodecCtx->width, pCodecCtx->height,SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL); SDL_Renderer *renderer = SDL_CreateRenderer(screen, -1, 0); if(!screen) { fprintf(stderr, "SDL: could not set video mode - exiting\n"); exit(1); } //bmp = SDL_CreateTexture(renderer,SDL_PIXELFORMAT_YV12,SDL_TEXTUREACCESS_STREAMING,pCodecCtx->width,pCodecCtx->height);//如果使用这个SDL_PIXELFORMAT_YV12,显示颜色失真! bmp = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING,pCodecCtx->width,pCodecCtx->height); //用于保存显示到SDL sws_ctx = sws_getContext(pCodecCtx->width,pCodecCtx->height, pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,PIX_FMT_YUV420P,SWS_BILINEAR,NULL,NULL,NULL); ////确定所需的缓冲区大小和分配缓冲区,用于显示到SDL的 numBytes = avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width,pCodecCtx->height); buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t)); // Assign appropriate parts of buffer to image planes in pFrameRGB // Note that pFrameRGB is an AVFrame, but AVFrame is a superset of AVPicture //分配适当的部分缓冲给在pFrameRGB中的图像平面,请注意,pFrameRGB 是一个AVFrame,但AVFrame却是AVPicture的超集,用于显示到SDL avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height); i=0; rect.x = 0; rect.y = 0; rect.w = pCodecCtx->width; rect.h = pCodecCtx->height; SDL_Thread *video_tid = SDL_CreateThread(sfp_refresh_thread,NULL,NULL); int iret; for(;;) { SDL_WaitEvent(&event); if(event.type==SFM_REFRESH_EVENT) { if(av_read_frame(pFormatCtx, &packet)>=0) { // 这是一个视频的包吗? if(packet.stream_index==videoStream) { // 解码视频帧 iret = avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished,&packet); if(iret < 0){ printf("Decode Error.(解码错误)\n"); return -1; } // 成功获得了视频帧? if(frameFinished) { // 将图像从原生格式转换成为目标格式 sws_scale(sws_ctx,(uint8_t const * const *)pFrame->data,pFrame->linesize, 0,pCodecCtx->height, pFrameRGB->data,pFrameRGB->linesize); //送到SDL2.0中显示,和SDL1.0明显不同! SDL_UpdateTexture( bmp, &rect, pFrameRGB->data[0], pFrameRGB->linesize[0] ); SDL_RenderClear( renderer ); SDL_RenderCopy( renderer, bmp, &rect, &rect ); SDL_RenderPresent( renderer ); } } // 释放av_read_frame分配的包 av_free_packet(&packet); }else{ thread_exit = 1; break; } } } SDL_DestroyTexture(bmp); sws_freeContext(sws_ctx); SDL_Quit(); // 释放RGB图像 av_free(buffer); av_free(pFrameRGB); // 释放YUV帧 av_free(pFrame); // 关闭解码器 avcodec_close(pCodecCtx); // 关闭视频文件 av_close_input_file(pFormatCtx); return 0; }
相关文章推荐
- FFMPEG教程1_解码后保存图片(使用2014年新SDK重新整理编译通过)
- FFMPEG教程4_让程序模块化-增加多线程(使用2014年新SDK重新整理编译通过)
- FFMPEG教程6_同步音频(使用2014年新SDK重新整理编译通过)
- FFMPEG教程7_快进和快退(使用2014年新SDK重新整理编译通过)
- FFMPEG教程5_同步视频(使用2014年新SDK重新整理编译通过)
- FFMPEG教程3_播放声音(使用2014年新SDK重新整理编译通过)
- 视频编解码之windows平台下编译ffmpeg的方法和使用教程
- iOS 开发 高级:通过AirServer使用AirPlay镜像并实现多屏幕显示控制
- 在Android中通过jni方式使用编译好的FFmpeg库-Android中使用FFmpeg媒体库(二)
- ArchieOpenGL教程第11课:使用位图字体 在屏幕上显示字体
- Qt5 : 在使用 QtDesigner 的时候编译通过窗口不显示
- 在Android中通过jni方式使用编译好的FFmpeg库-Android中使用FFmpeg媒体库(二)
- ffmpeg解码数据转为Mat通过opencv函数显示
- PowerDesigner使用过程中有时会将悬浮的工具面板关闭,关闭后可通过下面的方式使工具栏重新显示出来
- KITL 使用教程(重新整理)
- 天草VIP_逆向分析视频教程(无KEY高清版)[2014年重新整理可在线播放版]
- Android整理:SQlite数据库的使用以及通过listView显示数据
- windows form 视频显示 整理版vs2008下编译通过
- KITL 使用教程(重新整理)(转载)
- 在Android中通过jni方式使用编译好的FFmpeg库-Android中使用FFmpeg媒体库