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

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

一、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通信相关的接口。 定义了:

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:

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:

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通信只有一个接口:

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

`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代码:

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,但是它确实是个类!:-))

class IMediaPlayer: public IInterface{public: DECLARE_META_INTERFACE(MediaPlayer); virtual void disconnect() = 0; virtual status_t setVideoSurface(const sp& 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

其中有如下代码

virtual sp createMediaRecorder(pid_t pid);void removeMediaRecorderClient(wp client);virtual sp createMetadataRetriever(pid_t pid); // House keeping for media player clientsvirtual sp create(pid_t pid, const sp& client, const char* url);virtual sp create(pid_t pid, const sp& client, int fd, int64_t offset, int64_t length);

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

五、文末

在本篇中,我们知道了Media Framework在整个Android框架中的位置, 也了解了Media Framework自己是个什么样框架,以及它和各部分的联系。 以及他的源码分析。这也是音视频学习的重要部分。音视频进阶入门,请私信发送“核心笔记”或“手册”,即可获取音视频资料!

郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
(0)
用户投稿
上一篇 2022年6月25日
下一篇 2022年6月25日

相关推荐

  • 一顿早餐2000缅甸币,一千元人民币在缅甸可以玩多久?

    经济的快速发展让人们的生活水平越来越高,物质条件也越来越好。 物质好了,自然对精神方面的要求也更高了。 (此处已添加小程序,请到今日头条客户端查看) 在过去,人们的娱乐活动更多的是…

    2022年8月11日
  • 请问大学专业是通信工程的以后工作可以有哪些?

    我是一个工科985大学,通信工程本科2006年,通信与信息系统硕士2008年毕业的。结合自己和同学情况来尝试说说这个问题。 1: 运营商:中国移动,中国电信,中国联通 很多本科同学…

    2022年6月18日
  • 河南储户被赋红码—原来又是程序员背锅

    只能说程序员苦命,写代码写的头晕脑胀又犯了bug,和当地卫健委,银行管理人员无关。 但是,你信吗?

    2022年6月16日
  • 中国电科研制空间行波管累计在轨时间超430万小时

    来源:【中国电科】 近日,随着“四维高景二号01、02”卫星在太原成功发射,中国电科12所研制的空间行波管在轨总数量突破200支,累计在轨时间超430万小时。 空间行波管是卫星和飞…

    2022年8月18日
  • Git命令简单使用

    Git命令简单使用 背景 最近经常使用Github,每次修改个文件代码都要在网页端操作,感觉效率低下,所以简答学习了解了一下Git命令。至使于可以在命令行进行管理Git仓库,这样就…

    2022年6月16日
  • 替代CPU?阿里云以CIPU定义下一代云计算

    来源:【科学网】 2022阿里云峰会只有半天时间的云上跨时空连线,时间虽短,但发布的信息令人震撼。 最重磅的消息,当属阿里云智能总裁张建锋发布的全新“处理器”:CIPU(Cloud…

    2022年6月18日
  • 晚来天欲雪,能饮一杯无?ROG Z690 吹雪 + 追风者纯白主题装机实例

    Hello,大家好!我是沈少!最近几年白色主题的装机方案越来越流行,究其原因,还是在于大家已经看了太多传统的黑色主机,想来点不一样的。特别的现在炎炎夏日,组装一套清爽的白色主机视觉…

    2022年6月22日
  • Redmi G游戏本现已开启预售,首发价6299元起

    Redmi G游戏本现已开启预售,首发价6299元起 电竞大屏 16英寸 2.5K 165Hz、500nits 高亮度、ΔE< 1.5 高色准 新一代战力 12代酷睿H45、…

    2022年7月22日
  • VIVO X Note用户评价 VIVO X Note配置 VIVO X Note跑分

    VIVO X Note 是VIVO品牌的高端机之一,今天来介绍下各大电商用户评价和详细配置以及CPU跑分,这款手机的颜色深受很多女生和男生喜爱目前有三个版本,8GB+256GB 1…

    2022年8月29日
  • 总结下SpringData JPA 的常用语法

    SpringData JPA常用有两种写法,一个是用Jpa自带方法进行CRUD,适合简单查询场景、例如查询全部数据、根据某个字段查询,根据某字段排序等等。另一种是使用注解方式,@Q…

    2022年6月18日

联系我们

联系邮箱:admin#wlmqw.com
工作时间:周一至周五,10:30-18:30,节假日休息