Awesomeplayer 里解压和显示video的有关分析
来源:互联网 发布:dnf一键任务源码 2016 编辑:程序博客网 时间:2024/05/17 08:19
播放一个视频开始时要调用prepare , 在prepare 里调用 TimedEventQueue::start() ,即mQueue.start() ,会启动一个线程,然后在TimedEventQueue::threadEntry() 会收事件,处理事件。
TimedEventQueue 是一个按照事件约定时间来执行事件携带动作的类。事件的约定时间存在 QueueItem::realtime_us 里,往TimedEventQueue发事件使用 TimedEventQueue::postTimedEvent ,该方法除this以外的第一个参数是事件,第二个参数是该事件约定的执行时间,它是按顺序往列表里填事件的,请看这段代码:
TimedEventQueue::event_id TimedEventQueue::postTimedEvent() {
....
List<QueueItem>::iterator it = mQueue.begin();
while (it != mQueue.end() && realtime_us >= (*it).realtime_us) {
++it;
}
QueueItem item;
item.event = event;
item.realtime_us = realtime_us;
if (it == mQueue.begin()) {
mQueueHeadChangedCondition.signal();
}
mQueue.insert(it, item);
....
}
在TimedEventQueue::threadEntry()按顺序查事件:
List<QueueItem>::iterator it = mQueue.begin();
eventID = (*it).event->eventID();
按该事件约定时间延时后再取事件:event = removeEventFromQueue_l(eventID);
再执行事件携带的动作:event->fire(this, now_us);
事件携带的动作(Event::fire) 是在AwesomeEvent类里实现的
struct AwesomeEvent : public TimedEventQueue::Event {
AwesomeEvent(
AwesomePlayer *player,
void (AwesomePlayer::*method)())
: mPlayer(player),
mMethod(method) {
}
protected:
....
virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
(mPlayer->*mMethod)();
}
private:
AwesomePlayer *mPlayer;
void (AwesomePlayer::*mMethod)();
...
};
看下面两行代码:
virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
(mPlayer->*mMethod)();
}
mPlayer和mMethod 都是AwesomeEvent 的成员变量,(*mMethod)() 表示调用该指针指向的函数, mPlayer-> 表示把mPlayer 指针作为(*mMethod)()的第一个参数:this。
其中有关视频解压和显示的事件是 AwesomePlayer::mVideoEvent。
我们看看该事件是如何创建的:
AwesomePlayer::AwesomePlayer(){
.....
mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
}
可以看出 mVideoEvent 事件创建之后的 mPlayer是AwesomePlayer*, 而动作是AwesomePlayer::onVideoEvent。
我把AwesomePlayer::onVideoEvent()的代码简化和适当注释了一下放在了最后一段。开始通过调用mVideoSource->read(&mVideoBuffer, &options);来解压, 然后mVideoRenderer->render(mVideoBuffer);显示。中间有超时判断。不管哪个分支都有postVideoEvent_l()的调用,也就是说是每10ms就要触发一次解压和显示事件,然后根据视频帧的时戳决定是否延时。
在AwesomePlayer::onVideoEvent 里调用的 postVideoEvent_l(),原型是AwesomePlayer::postVideoEvent_l(int64_t delayUs=-1),声明缺省参数值是-1,所以在AwesomePlayer::onVideoEvent()不带参数调用的话,是以当时后延10ms的时间作为事件约定时间是来调用TimedEventQueue::postTimedEvent方法的。
通过 TimeSource *ts = ((mFlags & AUDIO_AT_EOS) || !(mFlags & AUDIOPLAYER_STARTED)) ? &mSystemTimeSource : mTimeSource;
这一句可以看出视频是用音频的时间作为同步参考时钟的。
void AwesomePlayer::onVideoEvent() {
Mutex::Autolock autoLock(mLock);
if (mSeeking != NO_SEEK) {
if (mVideoBuffer) {
mVideoBuffer->release();
mVideoBuffer = NULL;
}
}
for (;;) {
/// 这里做解压的动作,mVideoSource是一个基于OpenMax的decoder,在里面会通过连接的 DataSource 去读取原始的压缩数据,解压出可以显示的点阵数据。
status_t err = mVideoSource->read(&mVideoBuffer, &options); // mVideoSource is a video decoder
options.clearSeekTo();
break;
}
int64_t timeUs;
CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
mLastVideoTimeUs = timeUs;
TimeSource *ts =
((mFlags & AUDIO_AT_EOS) || !(mFlags & AUDIOPLAYER_STARTED))
? &mSystemTimeSource : mTimeSource; // mTimeSource = mAudioPlayer; so, timeSource is from audio.
if (mFlags & FIRST_FRAME) {
modifyFlags(FIRST_FRAME, CLEAR);
mSinceLastDropped = 0;
mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
}
int64_t realTimeUs, mediaTimeUs;
if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
&& mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
}
if (wasSeeking == NO_SEEK) { //忽略这一帧的显示
// Let's display the first frame after seeking right away.
int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
int64_t latenessUs = nowUs - timeUs;
if (latenessUs > 500000ll ) {
mVideoBuffer->release(); // delete this mediabuffer
mVideoBuffer = NULL;
mSeeking = SEEK_VIDEO_ONLY;
mSeekTimeUs = mediaTimeUs;
///给自己发一个10ms之后执行的事件。
postVideoEvent_l();
return;
}
if (latenessUs > 40000) { //忽略这一帧的显示
// We're more than 40ms late.
mVideoBuffer->release(); // delete this mediabuffer
mVideoBuffer = NULL;
++mStats.mNumVideoFramesDropped;
///给自己发一个10ms之后执行的事件。
postVideoEvent_l();
return;
}
if (latenessUs < -10000) {
// We're more than 10ms early.
///给自己发一个10ms之后执行的事件。
postVideoEvent_l(10000); // to display after a while
return;
}
}
if ((mNativeWindow != NULL)
&& (mVideoRendererIsPreview || mVideoRenderer == NULL)) {
mVideoRendererIsPreview = false;
initRenderer_l();
}
if (mVideoRenderer != NULL) {
mSinceLastDropped++;
//// 通过渲染库把点阵数据显示出来
mVideoRenderer->render(mVideoBuffer); // display it
}
mVideoBuffer->release();
mVideoBuffer = NULL;
if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) {
modifyFlags(SEEK_PREVIEW, CLEAR);
return;
}
///给自己发一个10ms之后执行的事件。
postVideoEvent_l();
}
- Awesomeplayer 里解压和显示video的有关分析
- AwesomePlayer 分析
- AwesomePlayer 源代码分析
- StagefrightPlayer&&AwesomePlayer 初步分析
- StagefrightPlayer&&AwesomePlayer 初步分析
- 2.awesomeplayer结构分析
- DirectX里的Video和Audio C#的哦
- linux 下tar命令有关的打包和解压
- linux shell ------有关文件的操作(压缩和解压)
- video buffer里的属性
- 有关ubi文件格式的解压
- Android-StageFright之数据流的封装和AwesomePlayer流程
- Android-StageFright之数据流的封装和AwesomePlayer流程
- Android-StageFright之数据流的封装和AwesomePlayer流程
- Android-StageFright之数据流的封装和AwesomePlayer流程
- Android-StageFright之数据流的封装和AwesomePlayer流程
- Android-StageFright之数据流的封装和AwesomePlayer流程
- Android-StageFright之数据流的封装和AwesomePlayer流程
- PAT中文1001-1005(Python 语言)
- tongeasy 中间件 API函数帮助文档
- extern 详解
- Android学习书籍参考
- ssh 免密码登录
- Awesomeplayer 里解压和显示video的有关分析
- 重载(overload)、覆盖(override)的区别
- android的一个activity的生命周期中有多少函数
- 第六章——根据执行计划优化性能(1)——理解哈希、合并、嵌套循环连接策略
- Orabbix插件的安装与配置
- 局域网中搭建James服务器并实现与外网收发邮件
- SQL表分区
- zookeeper安装
- dtree的一个简单的POJO树