- CompoundButton 源码分析
- LinearLayout 源码分析
- SearchView 源码解析
- LruCache 源码解析
- ViewDragHelper 源码解析
- BottomSheets 源码解析
- Media Player 源码分析
- NavigationView 源码解析
- Service 源码解析
- Binder 源码分析
- Android 应用 Preference 相关及源码浅析 SharePreferences 篇
- ScrollView 源码解析
- Handler 源码解析
- NestedScrollView 源码解析
- SQLiteOpenHelper/SQLiteDatabase/Cursor 源码解析
- Bundle 源码解析
- LocalBroadcastManager 源码解析
- Toast 源码解析
- TextInputLayout
- LayoutInflater 和 LayoutInflaterCompat 源码解析
- TextView 源码解析
- NestedScrolling 事件机制源码解析
- ViewGroup 源码解析
- StaticLayout 源码分析
- AtomicFile 源码解析
- AtomicFile 源码解析
- Spannable 源码分析
- Notification 之 Android 5.0 实现原理
- CoordinatorLayout 源码分析
- Scroller 源码解析
- SwipeRefreshLayout 源码分析
- FloatingActionButton 源码解析
- AsyncTask 源码分析
- TabLayout 源码解析
3.2 设置数据源
setDataSource 对应的是 jni 中的这个函数:
static void android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
{
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
// mediaplayer 为空
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
}
// 文件描述符为空
if (fileDescriptor == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return;
}
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
ALOGV("setDataSourceFD: fd %d", fd);
// 调用 mp->setDataSource(fd, offset, length) 为 mediaplayer 设置数据源
process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
}
可以看到函数开始先做了空指针的判断,之后调用了 mp->setDataSource(fd, offset, length) 方法来给 mediaplayer 设置数据源,同时 process_media_player_call 函数对 setDataSource 返回值做判断是否设置成功以及失败后抛出异常。
mediaplayer 中的 setDataSource 函数分为三种,分别对应播放文件、网络和流三种情况,现在只看播放文件的情况:
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
status_t err = UNKNOWN_ERROR;
// 获取 MediaPlayerService 接口
const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != 0) {
// 获取 MediaPlayer 接口
sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
// 设置数据源
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(fd, offset, length))) {
player.clear();
}
err = attachNewPlayer(player);
}
return err;
}这个函数分为三个部分,逐个分析。
3.2.1 获取 MediaPlayerService 接口
这里先是调用了 getMediaPlayerService 方法获取到一个 IMediaPlayerService
/*static*/const sp<IMediaPlayerService> &IMediaDeathNotifier::getMediaPlayerService()
{
ALOGV("getMediaPlayerService");
Mutex::Autolock _l(sServiceLock);
if (sMediaPlayerService == 0) {
// 获取 servicemanager
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
// 获取对应的 binder
binder = sm->getService(String16("media.player"));
if (binder != 0) {
break;
}
ALOGW("Media player service not published, waiting...");
usleep(500000); // 0.5 s
} while (true);
if (sDeathNotifier == NULL) {
sDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(sDeathNotifier);
// asInterface 获取 binder 中的 remote 对象
sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
}
ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
return sMediaPlayerService;
}IServiceManager 是 IInterface 类型,和用 AIDL 生成的接口相同,IInterface 中包含了 binder 和 remote 两个东西。在 ndk 中对应的是 BnInterface 和 BpInterface。在 Java 中,本地 Client 通过 ServiceConnection 中的 onServiceConnected(ComponentName name, IBinder service) 方法获得 Service 中在 onBind 时候返回的 binder,同理,这里通过 ServiceManager 的 getService 获得和 media.player 这个 Service 通信用的 binder。
到这里为止我们只拿到了 media.player Service 的 binder,要想调用接口中的方法还需要通过 asInterface 方法来获得与之对应的 IInterface 接口。这里的 interface_cast(binder) 方法就可以获得对应的接口,那么 interface_cast 是怎么做到的呢,其实很简单,利用了模板封装了 asInterface 的操作:
template<typename INTERFACE> inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}现在我们就拿到了 media.player Service 的接口。
看到这里会有一个疑问,这个 media.player 的 Service 是什么时候启动的呢。我们根据 media.player 这个线索找到了下面的代码:
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(String16("media.player"), new MediaPlayerService());
}
int main(int argc __unused, char** argv)
{
...
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
AudioFlinger::instantiate();
// 就是这里啦
MediaPlayerService::instantiate();
// 照相机
CameraService::instantiate();
// 音频
AudioPolicyService::instantiate();
// 语音识别
SoundTriggerHwService::instantiate();
registerExtensions();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
其中 MediaPlayerService 位于 MediaPlayerService.cpp 中,而 main 函数位于 main_mediaserver.cpp 。还记得在本文最开始的那张图么,其中的 mediaserver 对应的就是这个。它是在开机的时候启动的,被写在了启动脚本中:
这样在系统启动的时候这个进程就开启了,同时里面的 Service 也就启动了。
3.2.2 获取 MediaPlayer 接口
service->create(this, mAudioSessionId) 方法通过 IPC 的方式调用 MediaPlayerService 中的 create 方法获得 IMediaPlayer ,IMediaPlayer 从名字就可以看出是一个 IInterface,所以 MediaPlayer 也是通过 IPC 来调用的。先看这个方法做了什么:
sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client, int audioSessionId)
{
pid_t pid = IPCThreadState::self()->getCallingPid();
int32_t connId = android_atomic_inc(&mNextConnId);
// MediaPlayerClient
sp<Client> c = new Client(
this, pid, connId, client, audioSessionId,
IPCThreadState::self()->getCallingUid());
ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
IPCThreadState::self()->getCallingUid());
wp<Client> w = c;
{
Mutex::Autolock lock(mLock);
// 管理 Client
mClients.add(w);
}
return c;
}首先调用的时候传的参数是 MediaPlayer 本身,MediaPlayer 除了继承 IMediaDeathNotifier 同时还继承了 BnMediaPlayerClient,而 BnMediaPlayerClient 又继承了 BnInterface,所以这里的参数列表是一个 client 引用。其中 Client 的实现也在 MediaPlayerService.cpp 这个文件中,他的构造函数用来保存这些对象:
MediaPlayerService::Client::Client(
const sp<MediaPlayerService>& service, pid_t pid,
int32_t connId, const sp<IMediaPlayerClient>& client,
int audioSessionId, uid_t uid)
{
ALOGV("Client(%d) constructor", connId);
mPid = pid;
mConnId = connId;
mService = service;
mClient = client;
mLoop = false;
mStatus = NO_INIT;
mAudioSessionId = audioSessionId;
mUID = uid;
mRetransmitEndpointValid = false;
mAudioAttributes = NULL;
#if CALLBACK_ANTAGONIZER
ALOGD("create Antagonizer");
mAntagonizer = new Antagonizer(notify, this);
#endif
}最后 create 方法返回一个 MediaPlayer 的接口,这个接口通过 IPC 用来调用 Client 中的函数。
3.2.3 设置数据源
经过了之前的折腾,我们先拿到了 MediaPlayerService 的接口,通过 MediaPlayerService 的接口又拿到了 MediaPlayer 的接口,接下来就要进行这个函数的最终目的 设置数据源 。
同样是通过 IPC 调用了 MediaPlayer 的 setDataSource,定义如下:
status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
{
// 前面是一些输出要设置的数据源的信息的 log
...
// 获取播放器类型
player_type playerType = MediaPlayerFactory::getPlayerType(this, fd, offset, length);
// 创建播放器
sp<MediaPlayerBase> p = setDataSource_pre(playerType);
if (p == NULL) {
return NO_INIT;
}
// now set data source
setDataSource_post(p, p->setDataSource(fd, offset, length));
return mStatus;
}
首先是获取播放器类型,播放器类型定义在 MediaPlayerInterface.h 中:
enum player_type {
PV_PLAYER = 1,
SONIVOX_PLAYER = 2,
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,
};
下面说下这几种类型是做什么的,其中的每一个都对应一个工厂来创建对应的 Player,由于 PV_PLAYER 已经被抛弃了,所以在 5.1 的源码里并没有出现它
- PV_PLAYER 这个类型是 Android 最初采用的 OpenCore,由于太臃肿已经被抛弃
- SONIVOX_PLAYER 用来处理 midi 相关
- NU_PLAYER 全能型,在 5.x 上处于可选
- STAGEFRIGHT_PLAYER 5.x 之前的主力即 awesome player ,可以胜任除 midi 外全部的工作
- TEST_PLAYER 测试用
这些 player 都是由对应的 factory 创建的,对应的实现在 MediaPlayerFactory.cpp 中,其中的代码比较简单,这里就不分析了,主要是匹配不同类型对应不同的分数,然后选取分高的 player 创建。当前的主力是 STAGEFRIGHT_PLAYER 也就是 awesome player,而 NU_PLAYER 是未来的主力,从 Android M 目前的 源码 中也可以看出代码中只剩下了 NU_PLAYER 和 STAGEFRIGHT_PLAYER,其中 NU_PLAYER 负责网络和流的播放,STAGEFRIGHT_PLAYER 负责有 DRM 和文件的播放。
这里我们就以目前的主力 STAGEFRIGHT_PLAYER 播放器继续往下分析。获取到播放器类型后就到了 创建播放器
sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(player_type playerType)
{
...
// create the right type of player
sp<MediaPlayerBase> p = createPlayer(playerType);
if (p == NULL) {
return p;
}
...
return p;
}
sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
{
// mPlayer 是当前已经有的 player,如果是刚创建这个对象,
// 那么 player 是 null 需要创建新的 player
// 如果创建过了了则对比下需要用到的 player 类型,避免重复创建
sp<MediaPlayerBase> p = mPlayer;
if ((p != NULL) && (p->playerType() != playerType)) {
ALOGV("delete player");
p.clear();
}
if (p == NULL) {
p = MediaPlayerFactory::createPlayer(playerType, this, notify);
}
...
return p;
}
这里从 MediaPlayerFactory 创建了对应的播放器,之后使用创建好的 player 设置数据源:
status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
return mPlayer->setDataSource(dup(fd), offset, length);
}这里的 mPlayer 就是 AwesomePlayer,AwesomePlayer 在 StagefrightPlayer 类的构造函数中创建:
StagefrightPlayer::StagefrightPlayer(): mPlayer(new AwesomePlayer) {
ALOGV("StagefrightPlayer");
mPlayer->setListener(this);
}从 StagefrightPlayer 的源码可以看到对象中的 AwesomePlayer 来完成。代码如下:
status_t AwesomePlayer::setDataSource(
int fd, int64_t offset, int64_t length) {
Mutex::Autolock autoLock(mLock);
// 重置播放器状态
reset_l();
// 封装成 DataSource
sp<DataSource> dataSource = new FileSource(fd, offset, length);
...
return setDataSource_l(dataSource);
}
status_t AwesomePlayer::setDataSource_l(const sp<DataSource> &dataSource) {
// 通过 datasource 创建分离器
sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
if (extractor == NULL) {
return UNKNOWN_ERROR;
}
if (extractor->getDrmFlag()) {
checkDrmStatus(dataSource);
}
// 为分离器设置数据源
return setDataSource_l(extractor);
}这个分离器其实和 ffpmeg 中的 demuxer 一样,作用是将数据中的音频部分和视频部分分开,然后获取到对应的类型,调用对应的解码器进行解码:
status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
// Attempt to approximate overall stream bitrate by summing all
// tracks' individual bitrates, if not all of them advertise bitrate,
// we have to fail.
int64_t totalBitRate = 0;
mExtractor = extractor;
for (size_t i = 0; i < extractor->countTracks(); ++i) {
sp<MetaData> meta = extractor->getTrackMetaData(i);
int32_t bitrate;
if (!meta->findInt32(kKeyBitRate, &bitrate)) {
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
ALOGV("track of type '%s' does not publish bitrate", mime);
totalBitRate = -1;
break;
}
// 总的码率
totalBitRate += bitrate;
}
// metadata 就是数据中的元信息
sp<MetaData> fileMeta = mExtractor->getMetaData();
if (fileMeta != NULL) {
int64_t duration;
if (fileMeta->findInt64(kKeyDuration, &duration)) {
// 长度
mDurationUs = duration;
}
}
mBitrate = totalBitRate;
bool haveAudio = false;
bool haveVideo = false;
for (size_t i = 0; i < extractor->countTracks(); ++i) {
sp<MetaData> meta = extractor->getTrackMetaData(i);
const char *_mime;
CHECK(meta->findCString(kKeyMIMEType, &_mime));
String8 mime = String8(_mime);
// 视频
if (!haveVideo && !strncasecmp(mime.string(), "video/", 6)) {
setVideoSource(extractor->getTrack(i));
haveVideo = true;
...
// 音频
} else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6)) {
setAudioSource(extractor->getTrack(i));
haveAudio = true;
...
// ogg
if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_AUDIO_VORBIS)) {
// Only do this for vorbis audio, none of the other audio
// formats even support this ringtone specific hack and
// retrieving the metadata on some extractors may turn out
// to be very expensive.
sp<MetaData> fileMeta = extractor->getMetaData();
int32_t loop;
if (fileMeta != NULL
&& fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
modifyFlags(AUTO_LOOPING, SET);
}
}
} else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) {
addTextSource_l(i, extractor->getTrack(i));
}
}
...
return OK;
}这里通过分离器来确定数据源中是音频还是视频,然后对 player 的 videotrack 和 audiotrack 进行相对应的设置。
到此为止 setDataSource 的流程就算是走完了,如果继续往下分析的话就到了视频的编解码的知识了。Client 是 MediaPlayerService 的内部类。MediaPlayerService 通过 IPC 和 MediaPlayerService 通信获得 Client,Client 中包含了 StagefrightPlayer,而 StagefrightPlayer 最终通过调用 AwesomePlayer 对应的方法。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论