广告位联系
返回顶部
分享到

Android音视频开发Media FrameWork框架源码解析

Android 来源:互联网 作者:佚名 发布时间:2022-12-30 18:20:45 人浏览
摘要

一、Media FrameWork背景 Media Framework (媒体函数库):此函数库让Android 可以播放与录制许多常见的音频与视频文件,支持的文件类型包括MPEG4、H.264、MP3、AAC、AMR、JPG 与PNG 等。 Surface Manage

一、Media FrameWork背景

Media Framework (媒体函数库):此函数库让Android 可以播放与录制许多常见的音频与视频文件,支持的文件类型包括MPEG4、H.264、MP3、AAC、AMR、JPG 与PNG 等。 Surface Manager (外观管理函数库):管理图形界面的操作与2D、3D 图层的显示。

二、Media Framework“路线图”

我们可以看到用红色框框圈起来的地方。一个是app应用Gallery(也可以为第三方player);另外一个是Media Framework。对,没错,讲了这么多,我们的主角“Media Framework”登场了。让我们来看看它的庐山真面目, 如图所示:

接下来,给大家简单介绍下它。看的顺序是→ ↓ ← ↓ →(肿么都觉得是在打表情符号:-D)

2.1 代理端

这一端做的事情只是将下面复杂的逻辑进行封装(java),然后透过jni调用底下的native层方法来实现具体功能。并且,这些个具体的功能是在服务端实现的,他们分属不同的进程,通过Binder来通信,最终通过调用服务端的方法实现具体的逻辑处理。(有童鞋问:Binder是个什么东东呢? 小弟有时间会讲解的,现在就理解它是一个进程间通信的一种方式就好,求甚解的朋友们可以百度下_)

2.2 服务端

这边的主要任务就是在MediaPlayerFactory中,创建出NuplayerDriver(这个不是底层驱动啦,我们理解为一个抽象出来的NuPlayer的基类就好啦)。 然后Nuplayer中,我们可以看到有三大模块。

2.2.1 Source

这里是为咱们的播放器提供数据源的(解协议,解封装在这里)。

2.2.2 Decoder

这里是解码数据的地方(解码在这里)

2.2.3 Renderer

这里是用来做Display的,里面涉及到A/V同步的问题。

2.2.4 Foundation

这个部分是基础类。在后面的分析当中,我们会知道在NuPlayer中会启动相当多的线程,这些线程如何异步/同步的通信,需要依靠AMessage/ALooper/AHandler来支持

之后, 通过接口类IOMX来通过Binder进程间通信,远程调用具体的decoder来实现解码。

2.3 OMX端

这一端就比较靠近底层了,里面会有各种各样的插件注册其中。它还链接这Codec Driver,这里面就是放的各种具体的解码器啦。

2.4 Kernel端

最后, OMX的具体解码器在启动Kernel层的A/V Codec Driver完成解码操作。

三、media播放的流程

在framework中涉及media播放的流程头文件如下:IMediaPlayer.h mediaplayer.h IMediaPlayerClient.h

其中IMediaPlayer.h 定义了binder通信相关的接口。 定义了:

1

2

3

4

5

6

7

8

9

class BnMediaPlayer: public BnInterface

{

public:

    virtual status_t    onTransact( uint32_t code,

                                    const Parcel& data,

                                    Parcel* reply,

                                    uint32_t flags = 0);

};

?

IMediaPlayer.cpp 是binder通信接口的实现。

class BpMediaPlayer: public BpInterface; status_t BnMediaPlayer::onTransact();

mediaplayer.h 是定义binder通信的客户端。在mediaplayer.cpp中如下代码获取BpMediaPlayer:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

status_t MediaPlayer::setDataSource(

        const char *url, const KeyedVector *headers)

{

    LOGV("setDataSource(%s)", url);

    status_t err = BAD_VALUE;

    if (url != NULL) {

        const sp& service(getMediaPlayerService());

        if (service != 0) {

            sp player(

                    service->create(getpid(), this, url, headers));

            err = setDataSource(player);

        }

    }

    return err;

}

?

服务端在MediaPlayerService中。在MediaPlayerService.h中如下定义:

class Client : public BnMediaPlayer 在MediaPlayerService.cpp中,create函数创建了BnMediaPlayer:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

sp MediaPlayerService::create(

?

        pid_t pid, const sp& client, const char* url,

        const KeyedVector *headers)

{

    int32_t connId = android_atomic_inc(&mNextConnId);

    sp c = new Client(this, pid, connId, client);

    LOGV("Create new client(%d) from pid %d, url=%s, connId=%d", connId, pid, url, connId);

    if (NO_ERROR != c->setDataSource(url, headers))

    {

        c.clear();

        return c;

    }

    wp w = c;

    Mutex::Autolock lock(mLock);

    mClients.add(w);

    return c;

}

再来看一下MediaPlayer这个类的定义:

class MediaPlayer : public BnMediaPlayerClient, public virtual IMediaDeathNotifier{}

很奇怪:在binder通信的客户端又有了一个binder通信的服务端: BnMediaPlayerClient 在IMediaPlayerClient.h 中这个binder通信只有一个接口:

1

2

3

4

5

6

class IMediaPlayerClient: public IInterface

{

public:

    DECLARE_META_INTERFACE(MediaPlayerClient);?

    virtual void notify(int msg, int ext1, int ext2) = 0;

};

这个binder通信服务为谁提供呢?在回来看一下MediaPlayerServer中的create函数:

sp MediaPlayerService::create( pid_t pid, const sp& client, const char* url, const KeyedVector *headers)

客户端就在这里。这个binder通信的实质是一个消息回调函数。framework的media框架式一个双向binder通信框架。

以seek接口为例分析一下:

在mediaplayer.cpp 中调用seek 接口:

MediaPlayer (seek)->IMediaPlayer.cpp(bpMediaPlayer.cpp )->IMediaPlayer.cpp(bnMediaPlayer.cpp )

在这里其实已经达到了MediaPlayerServer中的client类。当底层的media 完成seek 以后会抛出来一消息,这个消息通过 const sp& client 通知给MediaPlayer。

在media相关的头文件中还有一个MediaPlayerInterface.h 。这个头文件定义了底层播放器的接口。

四、Media FrameWork源码分析

首先,针对android.media.MediaPlayer进行分析。

里面有很多native代码,我们找到native_setup这个jni调用,就可以找到整个框架的入口。

我们查看

android_media_MediaPlayer_native_setup@framworks/base/media/jni/android_media_MediaPlayer.cpp

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

`static` `void` `android_media_MediaPlayer_native_setup(

    JNIEnv *env, jobject thiz, jobject weak_this

    )``

    {

        ``  ``

    LOGV(``"native_setup"``);

        ``  ``sp mp = ``new` `MediaPlayer();

        ``  ``

        if` `(mp == NULL) {

        ``    ``

        jniThrowException(

            env, ``"java/lang/RuntimeException"``,

            ``"Out of memory"``);

            ``   

            ``return``;

            ``  ``

             

        }

            ` `  ``

            // create new listener and give it to MediaPlayer

            ``  ``

            sp listener = ``new` `JNIMediaPlayerListener(

                env, thiz, weak_this);

                ``  ``

                mp->setListener(listener);

                ` `  ``

                // Stow our new C++ MediaPlayer in an opaque field in the Java object.

                ``  ``

                setMediaPlayer(env, thiz, mp);

                ``

         

    }

        `

从这里的这段代码我们可以看到,android在这里实例化了一个变量mp:MediaPlayer。

并且为其设置了一个listener:JNIMediaPlayerListener

在后面我们会看到对mp的调用,现在让我们先看看MediaPlayer是什么东东。

MediaPlayer@framworks/base/include/media/mediaplayer.h MediaPlayer@framworks/base/media/libmedia/mediaplayer.cpp

在这里我们终于找到了MediaPlayer:BnMediaPlayerClient:IMediaPlayerClient

原来他也是对Bind Native的一个封装,而他本身提供了很多方法用于访问,包括start等。下面是start的cpp代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

status_t MediaPlayer::start()

{

    LOGV("start");

    Mutex::Autolock _l(mLock);

    if (mCurrentState & MEDIA_PLAYER_STARTED)

        return NO_ERROR;

    if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |

                    MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {

        mPlayer->setLooping(mLoop);

        mPlayer->setVolume(mLeftVolume, mRightVolume);

        mCurrentState = MEDIA_PLAYER_STARTED;

        status_t ret = mPlayer->start();

        if (ret != NO_ERROR) {

            mCurrentState = MEDIA_PLAYER_STATE_ERROR;

        } else {

            if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {

                LOGV("playback completed immediately following start()");

            }

        }

        return ret;

    }

    LOGE("start called in state %d", mCurrentState);

    return INVALID_OPERATION;

}

原来这里又调用了mPlayer:sp

从这里我们发现最终的服务,还是由IMediaPlayer这个东西提供的,而IMediaPlayer@framworks/base/include/media/IMediaPlayer.h

实际上是如下定义的一个类,它继承了IInterface@framworks/base/include/binder/IInterface.h这个类(注意虽然名字是Interface,但是它确实是个类!:-))

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

class IMediaPlayer: public IInterface

{

public:

    DECLARE_META_INTERFACE(MediaPlayer);

    virtual void            disconnect() = 0;

    virtual status_t        setVideoSurface(const sp<ISurface>& surface) = 0;

    virtual status_t        prepareAsync() = 0;

    virtual status_t        start() = 0;

    virtual status_t        stop() = 0;

    virtual status_t        pause() = 0;

    virtual status_t        isPlaying(bool* state) = 0;

    virtual status_t        seekTo(int msec) = 0;

    virtual status_t        getCurrentPosition(int* msec) = 0;

    virtual status_t        getDuration(int* msec) = 0;

    virtual status_t        reset() = 0;

    virtual status_t        setAudioStreamType(int type) = 0;

    virtual status_t        setLooping(int loop) = 0;

    virtual status_t        setVolume(float leftVolume, float rightVolume) = 0;

    virtual status_t        invoke(const Parcel& request, Parcel *reply) = 0;

    virtual status_t        setMetadataFilter(const Parcel& filter) = 0;

    virtual status_t        getMetadata(bool update_only,

                                        bool apply_filter,

                                        Parcel *metadata) = 0;

};

为了弄清楚,在什么地方产生的mPlayer,我转而分析MediaPlayerService@framworks/base/media/libmediaplayerservice/MediaPlayerService.h

其中有如下代码

1

2

3

4

5

6

virtual sp<IMediaRecorder>  createMediaRecorder(pid_t pid);

void    removeMediaRecorderClient(wp<MediaRecorderClient> client);

virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid);

// House keeping for media player clients

virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url);

virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length);

原来在这个地方会创建你sp对象。


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://juejin.cn/post/7181708962167783482
相关文章
  • RxJava构建流基本原理解析
    本节,我们从Rxjava使用代码入手,去结合自己已有的知识体系,加查阅部分源码验证的方式,来一起探索一下Rxjava实现的基本原理。 为了本
  • Android音视频开发Media FrameWork框架源码解析
    一、Media FrameWork背景 Media Framework (媒体函数库):此函数库让Android 可以播放与录制许多常见的音频与视频文件,支持的文件类型包括MPEG4、
  • 使用Flutter实现手写签名效果的教程
    思路 需要监听用户触摸的起始点和结束点,并记录途经点,这里我使用了StreamController 将途经点从起始位置到结束位置绘制出来,这里用到
  • Kotlin协程与挂起函数及suspend关键字深入理解

    Kotlin协程与挂起函数及suspend关键字深入理解
    1.挂起函数 挂起函数在Kotlin协程中是一个比较重要的知识点,协程的非阻塞式、Channel、Flow等API都对它有充分的理解才能在学习时事半功倍。
  • Android自定义View实现绘制水波浪温度刻度表

    Android自定义View实现绘制水波浪温度刻度表
    之前的绘制圆环,我们了解了如何绘制想要的形状和进度的一些特点,那么此篇文章我们更近一步,绘制一个稍微复杂一点的刻度与波浪。
  • Android硬件解码组件MediaCodec使用教程
    1.MediaCodec 是什么 MediaCodec类可以访问底层媒体编解码器框架(StageFright 或 OpenMAX),即编解码组件。是Android 的低层多媒体基础设施的一部分
  • Flow解决背压问题的方法介绍

    Flow解决背压问题的方法介绍
    随着时间的推移,越来越多的主流应用已经开始全面拥抱Kotlin,协程的引入,Flow的诞生,给予了开发很多便捷,作为协程与响应式编程结合
  • Andorid开发中反射机制的介绍
    在andorid开发中,经常遇见在某些工具类中没有Context上下文对象时,一些系统服务的代理对象无法创建出来,举个例子:比如在源码(framewo
  • Flutter加载图片的多样玩法汇总

    Flutter加载图片的多样玩法汇总
    加载本地图片 在项目目录下创建assets文件夹,再在其文件夹下创建images文件夹,后面将需要的图片复制到其中即可 在pubspec.yaml文件中添加引
  • Kotlin的Collection与Sequence操作异同点介绍

    Kotlin的Collection与Sequence操作异同点介绍
    在Android开发中,集合是我们必备的容器,Kotlin的标准库中提供了很多处理集合的方法,而且还提供了两种基于容器的工作方式:Collection 和
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计