]android多媒体框架之流媒体AHandler消息机制----base on jellybean(十)

本文主要是介绍]android多媒体框架之流媒体AHandler消息机制----base on jellybean(十),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

为什么我们要谈论流媒体的消息机制呢?因为在流媒体中,类似于我们写APP的时候,为了不阻塞UI线程,我们把利用handler,把UI线程分开异步执行,使用handler去执行某项比较费时的操作,然后异步更新UI线程。流媒体中也是类似的,因为联网,codec都很费时,需要异步执行。handler是java的实现机制,而我们下面要讲的AHandler就是基于C++的实现了。

我们知道handler消息机制,构成就必须包括一个Loop,message。那么对应的AHandler,也应该有对应的ALooper, AMessage。下面我们将以实例化NUplayerDrriver和setdataSource为例来具体讲述AHandler消息机制。

首先看下NuplayerDriver的构造函数,这是流媒体初始化函数。

 

static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,

        notify_callback_f notifyFunc){

caseNU_PLAYER:

            ALOGV(" createNuPlayer");

            p = newNuPlayerDriver;

}

 

NuPlayerDriver::NuPlayerDriver()

    : mResetInProgress(false),

      mPrepareInProgress(false),

      mIsPrepared(false),

      mDurationUs(-1),

      mPositionUs(-1),

      mNumFramesTotal(0),

      mNumFramesDropped(0),

      mLooper(new ALooper),-----创建一个新的ALooper

      mState(UNINITIALIZED),

      mAtEOS(false),

      mStartupSeekTimeUs(-1) {

      mLooper->setName("NuPlayerDriverLooper");----给该Looper取名字,以便与AHandler一一对应

    mLooper->start(

            false, /* runOnCallingThread */

            true,  /* canCallJava */

            PRIORITY_AUDIO);-------------启动该Looper

 

    mPlayer = new NuPlayer;------------创建一个AHandlerNuplayer

    mLooper->registerHandler(mPlayer);-----把该AHandler注册到Looper中,具体的实现我们往后看

    mPlayer->setDriver(this);

}

 

看看ALooper的启动函数:

 

status_t ALooper::start(

        bool runOnCallingThread, boolcanCallJava, int32_t priority) {

    if (runOnCallingThread) {------runOnCallingThread开始为false,不走这里

        …………

    }

 

    Mutex::Autolock autoLock(mLock);

 

    if (mThread != NULL || mRunningLocally) {

        return INVALID_OPERATION;

    }

 

    mThread = newLooperThread(this, canCallJava);----新建一个thread

 

    status_t err =mThread->run(

            mName.empty() ?"ALooper" : mName.c_str(), priority);----looper线程启动

    if (err != OK) {

        mThread.clear();

    }

 

    return err;

}

看下关键步骤注册Handler:

 

ALooper::handler_idALooper::registerHandler(const sp<AHandler> &handler) {

    return gLooperRoster.registerHandler(this,handler);

}

 

ALooper::handler_idALooperRoster::registerHandler(

        const sp<ALooper> looper, constsp<AHandler> &handler) {

    Mutex::Autolock autoLock(mLock);

 

    if (handler->id() != 0) {

        CHECK(!"A handler must only beregistered once.");

        return INVALID_OPERATION;

    }

    HandlerInfo info;

    info.mLooper = looper;----- NuPlayerDriver Looper

    info.mHandler = handler;------nuplayer

    ALooper::handler_idhandlerID = mNextHandlerID++;

    mHandlers.add(handlerID, info);-------KeyedVector<ALooper::handler_id,HandlerInfo> mHandlers;

    handler->setID(handlerID);------设置handlerID,以便发送message时找到对应的handler

    return handlerID;

}

ALooperRoster::ALooperRoster()

    : mNextHandlerID(1),------------------1开始

      mNextReplyID(1) {

}

 

 

有了LOOPER,也有了对应的handler,看看如何发送消息给LOOPER,交个相应的handler去处理。我们以setdataSource方法为例:

Nuplayer本身也是个AHandler,因为其继承自AHandler。

structNuPlayer : public AHandler {

}

我们看看其父类AHandler:

struct AHandler : public RefBase {

    AHandler()

        : mID(0){

    }

    ALooper::handler_id id() const {

        return mID;

    }

    sp<ALooper> looper();

protected:

    virtual voidonMessageReceived(const sp<AMessage> &msg) = 0;---处理消息函数

private:

    friend struct ALooperRoster;

    ALooper::handler_id mID;

    void setID(ALooper::handler_id id) {

        mID = id;

    }

    DISALLOW_EVIL_CONSTRUCTORS(AHandler);

};

 以setdataSource为例看看如何传递message

void NuPlayer::setDataSource(

        const char *url, constKeyedVector<String8, String8> *headers) {

   1 sp<AMessage> msg =new AMessage(kWhatSetDataSource, id());

    size_t len = strlen(url);

………..

elseif ((!strncasecmp(url, "http://", 7) || !strncasecmp(url,"https://", 8))

                    && ((len >= 4&& !strcasecmp(".sdp", &url[len - 4]))

                    || strstr(url,".sdp?"))) {

        source = newRTSPSource(url, headers, mUIDValid, mUID, true);

        mSourceType = kRtspSource;

    }

……….

    2msg->setObject("source", source);

    3msg->post();

}

 

首先新建一个AMessage的实例,传入的参数为事件的名称以及处理该消息的Handlerid,该id在    mLooper->registerHandler(mPlayer);方法中设置上。

 

我们看下AMessage:

 

AMessage::AMessage(uint32_twhat, ALooper::handler_id target)

    : mWhat(what),

      mTarget(target),

      mNumItems(0) {

}

 

void AMessage::setObject(const char *name, const sp<RefBase> &obj) {

    setObjectInternal(name, obj, kTypeObject);

}

void AMessage::setObjectInternal(

        const char *name, constsp<RefBase> &obj, Type type) {

    Item *item = allocateItem(name);

    item->mType = type;

 

    if (obj != NULL) { obj->incStrong(this);}

    item->u.refValue = obj.get();

}

 

POST 过程:

void AMessage::post(int64_t delayUs) {

    gLooperRoster.postMessage(this, delayUs);----调用ALooperRosterpostMessage函数

}

 

status_tALooperRoster::postMessage(

        const sp<AMessage> &msg,int64_t delayUs) {

    Mutex::Autolock autoLock(mLock);

    return postMessage_l(msg, delayUs);

}

 

status_t ALooperRoster::postMessage_l(

        const sp<AMessage> &msg,int64_t delayUs) {

    ssize_t index =mHandlers.indexOfKey(msg->target());--target即为Handler_id

 

    if (index < 0) {

        ALOGW("failed to post message.Target handler not registered.");

        return -ENOENT;

    }

 

    const HandlerInfo &info =mHandlers.valueAt(index);---根据handler_id找到HandlerInfo

 

    sp<ALooper>looper = info.mLooper.promote();----根据我们注册的HandlerInfo找到相应的ALooper,我们现在就是“NuPlayerDriver Looper

 

    if (looper == NULL) {

        ALOGW("failed to post message."

             "Target handler %d stillregistered, but object gone.",

             msg->target());

 

        mHandlers.removeItemsAt(index);

        return -ENOENT;

    }

 

    looper->post(msg,delayUs);---往“NuPlayerDriver Looper”里传递消息

 

    return OK;

}

 

void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) {

    Mutex::Autolock autoLock(mLock);

 

    int64_t whenUs;

    if (delayUs > 0) {

        whenUs = GetNowUs() + delayUs;

    } else {

        whenUs = GetNowUs();

    }

    List<Event>::iterator it =mEventQueue.begin();

    while (it != mEventQueue.end() &&(*it).mWhenUs <= whenUs) {

        ++it;

    }

    Event event;

    event.mWhenUs = whenUs;

    event.mMessage = msg;

 

    if (it == mEventQueue.begin()) {

        mQueueChangedCondition.signal();

    }

 

    mEventQueue.insert(it,event);----往消息队列里插入消息

}

 

当队列里有消息时便会触发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());

    }

 

    gLooperRoster.deliverMessage(event.mMessage);

    return true;

}

 

 

void ALooperRoster::deliverMessage(const sp<AMessage> &msg) {

    sp<AHandler> handler;

    {

        Mutex::Autolock autoLock(mLock);

        ssize_t index = mHandlers.indexOfKey(msg->target());

        if (index < 0) {

            ALOGW("failed to delivermessage. Target handler not registered.");

            return;

        }

        const HandlerInfo &info =mHandlers.valueAt(index);

        handler =info.mHandler.promote();

 

        if (handler == NULL) {

            ALOGW("failed to delivermessage. "

                 "Target handler %dregistered, but object gone.",

                 msg->target());

            mHandlers.removeItemsAt(index);

            return;

        }

    }

    handler->onMessageReceived(msg);------对应为Nuplayer

}

void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {

    switch (msg->what()) {

        case kWhatSetDataSource:

        {

………………………………………

            mSource = static_cast<Source*>(obj.get());

 

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

            mSource->setNotify(notify);

            mSource->connect();-------------RTSPSource

 

            break;

        }

}

至此我们的Ahandler的流程讲完了,大致就是启动一个threadLooper,监听looper的消息队列是否有变化,如有交个相应的Handler去处理。

这篇关于]android多媒体框架之流媒体AHandler消息机制----base on jellybean(十)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/278580

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个?

跨平台系列 cross-plateform 跨平台应用程序-01-概览 cross-plateform 跨平台应用程序-02-有哪些主流技术栈? cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个? cross-plateform 跨平台应用程序-04-React Native 介绍 cross-plateform 跨平台应用程序-05-Flutte

Spring框架5 - 容器的扩展功能 (ApplicationContext)

private static ApplicationContext applicationContext;static {applicationContext = new ClassPathXmlApplicationContext("bean.xml");} BeanFactory的功能扩展类ApplicationContext进行深度的分析。ApplicationConext与 BeanF

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

【Tools】大模型中的自注意力机制

摇来摇去摇碎点点的金黄 伸手牵来一片梦的霞光 南方的小巷推开多情的门窗 年轻和我们歌唱 摇来摇去摇着温柔的阳光 轻轻托起一件梦的衣裳 古老的都市每天都改变模样                      🎵 方芳《摇太阳》 自注意力机制(Self-Attention)是一种在Transformer等大模型中经常使用的注意力机制。该机制通过对输入序列中的每个元素计算与其他元素之间的相似性,

如何通俗理解注意力机制?

1、注意力机制(Attention Mechanism)是机器学习和深度学习中一种模拟人类注意力的方法,用于提高模型在处理大量信息时的效率和效果。通俗地理解,它就像是在一堆信息中找到最重要的部分,把注意力集中在这些关键点上,从而更好地完成任务。以下是几个简单的比喻来帮助理解注意力机制: 2、寻找重点:想象一下,你在阅读一篇文章的时候,有些段落特别重要,你会特别注意这些段落,反复阅读,而对其他部分