当前位置:操作系统 > 安卓/Android >>

android多媒体本地播放流程video playback--base on jellybean (四)

上一篇我们讲了mediaplayer播放的第一步骤setdataSource,下面我们来讲解preparesync的流程,在prepare前我们还有setDisplay这一步,即获取surfacetexture来进行画面的展示
setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface, jboolean mediaPlayerMustBeAlive)
{
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
………
    sp<ISurfaceTexture> new_st;
    if (jsurface) {
        sp<Surface> surface(Surface_getSurface(env, jsurface));
        if (surface != NULL) {
            new_st = surface->getSurfaceTexture();
            ---通过surface获取surfaceTexture
            new_st->incStrong(thiz);
……….
    }………….
    mp->setVideoSurfaceTexture(new_st);
}
 
为什么用surfaceTexture不用surface来展示呢?ICS之前都用的是surfaceview来展示video或者openGL的内容,surfacaview render在surface上,textureview render在surfaceTexture,textureview和surfaceview 这两者有什么区别呢?surfaceview跟应用的视窗不是同一个视窗,它自己new了一个window来展示openGL或者video的内容,这样做有一个好处就是不用重绘应用的视窗,本身就可以不停的更新,但这也带来一些局限性,surfaceview不是依附在应用视窗中,也就不能移动、缩放、旋转,应用ListView或者 ScrollView就比较费劲。Textureview就很好的解决了这些问题。它拥有surfaceview的一切特性外,它也拥有view的一切行为,可以当个view使用。
 
获取完surfaceTexture,我们就可以prepare/prepareAsync了,先给大伙看个大体时序图吧:
 
JNI的部分我们跳过,直接进入libmedia下的mediaplayer.cpp的 prepareAsync_l方法,prepare是个同步的过程,所以要加锁,prepareAsync_l后缀加_l就是表面是同步的过程。
status_t MediaPlayer::prepareAsync_l()
{
    if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
        mPlayer->setAudioStreamType(mStreamType);
        mCurrentState = MEDIA_PLAYER_PREPARING;
        return mPlayer->prepareAsync();
    }
    ALOGE("prepareAsync called in state %d", mCurrentState);
    return INVALID_OPERATION;
}
 
在上面的代码中,我们看到有个mPlayer,看过前一章的朋友都会记得,就是我们从Mediaplayerservice获得的BpMediaplayer.通过BpMediaplayer我们就可以长驱直入,直捣Awesomeplayer这条干实事的黄龙,前方的mediaplayerservice:client和stagefrightplayer都是些通风报信的料,不值得我们去深入研究,无非是些接口而已。进入了prepareAsync_l方法,我们的播放器所处的状态就是MEDIA_PLAYER_PREPARING了。好了,我们就来看看Awesomeplayer到底做了啥吧.
代码定位于:frameworks/av/media/libstagefright/Awesomeplayer.cpp
先看下prepareAsync_l吧:
status_t AwesomePlayer::prepareAsync_l() {
    if (mFlags & PREPARING) {
        return UNKNOWN_ERROR;  // async prepare already pending
    }
 
    if (!mQueueStarted) {
        mQueue.start();
        mQueueStarted = true;
    }
 
    modifyFlags(PREPARING, SET);
    mAsyncPrepareEvent = new AwesomeEvent(
            this, &AwesomePlayer::onPrepareAsyncEvent);
 
    mQueue.postEvent(mAsyncPrepareEvent);
 
    return OK;
}
 
  这里我们涉及到了TimeEventQueue,即时间事件队列模型,Awesomeplayer里面类似Handler的东西,它的实现方式是把事件响应时间和事件本身封装成一个queueItem,通过postEvent 插入队列,时间到了就会根据事件id进行相应的处理。
  首先我们来看下TimeEventQueue的start(mQueue.start();)方法都干了什么:
frameworks/av/media/libstagefright/TimedEventQueue.cpp
void TimedEventQueue::start() {
    if (mRunning) {
        return;
    }
……..
 
    pthread_create(&mThread, &attr, ThreadWrapper, this);
 
………
}
 
目的很明显就是在主线程创建一个子线程,可能很多没有写过C/C++的人对ptread_create这个创建线程的方法有点陌生,我们就来分析下:
int pthread_create(pthread_t *thread, pthread_addr_t *arr,
           void* (*start_routine)(void *), void *arg);
 
 thread   :用于返回创建的线程的ID
arr       : 用于指定的被创建的线程的属性
start_routine   : 这是一个函数指针,指向线程被创建后要调用的函数
arg      : 用于给线程传递参数
分析完了,我们就看下创建线程后调用的函数ThreadWrapper吧:
// static
void *TimedEventQueue::ThreadWrapper(void *me) {
……
    static_cast<TimedEventQueue *>(me)->threadEntry();
 
    return NULL;
}
跟踪到threadEntry:
frameworks/av/media/libstagefright/TimedEventQueue.cpp
void TimedEventQueue::threadEntry() {
    prctl(PR_SET_NAME, (unsigned long)"TimedEventQueue", 0, 0, 0);
 
    for (;;) {
        int64_t now_us = 0;
        sp<Event> event;
 
        {
            Mutex::Autolock autoLock(mLock);
 
            if (mStopped) {
                break;
            }
 
            while (mQueue.empty()) {
                mQueueNotEmptyCondition.wait(mLock);
            }
 
            event_id eventID = 0;
            for (;;) {
                if (mQueue.empty()) {
                    // The only event in the queue could have been cancelled
                    // while we were waiting for its scheduled time.
                    break;
                }
 
                List<QueueItem>::iterator it = mQueue.begin();
                eventID = (*it).event->eventID();
……&h

补充:移动开发 , Android ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,