ffmpeg,Stagefright 的时间管理及a/v同步
来源:互联网 发布:初中英语单词大全软件 编辑:程序博客网 时间:2024/05/06 07:02
一、ffmpeg中的时间, dts, pts
stream由一个个packet组成,packet有两个时间:
dts: 解码时间
pts: 显示时间(Presentation timestamp)
因为解码的时候,可能会有一些包需要在另一些包之前解,所以需要两个时间分开,
比如,输出的时候 a b c d ,但解包的时候需要按 b a c d 的顺序去解,这样 a b 的pts dts就不是按顺序来。涉及到I B P帧的概念,这点有待验证。
最后的输出以pts为准,另外每个stream有一个time_base(即ffmpeg的时间单位,由一个分子分母组成的struct)的概念,最后packet的输出的时机为:
timestamp_output = pts * av_q2d(st->time_base)
二、Stagefright中的时间:
1、Stagefright中音频的播放最后由AudioTrack进行播放速度的控制(代码分析参考后面4)。
无论有无Video,XXXSource返回的kKeyTime不影响音频的播放(但必须返回,否则CHECK通不过)
2、如果只有Video,以video的kKeyTime控制视频速度,
3、如果两者都有,则以音频为准进行a/v同步:
1)、取audio时间,计算latenessUs
// mediaTimeUs为audio的kKeyTime
// realTimeUs为AudioTrack返回的实际播放时间
mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs);
mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
// timeUs为video的kKeyTime
latenessUs = nowUs - timeUs;
2)、如果快了,视频解码休息
if (latenessUs < -10000) { // 10ms
postVideoEvent_l(10000); // 即下一个mVideoEvent延迟触发。
}
事实上只有video时,控制解码速度也是通过这里控制的,即控制mVideoEvent触发频率。
3)、慢了,往前seek,或丢帧
if (latenessUs > 500000ll) { // 500ms
mSeekTimeUs = mediaTimeUs; // 直接seek
}
if (latenessUs > 40000) { // 40ms
mVideoBuffer = NULL; // 丢帧,立即触发下一个mVideoEvent
postVideoEvent_l();
}
4、AudioTrack对音频播放速度的控制
1)、AudioTrack与Output的数据交换通过共享内存实现,即AudioTrack中的mCblk,(本文不具体分析mCblk的建立及数据流程)
2)、AudioTrack建立的时候,初始化了一个AudioTrackThread,线程循环进入 AudioTrack::processAudioBuffer,不停的去获取解码后的数据,buffer写入mCblk
3)、
AudioTrack::processAudioBuffer
{
obtainBuffer(&audioBuffer, -1);
// 这里回调 AudioPlayer::fillBuffer() 返回解码后的数据
// 解码流程与video一致,可参考前文《Stagefright,omx与Component的交互》的分析
mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
releaseBuffer(&audioBuffer);
}
4)、
AudioTrack::obtainBuffer()
{
while (framesAvail == 0) {
// 这里根据cblk控制了Buffer的获得,也就控制了最后回调获取解码后数据的频率
// 也间接控制了audio解包速度
// 但最后audio播放速度的控制应该是由output层控制,有待output层分析考证!
result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
}
}
三、 Stagefright Extractor使用ffmpeg的demux时,时间的控制
XXXSource中read返回的mKeyTime 使用 ffmpeg中timestamp_output的计算方法,转换为微妙(us)
四、以音频为例,这里顺便简单介绍一下Stagefright的线程管理
1、Awesomeplyer中的mAudioSource分两种:
当没有Decode流程(即Extractor返回解码后数据,如FLAC)时,为XXXSource
由Decode流程时,为OMXCode
a、Awesomeplayer的message处理线程,通过onVideoEvent()驱动
b、AudioTrack的回调线程,通过AudioTrack::processAudioBuffer驱动
mAudioSource 为OMXCodec时,通过OMXCodec::on_message驱动 (注意此时AudioTrack线程也在回调,但最后只是取回解码数据,并不驱动read)
stream由一个个packet组成,packet有两个时间:
dts: 解码时间
pts: 显示时间(Presentation timestamp)
因为解码的时候,可能会有一些包需要在另一些包之前解,所以需要两个时间分开,
比如,输出的时候 a b c d ,但解包的时候需要按 b a c d 的顺序去解,这样 a b 的pts dts就不是按顺序来。涉及到I B P帧的概念,这点有待验证。
最后的输出以pts为准,另外每个stream有一个time_base(即ffmpeg的时间单位,由一个分子分母组成的struct)的概念,最后packet的输出的时机为:
timestamp_output = pts * av_q2d(st->time_base)
二、Stagefright中的时间:
1、Stagefright中音频的播放最后由AudioTrack进行播放速度的控制(代码分析参考后面4)。
无论有无Video,XXXSource返回的kKeyTime不影响音频的播放(但必须返回,否则CHECK通不过)
2、如果只有Video,以video的kKeyTime控制视频速度,
3、如果两者都有,则以音频为准进行a/v同步:
1)、取audio时间,计算latenessUs
// mediaTimeUs为audio的kKeyTime
// realTimeUs为AudioTrack返回的实际播放时间
mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs);
mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
// timeUs为video的kKeyTime
latenessUs = nowUs - timeUs;
2)、如果快了,视频解码休息
if (latenessUs < -10000) { // 10ms
postVideoEvent_l(10000); // 即下一个mVideoEvent延迟触发。
}
事实上只有video时,控制解码速度也是通过这里控制的,即控制mVideoEvent触发频率。
3)、慢了,往前seek,或丢帧
if (latenessUs > 500000ll) { // 500ms
mSeekTimeUs = mediaTimeUs; // 直接seek
}
if (latenessUs > 40000) { // 40ms
mVideoBuffer = NULL; // 丢帧,立即触发下一个mVideoEvent
postVideoEvent_l();
}
4、AudioTrack对音频播放速度的控制
1)、AudioTrack与Output的数据交换通过共享内存实现,即AudioTrack中的mCblk,(本文不具体分析mCblk的建立及数据流程)
2)、AudioTrack建立的时候,初始化了一个AudioTrackThread,线程循环进入 AudioTrack::processAudioBuffer,不停的去获取解码后的数据,buffer写入mCblk
3)、
AudioTrack::processAudioBuffer
{
obtainBuffer(&audioBuffer, -1);
// 这里回调 AudioPlayer::fillBuffer() 返回解码后的数据
// 解码流程与video一致,可参考前文《Stagefright,omx与Component的交互》的分析
mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
releaseBuffer(&audioBuffer);
}
4)、
AudioTrack::obtainBuffer()
{
while (framesAvail == 0) {
// 这里根据cblk控制了Buffer的获得,也就控制了最后回调获取解码后数据的频率
// 也间接控制了audio解包速度
// 但最后audio播放速度的控制应该是由output层控制,有待output层分析考证!
result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
}
}
三、 Stagefright Extractor使用ffmpeg的demux时,时间的控制
XXXSource中read返回的mKeyTime 使用 ffmpeg中timestamp_output的计算方法,转换为微妙(us)
四、以音频为例,这里顺便简单介绍一下Stagefright的线程管理
1、Awesomeplyer中的mAudioSource分两种:
当没有Decode流程(即Extractor返回解码后数据,如FLAC)时,为XXXSource
由Decode流程时,为OMXCode
两者都是继承自MediaSource。
a、Awesomeplayer的message处理线程,通过onVideoEvent()驱动
b、AudioTrack的回调线程,通过AudioTrack::processAudioBuffer驱动
c、OMX的Aloop线程,通过回调 OMXCodec::on_message驱动
mAudioSource 为OMXCodec时,通过OMXCodec::on_message驱动 (注意此时AudioTrack线程也在回调,但最后只是取回解码数据,并不驱动read)
- ffmpeg,Stagefright 的时间管理及a/v同步
- A-V同步
- android stagefright音视频时间管理
- gstreamer A/V同步技术
- Gstreamer的一些基本概念与A/V同步分析
- Android多媒体之OpenCore的A/V同步机制
- Android多媒体之OpenCore的A/V同步机制
- Gstreamer的一些基本概念与A/V同步分析
- Gstreamer的一些基本概念与A/V同步分析(转载)
- Gstreamer的一些基本概念与A/V同步分析
- Android多媒体之OpenCore的A/V同步机制
- Gstreamer的一些基本概念与A/V同步分析
- Gstreamer的一些基本概念与A/V同步分析
- Gstreamer的一些基本概念与A/V同步分析
- Gstreamer的一些基本概念与A/V同步分析
- Stagefright (7) - Audio和Video的同步
- Stagefright (7) - Audio和Video的同步
- Stagefright (7) - Audio和Video的同步
- 程序锁的核心基本原理
- 学习水平方向进度条的方法
- junit批量测试
- kiki's game
- jsp 及 servlet 读写UTF-8 txt 乱码 解决方法
- ffmpeg,Stagefright 的时间管理及a/v同步
- 梦想的启航,那些年,那些书
- 【心情日记】从这里开始吧
- 如何在xmapp上搭建dvwa
- 手机连接wifi 显示“正在获取IP”解决方法
- 阿里巴巴笔试题
- hdu 4767 Bell
- Opengl Coordinate System
- 【LeetCode】Binary Tree Level Order Traversal--(二叉树层序遍历)