int i, videoStream(-1);
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVFrame *pFrame;
AVPacket packet;
int frameFinished;
float aspect_ratio;
AVCodecContext *aCodecCtx;
SDL_Overlay *bmp;
SDL_Surface *screen;
SDL_Rect rect;
SDL_Event event;
//初始化SDL
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER))
{
fprintf(stderr, "Could not initialize SDL - %s/n" , SDL_GetError());
exit(1);
}
av_register_all();
const char * filename = "D:\\Wildlife.wmv";
//申请一段内存
/* hwndDisplay= GetDlgItem(IDC_STATIC_PICTRUE)->GetSafeHwnd();
GetDlgItem(IDC_STATIC_PICTRUE)->GetClientRect(rcDisplay);
char szVar[MAX_PATH];
sprintf(szVar,"SDL_WINDOWID=0x%lx" ,hwndDisplay);
SDL_putenv(szVar);*/
pFormatCtx = avformat_alloc_context();
if (!pFormatCtx)
{
fprintf(stderr, "Memory error/n");
exit(1);
}
//参数ypFormatCtx包含一切媒体相关的上下文结构,有它就有了一切,本函数如果打开媒体成功|,
//会返回一个AVFormatContext的实例.
//参数yfilename是媒体文件名或URL.
//打开视频文件
if(avformat_open_input(&pFormatCtx, filename, NULL, NULL)!=0)
return;//打开失败
// 检查文件中的流信息
if(av_find_stream_info(pFormatCtx)<0)
return ;
// Dump information about file onto standard error
// Find the first video stream
//pFormatCtx->streams是一组大小为apFormatCtx->nb_streams的指针
//接着我们寻找一个视频流
for(i=0; i<pFormatCtx->nb_streams; i++)
{
if(pFormatCtx->streams[i]->codec->codec_type== AVMEDIA_TYPE_VIDEO&& videoStream<0)
{
videoStream=i;
}
}
if(videoStream==-1)
return ; // Didn't find a video stream
// Get a pointer to the codec context for the video stream
//流中关于编解码器的信息我们叫做code context,包含了所使用的编解码器信息,这里我们得到了指向他的指针
pCodecCtx=pFormatCtx->streams[videoStream]->codec;
//接下来寻找真的编解码器,并且打开他
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL)
{
fprintf(stderr, "Unsupported codec!/n");
return ; // Codec not found
}
// Open codec
if(avcodec_open(pCodecCtx, pCodec)<0)
return ; // Could not open codec
// Allocate video frame
pFrame=avcodec_alloc_frame();
uint8_t *buffer;
int numBytes;
// Determine required buffer size and allocate buffer
numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,
pCodecCtx->height);
buffer=(uint8_t *)av_malloc(numBytes* sizeof(uint8_t));
#ifndef __DARWIN__
screen = SDL_SetVideoMode(rcDisplay.Width(), rcDisplay.Height(), 0, 0);
#else
screen = SDL_SetVideoMode(rcDisplay.Width(), rcDisplay.Height(), 24, 0);
#endif
if(!screen)
{
fprintf(stderr, "SDL: could not set video mode - exiting/n" );
exit(1);
}
//创建绘制YUV数据的句柄
bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height,
SDL_YV12_OVERLAY, screen);
static struct SwsContext *img_convert_ctx;
if (img_convert_ctx == NULL)
{
//图像格式转化,返回上下文句柄
img_convert_ctx = sws_getContext(rcDisplay.Width(), rcDisplay.Height(),
pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height,
PIX_FMT_YUV420P,
sws_flags, NULL, NULL, NULL);
if (img_convert_ctx == NULL)
{
fprintf(stderr, "Cannot initialize the conversion context/n" );
exit(1);
}
}
i=0;
//不停的从码流中提取帧数据
while(av_read_frame(pFormatCtx, &packet)>=0)
{
// Is this a packet from the video stream?
if(packet.stream_index==videoStream)
{
// Decode video frame
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished,
&packet);
// Did we get a video frame?
if(frameFinished)
{
// Convert the image from its native format to RGB
/*sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize,
0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);*/
// Save the frame to disk
/*if(++i<=5)
SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);*/
///锁定一个覆盖,以便于在屏幕上显示
SDL_LockYUVOverlay(bmp);
AVPicture pict;
pict.data[0] = bmp->pixels[0];
pict.data[1] = bmp->pixels[2];
pict.data[2] = bmp->pixels[1];
pict.linesize[0] = bmp->pitches[0];
pict.linesize[1] = bmp->pitches[2];
pict.linesize[2] = bmp->pitches[1];
// Convert the image into YUV format that SDL uses
/*img_convert(&pict, PIX_FMT_YUV420P,
(AVPicture *)pFrame, pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height);*/
sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize,
0,pCodecCtx->height, pict.data, pict.linesize);
//解锁先前锁定的覆盖
SDL_UnlockYUVOverlay(bmp);
rect.x = 0;
rect.y = 0;
rect.w = rcDisplay.Width();
rect.h = rcDisplay.Height();
SDL_DisplayYUVOverlay(bmp, &rect);
}
}
// Free the packet that was allocated by av_read_frame
av_free_packet(&packet);
SDL_PollEvent(& event);
switch(event .type)
{
case SDL_QUIT:
SDL_Quit();
exit(0);
break;
default: break ;
}
}
// Free the YUV image
av_free(buffer);
//av_free(pFrameRGB);
// Free the YUV frame
av_free(pFrame);
// Close the codec
avcodec_close(pCodecCtx);
// Close the video file
av_close_input_file(pFormatCtx);
return ;
9 个解决方案
#1
你要根据PTS DTS做音视频同步
#2
http://blog.csdn.net/mu399/article/details/5814901
#3
没怎么看代码,太长!
视频播放太快的话,是不是帧率太大引起的,调低点试试
视频播放太快的话,是不是帧率太大引起的,调低点试试
#4
你是从文件里面读取出来的,一般简单的做一个sleep也是可以的,但是这个不准确
#5
调低了time_base,还是一样,但是pts和dts我不知道要设置成什么值
#6
用sleep没多大意义啊
#7
用ffmpeg了?那么请参考一下ffmpeg源码里那个ffplay.c吧
#8
最近在做音视频同步 蛋疼的很
#9
要做音视频同步
#1
你要根据PTS DTS做音视频同步
#2
http://blog.csdn.net/mu399/article/details/5814901
#3
没怎么看代码,太长!
视频播放太快的话,是不是帧率太大引起的,调低点试试
视频播放太快的话,是不是帧率太大引起的,调低点试试
#4
你是从文件里面读取出来的,一般简单的做一个sleep也是可以的,但是这个不准确
#5
调低了time_base,还是一样,但是pts和dts我不知道要设置成什么值
#6
用sleep没多大意义啊
#7
用ffmpeg了?那么请参考一下ffmpeg源码里那个ffplay.c吧
#8
最近在做音视频同步 蛋疼的很
#9
要做音视频同步