MediaPlayer补充

一般播放器模式:三个线程
1.解码线程:audiotrack将数据解码出来往共享缓存写
2.播放线程:AudioFlinger中的播放线程从共享缓存读取数据,然后往bsp写
3.控制线程:控制视频和音频的播放,从而保持一致。

status_t AwesomePlayer::prepareAsync_l() {
    if (!mQueueStarted) {
        mQueue.start();           //开启一个事件队列,不停的处理各种事件
        mQueueStarted = true;
    }

    modifyFlags(PREPARING, SET);
    mAsyncPrepareEvent = new AwesomeEvent(this, &AwesomePlayer::onPrepareAsyncEvent);  
    mQueue.postEvent(mAsyncPrepareEvent);  //发送第一个事件:PrepareAsyncEvent,做些初始化的事件。当处理这个事情的时候回调AwesomePlayer::onPrepareAsyncEvent
    return OK;
}

 

//做一些初始化的操作:初始化AudioDecoder和VideoDecoder
void
AwesomePlayer::onPrepareAsyncEvent() { finishSetDataSource_l(); initVideoDecoder(); initAudioDecoder(); } status_t AwesomePlayer::finishSetDataSource_l() { dataSource = DataSource::CreateFromURI(mUri.string(),...); sp<</span>MediaExtractor> extractor= MediaExtractor::Create(dataSource);  //依据mime类型来创建对应的解码器
 return setDataSource_l(extractor);  //然后依据extractor做A/V分离 }

 视频文件存储数据方式:一段一段的存储,每一段都有个头标识这一段是视频部分还是音频部分。

http://blog.csdn.net/mci2004/article/details/7629146

 

awesomeplayer中主要有如下几个事件
sp<TimedEventQueue::Event> mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent); --- 显示一帧画面,并负责同步处理
sp<TimedEventQueue::Event> mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone); -- 播放结束的处理
sp<TimedEventQueue::Event> mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate); -- cache数据
sp<TimedEventQueue::Event> mCheckAudioStatusEvent = new AwesomeEvent(this, &AwesomePlayer::onCheckAudioStatus); -- 监测audio 状态:seek以及播放结束
sp<TimedEventQueue::Event> mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate); -- 监测video 解码性能
sp<TimedEventQueue::Event> mAsyncPrepareEvent = new AwesomeEvent(this, &AwesomePlayer::onPrepareAsyncEvent); -- 完成prepareAsync工作
----------------------------------------------------------------------------------------------------------------------

把音视频轨道分离,生成mVideoTrack和mAudioTrack两个MediaSource。代码如下(AwesomePlayer.cpp):
   if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
        setVideoSource(extractor->getTrack(i));
        haveVideo = true;
   } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
        setAudioSource(extractor->getTrack(i));
        haveAudio = true;
   }

得到的这两个MediaSource,只具有parser功能,没有decode功能。还需要对这两个MediaSource做进一步的包装,获取了两个MediaSource(具有parse和decode功能):

initVideoDecoder()
mVideoSource = OMXCodec::Create(
            mClient.interface(), mVideoTrack->getFormat(),
            false, // createEncoder
            mVideoTrack,
            NULL, flags);

initAudioDecoder()
mAudioSource = OMXCodec::Create(
                mClient.interface(), mAudioTrack->getFormat(),
                false, // createEncoder
                mAudioTrack);
    当调用MediaSource.start()方法后,它的内部就会开始从数据源获取数据并解析,等到缓冲区满后便停止。在AwesomePlayer里就可以调用MediaSource的read方法读取解码后的数据。
    对于mVideoSource来说,读取的数据:mVideoSource->read(&mVideoBuffer, &options)交给显示模块进行渲染,mVideoRenderer->render(mVideoBuffer);
    对mAudioSource来说,用mAudioPlayer对mAudioSource进行封装,然后由mAudioPlayer负责读取数据和播放控制。
-----------------------------------------------------------------------------------------------------------------------------

//MediaPlayer.cpp
new MediaPlayer() {
    mStreamType = AUDIO_STREAM_MUSIC;//给的默认流类型是MUSIC
}

status_t MediaPlayer::prepare()
{
    status_t ret = prepareAsync_l();
}

status_t MediaPlayer::prepareAsync_l()
{
    mPlayer->setAudioStreamType(mStreamType);
    mCurrentState = MEDIA_PLAYER_PREPARING;
    return mPlayer->prepareAsync();
}

-----------------------------------------------------------------------------------------------

static player_type getDefaultPlayerType() {
    char value[PROPERTY_VALUE_MAX];
    if (property_get("media.stagefright.use-awesome", value, NULL)
            && (!strcmp("1", value) || !strcasecmp("true", value))) {
        return STAGEFRIGHT_PLAYER;
    }

    // TODO: remove this EXPERIMENTAL developer settings property
    if (property_get("persist.sys.media.use-awesome", value, NULL)
            && !strcasecmp("true", value)) {
        return STAGEFRIGHT_PLAYER;
    }

    return NU_PLAYER;
}


enum player_type {
    PV_PLAYER = 1,
    SONIVOX_PLAYER = 2,
    STAGEFRIGHT_PLAYER = 3,
    NU_PLAYER = 4,
    TEST_PLAYER = 5,
    DLNA_PLAYER = 1001,
    DTCPIP_PLAYER = 1002,
};

sony播放器优先使用NuPlayer来播放

~/log$ adb shell getprop |grep stagefright
[media.stagefright.enable-aac]: [true]
[media.stagefright.enable-fma2dp]: [true]
[media.stagefright.enable-http]: [true]
[media.stagefright.enable-player]: [true]
[media.stagefright.enable-qcp]: [true]
[media.stagefright.enable-scan]: [true]
daichenghui@daichenghui-OptiPlex-3020:~/log$

为了使用stagefrightplayer来播放,可以设置属性来达到目的

adb root && adb remount

adb shell setprop media.stagefright.use-awesome  1   //这里也可以设置成true

~/log$ adb shell getprop |grep stagefright
[media.stagefright.enable-aac]: [true]
[media.stagefright.enable-fma2dp]: [true]
[media.stagefright.enable-http]: [true]
[media.stagefright.enable-player]: [true]
[media.stagefright.enable-qcp]: [true]
[media.stagefright.enable-scan]: [true]
[media.stagefright.use-awesome]: [1]
daichenghui@daichenghui-OptiPlex-3020:~/log$

---------------------------------------------------------------------------

stagefright框架播放时,都会不停的调用size_t AudioPlayer::fillBuffer(void *data, size_t size)

而且AudioPlayer: mAudioSink.get() != NULL 也就是说回调函数是AudioSinkCallback

1.如果播放mp3数据  offload模式播放

2.如果播放raw AudioPlayer: buffer->size() = 32766, mPositionTimeMediaUs=0.00 mPositionTimeRealUs=0.00

size_t AudioPlayer::AudioSinkCallback(
        MediaPlayerBase::AudioSink * /* audioSink */,
        void *buffer, size_t size, void *cookie,
        MediaPlayerBase::AudioSink::cb_event_t event) {
    AudioPlayer *me = (AudioPlayer *)cookie;

    switch(event) {
    case MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER:
        return me->fillBuffer(buffer, size);

    case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END:
        ALOGV("AudioSinkCallback: stream end");
        me->mReachedEOS = true;
        me->notifyAudioEOS();
        break;

    case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN:
        ALOGV("AudioSinkCallback: Tear down event");
        me->mObserver->postAudioTearDown();
        break;
    }

    return 0;
}

 --------------------------------------------------------------------------------

AudioSystem是AudioPolicyService和AudioFlinger对外提供接口类。

[11:06:09] 刘思云: mmm external/tinyalsa/
[11:06:18] 刘思云: 生成alsa工具
[11:06:28] 刘思云: tinyplay/tinymix/tinycap
 -------------------------------------------------------------------

播放线程之间的关系:
线程1:UI线程prepare()的时候会在AudioPlayer中起一个线程mQueue来控制音频和视频的同步等控制
线程2:每创建一个track时,cbf!=null 都会创建这个track对应的工作线程AudioTrack::AudioTrackThread来调用回调函数,从而调用fillbuffer

AwesomePlayer {

    sp<MediaSource> mAudioTrack; //offload和raw模式下一般选择这个
    sp<MediaSource> mOmxSource;//一般不选这个
    sp<MediaSource> mAudioSource = mAudioTrack; //最终使用的MediaSource,这个是音频轨
    AudioPlayer *mAudioPlayer = new AudioPlayer(mAudioSink, flags, this);
    mAudioPlayer->setSource(mAudioSource);

   status_t AwesomePlayer::initAudioDecoder() {
         mOffloadAudio = canOffloadStream(meta, (mVideoSource != NULL), isStreamingHTTP(), streamType);
         //canOffloadStream()=> AudioSystem::isOffloadSupported(info)=>aps->isOffloadSupported(info)
         if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
             ALOGV("createAudioPlayer: bypass OMX (raw)");
             mAudioSource = mAudioTrack;
         } else {
             // If offloading we still create a OMX decoder as a fall-back
            // but we don't start it
            mOmxSource = OMXCodec::Create(
                mClient.interface(), mAudioTrack->getFormat(),
                false, // createEncoder
                mAudioTrack);

             if (mOffloadAudio) {
                 ALOGV("createAudioPlayer: bypass OMX (offload)");
                 mAudioSource = mAudioTrack;
             } else {
                mAudioSource = mOmxSource;
             }
         }

          status_t err = mAudioSource->start();
     }
}

class AudioPlayer{
    void AudioPlayer::setSource(const sp<MediaSource> &source) {
        mSource = source;
    }

    fillBuffer() {
        mSource->read(&mInputBuffer, &options);
    }
}

线程3:AudioFlinger中创建一个track的同时可能会创建一个播放线程PlayBackThread(如果该播放线程不存在)。

线程4:创建client的线程,这个线程始终只有一个。而且随着MediaPlayerService的启动而创建。来提供给外部MediaPlayer调用的。
也就是说UI只是通过MediaPlayerService::client发送一些简单命令。UI线程跟读写数据的线程是没有直接关系的。它只是负责一些简单的控制如start() stop()等
AudioFlinger中存在3个线程来协同工作:
一个是回调AudioPlayer::fillbuffer()=>track::write()写数据的线程
第二个是PlayerBackThread读数据往dsp写数据

第三个是创建client的线程,这个线程始终只有一个。而且随着MediaPlayerService的启动而创建。来提供给外部MediaPlayer调用的。

 -------------------------------------------------------------------------------

status_t MediaPlayerService::AudioCache::open()这个是流媒体用的,将数据存在cache中

status_t MediaPlayerService::AudioOutput::start()一般是用来播放本地媒体的

status_t MediaPlayerService::AudioOutput::start()
{
    ALOGV("start");
    if (mCallbackData != NULL) {
        mCallbackData->endTrackSwitch();
    }
    if (mTrack != 0) {
        mTrack->setVolume(mLeftVolume, mRightVolume);
        mTrack->setAuxEffectSendLevel(mSendLevel);
        return mTrack->start();
    }
    return NO_INIT;
}

 -----------------------------------------------------

class AudioPlayer : public TimeSource {}

//offload 模式下
fillBuffer(){ 
       if (mInputBuffer == NULL) {
            ALOGD("mInputBuffer == NULL");
            status_t err;

            if (mIsFirstBuffer) {
                ALOGD("mIsFirstBuffer == true");
                mInputBuffer = mFirstBuffer;
                mFirstBuffer = NULL;
                err = mFirstBufferResult;

                mIsFirstBuffer = false;
            } else {
                ALOGD("mIsFirstBuffer == false mSource->read()");
                err = mSource->read(&mInputBuffer, &options);
                if (err == OK && mInputBuffer == NULL && mSourcePaused) {
                    ALOGV("mSourcePaused, return 0 from fillBuffer");
                    return 0;
                }
            }
}

92:04-16 05:17:57.255   347  2082 E AudioPlayer: mAudioSink.get() ?
93:04-16 05:17:57.255   347  2082 E AudioPlayer: mAudioSink.get() != NULL
94:04-16 05:17:57.255   347  2082 V AudioPlayer: start, mBitsPerSample 16, mSampleRate 44100, channelMask 0, audioFormat 16777216
208:04-16 05:17:57.288   347  7212 V AudioPlayer: AudioCallback fillBuffer()
209:04-16 05:17:57.288   347  7212 V AudioPlayer: AudioCallback
210:04-16 05:17:57.288   347  7212 D AudioPlayer: mInputBuffer == NULL
211:04-16 05:17:57.288   347  7212 D AudioPlayer: mIsFirstBuffer == true
212:04-16 05:17:57.288   347  7212 D AudioPlayer: mInputBuffer == NULL
213:04-16 05:17:57.288   347  7212 D AudioPlayer: mIsFirstBuffer == false mSource->read()
214:04-16 05:17:57.288   347  7212 D AudioPlayer: mInputBuffer == NULL
215:04-16 05:17:57.288   347  7212 D AudioPlayer: mIsFirstBuffer == false mSource->read()
216:04-16 05:17:57.288   347  7212 D AudioPlayer: mInputBuffer == NULL
217:04-16 05:17:57.288   347  7212 D AudioPlayer: mIsFirstBuffer == false mSource->read()
......................
570:04-16 05:17:57.316   347  7212 V AudioPlayer: AudioCallback fillBuffer()
571:04-16 05:17:57.316   347  7212 D AudioPlayer: mInputBuffer == NULL
572:04-16 05:17:57.316   347  7212 D AudioPlayer: mIsFirstBuffer == false mSource->read()
573:04-16 05:17:57.316   347  7212 D AudioPlayer: mInputBuffer == NULL
574:04-16 05:17:57.316   347  7212 D AudioPlayer: mIsFirstBuffer == false mSource->read()
........................

570:04-16 05:17:57.316   347  7212 V AudioPlayer: AudioCallback fillBuffer()
571:04-16 05:17:57.316   347  7212 D AudioPlayer: mInputBuffer == NULL
572:04-16 05:17:57.316   347  7212 D AudioPlayer: mIsFirstBuffer == false mSource->read()
573:04-16 05:17:57.316   347  7212 D AudioPlayer: mInputBuffer == NULL
574:04-16 05:17:57.316   347  7212 D AudioPlayer: mIsFirstBuffer == false mSource->read()

 非offload模式

116:04-16 05:17:25.440   347  1054 E AudioPlayer: mAudioSink.get() ?
117:04-16 05:17:25.440   347  1054 E AudioPlayer: mAudioSink.get() != NULL
118:04-16 05:17:25.440   347  1054 V AudioPlayer: start, mBitsPerSample 24, mSampleRate 32000, channelMask 3, audioFormat 6
185:04-16 05:17:25.449   347  7188 V AudioPlayer: AudioCallback fillBuffer()
186:04-16 05:17:25.450   347  7188 V AudioPlayer: AudioCallback
187:04-16 05:17:25.450   347  7188 D AudioPlayer: mInputBuffer == NULL
188:04-16 05:17:25.450   347  7188 D AudioPlayer: mIsFirstBuffer == true
189:04-16 05:17:25.450   347  7188 V AudioPlayer: buffer->size() = 32766, mPositionTimeMediaUs=0.00 mPositionTimeRealUs=0.00
191:04-16 05:17:25.450   347  7188 V AudioPlayer: AudioCallback fillBuffer()
193:04-16 05:17:25.450   347  7188 V AudioPlayer: AudioCallback fillBuffer()
198:04-16 05:17:25.454   347   347 V AudioPlayer: getRealTimeUsLocked -196401
251:04-16 05:17:25.747   347  7188 V AudioPlayer: AudioCallback fillBuffer()
255:04-16 05:17:25.772   347  7188 V AudioPlayer: AudioCallback fillBuffer()
257:04-16 05:17:25.772   347  7188 V AudioPlayer: AudioCallback fillBuffer()
258:04-16 05:17:25.772   347  7188 D AudioPlayer: mInputBuffer == NULL
259:04-16 05:17:25.772   347  7188 D AudioPlayer: mIsFirstBuffer == false mSource->read()
260:04-16 05:17:25.773   347  7188 V AudioPlayer: buffer->size() = 32766, mPositionTimeMediaUs=0.17 mPositionTimeRealUs=0.17
284:04-16 05:17:25.871   347  7188 V AudioPlayer: AudioCallback fillBuffer()
287:04-16 05:17:25.901   347  7188 V AudioPlayer: AudioCallback fillBuffer()
288:04-16 05:17:25.901   347  7188 D AudioPlayer: mInputBuffer == NULL
289:04-16 05:17:25.901   347  7188 D AudioPlayer: mIsFirstBuffer == false mSource->read()
290:04-16 05:17:25.901   347  7188 V AudioPlayer: buffer->size() = 32766, mPositionTimeMediaUs=0.34 mPositionTimeRealUs=0.34

 ------------------------------------------------------------------------------------

daichenghui@daichenghui-OptiPlex-3020:~/log/log$ grep -n AwesomePlayer  raw.log
74:04-16 05:17:25.347   347   347 V AwesomePlayer: AwesomePlayer running on behalf of uid 10247
80:04-16 05:17:25.431   347   347 V AwesomePlayer: track of type 'audio/raw' does not publish bitrate
81:04-16 05:17:25.431   347   347 V AwesomePlayer: mBitrate = -1 bits/sec
87:04-16 05:17:25.434   347  7187 D AwesomePlayer: AwesomePlayer::initAudioDecoder()
91:04-16 05:17:25.434   347  7187 V AwesomePlayer: createAudioPlayer: bypass OMX (raw)   mAudioSource = mAudioTrack
93:04-16 05:17:25.434   347  7187 I AwesomePlayer: Could not offload audio decode, try pcm offload
112:04-16 05:17:25.440   347  1054 V AwesomePlayer: createAudioPlayer_l()

04-27 13:37:27.357   344   964 D AudioFlinger: mNormalSink != 0
04-27 13:37:27.357   344   964 D AudioFlinger: mNormalSink != 0 mNormalSink->write()
04-27 13:37:27.357   344   964 D audio_hw_primary: out_write()
04-27 13:37:27.377   344   964 D AudioFlinger: mNormalSink != 0
04-27 13:37:27.377   344   964 D AudioFlinger: mNormalSink != 0 mNormalSink->write()
04-27 13:37:27.377   344   964 D audio_hw_primary: out_write()

------------------------------
daichenghui@daichenghui-OptiPlex-3020:~/log/log$ grep -n AwesomePlayer  offload.log
47:04-16 05:17:57.222   347  1054 V AwesomePlayer: AwesomePlayer running on behalf of uid 10247
53:04-16 05:17:57.246   347  1054 V AwesomePlayer: mBitrate = 128000 bits/sec
59:04-16 05:17:57.248   347  7209 D AwesomePlayer: AwesomePlayer::initAudioDecoder()
74:04-16 05:17:57.252   347  7209 V AwesomePlayer: createAudioPlayer: bypass OMX (offload) mAudioSource = mAudioTrack;
89:04-16 05:17:57.255   347  2082 V AwesomePlayer: createAudioPlayer_l()

04-27 13:35:45.626   344  8004 D AudioFlinger: mNormalSink == 0
04-27 13:35:45.626   344  8004 D audio_hw_primary: out_write()
04-27 13:35:45.628   344  8004 V AudioFlinger: OffloadThread::prepareTracks_l active tracks 1
04-27 13:35:45.629   344  8004 D AudioFlinger: mNormalSink == 0
04-27 13:35:45.629   344  8004 D audio_hw_primary: out_write()

---------------------------------------------------------------------------------------

 

posted @ 2015-04-14 10:55  牧 天  阅读(578)  评论(0)    收藏  举报