7. Android MultiMedia框架完全解析 - ALooper-AHandler-AMessage机制分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yanbixing123/article/details/88927323

先来看整个框架图:

NuPlayer基于Stagefright的基础类构建,使用了更底层的ALooper-AHandler-AMessage机制来异步处理消息。

AMessage作为一个消息载体,保存这与这个消息有关的信息;

ALooper是一个循环,它运行着一个后台线程,来循环处理接收到的消息(将信息转给AHandler来处理,它相当于一个中转站);

AHandler作为一个句柄,它是最终对消息进行处理的。

在实现上NuPlayer和Awesomeplayer不同,NuPlayer基于StagefrightPlayer的基础类构建,利用了更底层的ALooper/AHandler机制来异步地处理请求,ALooper列队消息请求,AHandler中去处理,所以有更少的Mutex/Lock在NuPlayer中。Awesomeplayer中利用了omxcodec,而NuPlayer中利用了Acodec。

首先需要分析AHandler,因为在Amessage::setTarget函数中,需要使用AHandler中的const_cast<AHandler *>(this)和mLooper,而这两个值需要在AHandler中初始化。

1. AHandler

先来看AHandler的定义:

android_m6.0.1_2.1.0/frameworks/av/include/media/stagefright/foundation/AHandler.h)

struct AHandler : public RefBase {
    AHandler()
        : mID(0),
          mVerboseStats(false),
          mMessageCounter(0) {
    }//构造函数,为mID,mVerboseStats,mMessageCounter三个变量赋初始值。

    ALooper::handler_id id() const {
        return mID;
    }

    sp<ALooper> looper() const {
        return mLooper.promote();
    }

    wp<ALooper> getLooper() const {
        return mLooper;
    }

    wp<AHandler> getHandler() const {
        // allow getting a weak reference to a const handler
        return const_cast<AHandler *>(this);
    }

protected:
    virtual void onMessageReceived(const sp<AMessage> &msg) = 0;
//这是个虚函数,每个继承自AHandler的子类都需要实现这个虚函数,比如在NuPlayer中就实现了这个虚函数,最终对于Message的处理还是在这个函数中。

private:
    friend struct AMessage;      // deliverMessage()
    friend struct ALooperRoster; // setID()

    ALooper::handler_id mID;
    wp<ALooper> mLooper;

    inline void setID(ALooper::handler_id id, wp<ALooper> looper) {
        mID = id;
        mLooper = looper;
    }//这个函数供友元类ALooperRoster来使用。

    bool mVerboseStats;
    uint32_t mMessageCounter;
    KeyedVector<uint32_t, uint32_t> mMessages;
//这里是一个KeyedVector,用来存放Messages,它是一个键值对类型的容器。

    void deliverMessage(const sp<AMessage> &msg);
//这个函数是AHandler.cpp需要去实现的一个函数,在里面调用onMessageReceived(msg)函数后再对mMessageCounter进行操作。这个函数是在AMessage::deliver()函数中调用的。

    DISALLOW_EVIL_CONSTRUCTORS(AHandler);
};

从上面的接口来看,初步印象是AHandler没有直接对外的接口(只有获取成员变量的接口),基本上只有一个onMessageReceived用于子类的继承,deliverMessage用于给类AMessage使用,setID用于给友元类ALooperRoster来使用。所以从这点来说,真正的代码可能在AMessage中。

那这个AHandler是给谁用的呢?从名字上来看,它是一个句柄,同时也是这个ALooper-AHandler-AMessage机制的一个核心,所以如果想要在某个程序中使用这个消息机制,就要让主体继承自这个AHandler,然后在主体中实现onMessageReceived函数,同时也就可以使用AMessage了。

比如在Media playback中,这个主体就是NuPlayer,所以NuPlayer继承自AHanlder。

1.2 ALooperRoster类

从AHandler中setID函数的实现上面来看,是为AHandler中的的mID,mLooper两个成员赋初始值,而调用这个setID函数的正是ALooperRoster::registerHandler()和ALooperRoster::unregisterHandler()这两个函数,同时Roster的翻译就是花名册,所以,可以理解为ALooperRoster类来将ALooper和AHandler类关联起来,它是用来管理ALooper的。

2. AMessage类

.\libstagefright\foundation\AMessage.cpp
.\media\stagefright\foundation\AMessage.h

struct AMessage : public RefBase {
    AMessage();
    AMessage(uint32_t what, const sp<const AHandler> &handler);
//两个构造函数,但是第二个是常用的构造函数,通常指定id和需要哪个AHanlder来处理。

    static sp<AMessage> FromParcel(const Parcel &parcel);
    void writeToParcel(Parcel *parcel) const;

    void setWhat(uint32_t what);
    uint32_t what() const;
//如果不通过构造函数传入id的话,也可以通过这两个设置。

    void setTarget(const sp<const AHandler> &handler);
//这个函数还是蛮重要的,通过这个函数,可以为这个类中的mTarget,mHandler,mLooper赋值,这个函数通常会被这样调用:msg->setTarget(this);通过这一步,就可以为msg设置Handler和Looper。注意这里本身传入的就是一个AHandler。

    void clear();

    void setInt32(const char *name, int32_t value);
    void setInt64(const char *name, int64_t value);
    void setSize(const char *name, size_t value);
    void setFloat(const char *name, float value);
    void setDouble(const char *name, double value);
    void setPointer(const char *name, void *value);
    void setString(const char *name, const char *s, ssize_t len = -1);
    void setString(const char *name, const AString &s);
    void setObject(const char *name, const sp<RefBase> &obj);
    void setBuffer(const char *name, const sp<ABuffer> &buffer);
    void setMessage(const char *name, const sp<AMessage> &obj);

    void setRect(
            const char *name,
            int32_t left, int32_t top, int32_t right, int32_t bottom);

    bool contains(const char *name) const;

    bool findInt32(const char *name, int32_t *value) const;
    bool findInt64(const char *name, int64_t *value) const;
    bool findSize(const char *name, size_t *value) const;
    bool findFloat(const char *name, float *value) const;
    bool findDouble(const char *name, double *value) const;
    bool findPointer(const char *name, void **value) const;
    bool findString(const char *name, AString *value) const;
    bool findObject(const char *name, sp<RefBase> *obj) const;
    bool findBuffer(const char *name, sp<ABuffer> *buffer) const;
    bool findMessage(const char *name, sp<AMessage> *obj) const;

    bool findRect(
            const char *name,
            int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const;

    status_t post(int64_t delayUs = 0);
//投递消息,新建一个消息后,设置属性,就可以调用post投递了。

    status_t postAndAwaitResponse(sp<AMessage> *response);

    bool senderAwaitsResponse(sp<AReplyToken> *replyID);

    status_t postReply(const sp<AReplyToken> &replyID);

    sp<AMessage> dup() const;

    size_t countEntries() const;
    const char *getEntryNameAt(size_t index, Type *type) const;

protected:
    virtual ~AMessage();

private:
    friend struct ALooper; // deliver()

    uint32_t mWhat;

    // used only for debugging
    ALooper::handler_id mTarget;

    wp<AHandler> mHandler;
    wp<ALooper> mLooper;

    Item *allocateItem(const char *name);
    void freeItemValue(Item *item);
    const Item *findItem(const char *name, Type type) const;

    void setObjectInternal(
            const char *name, const sp<RefBase> &obj, Type type);

    size_t findItemIndex(const char *name, size_t len) const;

    void deliver();//这个接口给ALooper调用,发送消息的接口。

    DISALLOW_EVIL_CONSTRUCTORS(AMessage);
};

从上面的接口可以看出,在使用AMessage时只需要指定消息的id和要处理该消息的AHandler即可,可以通过AMessage的构造函数中指定,也可以单独调用setWhat和setTarget接口。AMessage构造完成之后,可以调用setxxx设置对应的参数,通过findxxx获取传递的参数。最后通过post即可将消息投递到AHandler的消息队列中。

下面就是一个消息从创建到发送的过程:

    sp<AMessage> notify = dupNotify();
    notify->setInt32("what", kWhatPrepared);
    notify->setInt32("err", err);
    notify->post();

3. ALooper

(这里插入ALooper类)

ALooper的对外接口比较简单,通常就是NuPlayerDriver构造函数中的调用逻辑,先创建一个ALooper对象,然后调用setName和start接口,之后调用registerHandler设置一个Handler,这样就完成了初始化。

创建过程

mLooper(new ALooper),
mLooper->setName("NuPlayerDriver Looper");

mLooper->start(
            false, /* runOnCallingThread */
            true,  /* canCallJava */
            PRIORITY_AUDIO);

mLooper->registerHandler(mPlayer);

在ALooper::start函数中会启动一个线程,并调用ALooper::loop函数,该函数主要实现消息的实际执行,如下所示:

bool ALooper::loop() {
    Event event;
    {
        Mutex::Autolock autoLock(mLock);
        if (mThread == NULL && !mRunningLocally) {
            return false;
        }
        if (mEventQueue.empty()) {
            mQueueChangedCondition.wait(mLock);
            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());
    }

    event.mMessage->deliver();

    // NOTE: It's important to note that at this point our "ALooper" object
    // may no longer exist (its final reference may have gone away while
    // delivering the message). We have made sure, however, that loop()
    // won't be called again.

    return true;
}

说一下这里的逻辑:首先ALooper中维护着一个Event链表,List<Event> mEventQueue;这个Event结构体中包含一个AMessage消息和一个时间值,在ALooper::loop()函数中会一直监听着这个链表,如果有一个Event的话,就从链表中取出Event,调用event.mMessage->deliver()函数。

在AMessage::deliver()函数中,就会去获取这个AMessage的Ahandler,然后调用对应AHandler的deliverMessage函数:handler->deliverMessage(this)。

在AHandler::deliverMessage(const sp<AMessage> &msg)函数中,就会调用AHandler中的onMessageReceived(msg)函数,如果这时候传入的是AHandler子类的话,就会去调用AHandler子类的onMessageReceived(msg)函数。

4. 实例

void NuPlayer::setVideoSurfaceTextureAsync(
        const sp<IGraphicBufferProducer> &bufferProducer) {
    sp<AMessage> msg = new AMessage(kWhatSetVideoSurface, this);

    if (bufferProducer == NULL) {
        msg->setObject("surface", NULL);
    } else {
        msg->setObject("surface", new Surface(bufferProducer, true /* controlledByApp */));
    }

    msg->post();
}

5. 上面这些消息都是异步实现的,如果想要同步消息,在这个消息机制中的设计很巧妙,它是新建一个AMessage,然后通过这个新建的AMessage来传输回复的消息,实例如下:

status_t NuPlayer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
    sp<AMessage> msg = new AMessage(kWhatGetPlaybackSettings, this);
    sp<AMessage> response;
    status_t err = msg->postAndAwaitResponse(&response);
    if (err == OK && response != NULL) {
        CHECK(response->findInt32("err", &err));
        if (err == OK) {
            readFromAMessage(response, rate);
        }
    }
    return err;
}

6.

sp<AReplyToken> replyID;

CHECK(msg->senderAwaitsResponse(&replyID));

7.

sp<AMessage> response = new AMessage;

response->setInt32("err", err);

response->postReply(replyID);

8. msg中findObject和setObject的用法:

void NuPlayer::setVideoSurfaceTextureAsync(

const sp<IGraphicBufferProducer> &bufferProducer) {

sp<AMessage> msg = new AMessage(kWhatSetVideoSurface, this);

if (bufferProducer == NULL) {

msg->setObject("surface", NULL);

} else {

msg->setObject("surface", new Surface(bufferProducer, true /* controlledByApp */));

}

msg->post();

}

之后在OnMessageReceived函数中:

case kWhatSetVideoSurface:

{

sp<RefBase> obj;

CHECK(msg->findObject("surface", &obj));

sp<Surface> surface = static_cast<Surface *>(obj.get());

这里通过一个static_cast转换,就能够把这个sp<Surface>结构体通过msg传递过来。

最终总结一句:很多同学到这里就不理解了,为什么这里要使用这么复杂的机制,直接在函数中把这些操作直接顺序写下来不就行了?因为在Media相关的地方,很多操作都是耗时很长的操作,但是用户对于画面的流程度的容忍度很低,举一个很简单的例子,在视频的播放过程中,如果我想直接把进度条拖到中间的位置开始播放,当我点击完毕后,NuPlayer内部就开始执行了seek操作,但是这时候耗时比较长,画面就卡在这里了,用户体验度很差。但是如果我使用类似的机制,画面继续播放之前缓冲的数据,而NuPlayer抓紧去执行seek操作,当seek操作执行完毕后,直接把画面切换到这个位置开始播放,这样的话,画面不会卡住,而用户体验度就会好很多。

猜你喜欢

转载自blog.csdn.net/yanbixing123/article/details/88927323