博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android Mediaplayer解读
阅读量:5929 次
发布时间:2019-06-19

本文共 8712 字,大约阅读时间需要 29 分钟。

1 Gallery应用端表现
    Gallery仅仅提供一个呈现框架,Gallery用来管理所有的视频和图片文件,具有播放、查看、删除等功能。自动搜索本地sdcard存有的picture和video,并分类将同性质文件picture和video集中在一起,播放时呈现。Gallery内部实现的播放主用是同MediaPlayer,主要包含了Audio和video的播放功能。
    
    Gallery中增加从指定目录选择播放文件的功能:
方法:首先遍历sdcard下的目录,然后通过选择某个目录,再遍历文件,点击文件播放。
说明:
    定义了两个List表:
    videoPathList:遍历/sdcard下目录,并存于此List。
    videlFileList:遍历相应目录下的文件,并存于此List。
    定义了两个Activity:
    VideoList2Play:实现/sdcard下目录和文件遍历。
    VideoPlayer:利用VideoView类实现视频播放。
    从Gallery的按钮和菜单项着手,将该功能植入Gallery。
    Gallery首次加载的图框上“拍照按钮”,能够找到内部功能实现的类和方法,并可以将该功能加入。
    利用more菜单,增加“选择其它视频”功能,涉及内部类复杂,需进一步研究,暂没有实现。
    利用视频播放是的MovieView中增加“选择其它视频”按钮,当有视频真正在播放时,点击按钮选择其它视频,会有冲突。
需改进:研究通过弹出选择对话框方式,可以自由选择/sdcard下的目录和文件,并实现播放。
    Gallery中数据缓存及处理流程
    在应用程序中有三个线程存在:主线程(随activity的声明周期启动销毁)、feed初始化线程(进入程序时只运行一次,用于加载相册初始信息)、feed监听线程(监听相册和相片的变更)。主要流程归纳如下:
    1、首次进入程序Gallery调用onCreate,此时发送初始化消息进入消息队列;然后Gallery调用onResume,向下进入GridLayer的onResume。MediaFeed对象需要进行初始化,然后才可调用MediaFeed 的onResume;
    2、处理消息队列中的HANDLE_INTENT消息,Gallery处理这个消息会初始化数据源,从而调用GridLayer的setDataSource方法,这个方法会触发底层MediaFeed的启动方法start,执行完后启动feed监听线程继续执行MediaFeed的run方法。
    start方法会作两件事:调用自己底层的重新开始方法onResume,onResume中会为图像和视频这两个媒体源分别增加“内容变化监听器”,并请求刷新这两个媒体源(加入全局的刷新请求列表);启动feed初始化线程mAlbumSourceThread。
    3、其中MediaFeed初始化线程的工作是:调用MediaFeed的loadMediaSets加载相册,它又调用了下层 LocalDataSource中的refresh方法(查询数据库是否有相册变化,新增或修改feed中相应的MediaSet相册的名字)和 loadMediaSets方法(调用下层CacheService.loadMediaSets方法)加载所有相册和相册中的所有相片信息。
    4、MediaFeed监听线程MediaFeed.run()的工作是:根据“内容变化监听器”返回的媒体变动消息(增删改),持续不断的更新MediaFeed中的相册和相片变量。具体机制如下:如果全局的刷新请求列表中有内容,则调用LocalDataSource.refresh进行相册信息的更新(其中 LocalDataSource.refresh调用了CacheService的computeDirtySets),然后run遍历每个相册并调用dataSource.loadItemsForSet()方法为相册加载相片记录。
2 功能模块说明
1) 层次结构
    分为三层:上层Java应用程、中层Framework层、下层是底层libaries层。整个MediaPlayer在运行的时候,可以大致上分成Client和Server两个部分,它们分别在两个进程中运行,它们之间使用Binder机制实现IPC通讯。
2) 说明
  2.1) Gallery.java中通过Handler实现实现进程间通信,涉及sendInitialMessage()方法;检查存储的媒体文件,涉及checkStorage()方法;并初始化Data Source,涉及initializeDatasource()方法;判定数据类型后,通过onActivityResult()执行相应的活动。涉及到图层,GridLayer主图层,同GridDrawManager管理媒体的呈现。
  
 2.2) MediaPlayer的JAVA本地调用部分
    MediaPlayer的JAVA本地调用部分在目录frameworks/base/media/jni/的 android_media_MediaPlayer.cpp中的文件中实现。android.media.MediaPlayer中有2部分,一部分供java上层如VideoView调用,一部分为native方法,调用jni。
    通过MediaPlayerService实现client端和MediaPlayer进行交互和数据通信,其中涉及通过MediaProvider(多媒体内容提供者)调用数据源,MediaScannerService(多媒体扫描服务)和MediaScannerReceiver检查数据类型(这两个类之间通过Server和BroadcasterRevceiver, 主要的方法scan()、scanFlle()),并将统一类型的文件归类用MediaStore(多媒体存储)进行数据存储;MediaPlayer.java调用jni_android_media_MediaPlayer.jni进行同MediaPalyer.cpp实现通信。        
    说明:
• MediaStore这个类是android系统提供的一个多媒体数据库,android中多媒体信息都可以从这里提取。这个MediaStore包括了多媒体数据库的所有信息,包括音频、视频和图像。
• MediaScannerReceiver在任何的ACTION_BOOT_COMPLETED, ACTION_MEDIA_MOUNTED或 ACTION_MEDIA_SCANNER_SCAN_FILE 意图(intent)发出的时候启动。因为解析媒体文件的元数据或许会需要很长时间,所以MediaScannerReceiver会启动MediaScannerService。
• MediaScannerService调用一个公用类MediaScanner进行媒体扫描工作。MediaScannerReceiver维持两种扫描目录:一种是内部卷(internal volume)指向$(ANDROID_ROOT)/media. 另一种是外部卷(external volume)指向$(EXTERNAL_STORAGE).
3) MediaPlayer
    Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调用MediaPlayer实现的,上层还包含了进程间通讯等内容,这种进程间通讯的基础是Android基本库中的Binder机制。Android的媒体播放功能分成两部分,一部分是媒体播放应用,一部分是媒体播放服务。这两部分分别跑在不同的进程中。媒体播放应用包括Java程序和部分C++代码,媒体播放服务是C++代码。媒体播放应用和媒体播放服务之间需要通过binder机制来进行相互调用,这些调用包括:
   (1) 媒体播放应用向媒体播放服务发控制指令;
   (2) 媒体播放服务向媒体播放应用发事件通知(notify)。
•    媒体播放服务对外提供多个接口,其中有2个重要的接口:IMediaPlayerService和IMediaPlayer;IMediaPlayerServer用于创建和管理播放实例,而IMediaPlayer接口则是播放接口,用于实现指定媒体文件的播放以及播放过程的控制。
•        媒体播放应用向媒体播放服务提供的1个接口:IMediaPlayerClient,用于接收notify()。这些接口需要跨进程调用,涉及到binder机制(就是让这两部分之间建立联系)。每个接口包括两部分实现,一部分是接口功能的真正实现(BnInterface),这部分运行在接口提供进程中;另一部分是接口的proxy(BpInterface),这部分运行在调用接口的进程中。
3 代码框架
 
1) JAVA程序的路径:
packages/apps/Camera/
编译后生成Camera.apk,对应于Camera、Gallery、Camcorder三个应用。
packages/apps/Gallery/src/com/android/camera/gallery、
packages/apps/Gallery3D/src/com/cooliris/app
packages/providers/MediaProvider/
含有类MediaProvider.java、MediaScannerService.java、MediaScannerReceiver.java,
编译后生成MediaProvider.apk。会在开机时扫描本机和sdcard上的媒体文件(图片、视频、音频),并在/data/data/com.android.providers.media/databases 目录下生成internal.db(/system/meida)和external-?.db(/sdcard)两个数据库文件。此后所有的多媒体信息都从这两个数据库中获取。
2) JAVA Framework的路径:
frameworks/base/core/java/android/provider/MediaStore.java
提供的多媒体数据库,所有多媒体数据信息都可以从这里提取。数据库的操作通过利用ContentResolver调用相关的接口实现。
frameworks/base/media/java/android/media/
提供了android上 多媒体应用层的操作接口。主要说明:
• MediaPlayer.java:提供了视频、音频、数据流的播放控制等操作的接口。
• MediaScanner*.java:提供了媒体扫描接口的支持,媒体扫描后加入数据库中,涉及MediaScannerConnection.java和MediaScannerConnectionClient.java。
3) JAVA本地调用部分(JNI):
frameworks/base/media/jni
JAVA本地调用部分。编译后生成的目标是libmedia_jni.so。
•    android_media_MediaPlayer.cpp:JAVA本地调用部分,它定义了一个JNINativeMethod(JAVA本地调用方法)类型的数据gMethods用来描述接口的关联信息;定义了JNIMediaPlayerListener:MediaPlayerListener的notify()方法(该方法是调用c++层次的mediaplayer中,实现播放管制)。
•    android_media_MediaScanner.cpp: 媒体扫描相关的本地调用实现。处理路径、文件和Ablum相册内容释放。
•    soundpool/android_media_SoundPool.cpp:定义了音频系统的本地调用实现、MediaPlayer回调方法android_media_callback()。
4) 多媒体底层库:
frameworks/base/include/media/、frameworks/base/media/libmedia/
    这里为多媒体的的底层库,编译生成libmedia.so。这个库处于android多媒体架构的核心位置,它对上层提供的接口主要有MediaPlayer、MediaScanner等类。
    android.meida.* 就是通过libmedia_jni.so调用libmedia.so实现的接口实现的。    
    A) MediaPlayerInterface.h头文件定义了MediaPlayer的底层接口,定义了以下类:
•    MediaPlayerBase:MediaPlayerInterface的抽象基础类,里面包含了音频输出、视频输出、播放控制等的基本接口。
•        MediaPlayerInterface、MediaPlayerHWInterface 继承自MediaPlayerBase针对不同输出作出的扩展。
•        MediaPlayerInterface得到具有相同的播放接口,可以通过继承MediaPlayerInterface的方法,实现增加新的播放器实现。
    B) IMediaPlayer.h定义了BnMediaPlayer本地播放类;IMediaPlayer.cpp定义了BpMediaPlayer代理类(其中通过remote()->transact()方法发送消息)和实现了BnMediaPlayer:onTransact()的具体方法。
    C) IMediaPlayerClient.h定义了BnMediaPlayerClient本地客户端类;IMediaPlayerClient.cpp定义了BpMediaPlayerClient代理类(其中通过notify()中的remote()->transact()方法发送消息)和实现了BnMediaPlayerClient:onTransact()方法。
    D) IMediaPlayerService.h定义了BnMediaPlayerService本地服务端类;IMediaPlayerService.cpp定义了BpMediaPlayerService代理类(其中通过remote()->transact()方法发送消息)和实现了BnMediaPlayerService:onTransact()方法。
    E) mediaplayer.h定义了MediaPlayerListener类的notify()方法和类MediaPlayer:BnMediaPlayerClient;mediaplayer.cpp主要实现了MediaPlayer的数据设置播放和实现了MediaPlayerListener类的notify()具体方法。
5) 多媒体服务部分:
frameworks/base/media/libmediaplayerservice/
文件为mediaplayerservice.h和mediaplayerservice.cpp
    这是多媒体的服务部分(提供Media Player执行的Proxy,同Client端建立连接、设置数据源、根据不同类型创建播放),编译生成libmediaplayerservice.so。     
• MediaPlayerService.cpp 通过instantiate()方法实现了一个名字为media.player的服务,MediaPlayer通过IPC同其实现通讯;
• 根据playerType的类型来决定创建不同的播放器;
• 实现了notify()通知Client端、callbackThread()回调机制、decode解码。
frameworks/base/media/mediaserver/
文件为main_mediaserver.cpp是Mediaplayer Server启动的主程序,涉及AudioFlinger()、AudioPolicyService()、MediaPlayerService()的加载。
6) MediaPlayer生命周期:
 
4 Audio概念
Audio系统在Android中负责音频方面输入/输出和管理层次,一般负责播放PCM声音输出和从外部获取PCM声音,以及管理声音设备和设置。主要涉及到AudioManager、AudioTrack、AudioServiece、AudioRecord。主要分成如下几个层次:
 (1) media库提供的Audio系统本地部分接口;
 (2) AudioFlinger作为Audio系统的中间层;
 (3) Audio的硬件抽象层提供底层支持;
 (4) Audio接口通过JNI和Java框架提供给上层。
    Audio管理环节    Audio输出    Audio输入
Java层    android.media.
AudioSystem    android.media
AudioTrack    android.media.
AudioRecorder
本地框架层    AudioSystem    AudioTrack    AudioRecorder
AudioFlinger    IAudioFlinger    IAudioTrack    IAudioRecorder
硬件抽象层    AudioHardwareInterface    AudioStreamOut    AudioStreamIn
AudioTrack.java:SoundPool.java 播放android application的生音资源。
AudioRecord.java: 为android applicatio 提供录音设置(sample、chanel等)的接口;
AudioManager.java: 提供了音频音量,以及播放模式(静音、震动等)的控制。
说明:
1) Audio驱动程序(Linux系统,因不同平台而已)
2) Audio硬件抽象层:hardware/libhardware_legacy/include/hardware/
    AudioHardwareInterface.h(定义Audio硬件抽象层的接口),其中三个主要类AuidoStreamOut/AudioStreamIn/AuidoHardwareInterface实现Audio的输出/输入/管理。
    2.1) AudioStreamOut关键接口write(const void* buffer, size_t bytes)/AudioStreamIn关键接口read(void* buffer, size_t bytes),通过定义内存的指针和长度音频数据的输出和输入。
    2.2) AudioHardwareInterface使用openOutputStream()和openInputStream()函数来获取AudioStreamOut和AudioStreamIn。
    2.3) AudioHardwareInterface中所涉及的参数是在AudioSystem.h中定义,通过setParameters和getParameters接口设置和获取参数,通过setMode()设置系统模式。
    2.4) Audio中引进了策略管理AudioPolicyInterface,目的是将Audio核心部分和辅助性功能分离。
3) AudioFlinger的实现方式
    3.1) 通用方式AndroidHardwareGeneric实现基于特定驱动的通用Audio硬件抽象层。
    3.2) 桩实现方式AndroidHardwareStub,实现Audio硬件抽象层的一个桩,是个空操作,保证没有Audio设备时系统正常工作。
    3.3) AudioDumpInterface实现以文件为输入输出的Audio硬件抽象层,以文件模拟Audio硬件流的输入输出环节。
Audio代码分布:
(1) Java部分:frameworks/base/media/java/android/media
与audio相关的java package是android.media,主要包含audio manager和audio系统的几个类,这部分主要给上层的AP部分提供audio相关的接口。
(2) JNI部分: frameworks/base/core/jni
Android系统会生成一个libandroid_runtime.so,audio的JNI是其中的一个部分。
(3) audio frameworks
头文件路径:frameworks/base/include/media/
代码路径:frameworks/base/media/libmedia/
Audio本地框架是media库的一部分,本部分的内容被编译成库libmedia.so,提供audio部分的接口(其中包括基于binder的IPC机制)。
(4) Audio Flinger:frameworks/base/libs/audioflinger
这部分内容被编译成库libaudioflinger.so,它是audio系统的本地服务部分。

转载地址:http://oqktx.baihongyu.com/

你可能感兴趣的文章
Unity小记
查看>>
IIS负载均衡-Application Request Route详解第二篇:创建与配置Server Farm
查看>>
js/jquery/插件表单验证
查看>>
Bandwidth内存带宽測试工具
查看>>
为Node.js编写组件的几种方式
查看>>
(轉貼) Anders Hejlsberg談C#、Java和C++中的泛型 (.NET) (C#)
查看>>
30天敏捷结果(24):恢复你的精力
查看>>
JNI——访问数组
查看>>
C#开发和调用Web Service
查看>>
Android6.0机型上调用系统相机拍照返回的resultCode值始终等于0的问题
查看>>
全面理解Git
查看>>
JS敏感信息泄露:不容忽视的WEB漏洞
查看>>
让我们荡起双桨,Android 小船波浪动画
查看>>
ApacheCN 翻译活动进度公告 2019.2.18
查看>>
分布式memcached服务器代理magent安装配置(CentOS6.6)
查看>>
Create Volume 操作(Part III) - 每天5分钟玩转 OpenStack(52)
查看>>
物联网的广泛应用将扭转发展中经济体的局面 为全球发展带来新机遇
查看>>
Polar码引发舆论狂欢 5G标准远未定局
查看>>
IntersectionObserver + Custom Elements 实现图片懒加载(滚动加载)/点击重试
查看>>
KSImageNamed-Xcode-master
查看>>