Android流媒体的实现

在mps的setDataSource中,根据url判断应该生成那种dataSource,然后获取默认的player,即nuplayer。进入NuPlayerDriver的setDataSource,
再进入void NuPlayer::setDataSourceAsync(const sp<IStreamSource> &source) {
#ifdef MTK_AOSP_ENHANCEMENT
    mIsStreamSource = true;
#endif
    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());

    sp<AMessage> notify = new AMessage(kWhatSourceNotify, id());

    msg->setObject("source", new StreamingSource(notify, source));
    msg->post();
}

到了NuPlayer异步消息的世界,进入setDataSourceAsync
首先判断是什么流媒体
        if (!strncasecmp(url, "http://", 7)
                || !strncasecmp(url, "https://", 8)) {
            mDataSourceType = SOURCE_Http;
            ALOGI("Is http Streaming");
生成一个sp<GenericSource> genericSource =
                new GenericSource(notify, mUIDValid, mUID);
然后触发了kWhatSetDataSource
进入NuPlayerDriver的
void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
    Mutex::Autolock autoLock(mLock);

    CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);

    mAsyncResult = err;
    mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
#ifdef MTK_AOSP_ENHANCEMENT
    ALOGD("after notifySetDataSourceCompleted mState=%d", mState);
#endif
    mCondition.broadcast();
}
注意,mCondition是在MPS调用NuPlayerDriver的API的时候就已经wait了的
status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
    ALOGV("setDataSource(%p) file(%d)", this, fd);
    Mutex::Autolock autoLock(mLock);

    if (mState != STATE_IDLE) {
        return INVALID_OPERATION;
    }

    mState = STATE_SET_DATASOURCE_PENDING;

    mPlayer->setDataSourceAsync(fd, offset, length);

    while (mState == STATE_SET_DATASOURCE_PENDING) {
        mCondition.wait(mLock);
    }

    return mAsyncResult;
}
好,下面该prepare了

status_t NuPlayerDriver::prepare_l() {
    switch (mState) {
        case STATE_UNPREPARED:
            mState = STATE_PREPARING;

            // Make sure we're not posting any notifications, success or
            // failure information is only communicated through our result
            // code.
            mIsAsyncPrepare = false;
            mPlayer->prepareAsync();
            while (mState == STATE_PREPARING) {
                mCondition.wait(mLock);
            }
            return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR;
        case STATE_STOPPED:
            // this is really just paused. handle as seek to start
            mAtEOS = false;
            mState = STATE_STOPPED_AND_PREPARING;
            mIsAsyncPrepare = false;
            mPlayer->seekToAsync(0, true /* needNotify */);
            while (mState == STATE_STOPPED_AND_PREPARING) {
                mCondition.wait(mLock);
            }
            return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR;
        default:
            return INVALID_OPERATION;
    };
}

进到NuPlayer的消息处理机制
        case kWhatPrepare:
        {
#ifdef MTK_AOSP_ENHANCEMENT
           ATRACE_ASYNC_BEGIN("Prepare",mPlayerCnt);

            ALOGD("kWhatPrepare, source type = %d", (int)mDataSourceType);
            if (mPrepare == PREPARING)
                break;
            mPrepare = PREPARING;
            if (mSource == NULL) {
                ALOGW("prepare error: source is not ready");
                finishPrepare(UNKNOWN_ERROR);
                break;
            }
#endif
            mSource->prepareAsync();
            break;
        }
这个mSource是GenericSource
进入了onPrepareAsync
此时去create 一个dataSource 
mDataSource = DataSource::CreateFromURI(
                   mHTTPService, uri, &mUriHeaders, &mContentType,
                   static_cast<HTTPBase *>(mHttpSource.get()));

此时就涉及到两个Source,一个是从网络获取数据的Http,一个是cache在本地的流媒体数据

Http的Source被这样创建
mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
mHttpSource继承于DataSource

第一个Source是聚合在NuCachedSource2中的一个Source

cache的Source被这样创建,本质上也是一个DataSource,因为NuCachedSource2是dataSource的子类

            source = new NuCachedSource2(
                    httpSource,
                    cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
                    disconnectAtHighwatermark);

然后进入initFromDataSource,也就是去选择extractor的类型,这个需要一些数据来判断是哪种流媒体格式

        extractor = MediaExtractor::Create(mDataSource,
                mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str());

那些初始下载的数据是什么时候下的呢?在创建NuCachedSource2的时候就开始了
这是另外一个线程在做的事情
    ssize_t n = mSource->readAt(
            mCacheOffset + mCache->totalSize(), page->mData, kPageSize);
一次性获取kPageSize大小的数据
此时是靠IMediaHTTPConnection来通过匿名共享内存和binder获取的

Bn的部分在MediaHTTPConnection.java (base\media\java\android\media) 

而它使用的又是 HttpURLConnection,是现在libcore下,属于基础架构


回到Extractor,它会调用ssize_t NuCachedSource2::readAt(off64_t offset, void *data, size_t size) {
发kWhatRead调用onRead,然后调用readInternal,从mCache里面copy数据
mCache->copy(delta, data, avail);

有多少拷多少,data是输出参数,给Extractor

注意,判断是什么类型是需要一点数据,这点数据往往就是tmd的tts数据了

bool DataSource::sniff(
        String8 *mimeType, float *confidence, sp<AMessage> *meta) {

策略是所有Sniff,挨个闻一遍,哪个confidence高用谁的,Sniff是Extractor的一个副产品
发布了198 篇原创文章 · 获赞 45 · 访问量 30万+
展开阅读全文

MediaPlayer info/warning (703, 0),播放没声

04-07

04-07 09:15:53.501 3820-3820/pc.dialog.com.wutils I/MediaPlayActivity: onStart=http://jiayin-10076642.video.myqcloud.com/jsmy02/W38833d49-f783-4d27-919a-c198de8678ef.mp3 04-07 09:15:53.512 3820-3820/pc.dialog.com.wutils E/ExtMediaPlayer-JNI: env->IsInstanceOf fails 04-07 09:15:53.512 3820-3820/pc.dialog.com.wutils E/MediaPlayer-JNI: JNIMediaPlayerFactory: bIsQCMediaPlayerPresent 0 04-07 09:15:53.512 3820-3820/pc.dialog.com.wutils E/ExtMediaPlayer-JNI: env->IsInstanceOf fails 04-07 09:15:53.512 3820-3820/pc.dialog.com.wutils E/MediaPlayer-JNI: JNIMediaPlayerFactory: bIsQCMediaPlayerPresent 0 04-07 09:15:53.513 3820-3820/pc.dialog.com.wutils W/MediaPlayer: Couldn't open file on client side; trying server side: java.io.FileNotFoundException: No content provider: http://jiayin-10076642.video.myqcloud.com/jsmy02/W38833d49-f783-4d27-919a-c198de8678ef.mp3 04-07 09:15:53.517 3820-4027/pc.dialog.com.wutils D/MediaHTTPConnection: filterOutInternalHeaders: key=User-Agent, val= stagefright/1.2 (Linux;Android 6.0.1) 04-07 09:15:53.518 3820-3851/pc.dialog.com.wutils D/MediaHTTPConnection: proxy null port 0 04-07 09:15:54.746 3820-3820/pc.dialog.com.wutils D/MediaPlayer: setSubtitleAnchor in MediaPlayer 04-07 09:15:54.752 3820-3820/pc.dialog.com.wutils I/Choreographer: Skipped 77 frames! The application may be doing too much work on its main thread. 04-07 09:15:54.822 3820-3820/pc.dialog.com.wutils I/MediaPlayActivity: onPrepared 04-07 09:15:59.782 3820-3820/pc.dialog.com.wutils I/MediaPlayActivity: onStart=http://jiayin-10076642.video.myqcloud.com/jsmy02/W38833d49-f783-4d27-919a-c198de8678ef.mp3 04-07 09:15:59.783 3820-3820/pc.dialog.com.wutils E/ExtMediaPlayer-JNI: env->IsInstanceOf fails 04-07 09:15:59.783 3820-3820/pc.dialog.com.wutils E/MediaPlayer-JNI: JNIMediaPlayerFactory: bIsQCMediaPlayerPresent 0 04-07 09:15:59.783 3820-3820/pc.dialog.com.wutils E/ExtMediaPlayer-JNI: env->IsInstanceOf fails 04-07 09:15:59.783 3820-3820/pc.dialog.com.wutils E/MediaPlayer-JNI: JNIMediaPlayerFactory: bIsQCMediaPlayerPresent 0 04-07 09:15:59.789 3820-3820/pc.dialog.com.wutils W/MediaPlayer: Couldn't open file on client side; trying server side: java.io.FileNotFoundException: No content provider: http://jiayin-10076642.video.myqcloud.com/jsmy02/W38833d49-f783-4d27-919a-c198de8678ef.mp3 04-07 09:15:59.800 3820-3848/pc.dialog.com.wutils D/MediaHTTPConnection: filterOutInternalHeaders: key=User-Agent, val= stagefright/1.2 (Linux;Android 6.0.1) 04-07 09:15:59.801 3820-3820/pc.dialog.com.wutils D/MediaPlayer: setSubtitleAnchor in MediaPlayer 04-07 09:15:59.804 3820-7079/pc.dialog.com.wutils D/MediaHTTPConnection: proxy null port 0 04-07 09:15:59.851 3820-3820/pc.dialog.com.wutils I/MediaPlayActivity: onPrepared 04-07 09:15:59.852 3820-7079/pc.dialog.com.wutils D/MediaHTTPConnection: proxy null port 0 04-07 09:15:59.863 3820-4027/pc.dialog.com.wutils W/MediaPlayer: info/warning (703, 0) 04-07 09:15:59.863 3820-4027/pc.dialog.com.wutils W/MediaPlayer: info/warning (701, 0) 04-07 09:16:02.832 3820-4027/pc.dialog.com.wutils D/MediaHTTPConnection: filterOutInternalHeaders: key=User-Agent, val= stagefright/1.2 (Linux;Android 6.0.1) 04-07 09:16:02.835 3820-3851/pc.dialog.com.wutils D/MediaHTTPConnection: proxy null port 0 04-07 09:16:05.885 3820-3851/pc.dialog.com.wutils D/MediaHTTPConnection: filterOutInternalHeaders: key=User-Agent, val= stagefright/1.2 (Linux;Android 6.0.1) 04-07 09:16:05.886 3820-4027/pc.dialog.com.wutils D/MediaHTTPConnection: proxy null port 0 04-07 09:16:06.867 3820-7079/pc.dialog.com.wutils D/MediaHTTPConnection: proxy null port 0 04-07 09:16:08.923 3820-7079/pc.dialog.com.wutils D/MediaHTTPConnection: filterOutInternalHeaders: key=User-Agent, val= stagefright/1.2 (Linux;Android 6.0.1)__![图片说明](https://img-ask.csdn.net/upload/201704/07/1491528189_523347.png) void init(String url){ mMediaPlayer =MediaPlayer.create(mContext,Uri.parse(url)); mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mMediaPlayer.setOnErrorListener(this); mMediaPlayer.setOnPreparedListener(this); mMediaPlayer.setOnCompletionListener(this); mMediaPlayer.setOnTimedMetaDataAvailableListener(this); mMediaPlayer.setOnTimedTextListener(this); mMediaPlayer.setOnSeekCompleteListener(this); mMediaPlayer.setOnBufferingUpdateListener(this); mMediaPlayer.setOnVideoSizeChangedListener(this); } public void playUrl(String url){ if (mOnMediaPlayerListener!=null){ mOnMediaPlayerListener.onStart(url); } if (mMediaPlayer!=null){ destroy(); } init(url); } public void stop(){ if (mMediaPlayer!=null){ mMediaPlayer.stop(); } } public void destroy(){ if (mMediaPlayer!=null){ stop(); mMediaPlayer.reset(); mMediaPlayer.release(); mMediaPlayer=null; } } public void pause(){ if (isPlaying()){ mMediaPlayer.pause(); } } ----------------------------------------- @Override public void onPrepared(MediaPlayer mp) { mp.start(); L.d(TAG,"onPrepared"); } 请教高人解答 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览