本文分析了android4.4.4的MediaPlayer的初始化和设置数据的过程
{"native_init", "()V", (void *)android_media_MediaPlayer_native_init},
static void android_media_MediaPlayer_native_init(JNIEnv *env)初始化,得到Java层的各种用于jni层的变量,回调函数
{
jclass clazz;
clazz = env->FindClass("android/media/MediaPlayer");
if (clazz == NULL) {
return;
}
fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
if (fields.context == NULL) {
return;
}
fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
if (fields.post_event == NULL) {
return;
}
fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "I");
if (fields.surface_texture == NULL) {
return;
}
clazz = env->FindClass("android/net/ProxyProperties");
if (clazz == NULL) {
return;
}
fields.proxyConfigGetHost =
env->GetMethodID(clazz, "getHost", "()Ljava/lang/String;");
fields.proxyConfigGetPort =
env->GetMethodID(clazz, "getPort", "()I");
fields.proxyConfigGetExclusionList =
env->GetMethodID(clazz, "getExclusionList", "()Ljava/lang/String;");
}
{"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup},
static voidmp = new MediaPlayer();
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
ALOGV("native_setup");
sp<MediaPlayer> mp = new MediaPlayer();
if (mp == NULL) {
jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
return;
}
// create new listener and give it to MediaPlayer
sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
mp->setListener(listener);
// Stow our new C++ MediaPlayer in an opaque field in the Java object.
setMediaPlayer(env, thiz, mp);
}
MediaPlayer::MediaPlayer()mAudioSessionId = AUdioSystem::newAudioSessionId();,得到新的AudioSessionId
{
ALOGV("constructor");
mListener = NULL;
mCookie = NULL;
mStreamType = AUDIO_STREAM_MUSIC;
mCurrentPosition = -1;
mSeekPosition = -1;
mCurrentState = MEDIA_PLAYER_IDLE;
mPrepareSync = false;
mPrepareStatus = NO_ERROR;
mLoop = false;
mLeftVolume = mRightVolume = 1.0;
mVideoWidth = mVideoHeight = 0;
mLockThreadId = 0;
mAudioSessionId = AudioSystem::newAudioSessionId();
AudioSystem::acquireAudioSessionId(mAudioSessionId);
mSendLevel = 0;
mRetransmitEndpointValid = false;
int AudioSystem::newAudioSessionId() {获取audioflinger的BpBinder
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return 0;
return af->newAudioSessionId();
}
AudioSystem::get_audio_flinger()
const sp<IAudioFlinger>& AudioSystem::get_audio_flinger()
{
Mutex::Autolock _l(gLock);
if (gAudioFlinger == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.audio_flinger"));
if (binder != 0)
break;
ALOGW("AudioFlinger not published, waiting...");
usleep(500000); // 0.5 s
} while (true);
if (gAudioFlingerClient == NULL) {
gAudioFlingerClient = new AudioFlingerClient();
} else {
if (gAudioErrorCallback) {
gAudioErrorCallback(NO_ERROR);
}
}
binder->linkToDeath(gAudioFlingerClient);
gAudioFlinger = interface_cast<IAudioFlinger>(binder);
gAudioFlinger->registerClient(gAudioFlingerClient);
}
ALOGE_IF(gAudioFlinger==0, "no AudioFlinger!?");
return gAudioFlinger;
}
af->newAUdioSessionId()
int AudioFlinger::newAudioSessionId()nextUniqueId()
{
return nextUniqueId();
}
uint32_t AudioFlinger::nextUniqueId()每增加一个audiosession,将使用mNextUniqueId记录这个session号,它的声明如下:
{
return android_atomic_inc(&mNextUniqueId);
}
volatile int32_t mNextUniqueId;使得访问它的线程都可以获取到,同时使用android_atomic_inc函数,原子增加它,防止竞争,提高了线程安全。volatile只是实现了变量的可见性,不提供原子操作性。
AudioSystem::acquireAudioSessionId(int audioSession)
void AudioSystem::acquireAudioSessionId(int audioSession) {af->acquireAudioSessionId(sessionid)
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af != 0) {
af->acquireAudioSessionId(audioSession);
}
}
void AudioFlinger::acquireAudioSessionId(int audioSession)通过audiosessionId,将mediaplayer,audioflinger绑定起来。每个audiosession和一个pid对应,组成了一个AudioSessionRef。AudioSessionRefs队列维护当前系统中运行的audiosession。
{
Mutex::Autolock _l(mLock);
pid_t caller = IPCThreadState::self()->getCallingPid();
ALOGV("acquiring %d from %d", audioSession, caller);
// Ignore requests received from processes not known as notification client. The request
// is likely proxied by mediaserver (e.g CameraService) and releaseAudioSessionId() can be
// called from a different pid leaving a stale session reference. Also we don't know how
// to clear this reference if the client process dies.
if (mNotificationClients.indexOfKey(caller) < 0) {
ALOGV("acquireAudioSessionId() unknown client %d for session %d", caller, audioSession);
return;
}
size_t num = mAudioSessionRefs.size();
for (size_t i = 0; i< num; i++) {
AudioSessionRef *ref = mAudioSessionRefs.editItemAt(i);
if (ref->mSessionid == audioSession && ref->mPid == caller) {
ref->mCnt++;
ALOGV(" incremented refcount to %d", ref->mCnt);
return;
}
}
mAudioSessionRefs.push(new AudioSessionRef(audioSession, caller));
ALOGV(" added new entry for %d", audioSession);
}
mp->setListener()
status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)mListener用于MediaPlayer::notify()中,功能是将底层的各种状态,通过它返回到java层。
{
ALOGV("setListener");
Mutex::Autolock _l(mLock);
mListener = listener;
return NO_ERROR;
}
setMediaPlayer(),对新旧player的引用计数。
static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
{
Mutex::Autolock l(sLock);
sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context);
if (player.get()) {
player->incStrong((void*)setMediaPlayer);
}
if (old != 0) {
old->decStrong((void*)setMediaPlayer);
}
env->SetIntField(thiz, fields.context, (int)player.get());
return old;
}
SetIntField(thiz, fields.context, (int)player.get()),将创建的player与Java层的mNativeContext联系起来。mNativeContext在Java层的EventHandler.handleMessage中判断是否是对应的底层mediaplayer返回的信息。如果不是,就不处理。
MediaPlayer::setDataSource()
status_t MediaPlayer::setDataSource(const sp<IStreamSource> &source)getMediaPlayerService()
{
ALOGV("setDataSource");
status_t err = UNKNOWN_ERROR;
const sp<IMediaPlayerService>& service(getMediaPlayerService()); // 获得BpMediaPlayerService对象
if (service != 0) {
sp<IMediaPlayer> player(service->create(this, mAudioSessionId)); // 获得BpMediaPlayer
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(source))) {
player.clear();
}
err = attachNewPlayer(player);
}
return err;
}
const sp<IMediaPlayerService>&该函数从ServiceManager得到了MediaPlayerPlayerService的Bp端,sMediaPlayerService就是BpMediaPlayerService。
IMediaDeathNotifier::getMediaPlayerService()
{
ALOGV("getMediaPlayerService");
Mutex::Autolock _l(sServiceLock);
if (sMediaPlayerService == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
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);
sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
}
ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
return sMediaPlayerService;
}
之后对IMediaPlayer player进行赋值。
service->create(this, mAudioSessionId)。create是BpMediaPlayerService里的函数。
virtual sp<IMediaPlayer> create(该函数向BnMediaPlayerService发送了CREATE请求,请求Bn端创建一个BpMediaPlayer。
const sp<IMediaPlayerClient>& client, int audioSessionId) {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeStrongBinder(client->asBinder());
data.writeInt32(audioSessionId);
remote()->transact(CREATE, data, &reply);
return interface_cast<IMediaPlayer>(reply.readStrongBinder());
}
经过Binder驱动的调用,现在BnMediaPlayerService接收到了transact发送过来的命令,接着将在Bn端的OnTransact中处理CREATE命令
status_t BnMediaPlayerService::onTransact(BnMediaPlayerService接收到命令,取得client(IMediaPlayerClient)和audioSessionId后,将调用MediaPlayerService::create函数。
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch (code) {
case CREATE: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
sp<IMediaPlayerClient> client =
interface_cast<IMediaPlayerClient>(data.readStrongBinder());
int audioSessionId = data.readInt32();
sp<IMediaPlayer> player = create(client, audioSessionId);
reply->writeStrongBinder(player->asBinder()); // 返回BpMediaPlayer
return NO_ERROR;
} break;
sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,create函数此时将创建BnMediaPlayer,也就是Client类。之后将得到的client经过binder返回给BpMediaPlayer
int audioSessionId)
{
pid_t pid = IPCThreadState::self()->getCallingPid();
int32_t connId = android_atomic_inc(&mNextConnId);
sp<Client> c = new Client(
this, pid, connId, client, audioSessionId,
IPCThreadState::self()->getCallingUid()); // 创建一个BnMediaPlayer
ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
IPCThreadState::self()->getCallingUid());
wp<Client> w = c;
{
Mutex::Autolock lock(mLock);
mClients.add(w);
}
return c;
}
接着进入player->setDataSource(source),由于player是BpMediaPlayer,所以需要到BnMediaPlayer里找对应的处理。
status_t setDataSource(const sp<IStreamSource> &source) {SET_DATA_SOURCE_FD命令在Bn端的处理
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
data.writeStrongBinder(source->asBinder());
remote()->transact(SET_DATA_SOURCE_STREAM, data, &reply);
return reply.readInt32();
}
case SET_DATA_SOURCE_STREAM: {接着找到setDataSource函数对应的MediaPlayerService文件中的调用
CHECK_INTERFACE(IMediaPlayer, data, reply);
sp<IStreamSource> source =
interface_cast<IStreamSource>(data.readStrongBinder());
reply->writeInt32(setDataSource(fd, offset, length));
return NO_ERROR;
}
status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)在这里先暂停分析,先介绍android中自带的几种播放器以及注册过程。
{
ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
struct stat sb;
int ret = fstat(fd, &sb);
if (ret != 0) {
ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
return UNKNOWN_ERROR;
}
if (offset >= sb.st_size) {
ALOGE("offset error");
::close(fd);
return UNKNOWN_ERROR;
}
if (offset + length > sb.st_size) {
length = sb.st_size - offset;
ALOGV("calculated length = %lld", length);
}
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;
}
在MediaPlayerService对象创建时,会注册几种系统默认的播放器。
MediaPlayerService::MediaPlayerService()registerBuiltinFactories()
{
ALOGV("MediaPlayerService created");
mNextConnId = 1;
。。。
MediaPlayerFactory::registerBuiltinFactories();
}
void MediaPlayerFactory::registerBuiltinFactories() {好了在这里看到了系统默认注册的4个播放器,分别是StagefrightPlayer, NuPlayer, SonivoxPlayer和TestPlayer。
Mutex::Autolock lock_(&sLock);
if (sInitComplete)
return;
registerFactory_l(new StagefrightPlayerFactory(), STAGEFRIGHT_PLAYER);
registerFactory_l(new NuPlayerFactory(), NU_PLAYER);
registerFactory_l(new SonivoxPlayerFactory(), SONIVOX_PLAYER);
registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);
sInitComplete = true;
}
其实系统中定义了播放器类型的枚举
enum player_type {由于android在2.3之后不适用opencore架构了,现在使用的是stagefright架构,所以pvplayer代码中已经消失了。
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,
};
registerFactory_l(IFactory* factory, player_type type)
status_t MediaPlayerFactory::registerFactory_l(IFactory* factory,向sFactoryMap的键值对中加入对应类型的播放器。
player_type type) {
if (NULL == factory) {
ALOGE("Failed to register MediaPlayerFactory of type %d, factory is"
" NULL.", type);
return BAD_VALUE;
}
if (sFactoryMap.indexOfKey(type) >= 0) {
ALOGE("Failed to register MediaPlayerFactory of type %d, type is"
" already registered.", type);
return ALREADY_EXISTS;
}
if (sFactoryMap.add(type, factory) < 0) {
ALOGE("Failed to register MediaPlayerFactory of type %d, failed to add"
" to map.", type);
return UNKNOWN_ERROR;
}
return OK;
}
回到setDataSource函数,此时需要得到文件对应的播放器,函数MediaPlayerFactory::getPlayerType其实就是一个宏定义
#define GET_PLAYER_TYPE_IMPL(a...) \里面会对每个播放器进行打分,也就是看哪种播放器最合适。这其实是根据文件类型判断的,每种媒体文件都有指示文件格式的字段。
Mutex::Autolock lock_(&sLock); \
\
player_type ret = STAGEFRIGHT_PLAYER; \
float bestScore = 0.0; \
\
for (size_t i = 0; i < sFactoryMap.size(); ++i) { \
\
IFactory* v = sFactoryMap.valueAt(i); \
float thisScore; \
CHECK(v != NULL); \
thisScore = v->scoreFactory(a, bestScore); \
if (thisScore > bestScore) { \
ret = sFactoryMap.keyAt(i); \
bestScore = thisScore; \
} \
} \
\
if (0.0 == bestScore) { \
ret = getDefaultPlayerType(); \
} \
\
return ret;
一般都是选择StageFrightPlayer。那么假定player_type是STAGEFRIGHT_PLAYER。
接着进入MediaPlayerService::Client::setDataSource_pre(player_type playerType)
sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(该函数将创建对应的播放器,并且设置AudioOutput。
player_type playerType)
{
ALOGV("player type = %d", playerType);
// create the right type of player
sp<MediaPlayerBase> p = createPlayer(playerType);
if (p == NULL) {
return p;
}
if (!p->hardwareOutput()) {
mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid());
static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
}
return p;
}
createPlayer(player_type)
sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)继续看MediaPlayerFactory::createPlayer
{
// determine if we have the right player type
sp<MediaPlayerBase> p = mPlayer;
if ((p != NULL) && (p->playerType() != playerType)) {
ALOGV("delete player");
p.clear();
}
if (p == NULL) {
p = MediaPlayerFactory::createPlayer(playerType, this, notify);
}
if (p != NULL) {
p->setUID(mUID);
}
return p;
}
sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(首先检查传入的类型是否有播放器注册,如果没有就报错。有的话会调用播放器创建函数进行创建。
player_type playerType,
void* cookie,
notify_callback_f notifyFunc) {
sp<MediaPlayerBase> p;
IFactory* factory;
status_t init_result;
Mutex::Autolock lock_(&sLock);
if (sFactoryMap.indexOfKey(playerType) < 0) {
ALOGE("Failed to create player object of type %d, no registered"
" factory", playerType);
return p;
}
factory = sFactoryMap.valueFor(playerType);
CHECK(NULL != factory);
p = factory->createPlayer();
if (p == NULL) {
ALOGE("Failed to create player object of type %d, create failed",
playerType);
return p;
}
init_result = p->initCheck();
if (init_result == NO_ERROR) {
p->setNotifyCallback(cookie, notifyFunc);
} else {
ALOGE("Failed to create player object of type %d, initCheck failed"
" (res = %d)", playerType, init_result);
p.clear();
}
return p;
}
class StagefrightPlayerFactory :StagefrightPlayer()
public MediaPlayerFactory::IFactory {
public:
virtual sp<MediaPlayerBase> createPlayer() {
ALOGV(" create StagefrightPlayer");
return new StagefrightPlayer();
}
};
StagefrightPlayer::StagefrightPlayer()至此,我们终于见到了播放器的庐山真面目,原来是AwsomePlayer,帅得兜了好几个圈子。
: mPlayer(new AwesomePlayer) {
ALOGV("StagefrightPlayer");
mPlayer->setListener(this);
}
当看完StagefrightPlayer.cpp后,我们发现,原来这个StagefrightPlayer就是AwsomePlayer封装了一层,里面所有的工作几乎都是AwsomwPlayer去完成的。
那么后面的分析,我们将跳过StagefrightPlayer文件,直接分析AwsomePlayer。
setDataSource_post(p, p->setDataSource(fd, offset, length));
先看p->setDataSource(),这其实是调用AwsomePlayer的setDataSource
status_t AwesomePlayer::setDataSource(AwesomePlayer::setDataSource_l()
int fd, int64_t offset, int64_t length) {
Mutex::Autolock autoLock(mLock);
reset_l();
sp<DataSource> dataSource = new FileSource(fd, offset, length);
status_t err = dataSource->initCheck();
if (err != OK) {
return err;
}
mFileSource = dataSource;
{
Mutex::Autolock autoLock(mStatsLock);
mStats.mFd = fd;
mStats.mURI = String8();
}
return setDataSource_l(dataSource);
status_t AwesomePlayer::setDataSource_l(MediaExtractor::Create(dataSource)
const sp<DataSource> &dataSource) {
sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
if (extractor == NULL) {
return UNKNOWN_ERROR;
}
if (extractor->getDrmFlag()) {
checkDrmStatus(dataSource);
}
return setDataSource_l(extractor);
}
sp<MediaExtractor> MediaExtractor::Create(由于传入的mime是null,所以extractor需要sniff出mime类型。
const sp<DataSource> &source, const char *mime) {
sp<AMessage> meta;
String8 tmp;
if (mime == NULL) {
float confidence;
if (!source->sniff(&tmp, &confidence, &meta)) {
ALOGV("FAILED to autodetect media content.");
return NULL;
}
mime = tmp.string();
ALOGV("Autodetected media content as '%s' with confidence %.2f",
mime, confidence);
}
bool isDrm = false;
// DRM MIME type syntax is "drm+type+original" where
// type is "es_based" or "container_based" and
// original is the content's cleartext MIME type
if (!strncmp(mime, "drm+", 4)) {
const char *originalMime = strchr(mime+4, '+');
if (originalMime == NULL) {
// second + not found
return NULL;
}
++originalMime;
if (!strncmp(mime, "drm+es_based+", 13)) {
// DRMExtractor sets container metadata kKeyIsDRM to 1
return new DRMExtractor(source, originalMime);
} else if (!strncmp(mime, "drm+container_based+", 20)) {
mime = originalMime;
isDrm = true;
} else {
return NULL;
}
}
MediaExtractor *ret = NULL;
if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
|| !strcasecmp(mime, "audio/mp4")) {
ret = new MPEG4Extractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
ret = new MP3Extractor(source, meta);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
|| !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
ret = new AMRExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
ret = new FLACExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {
ret = new WAVExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {
ret = new OggExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {
ret = new MatroskaExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
ret = new MPEG2TSExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM)) {
// Return now. WVExtractor should not have the DrmFlag set in the block below.
return new WVMExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
ret = new AACExtractor(source, meta);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
ret = new MPEG2PSExtractor(source);
}
if (ret != NULL) {
if (isDrm) {
ret->setDrmFlag(true);
} else {
ret->setDrmFlag(false);
}
}
return ret;
}
系统默认注册了几种文件类型
void DataSource::RegisterDefaultSniffers() {sniff函数的流程
Mutex::Autolock autoLock(gSnifferMutex);
if (gSniffersRegistered) {
return;
}
RegisterSniffer_l(SniffMPEG4);
RegisterSniffer_l(SniffMatroska);
RegisterSniffer_l(SniffOgg);
RegisterSniffer_l(SniffWAV);
RegisterSniffer_l(SniffFLAC);
RegisterSniffer_l(SniffAMR);
RegisterSniffer_l(SniffMPEG2TS);
RegisterSniffer_l(SniffMP3);
RegisterSniffer_l(SniffAAC);
RegisterSniffer_l(SniffMPEG2PS);
RegisterSniffer_l(SniffWVM);
char value[PROPERTY_VALUE_MAX];
if (property_get("drm.service.enabled", value, NULL)
&& (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
RegisterSniffer_l(SniffDRM);
}
gSniffersRegistered = true;
}
bool DataSource::sniff(待判断出MIMWTYPE后,就会调用对应的提取器XXXExatractor对文件进行提取。
String8 *mimeType, float *confidence, sp<AMessage> *meta) {
*mimeType = "";
*confidence = 0.0f;
meta->clear();
{
Mutex::Autolock autoLock(gSnifferMutex);
if (!gSniffersRegistered) {
return false;
}
}
for (List<SnifferFunc>::iterator it = gSniffers.begin();
it != gSniffers.end(); ++it) {
String8 newMimeType;
float newConfidence;
sp<AMessage> newMeta;
if ((*it)(this, &newMimeType, &newConfidence, &newMeta)) {
if (newConfidence > *confidence) {
*mimeType = newMimeType;
*confidence = newConfidence;
*meta = newMeta;
}
}
}
return *confidence > 0.0;
}
setDataSource_l(extractor)函数做了如下工作:
1 获取文件的bitrate,kKeyBitRate
2 获取视频流
2.1 获取视频宽度,kKeyDisplayWidth
2.2 获取视频高度,kKeyDisplayHeight
3 获取音频流
4 获得视频的字幕
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;
}
mBitrate = totalBitRate;
ALOGV("mBitrate = %lld bits/sec", mBitrate);
{
Mutex::Autolock autoLock(mStatsLock);
mStats.mBitrate = mBitrate;
mStats.mTracks.clear();
mStats.mAudioTrackIndex = -1;
mStats.mVideoTrackIndex = -1;
}
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;
// Set the presentation/display size
int32_t displayWidth, displayHeight;
bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth);
if (success) {
success = meta->findInt32(kKeyDisplayHeight, &displayHeight);
}
if (success) {
mDisplayWidth = displayWidth;
mDisplayHeight = displayHeight;
}
{
Mutex::Autolock autoLock(mStatsLock);
mStats.mVideoTrackIndex = mStats.mTracks.size();
mStats.mTracks.push();
TrackStat *stat =
&mStats.mTracks.editItemAt(mStats.mVideoTrackIndex);
stat->mMIME = mime.string();
}
} else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6)) {
setAudioSource(extractor->getTrack(i));
haveAudio = true;
mActiveAudioTrackIndex = i;
{
Mutex::Autolock autoLock(mStatsLock);
mStats.mAudioTrackIndex = mStats.mTracks.size();
mStats.mTracks.push();
TrackStat *stat =
&mStats.mTracks.editItemAt(mStats.mAudioTrackIndex);
stat->mMIME = mime.string();
}
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));
}
}
if (!haveAudio && !haveVideo) {
if (mWVMExtractor != NULL) {
return mWVMExtractor->getError();
} else {
return UNKNOWN_ERROR;
}
}
mExtractorFlags = extractor->flags();
return OK;
}
这里主要分析getTrack,给函数主要用于读取音视频的track记录。下面各举一栗子。video的是mpeg4,audio的是amr
video的track
MPEG4Extractor::getTrack
sp<MediaSource> MPEG4Extractor::getTrack(size_t index) {
status_t err;
if ((err = readMetaData()) != OK) {
return NULL;
}
Track *track = mFirstTrack;
while (index > 0) {
if (track == NULL) {
return NULL;
}
track = track->next;
--index;
}
if (track == NULL) {
return NULL;
}
ALOGV("getTrack called, pssh: %d", mPssh.size());
return new MPEG4Source(
track->meta, mDataSource, track->timescale, track->sampleTable,
mSidxEntries, mMoofOffset);
}
之后是AwesomePlayer::setVideoSource
void AwesomePlayer::setVideoSource(sp<MediaSource> source) {mVideoTrack在后面用于codec的视频解码用。
CHECK(source != NULL);
mVideoTrack = source;
}
audio的track
AMRExtrator::getTrack
sp<MediaSource> AMRExtractor::getTrack(size_t index) {创建一个AMRSource对象。
if (mInitCheck != OK || index != 0) {
return NULL;
}
return new AMRSource(mDataSource, mMeta, mIsWide,
mOffsetTable, mOffsetTableLength);
}
之后是AwesomePlayer::setAudioSource
void AwesomePlayer::setAudioSource(sp<MediaSource> source) {mAudioTrack用于之后的codec音频解码用。
CHECK(source != NULL);
mAudioTrack = source;
}
最后是setDataSource_post,它返回之前设置的状态
void MediaPlayerService::Client::setDataSource_post(
const sp<MediaPlayerBase>& p,
status_t status)
{
ALOGV(" setDataSource");
mStatus = status;
if (mStatus != OK) {
ALOGE(" error: %d", mStatus);
return;
}
// Set the re-transmission endpoint if one was chosen.
if (mRetransmitEndpointValid) {
mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint);
if (mStatus != NO_ERROR) {
ALOGE("setRetransmitEndpoint error: %d", mStatus);
}
}
if (mStatus == OK) {
mPlayer = p;
}
}