ffmpeg+sdl播放视频过快

ronaldomanu999 2013-10-18 05:11:57
AVFormatContext *pFormatCtx;
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 ;
...全文
279 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
zwtchy123 2013-12-04
  • 打赏
  • 举报
回复
要做音视频同步
luoxiang000 2013-10-22
  • 打赏
  • 举报
回复
最近在做音视频同步 蛋疼的很
ronaldomanu999 2013-10-21
  • 打赏
  • 举报
回复
引用 4 楼 luoxiang000 的回复:
你是从文件里面读取出来的,一般简单的做一个sleep也是可以的,但是这个不准确
用sleep没多大意义啊
ronaldomanu999 2013-10-21
  • 打赏
  • 举报
回复
引用 3 楼 max_min_ 的回复:
没怎么看代码,太长! 视频播放太快的话,是不是帧率太大引起的,调低点试试
调低了time_base,还是一样,但是pts和dts我不知道要设置成什么值
mstlq 2013-10-21
  • 打赏
  • 举报
回复
用ffmpeg了?那么请参考一下ffmpeg源码里那个ffplay.c吧
luoxiang000 2013-10-18
  • 打赏
  • 举报
回复
你是从文件里面读取出来的,一般简单的做一个sleep也是可以的,但是这个不准确
max_min_ 2013-10-18
  • 打赏
  • 举报
回复
没怎么看代码,太长! 视频播放太快的话,是不是帧率太大引起的,调低点试试
luoxiang000 2013-10-18
  • 打赏
  • 举报
回复
http://blog.csdn.net/mu399/article/details/5814901
luoxiang000 2013-10-18
  • 打赏
  • 举报
回复
你要根据PTS DTS做音视频同步

64,683

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧