【音视频播放】一、播放基础流程及相关服务

前言

安利一个音视频博主,他的博文写的很详细。本博文只是简单介绍大致的播放流程。
文章大纲

1 播放音视频文件流程

在这里插入图片描述
图片来源

音视频播放流程:

  1. 获取音视频来源source(本地文件或者链接)
  2. 分离出source中的音频和视频extractor
  3. 对音视频数据进行解码decoder
  4. 解码后的数据进行渲染render(其中包含音视频同步)
  5. 渲染后的数据交给device播放

大致流程就这,建议先熟悉这个流程图再结合代码看,代码是实现的那一部分的功能。

2 media相关服务

2.1 查看命令

2.1.1 service

service list | grep media

重点关注下
media.extractor 分离音视频
media.player media播放
media.audio_flinger 音频执行
media.audio_policy 音频策略
media相关service

2.1.2 进程

ps -ef | grep media

media相关进程

只需要先了解有如下四个进程就ok:
media.extractor(分离)
mediaserver(media服务,总管media)
mediacodec(分软件解码和硬件解码)
软件解码 media.swcodec oid.media.swcodec/bin/mediaswcodec
硬件解码 media.codec hw/android.hardware.media.omx@1.0-service

2.2 service简单介绍

2.2.1 mediaplayer

在main_mediaserver.cpp中会创建"media_player"服务。
主要就是创建MediaPlayerService,然后添加到ServiceManager中。
再往下追一点点,追到NuPlayer就行。

//Main_mediaserver.cpp (frameworks\av\media\mediaserver)
int main(int argc __unused, char **argv __unused)
{
	//创建service管理器
    sp<IServiceManager> sm(defaultServiceManager());
	//初始化mediaplayer服务
    MediaPlayerService::instantiate();
}

//MediaPlayerService.cpp (frameworks\av\media\libmediaplayerservice)
void MediaPlayerService::instantiate() {
    defaultServiceManager()->addService(
            String16("media.player"), new MediaPlayerService());
}

MediaPlayerService::MediaPlayerService()
{
    ALOGV("MediaPlayerService created");
    mNextConnId = 1;

	//创建
    MediaPlayerFactory::registerBuiltinFactories();
}

void MediaPlayerFactory::registerBuiltinFactories() {
    Mutex::Autolock lock_(&sLock);

    if (sInitComplete)
        return;

	//创建NuPlayerFactory实例
    IFactory* factory = new NuPlayerFactory();
    if (registerFactory_l(factory, NU_PLAYER) != OK)
        delete factory;
    //创建TestPlayer实例
    factory = new TestPlayerFactory();
    if (registerFactory_l(factory, TEST_PLAYER) != OK)
        delete factory;

    sInitComplete = true;
}

enum player_type {
    STAGEFRIGHT_PLAYER = 3,
    NU_PLAYER = 4,
    // Test players are available only in the 'test' and 'eng' builds.
    // The shared library with the test player is passed passed as an
    // argument to the 'test:' url in the setDataSource call.
    TEST_PLAYER = 5,
};

需要注意的是,mediaplayer的实例创建了两个,分别是NuPlayer和TestPlayer,实际使用中使用的是NuPlayer,TestPlayer有兴趣的可以看看,代码比较少。

至此,我们简单了解了mediaplay服务的创建以及mediaplayer的实例是nuplayer。

2.2.2 audioserver

顺便了解一下音频的server创建。

AudioPolicyService是策略的制定者,比如什么时候打开音频接口设备、某种Stream类型的音频对应什么设备等等。而AudioFlinger则是策略的执行者,例如具体如何与音频设备通信,如何维护现有系统中的音频设备,以及多个音频流的混音如何处理等等都得由它来完成。AudioPolicyService根据用户配置来指导AudioFlinger加载设备接口,起到路由功能。
来源文章:深入剖析Android音频之AudioPolicyService

//Main_audioserver.cpp (frameworks\av\media\audioserver)
int main(int argc __unused, char **argv)
{
        sp<IServiceManager> sm = defaultServiceManager();
        //创建执行
        AudioFlinger::instantiate();
        //创建策略制定
        AudioPolicyService::instantiate();
        //创建语音识别服务
        SoundTriggerHwService::instantiate();
    }
}

2.2.3 surface

视频的显示依赖surface
视频数据渲染之后就是通过这个类进行送显的,先了解一下。

//Main_surfaceflinger.cpp (frameworks\native\services\surfaceflinger)
int main(int, char**) {
	//绘图Graphics服务启动
    startGraphicsAllocatorService();

    //创建SurfaceFlinger
    sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger();

    //添加SurfaceFlinger到ServiceManager
    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);

	//启动显示服务
    startDisplayService(); // dependency on SF getting registered above
}

在这里插入图片描述

2.2.4 服务框架

图片来源:Android MultiMedia框架完全解析 - 概览
在这里插入图片描述
上图的框架图特别好,service的关系也理清了。

  1. 目前我们有左侧的这几个主要server启动了
    mediaserver多媒体服务,extractorservice分离音视频数据,mediacodecservice音视频数据解码,mediadrmserver音视频数字版权管理服务(有兴趣的可以去搜下)
  2. app创建mediaplayer,实例是nuplayer,nuplayer再访问这些service进行数据处理
  3. 解码部分:OMX
  4. 音频输出部分:audioflinger
  5. 视频显示部分:surfaceflinger

2.3 小结

  1. 音视频播放服务是“media.player”,创建一个实例NuPlayerFactory用于实际的播放。
  2. 音频输出依赖于执行者“media.audio_flinger”和策略者“media.audio_policy”
  3. 视频输出依赖于“SurfaceFlinger”

在nuplayer的实现中会访问到音频和视频的server去实现播放。
在这里插入图片描述

3 代码查看

安卓官网上查看下mediaplayer的介绍。

3.1 支持的媒体源

MediaPlayer 类是媒体框架最重要的组成部分之一。此类的对象能够获取、解码以及播放音频和视频,而且只需极少量设置。它支持多种不同的媒体源,例如:

  • 本地资源
  • 内部 URI,例如您可能从内容解析器那获取的
  • URI 外部网址(流式传输)

3.2 以本地文件播放为例

看下java层的播放流程。

  1. 创建mediaplayer
  2. 获取音频播放流的类型stream_type(默认是music)
  3. 获取播放文件资源source
  4. 播放准备(分离音视频数据)
  5. 播放开始(解码、渲染、输出)
    Uri myUri = ....; // initialize Uri here
    // 1. 创建mediaplayer
    MediaPlayer mediaPlayer = new MediaPlayer();
    // 2. 获取音频播放流的类型stream_type(默认是music)
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    // 3. 获取播放文件资源source
    mediaPlayer.setDataSource(getApplicationContext(), myUri);
    // 4. 播放准备
    mediaPlayer.prepare();
    // 5. 播放开始
    mediaPlayer.start();

主要的播放流程就是这样,结合文章最开始的图片查看,其中准备阶段内包含了分离音视频数据,播放开始阶段才进行解码、渲染、输出。

3.3 函数调用流程

图片来源:Android MultiMedia框架完全解析 - 概览
建议看下这个博主的文章,写的都特别赞。

在这里插入图片描述
首先java层向下调用,中间有个jni,是用于java和cpp交互的,也就是android_media_MediaPlayer.cpp

文件路径:android\frameworks\base\media\jni

java层

	//android\frameworks\base\media\java\android\media\MediaPlayer.java
	//java层会调用startImpl函数用于播放
    private void startImpl() {
        baseStart();
        stayAwake(true);
        _start();
    }
    
	//定义了_start函数是调用到native层
    private native void _start() throws IllegalStateException;

jni层

//android_media_MediaPlayer.cpp (frameworks\base\media\jni)
//定义了_start的native层对应的是android_media_MediaPlayer_start
static const JNINativeMethod gMethods[] = {
    {"_start",              "()V",                              (void *)android_media_MediaPlayer_start},
}

//jni层函数定义
android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
{
    ALOGV("start");
    //获取mediaplayer    
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
	
	//调用mediaplayer的start函数
    process_media_player_call( env, thiz, mp->start(), NULL, NULL );
}

native层(cpp文件)

//Mediaplayer.cpp (frameworks\av\media\libmedia)
status_t MediaPlayer::start()
{
    ALOGV("start");
	//省略许多代码
	
		//调用mediaplayer的实例的start函数
        ret = mPlayer->start();
}

//Mediaplayer.h (frameworks\av\media\libmedia)
//mPlayer类型为IMediaPlayer,有代理
sp<IMediaPlayer>            mPlayer;

//MediaPlayerService.cpp (frameworks\av\media\libmediaplayerservice)
//这里只是获取基础类MediaPlayerBase,然后调用定义的start函数
status_t MediaPlayerService::Client::start()
{
    ALOGV("[%d] start", mConnId);
    sp<MediaPlayerBase> p = getPlayer();
    
    return p->start();
}

//MediaPlayerInterface.h (frameworks\av\include\media)
定义一个虚函数
        virtual status_t    start() = 0;

实际上start函数在mediaplayer实例化的时候会被重载,也就是我们的nuplayer。
当然nuplayer只是一种实例,还有旧版的awesomeplayer等等,有兴趣可以了解一下。

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值