AwesomePlayer 源代码分析

10 篇文章 1 订阅
3 篇文章 0 订阅
 

  1,AwesomeEvent 这个是同步相应的事件而做的一个类,跟framework层的looper和handler作用相似,player有一些异步操作比如解析文件,这些操作比较耗时,做异步操作然后做回调会有更好的用户体验

struct AwesomeEvent : public TimedEventQueue::Event

    继承自TimedEventQueue::Event  ,关于c++的内部类可以参考以前的blog,TimedEventQueue会起一个thread,来做event的post操作


 

  2, AwesomeRemoteRenderer

   AwesomeLocalRenderer

 这两个类是往surface上post数据,而remote据说是因为omx node的使用,还没有细研究,而localrenderer会根据有无硬件加速调用不同的方法


 

3 构造函数会初始化event,这些后面再说

mediaplayer的一般方法流程是

setdatasource

prepareAsync

start

现在只针对filesource做流程分析

 

 setdatasource 一般会设置file的uri

mUri = uri;现在只是设置一下uri,下面有段注释

    // The actual work will be done during preparation in the call to
    // ::finishSetDataSource_l to avoid blocking the calling thread in
    // setDataSource for any significant time.

现在不会做其他的操作,因为会消耗太多的时间有可能导致上层的ANR,这个操作是同步操作

重头戏就在prepareAsync里面了,看这个函数

    if (!mQueueStarted) {
        mQueue.start();
        mQueueStarted = true;
    }//会把eventqueue打开,为以后的event post做准备,这个时候会建立一个线程

    mAsyncPrepareEvent = new AwesomeEvent(
            this, &AwesomePlayer::onPrepareAsyncEvent);

    mQueue.postEvent(mAsyncPrepareEvent);
//为了能异步,postevent


 

到   onPrepareAsyncEvent()

 if (mUri.size() > 0) {
        status_t err = finishSetDataSource_l();

        if (err != OK) {
            abortPrepare(err);
            return;
        }
    }


 

finishSetDataSource_l();//这个就是上面注释的那个函数 这个函数会根据source类型建立不同的extractor

针对filesource,实际就是这个dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);//uriheaders为null,不用管它

接着跳转 到source = new FileSource(uri+7);建立filesource,它会注册不同的extractor,sniffer出不同的mimetype,操作filesource

接着回到  finishSetDataSource_l(),

sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource,mime);

这个时候datasource会sniffer出不同的extractor,从而根据mime type建立不同的extractor

最后就是setdatasource这个本来应该第一步做的操作

这个时候会解析出audio track和viedo track,为下面的codec做准备


    if (mVideoTrack != NULL && mVideoSource == NULL) {
        // Use NPT timestamps if playing
        // RTSP streaming with video only content
        // (no audio to drive the clock for media time)
        uint32_t flags = 0;
        if (mRTSPController != NULL && mAudioTrack == NULL) {
            flags |= OMXCodec::kUseNptTimestamp;
        }
        status_t err = initVideoDecoder(flags);

        if (err != OK) {
            abortPrepare(err);
            return;
        }
    }

    if (mAudioTrack != NULL && mAudioSource == NULL) {
        status_t err = initAudioDecoder();

        if (err != OK) {
            abortPrepare(err);
            return;
        }
    }

这个就是涉及最关键的部分了 codec部分

从上面下来 audiotrack 和videotrack都已经有了 这个时候就要初始化codec了

initVideoDecoder(flags);

initAudioDecoder();


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

OMXCodec是个很关键的类,这个就到了前几天写的stagefright的code里面了,我会继续写那个,不在这里说了,总之会返回一个Vide​osource,这个是根据videotrack解码过的数据


    if (mVideoSource != NULL) {

        int64_t durationUs;
        if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
            Mutex::Autolock autoLock(mMiscStateLock);
            if (mDurationUs < 0 || durationUs > mDurationUs) {
                mDurationUs = durationUs;
            }
        }

        CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
        CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));

        status_t err = mVideoSource->start(); //这个时候videosource和viedotrack都会准备好,申请buffer

        if (err != OK) {
            mVideoSource.clear();
            return err;
        }
    }

    return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
}

​弄好以后就会更改状态,做上层的prepareAsync的回调


数据已经准备了,

play_l()

​ if ((mVideoSource != NULL) && (!mVideoBuffer))

{
    // Changes to fix Audio starts playing before video.
    // First video frame is returned late as it is referenced to decode subsequent P and B frames.
    // For higher resolutions (e.g. 1080p) this returning time is significant.
    // We need to trigger Video decoder earlier than audio so that Video catch up with audio in time.
        MediaSource::ReadOptions options;
        if (mSeeking) {
            LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);

            options.setSeekTo(
                    mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
        }
        for (;;) {
            status_t err = mVideoSource->read(&mVideoBuffer, &options);
            options.clearSeekTo();

            if (err != OK) {
                CHECK_EQ(mVideoBuffer, NULL);

                if (err == INFO_FORMAT_CHANGED) {
                    LOGV("VideoSource signalled format change.");

                    if (mVideoRenderer != NULL) {
                        mVideoRendererIsPreview = false;
                        initRenderer_l();
                    }
                    continue;
                }
                break;
            }

 

            break;
        }
    }

    if (mVideoSource != NULL) {
        // Kick off video playback
        postVideoEvent_l();
    }

就会把得到的mVideoBuffer render到surface上面

而audio会调用audioplayer

 mAudioPlayer = new AudioPlayer(mAudioSink, this);
                mAudioPlayer->setSource(mAudioSource);

                // We've already started the MediaSource in order to enable
                // the prefetcher to read its data.
                status_t err = mAudioPlayer->start(
                        true /* sourceAlreadyStarted */);

还有音视频同步,seek的问题,下次再写

ps-----这篇是针对2.3的代码,4.0以后又发生了一些变化,后面的问题就没有写完,会写一些4.0相关的东西


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值