初接触根据网上资料写的一个播放器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;
}