一、android多媒体播放的调用步骤:

a) android中定义一个MediaPlayer类

b) 在MediaPlayer中使用JNI技术调用的是android_media_MediaPlayer.cpp(media\jni,在这个类中对标准的JNI函数名称进行的转换)

c) 以下涉及的都是C++,android_media_MediaPlayer中调用的是mediaplayer.cpp(media\libmedia,涉及的库libmedia.so)中的函数

d) 然后调用MediaPlayerService.cpp(media\libmediaplayerservice)中的函数

e) 之后开始选择是使用OpenCore还是Stagefright(2.3中使用的是Stagefright),因此接下来调用的是StagefrightPlayer.cpp(media\libmediaplayerservice)中的相关函数

f) 接下去就到了最关键的一个类AwesomePlayer.cpp(media\libstagefright),在这个类里面我们要对read进的buffer进行一些相应的处理,然后再render渲染到surface(这边涉及的库可能是libStagefright.so)

二、以setDataSource()来分析android多媒体播放过程:

a) MediaPlayer类有setDataSource方法,查看源码,它最后调用的是一个native函数(JNI标准),public native void setDataSource(String path),这个函数在android_media_MediaPlayer.cpp中实现

b) android_media_MediaPlayer.cpp中

android_media_MediaPlayer_setDataSourceAndHeaders(

JNIEnv *env, jobject thiz, jstring path, jobject headers)

sp<MediaPlayer> mp = getMediaPlayer(env, thiz);

。。。

status_t opStatus = mp->setDataSource(String8(pathStr), headers ? &headersVector : NULL);

。。。

其中mp是一个MediaPlayer的实例对象,pathStr是视频路径,之后会进入到 mediaplayer.cpp中的 setDataSource()函数

c) Mediaplayer.cpp中

status_t MediaPlayer::setDataSource(

const char *url, const KeyedVector<String8, String8> *headers)

{

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

status_t err = BAD_VALUE;

if (url != NULL) {

const sp<IMediaPlayerService>& service(getMediaPlayerService());

if (service != 0) {

sp<IMediaPlayer> player(

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

err = setDataSource(player);

}

}

return err;

}

这里会调用service的create()函数

d) 在MediaPlayerService.cpp中

sp<IMediaPlayer> MediaPlayerService::create(

pid_t pid, const sp<IMediaPlayerClient>& client, const char* url,

const KeyedVector<String8, String8> *headers, int audioSessionId)

{

int32_t connId = android_atomic_inc(&mNextConnId);

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

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

connId, pid, url, connId, audioSessionId);

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

{

c.clear();

return c;

}

wp<Client> w = c;

Mutex::Autolock lock(mLock);

mClients.add(w);

return c;

}

其中调用了Client类的setDataSource()函数,这个Client比较难找,其实它 是在MediaPlayerService.h中定义的,在java中叫内部类,C++中忘了,查看 Client类中的setDataSource()函数的代码

status_t MediaPlayerService::Client::setDataSource(

const char *url, const KeyedVector<String8, String8> *headers)

{

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

if (url == NULL)

return UNKNOWN_ERROR;

if (strncmp(url, "content://", 10) == 0) {

// get a filedescriptor for the content Uri and

// pass it to the setDataSource(fd) method

String16 url16(url);

int fd = android::openContentProviderFile(url16);

if (fd < 0)

{

LOGE("Couldn't open fd for %s", url);

return UNKNOWN_ERROR;

}

setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus

close(fd);

return mStatus;

} else {

player_type playerType = getPlayerType(url);

LOGV("player type = %d", playerType);

// create the right type of player

sp<MediaPlayerBase> p = createPlayer(playerType);

if (p == NULL) return NO_INIT;

if (!p->hardwareOutput()) {

mAudioOutput = new AudioOutput(mAudioSessionId);

static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);

}

// now set data source

LOGV(" setDataSource");

mStatus = p->setDataSource(url, headers);

if (mStatus == NO_ERROR) {

mPlayer = p;

} else {

LOGE("  error: %d", mStatus);

}

return mStatus;

}

}

其中定义了一个MediaPlayerBase类的实例对象p,并且接下去调用了p的 setDataSource()函数,我们先看看createPlayer()这个函数的源码

static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,

notify_callback_f notifyFunc)

{

sp<MediaPlayerBase> p;

switch (playerType) {

#ifndef NO_OPENCORE

case PV_PLAYER:

LOGV(" create PVPlayer");

p = new PVPlayer();

break;

#endif

case SONIVOX_PLAYER:

LOGV(" create MidiFile");

p = new MidiFile();

break;

case STAGEFRIGHT_PLAYER:

LOGV(" create StagefrightPlayer");

p = new StagefrightPlayer;

break;

case TEST_PLAYER:

LOGV("Create Test Player stub");

p = new TestPlayerStub();

break;

}

if (p != NULL) {

if (p->initCheck() == NO_ERROR) {

p->setNotifyCallback(cookie, notifyFunc);

} else {

p.clear();

}

}

if (p == NULL) {

LOGE("Failed to create player object");

}

return p;

}

值得注意的是红色部分,这边就到了StagefrightPlayer.cpp,上面说到定义了一 个MediaPlayerBase类的实例对象p,并且接下去调用了p的 setDataSource() 函数,那么我们就理所当然地去找MediaPlayerBase类了,但是找了很久没找到, 现在知道了,上面红色部分将new出来的StagefrightPlayer对象赋给了P,那么 P调 用的setDataSource()事实上是StagefrightPlayer这个类中的 setDataSource()这个函数

e) 在StagefrightPlayer.cpp中

status_t StagefrightPlayer::setDataSource(

const char *url, const KeyedVector<String8, String8> *headers) {

LOGI("setDataSource('%s')", url);

return mPlayer->setDataSource(url, headers);

}

其中,直接调用mPlayer->setDataSource(url, headers),那么这个mPlayer是什么 呢?在上一个步骤中的new StagefrightPlayer中其实已经赋值了,源码如下

StagefrightPlayer::StagefrightPlayer()

: mPlayer(new AwesomePlayer) {

LOGV("StagefrightPlayer");

mPlayer->setListener(this);

}

从红色部分可以看出mPlayer是一个AwesomePlayer类的实例对象,那么这个 setDataSource()函数自然就到这个类中去找了

f) 在AwesomePlayer.cpp中

void AwesomePlayer::onVideoEvent() {

。。。。。。

for (;;) {

。。。。。。

status_t err = mVideoSource->read(&mVideoBuffer, &options);

options.clearSeekTo();

。。。。。。

。。。。。。

if (mVideoRenderer != NULL) {

mVideoRenderer->render(mVideoBuffer);

}

。。。。。。

}

第一行红色字表示将帧数据读入mVideoBuffer,第二行红色字体是将这些帧数据渲染到画布中。我们需要修改的就是这个部分,不往下分析了。

三、以start()来分析android多媒体播放过程

a) 首先查看MediaPlayer.java这个类的源码

public  void start() throws IllegalStateException {

stayAwake(true);

_start();

}

之后调用的是_start()这个native函数(JNI标准),即private native void _start() throws IllegalStateException这个函数在android_media_MediaPlayer.cpp中实现

b) 在Android_media_MediaPlayer.cpp中

static void

android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)

{

LOGV("start");

sp<MediaPlayer> mp = getMediaPlayer(env, thiz);

if (mp == NULL ) {

jniThrowException(env, "java/lang/IllegalStateException", NULL);

return;

}

process_media_player_call( env, thiz, mp->start(), NULL, NULL );

}

我们看红色部分的代码,最终调用的是mp->start(),这个mp其实是MediaPlayer的一个对象,那么我们就去MediaPlayer.cpp中查看源码

c) 在MediaPlayer.cpp中

status_t MediaPlayer::start()

{

。。。。。。

mCurrentState = MEDIA_PLAYER_STARTED;

status_t ret = mPlayer->start();

if (ret != NO_ERROR) {

mCurrentState = MEDIA_PLAYER_STATE_ERROR;

} else {

。。。。。。

}
这时候调用了mPlayer的start()这个函数,查看MediaPlayer.h中,可以发现sp<IMediaPlayer> mPlayer,那么再去IMediaPlayer.cpp中去看看

d) 在IMediaPlayer.cpp中

status_t start()

{

Parcel data, reply;

data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());

remote()->transact(START, data, &reply);

return reply.readInt32();

}

Android多媒体播放器源码解析(stagefright框架)相关推荐

  1. Android通知系统源码解析

    Android通知系统源码解析 1. 概述 2. 流程图 2.1. 发送通知流程图 3. 源码解析 3.1. 使用通知--APP进程 3.1.1. 创建通知: 3.1.2. 发送(更新)通知: 3.1 ...

  2. 简单开发的android阅读器源码,包含了读取数据库和文件流处理功能

    原文:简单开发的android阅读器源码,包含了读取数据库和文件流处理功能 源代码下载地址:http://www.zuidaima.com/share/1838906559466496.htm 简单地 ...

  3. http://a.codekk.com/detail/Android/grumoon/Volley 源码解析

    http://a.codekk.com/detail/Android/grumoon/Volley 源码解析

  4. dubbo源码解析之框架粗谈

    dubbo框架设计 一.dubbo框架整体设计 二.各层说明 三.dubbo工程模块分包 四.依赖关系 五.调用链 文章系列 [一.dubbo源码解析之框架粗谈] [二.dubbo源码解析之dubbo ...

  5. 多款Android播放器源码集锦

    Android传说中的3D播放器源码 Android 3D播放器 源码 170 2011-09-28 by:豆沙包 • android音乐播放器源码 android 237 2011-09-03 by ...

  6. Android Hawk的源码解析,一款基于SharedPreferences的存储框架

    转载请标注:http://blog.csdn.net/friendlychen/article/details/76218033 一.概念 SharedPreferences的使用大家应该非常熟悉啦. ...

  7. Android之EasyPermissions源码解析

    转载请标明出处:[顾林海的博客] 个人开发的微信小程序,目前功能是书籍推荐,后续会完善一些新功能,希望大家多多支持! 前言 我们知道在Android中想要申请权限就需要在AndroidManifest ...

  8. Android之DiskLruCache源码解析

    转载请标明出处: http://blog.csdn.net/hai_qing_xu_kong/article/details/73863258 本文出自:[顾林海的博客] 个人开发的微信小程序,目前功 ...

  9. 美女图片采集器 源码+解析

    前言: 有一段时间没写博客了, "持之以恒"徽章都暗了, 实在不该. 前一段确实比较忙, ...小小地给自己的懒找个借口吧. 大二即将结束, 学习iOS也有一段时间了.今天抽点时间 ...

最新文章

  1. 【CSAPP】三、程序的机器级表示
  2. 工作流引擎Activiti使用总结
  3. 01-将自己的Ubuntu电脑设置为一台可远程访问的服务器
  4. 2021年,Java开发者值得学习的13项技能
  5. docker安装软件(vim,service)
  6. @程序员,入行物联网的避坑指南!| 技术头条
  7. 沙盘 服务器未响应,为什么沙盘总是服务启动失败
  8. Redis 菜鸟教程学习笔记- Redis 命令- Key
  9. golang语言环境搭建
  10. 第三章 机器人系统的动力学模型
  11. 新版Airplayer--新功能介绍
  12. 【转载】红外遥控HS0038B接法
  13. Host文件位置和作用介绍
  14. 六、线性方程组求解--Jacobi和Gauss-Seidel迭代求解
  15. NAT地址转换实验记录
  16. VMWare虚拟机下载|最新版|破解版
  17. java p2p技术内幕.pdf_JavaP2P技术内幕
  18. 基于LSTM的股票价格预测
  19. mysql数据库的行级锁有几种_数据库行级锁和表锁区别
  20. linux命令记忆方法,Linux命令快速巧记法

热门文章

  1. 如何手动运行dll文件,非注册dll
  2. 常见电脑故障维修---主板篇
  3. JSP、表单T交、数据库乱码,,,,
  4. 烟花特效-第14届蓝桥杯STEMA测评Scratch真题精选
  5. android设备安装kali,在Android设备上安装Kali Linux基于Android设备的Kali Linux渗透测试教程大学霸...
  6. 西南大学计算机复试经验
  7. windows下 强行格式化
  8. 蘑菇街CEO陈琪上市致辞:科技是生产力 美丽也是生产力
  9. python快捷键注册
  10. Deep Forest(gcforest)通俗易懂理解