FFMpeg学习笔记(1)

本文介绍了一个使用FFmpeg和SDL实现的简单播放器Demo。该Demo通过FFmpeg读取并解码视频文件,利用SDL进行视频帧的显示。文章提供了完整的源代码,并详细解释了各部分的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

初接触根据网上资料写的一个播放器Demo

准备工作:

1.下载FFMpeg的最新sdk

2.下载SDL的最新sdk

代码如下:

#include "stdafx.h"
#include <Windows.h>
#include <SDL.h>
#include <string>
using namespace std;
#pragma comment(lib, "SDL.lib")   

extern "C"  
{  
#include "libavcodec/avcodec.h"   
#include "libavformat/avformat.h"   
#include "libswscale/swscale.h"   
#pragma comment(lib, "avcodec.lib")   
#pragma comment(lib, "avutil.lib")   
#pragma comment(lib, "avformat.lib")   
#pragma comment(lib, "swscale.lib")   
}  

string GetFilePath(string strFileName)
{
	char szPath[MAX_PATH];
	GetModuleFileNameA(NULL,szPath,MAX_PATH);
	char* pEnd = strrchr(szPath,'\\');
	*(pEnd+1) = '\0';
	string strPath = szPath;
	return strPath + strFileName;
}

int _tmain(int argc, _TCHAR* argv[])  
{  
	string strFileName = GetFilePath("test.mp4");  
	//初始化,注册所有基于FFMpeg的编码器   
	av_register_all();  
	//打开视频流文件,获取头   
	AVFormatContext* pFormatCtx = NULL;  
	if(avformat_open_input(&pFormatCtx,strFileName.c_str(),NULL,NULL) != 0)  
	{  
		printf("av_open_input_file error.");  
		return -1;  
	}  
	//获取视频流信息   
	if(av_find_stream_info(pFormatCtx) < 0)  
	{  
		printf("av_find_stream_info error.");  
		return -1;  
	}  
	//获取其他信息   
	av_dump_format(pFormatCtx,0,strFileName.c_str(),0);  
	//查找视频流   
	int nVideoStream =-1;  
	for(unsigned int i = 0;i < pFormatCtx->nb_streams;i++)  
	{  
		if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)   
		{  
			nVideoStream = i;  
			break;  
		}  
	}  
	if(nVideoStream == -1)  
	{  
		printf("nVideoStream == -1 error.");  
		return -1; // Didn't find a video stream   
	}  
	//获取视频流信息指针   
	AVCodecContext* pCodecCtx = pFormatCtx->streams[nVideoStream]->codec;  
	//查找视频流解码器   
	AVCodec* pCodec = avcodec_find_decoder(pCodecCtx->codec_id);  
	if(pCodec == NULL)  
	{  
		printf("avcodec_find_decoder error.");  
		return -1; // Codec not found   
	}  
	//打开解码器   
	if(avcodec_open(pCodecCtx,pCodec) < 0)  
	{  
		printf("avcodec_open error.");  
		return -1;  
	}  
	//初始化SDL   
	if(SDL_Init(SDL_INIT_VIDEO))   
	{  
		fprintf(stderr, "Could not initialize SDL - %s\n",SDL_GetError());  
	}    
	int screen_w = pCodecCtx->width;    
	int screen_h = pCodecCtx->height;   
	SDL_Surface* screen = SDL_SetVideoMode(screen_w, screen_h, 0, 0);  
	SDL_Overlay* bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height,SDL_YV12_OVERLAY, screen);  
	//用于保存解码前的视频数据帧   
	AVFrame* pFrame = avcodec_alloc_frame();  
	//用于保存解码后的视频数据帧   
	AVFrame* pFrameRGB = avcodec_alloc_frame();  
	int numBytes = avpicture_get_size(AV_PIX_FMT_YUVJ420P,pCodecCtx->width,pCodecCtx->height);  
	uint8_t* buffer = (uint8_t*)av_malloc(numBytes*sizeof(uint8_t));  
	avpicture_fill((AVPicture *)pFrameRGB,buffer,AV_PIX_FMT_YUVJ420P,pCodecCtx->width, pCodecCtx->height);  
	//用于解码后数据格式转换   
	SwsContext* pSwsCtx = sws_getContext(pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,AV_PIX_FMT_YUVJ420P,SWS_BICUBIC,NULL, NULL, NULL);  
	AVPacket packet;  
	while(av_read_frame(pFormatCtx,&packet)>=0)   
	{  
		//当前读取的数据流是否为视频流数据   
		if(packet.stream_index == nVideoStream)   
		{  
			//是否一帧已经完成   
			int frameFinished;  
			//解码视频流数据   
			avcodec_decode_video2(pCodecCtx,pFrame,&frameFinished,&packet);  
			if(frameFinished)   
			{   //视频流转换   
				sws_scale(pSwsCtx,pFrame->data,pFrame->linesize,0,pCodecCtx->height,pFrameRGB->data, pFrameRGB->linesize);  
				//锁定   
				SDL_LockYUVOverlay(bmp);  
				bmp->pixels[0]=pFrameRGB->data[0];    
				bmp->pixels[2]=pFrameRGB->data[1];    
				bmp->pixels[1]=pFrameRGB->data[2];         
				bmp->pitches[0]=pFrameRGB->linesize[0];    
				bmp->pitches[2]=pFrameRGB->linesize[1];       
				bmp->pitches[1]=pFrameRGB->linesize[2];    
				SDL_UnlockYUVOverlay(bmp);  
				//显示   
				int nViewCount = 1;  
				for(int i = 0;i < nViewCount*nViewCount;i++)  
				{  
					SDL_Rect rect;  
					rect.x = (i%nViewCount)*screen_w/nViewCount;  
					rect.y = (i/nViewCount)*screen_h/nViewCount;  
					rect.w = screen_w/nViewCount;  
					rect.h = screen_h/nViewCount;  
					SDL_DisplayYUVOverlay(bmp, &rect);  
				}  
				SDL_Delay(40);  
			}  
		}  
		av_free_packet(&packet);  
	}  
	//释放   
	SDL_Quit();  
	av_free(buffer);  
	av_free(pFrameRGB);  
	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、付费专栏及课程。

余额充值