zoukankan      html  css  js  c++  java
  • Android Mediaplayer解读

    http://blog.csdn.net/menguio/article/details/6323965

    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系统的本地服务部分。
  • 相关阅读:
    【NOIP 2003】 加分二叉树
    【POJ 1655】 Balancing Act
    【HDU 3613】Best Reward
    【POJ 3461】 Oulipo
    【POJ 2752】 Seek the Name, Seek the Fame
    【POJ 1961】 Period
    【POJ 2406】 Power Strings
    BZOJ3028 食物(生成函数)
    BZOJ5372 PKUSC2018神仙的游戏(NTT)
    BZOJ4836 二元运算(分治FFT)
  • 原文地址:https://www.cnblogs.com/eustoma/p/2415824.html
Copyright © 2011-2022 走看看