zoukankan      html  css  js  c++  java
  • libstagefright 音视频同步方案

    1:音视频数据都有一个list,用于存放解码后的数据;
       List mFilledBuffers;
    2:解码后的音视频数据不断的往list中存放,不做音视频同步方面的时间上控制
       mFilledBuffers.push_back(i);
    3:音视频同步主要表现在从list中取数据进行视频的显示和音频的输出;
    4:其中audio数据在线程函数threadLoop中调用AudioPlayer的回调函数循环读取,不做时间上的控制;
    4:视频数据正常情况下按照每10ms的时间取一次,如果有音视频不同步的情况,就可能需要做以下三种情况的处理
       1:如果视频数据过快,超过音频时间10ms,则显示当前帧后,将读取数据的事件延时(慢的时间-10ms)后放入队列;
       2:如果视频数据过慢,慢于音频时间40ms,则丢弃当前帧,然后再去取数据;
       3:如果视频数据过慢,慢于音频时间500ms,则丢弃当前帧,并且需要丢弃一段视频帧,直接对video部分(SEEK_VIDEO_ONLY)seek到音频当前帧的时间戳;
       PS:上面的三个时间参数可能会微调;
    6:视频当前时间是指视频当前帧携带的时间戳,是通过该帧的sampleIndex从stts表中读取出来的;
       int64_t timeUs;
       CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
    7:音频的时间戳通过以下方式计算:
        result + diffUs - realtime_us + mediatime_us = -mLatencyUs + ALooper::GetNowUs() - mNumFramesPlayedSysTimeUs + mediatime_us
        mNumFramesPlayedSysTimeUs = ALooper::GetNowUs() 和前面那个函数有一定的时间差
    8:循环读取数据的机制       
       android中循环读取数据都是通过Thread类的threadLoop函数实现,这个函数的介绍如下:
          Derived class must implement threadLoop(). The thread starts its life here. There are two ways of using the Thread object:
         1) loop: if threadLoop() returns true, it will be called again if
                  requestExit() wasn't called.
         2) once: if threadLoop() returns false, the thread will exit upon return.
         virtual bool        threadLoop() = 0;
       如果函数返回true,且没有调用requestExit()函数,则一直循环执行  ----------正常播放情况
       如果函数返回true,但调用requestExit()函数,则停止执行          ----------停止播放情况
       如果函数返回false,执行一次后返回 
    9:正常情况下音视频对应的threadLoop函数都在循环执行,并没有时间上的控制,音频数据确实如此,但是视频数据通过下面的机制控制读取
       读取视频数据被封装为一个个事件,这些事件都会携带一个什么执行的时间戳,这些事件按照执行时间的先后顺序放入一个队列;
       threadLoop函数循环执行的时候,会判断当前时间和队头事件的时间戳
           前者大于等于后者,取出时间执行,return true;
           前者小于后者,做下面的操作:       
            int64_t whenUs = (*mEventQueue.begin()).mWhenUs;
            int64_t nowUs = GetNowUs();
            if (whenUs > nowUs) {
                int64_t delayUs = whenUs - nowUs;
                mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);
                return true;
            event = *mEventQueue.begin();
            mEventQueue.erase(mEventQueue.begin());
            gLooperRoster.deliverMessage(event.mMessage);
  • 相关阅读:
    Codeforces Round #319 (Div. 2) D
    因为网络请求是 异步的,
    ios真蛋疼,
    单例模式的两种实现,
    jump, jump,
    一点 误删,
    关于代理,
    button上的两个手势,
    数据,
    header 的蓝色,
  • 原文地址:https://www.cnblogs.com/nsnow/p/3872272.html
Copyright © 2011-2022 走看看