原文地址:http://blog.yundiantech.com/?log=blog&id=11
前面分别讲解了:
用FFMPEG和Qt解码视频并显示到界面上。
用FFMPEG+SDL解码播放音频。
现在我们就将视频和音频合并,并让声音和画面同步。
加入音频的部分就不做讲解了,这里主要讲下声音和视频同步的步骤。
首先刚开始播放的时候通过av_gettime()获取系统主时钟,记录下来。
以后便不断调用av_gettime()获取系统时钟 减去之前记录下的差值,便得到了一个视频播放了多久的实际时间。
对于视频的同步我们这样做:
从视频读取出的数据中包含一个pts的信息(每一帧图像都会带有pts的信息,pts就是播放视频的时候此图像应该显示的时间)。 这样只需要使用pts和前面获取的时间进行对比,pts比实际时间大,就调用sleep函数等一等,否则就直接播放出来。这样就达到了某种意义上的同步了。
而对于音频:
从前面使用SDL的例子,其实就能够发现一个现象:我们读取音频的线程差不多就是瞬间读完放入队列的,但是音频播放速度却是正常的,并不是一下子播放完毕。因此可以看出,在音频播放上,SDL已经帮我们做了处理了,只需要将数据直接交给SDL就行了。
视频部分同步代码大致如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
int64_t start_time = av_gettime();
int64_t pts = 0;
//当前视频的pts
while
(1)
{
if
(av_read_frame(pFormatCtx, packet) < 0)
{
break
;
//这里认为视频读取完了
}
int64_t realTime = av_gettime() - start_time;
//主时钟时间
while
(pts > realTime)
{
SDL_Delay(10);
realTime = av_gettime() - start_time;
//主时钟时间
}
if
(packet->stream_index == videoStream)
{
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,packet);
if
(packet->dts == AV_NOPTS_VALUE && pFrame->opaque&& *(uint64_t*) pFrame->opaque != AV_NOPTS_VALUE)
{
pts = *(uint64_t *) pFrame->opaque;
}
else
if
(packet->dts != AV_NOPTS_VALUE)
{
pts = packet->dts;
}
else
{
pts = 0;
}
pts *= 1000000 * av_q2d(mVideoState.video_st->time_base);
pts = synchronize_video(&mVideoState, pFrame, pts);
if
(got_picture) {
sws_scale(img_convert_ctx,
(uint8_t
const
*
const
*) pFrame->data,
pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data,
pFrameRGB->linesize);
//把这个RGB数据 用QImage加载
QImage tmpImg((uchar *)out_buffer,pCodecCtx->width,pCodecCtx->height,QImage::Format_RGB32);
QImage image = tmpImg.copy();
//把图像复制一份 传递给界面显示
emit sig_GetOneFrame(image);
//发送信号
}
av_free_packet(packet);
}
|
synchronize_video函数是根据解码后的视频数据 计算出视频的pts:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
static
double
synchronize_video(VideoState *is, AVFrame *src_frame,
double
pts) {
double
frame_delay;
if
(pts != 0) {
/* if we have pts, set video clock to it */
is->video_clock = pts;
}
else
{
/* if we aren't given a pts, set it to the clock */
pts = is->video_clock;
}
/* update the video clock */
frame_delay = av_q2d(is->video_st->codec->time_base);
/* if we are repeating a frame, adjust clock accordingly */
frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
is->video_clock += frame_delay;
return
pts;
}
|
到此,播放器已经有点样子了,已经可以播放大部分的视频了,是的,我说的是大部分,还有些特别的视频,播放的时候音视频同步有问题,后面再来完善它。
完整工程下载地址:
http://download.csdn.net/detail/qq214517703/9628842
音视频技术交流讨论欢迎加 QQ群 121376426
原文地址:http://blog.yundiantech.com/?log=blog&id=11