Android多媒体播放器源码解析(stagefright框架)
一、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框架)相关推荐
- Android通知系统源码解析
Android通知系统源码解析 1. 概述 2. 流程图 2.1. 发送通知流程图 3. 源码解析 3.1. 使用通知--APP进程 3.1.1. 创建通知: 3.1.2. 发送(更新)通知: 3.1 ...
- 简单开发的android阅读器源码,包含了读取数据库和文件流处理功能
原文:简单开发的android阅读器源码,包含了读取数据库和文件流处理功能 源代码下载地址:http://www.zuidaima.com/share/1838906559466496.htm 简单地 ...
- http://a.codekk.com/detail/Android/grumoon/Volley 源码解析
http://a.codekk.com/detail/Android/grumoon/Volley 源码解析
- dubbo源码解析之框架粗谈
dubbo框架设计 一.dubbo框架整体设计 二.各层说明 三.dubbo工程模块分包 四.依赖关系 五.调用链 文章系列 [一.dubbo源码解析之框架粗谈] [二.dubbo源码解析之dubbo ...
- 多款Android播放器源码集锦
Android传说中的3D播放器源码 Android 3D播放器 源码 170 2011-09-28 by:豆沙包 • android音乐播放器源码 android 237 2011-09-03 by ...
- Android Hawk的源码解析,一款基于SharedPreferences的存储框架
转载请标注:http://blog.csdn.net/friendlychen/article/details/76218033 一.概念 SharedPreferences的使用大家应该非常熟悉啦. ...
- Android之EasyPermissions源码解析
转载请标明出处:[顾林海的博客] 个人开发的微信小程序,目前功能是书籍推荐,后续会完善一些新功能,希望大家多多支持! 前言 我们知道在Android中想要申请权限就需要在AndroidManifest ...
- Android之DiskLruCache源码解析
转载请标明出处: http://blog.csdn.net/hai_qing_xu_kong/article/details/73863258 本文出自:[顾林海的博客] 个人开发的微信小程序,目前功 ...
- 美女图片采集器 源码+解析
前言: 有一段时间没写博客了, "持之以恒"徽章都暗了, 实在不该. 前一段确实比较忙, ...小小地给自己的懒找个借口吧. 大二即将结束, 学习iOS也有一段时间了.今天抽点时间 ...
最新文章
- 【CSAPP】三、程序的机器级表示
- 工作流引擎Activiti使用总结
- 01-将自己的Ubuntu电脑设置为一台可远程访问的服务器
- 2021年,Java开发者值得学习的13项技能
- docker安装软件(vim,service)
- @程序员,入行物联网的避坑指南!| 技术头条
- 沙盘 服务器未响应,为什么沙盘总是服务启动失败
- Redis 菜鸟教程学习笔记- Redis 命令- Key
- golang语言环境搭建
- 第三章 机器人系统的动力学模型
- 新版Airplayer--新功能介绍
- 【转载】红外遥控HS0038B接法
- Host文件位置和作用介绍
- 六、线性方程组求解--Jacobi和Gauss-Seidel迭代求解
- NAT地址转换实验记录
- VMWare虚拟机下载|最新版|破解版
- java p2p技术内幕.pdf_JavaP2P技术内幕
- 基于LSTM的股票价格预测
- mysql数据库的行级锁有几种_数据库行级锁和表锁区别
- linux命令记忆方法,Linux命令快速巧记法