FFMPEG教程2_解码后在屏幕显示(使用2014年新SDK重新整理编译通过)

#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;


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值