Android MediaPlayer框架分析
来源:互联网 发布:铁塔基础设计软件 编辑:程序博客网 时间:2024/05/17 01:23
应用层:从setDataSource说起
先来看看应用层Mediaplayer的例子:
public class MediaPlayerStudy extends Activity { private Button bplay,bpause,bstop; private MediaPlayer mp = new MediaPlayer(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); bplay = (Button)findViewById(R.id.play); bpause = (Button)findViewById(R.id.pause); bstop = (Button)findViewById(R.id.stop); bplay.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { try { mp.setDataSource("/sdcard/test.mp3"); mp.prepare(); mp.start(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } mp.setOnCompletionListener(new OnCompletionListener(){ @Override public void onCompletion(MediaPlayer mp) { mp.release(); } }); } }); bpause.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { if(mp != null){ mp.pause(); } } }); bstop.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { if(mp != null){ mp.stop(); } } }); } @Override protected void onDestroy() { if(mp != null) mp.release(); super.onDestroy(); }}
mediaserver的启动
mediaserver在开机时启动,在init.rc文件中有体现:
/system/core/rootdir/init.rc
service media /system/bin/mediaserver class main user media group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm ioprio rt 4
mediaserver的main函数里初始化了AudioFlinger,MediaPlayerService,ResourceManagerService,CameraService,AudioPolicyService,SoundTriggerHwService和
RadioService等service。
/frameworks/av/media/mediaserver/main_mediaserver.cpp
...AudioFlinger::instantiate();MediaPlayerService::instantiate();ResourceManagerService::instantiate();CameraService::instantiate();AudioPolicyService::instantiate();SoundTriggerHwService::instantiate();RadioService::instantiate();...
这里只涉及MediaPlayerService,看看其instantiate函数实现:
/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
void MediaPlayerService::instantiate() { defaultServiceManager()->addService( String16("media.player"), new MediaPlayerService());}
MediaPlayerService::instantiate()主要作用是向ServiceManager注册服务。
MediaPlayer的启动
MediaPlayer构造函数执行之前加载了libmedia_jni.so,并调用了native函数native_init。
/frameworks/base/media/java/android/media/MediaPlayer.java
static { System.loadLibrary("media_jni"); native_init(); }
进程执行native_init时会切换到JNI环境,执行JNI_OnLoad函数:
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
jint JNI_OnLoad(JavaVM* vm, void* /* reserved */){ JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { ALOGE("ERROR: GetEnv failed\n"); goto bail; } assert(env != NULL); ... if (register_android_media_MediaPlayer(env) < 0) { ALOGE("ERROR: MediaPlayer native registration failed\n"); goto bail; } ...
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
static int register_android_media_MediaPlayer(JNIEnv *env){ return AndroidRuntime::registerNativeMethods(env, "android/media/MediaPlayer", gMethods, NELEM(gMethods));}
Java层的函数与JNI层的函数对应关系写在gMethods数组中:
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
static JNINativeMethod gMethods[] = { ... {"native_init", "()V", (void *)android_media_MediaPlayer_native_init}, {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup}, ...
native层fields是个struct fields_t类型的static变量。
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
struct fields_t { jfieldID context; jfieldID surface_texture; jmethodID post_event; jmethodID proxyConfigGetHost; jmethodID proxyConfigGetPort; jmethodID proxyConfigGetExclusionList;};
android_media_MediaPlayer_native_init负责将Java层的一些信息保存在JNI层,如Java层的long型(J)的成员mNativeContext保存在fields.context中,函数成员postEventFromNative保存在fields.post_event中( (Ljava/lang/Object;IIILjava/lang/Object;)V”)表示该函数接收五个参数Object,int,int,int,Object,返回值为void )等等。
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
static voidandroid_media_MediaPlayer_native_init(JNIEnv *env){ jclass clazz; clazz = env->FindClass("android/media/MediaPlayer"); if (clazz == NULL) { return; } fields.context = env->GetFieldID(clazz, "mNativeContext", "J"); 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", "J"); if (fields.surface_texture == NULL) { return; } env->DeleteLocalRef(clazz); clazz = env->FindClass("android/net/ProxyInfo"); 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, "getExclusionListAsString", "()Ljava/lang/String;"); env->DeleteLocalRef(clazz); gPlaybackParamsFields.init(env); gSyncParamsFields.init(env);}
这样,MediaPlayer.java的静态代码块执行完毕。返回Java层MediaPlayer的构造函数中,开始为MediaPlayer设置了Looper和EventHandler,末尾调用native函数native_setup,并传入该MediaPlayer对象的弱引用。这里传入MediaPlayer对象的弱引用的原因是当这个MediaPlayer在不再被需要时(被置null)能被GC回收。
/frameworks/base/media/java/android/media/MediaPlayer.java
public MediaPlayer() { Looper looper; if ((looper = Looper.myLooper()) != null) { mEventHandler = new EventHandler(this, looper); } else if ((looper = Looper.getMainLooper()) != null) { mEventHandler = new EventHandler(this, looper); } else { mEventHandler = null; } mTimeProvider = new TimeProvider(this); mOpenSubtitleSources = new Vector<InputStream>(); IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE); mAppOps = IAppOpsService.Stub.asInterface(b); /* Native setup requires a weak reference to our object. * It's easier to create it here than in C++. */ native_setup(new WeakReference<MediaPlayer>(this)); }
同理,native_setup最终会调到JNI层的android_media_MediaPlayer_native_setup函数。
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
static voidandroid_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);}
android_media_MediaPlayer_native_setup中首先new了一个C++层的MediaPlayer对象。接着new了一个回调用的JNIMediaPlayerListener,weak_thiz传入Java层传下来的MediaPlayer弱引用。GetObjectClass从对象实例thiz中获取class,mclass为android/media/MediaPlayer的全局引用,mObject为MediaPlayer弱引用的全局引用。如果希望创建的对象实例在作用域外也能使用,则需要使用NewGlobalRef接口将其提升为Global Reference——需要注意的是,当Global Reference不再使用后,需要显式的释放,以便通知JVM进行垃圾收集。
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz){ // Hold onto the MediaPlayer class for use in calling the static method // that posts events to the application thread. jclass clazz = env->GetObjectClass(thiz); if (clazz == NULL) { ALOGE("Can't find android/media/MediaPlayer"); jniThrowException(env, "java/lang/Exception", NULL); return; } mClass = (jclass)env->NewGlobalRef(clazz); // We use a weak reference so the MediaPlayer object can be garbage collected. // The reference is only used as a proxy for callbacks. mObject = env->NewGlobalRef();}
setListener将JNIMediaPlayerListener(JNIMediaPlayerListener继承自MediaPlayerListener)保存在成员变量mListener中。这样,C++层的MediaPlayer能够回调JNIMediaPlayerListener的唯一的接口实现notify函数。
/frameworks/av/media/libmedia/mediaplayer.cpp
status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener){ ALOGV("setListener"); Mutex::Autolock _l(mLock); mListener = listener; return NO_ERROR;}
JNIMediaPlayerListener::notify在JNI层调用Java层的方法。fields.post_event存储的是Java层的postEventFromNative函数,mclass为android/media/MediaPlayer这个class的全局引用,mObject为Java层MediaPlayer对象的全局引用。调用Java层的静态方法或访问Java层的静态变量时,CallStaticVoidMethod第一个参数为jclass,否则为jobject,因为静态方法或静态变量为类所有,不为特定对象所有。mObject,msg, ext1, ext2, jParcel作为Java层的函数参数传入。
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj){ JNIEnv *env = AndroidRuntime::getJNIEnv(); if (obj && obj->dataSize() > 0) { jobject jParcel = createJavaParcelObject(env); if (jParcel != NULL) { Parcel* nativeParcel = parcelForJavaObject(env, jParcel); nativeParcel->setData(obj->data(), obj->dataSize()); env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, jParcel); env->DeleteLocalRef(jParcel); } } else { env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, NULL); } if (env->ExceptionCheck()) { ALOGW("An exception occurred while notifying an event."); LOGW_EX(env); env->ExceptionClear(); }}
Java层的postEventFromNative函数中,首先把native_setup传到C++层的MediaPlayer弱引用捞上来,获得对应的MediaPlayer对象。最后,将what, arg1, arg2, obj参数封装成一个Message发送出去。
/frameworks/base/media/java/android/media/MediaPlayer.java
private static void postEventFromNative(Object mediaplayer_ref, int what, int arg1, int arg2, Object obj) { MediaPlayer mp = (MediaPlayer)((WeakReference)mediaplayer_ref).get(); if (mp == null) { return; } if (what == MEDIA_INFO && arg1 == MEDIA_INFO_STARTED_AS_NEXT) { // this acquires the wakelock if needed, and sets the client side state mp.start(); } if (mp.mEventHandler != null) { Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj); mp.mEventHandler.sendMessage(m); } }
回到android_media_MediaPlayer_native_setup函数中,最后一步是调用setMediaPlayer。GetLongField获取Java层mNativeContext的值,mNativeContext保存的是C++层MediaPlayer的地址。将最新new的MediaPlayer强引用计数加1,将旧的MediaPlaye强引用计数减1,使旧的MediaPlayer自动释放内存。最后,把新的MediaPlayer的地址保存在mNativeContext中。
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player){ Mutex::Autolock l(sLock); sp<MediaPlayer> old = (MediaPlayer*)env->GetLongField(thiz, fields.context); if (player.get()) { player->incStrong((void*)setMediaPlayer); } if (old != 0) { old->decStrong((void*)setMediaPlayer); } env->SetLongField(thiz, fields.context, (jlong)player.get()); return old;}
至此,MediaPlayer的启动流程介绍完毕。
MediaPlayer和MediaPlayerService的关系
从mp.setDataSource(“/sdcard/test.mp3”)出发,说明MediaPlayer和MediaPlayer的关系。
setDataSource最终会调到native函数android_media_MediaPlayer_setDataSourceAndHeaders。
/frameworks/base/media/java/android/media/MediaPlayer.java
public void setDataSource(String path) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { setDataSource(path, null, null); }
MediaHTTPService.createHttpServiceBinderIfNecessary的作用是:如果path是网络路径(”http://”,”https://”或”widevine://”),则返回一个BpMediaHTTPService。由于我们是用的是本地路径,所以该函数返回null。
/frameworks/base/media/java/android/media/MediaPlayer.java
private void setDataSource(String path, String[] keys, String[] values) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { final Uri uri = Uri.parse(path); final String scheme = uri.getScheme(); if ("file".equals(scheme)) { path = uri.getPath(); } else if (scheme != null) { // handle non-file sources nativeSetDataSource( MediaHTTPService.createHttpServiceBinderIfNecessary(path), path, keys, values); return; }
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
static JNINativeMethod gMethods[] = { { "nativeSetDataSource", "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;" "[Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSourceAndHeaders }, ...
getMediaPlayer返回Java层mNativeContext保存的C++层MediaPlayer的强指针。GetStringUTFChars将Java的字符串转化为C++的字符串。C++层的MediaPlayer实际上是调用setDataSource(null,”/sdcard/test.mp3”,null)。
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
static voidandroid_media_MediaPlayer_setDataSourceAndHeaders( JNIEnv *env, jobject thiz, jobject httpServiceBinderObj, jstring path, jobjectArray keys, jobjectArray values) { sp<MediaPlayer> mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } if (path == NULL) { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return; } const char *tmp = env->GetStringUTFChars(path, NULL); if (tmp == NULL) { // Out of memory return; } ALOGV("setDataSource: path %s", tmp); String8 pathStr(tmp); env->ReleaseStringUTFChars(path, tmp); tmp = NULL; // We build a KeyedVector out of the key and val arrays KeyedVector<String8, String8> headersVector; if (!ConvertKeyValueArraysToKeyedVector( env, keys, values, &headersVector)) { return; } sp<IMediaHTTPService> httpService; if (httpServiceBinderObj != NULL) { sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj); httpService = interface_cast<IMediaHTTPService>(binder); } status_t opStatus = mp->setDataSource( httpService, pathStr, headersVector.size() > 0? &headersVector : NULL); process_media_player_call( env, thiz, opStatus, "java/io/IOException", "setDataSource failed." );}
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz){ Mutex::Autolock l(sLock); MediaPlayer* const p = (MediaPlayer*)env->GetLongField(thiz, fields.context); return sp<MediaPlayer>(p);}
MediaPlayer::setDataSource函数中,首先会调用getMediaPlayerService去获得MediaPlayerService的BpMediaPlayerService对象。getMediaPlayerService定义在MediaPlayer父类IMediaDeathNotifier的cpp实现文件中。
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
status_t MediaPlayer::setDataSource( const sp<IMediaHTTPService> &httpService, const char *url, const KeyedVector<String8, String8> *headers){ ALOGV("setDataSource(%s)", url); status_t err = BAD_VALUE; if (url != NULL) { const sp<IMediaPlayerService>& service(getMediaPlayerService()); if (service != 0) { sp<IMediaPlayer> player(service->create(this, mAudioSessionId)); if ((NO_ERROR != doSetRetransmitEndpoint(player)) || (NO_ERROR != player->setDataSource(httpService, url, headers))) { player.clear(); } err = attachNewPlayer(player); } } return err;}
/frameworks/av/media/libmedia/IMediaDeathNotifier.cpp
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;}
MediaPlayerService::create函数创建了MediaPlayerService::Client的弱引用,并添加到SortedVector< wp >。SortedVector是一个排序Vector,排序方法是按里面元素的数值大小进行排序。MediaPlayerService::Client以进程的PID,connId(每次连上MediaPlayerService该值都会加1),audioSessionId,UID等为标识。MediaPlayerService::create函数返回Client的强引用。MediaPlayerService::Client的作用类似于套接字,MediaPlayer的主要功能函数在MediaPlayerService::Client这端能找到同名函数,MediaPlayer通过Client对象,使调用流程从客户端转移到服务端。
/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client, 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()); 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初始化为MediaPlayerService::Client的强引用。然后调用MediaPlayerService::Client::setDataSource函数。如果传入的url开头为”http://”,”https://”或”rtsp://”(网络内容),则需要检查网络权限。如果传入的url是数据库内容,使用openContentProviderFile函数打开。应用层传下来的url是本地路径,属于第三种情况。
/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
status_t MediaPlayerService::Client::setDataSource( const sp<IMediaHTTPService> &httpService, const char *url, const KeyedVector<String8, String8> *headers){ ALOGV("setDataSource(%s)", url); if (url == NULL) return UNKNOWN_ERROR; if ((strncmp(url, "http://", 7) == 0) || (strncmp(url, "https://", 8) == 0) || (strncmp(url, "rtsp://", 7) == 0)) { if (!checkPermission("android.permission.INTERNET")) { return PERMISSION_DENIED; } } 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) { ALOGE("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 = MediaPlayerFactory::getPlayerType(this, url); sp<MediaPlayerBase> p = setDataSource_pre(playerType); if (p == NULL) { return NO_INIT; } setDataSource_post(p, p->setDataSource(httpService, url, headers)); return mStatus; }}
getPlayerType函数根据视频源获取所需要的播放器。
/frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp
player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client, const char* url) { GET_PLAYER_TYPE_IMPL(client, url);}
sFactoryMap类型为KeyedVector< player_type,IFactory*>,player_type是枚举类型,列出了播放器的id;IFactory*对应具体的播放器产品接口实现类。每次要添加播放器时,都要添加播放器id和实现类这对键值对到sFactoryMap中来实现注册。
/frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp
#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;
/frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp
virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/, const char* url, float /*curScore*/) { if (legacyDrm() && !strncasecmp("widevine://", url, 11)) { return 1.0; } return 0.0; }
/frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.h
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,};
MediaPlayerFactory是一个工厂类,MediaPlayerFactory::IFactory是一个抽象基类,同时也是一个接口类。产品接口实现类在MediaPlayerFactory.cpp中,分别是tagefrightPlayerFactory,NuPlayerFactory和TestPlayerFactory。它们均继承自IFactory,并各自实现了scoreFactory和createPlayer方法,scoreFactory定义了规则来帮助选取合适的播放器,createPlayer直接创建播放器的实例。所以,MediaPlayerFactory::getPlayerType是一个工厂方法,只需传入额外的url参数就能选取到合适的播放器。
/frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.h
class MediaPlayerFactory { public: class IFactory { public: virtual ~IFactory() { } virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/, const char* /*url*/, float /*curScore*/) { return 0.0; } virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/, int /*fd*/, int64_t /*offset*/, int64_t /*length*/, float /*curScore*/) { return 0.0; } virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/, const sp<IStreamSource> &/*source*/, float /*curScore*/) { return 0.0; } virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/, const sp<DataSource> &/*source*/, float /*curScore*/) { return 0.0; } virtual sp<MediaPlayerBase> createPlayer(pid_t pid) = 0; }; ...
接着回到MediaPlayerService::Client::setDataSource函数中,createPlayer创建了具体的播放器实例。mp3文件使用的播放器id为STAGEFRIGHT_PLAYER,所以这里直接跳过细节,假设createPlayer(playerType)返回的是StagefrightPlayer对象指针。
/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre( 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()) { Mutex::Autolock l(mLock); mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(), mPid, mAudioAttributes); static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput); } return p;}
MediaPlayerService::Client::setDataSource的最后一步是调用setDataSource_post,p->setDataSource(httpService, url, headers)这步是播放器真正解析数据的过程,setDataSource_post函数还将MediaPlayerService的mPlayer成员设为播放器对象指针。StagefrightPlayer的mPlayer指向一个AwesomePlayer对象,AwesomePlayer::setDataSource将url保存在struct Stats类型的成员变量mStats的mURI成员中,这样便完成了播放器数据源的设置。
/frameworks/av/media/libmediaplayerservice/StagefrightPlayer.cpp
StagefrightPlayer::StagefrightPlayer() : mPlayer(new AwesomePlayer) { ALOGV("StagefrightPlayer"); mPlayer->setListener(this);}
/frameworks/av/media/libmediaplayerservice/StagefrightPlayer.cpp
status_t StagefrightPlayer::setDataSource( const sp<IMediaHTTPService> &httpService, const char *url, const KeyedVector<String8, String8> *headers) { return mPlayer->setDataSource(httpService, url, headers);}
/frameworks/av/media/libstagefright/AwesomePlayer.cpp
status_t AwesomePlayer::setDataSource( const sp<IMediaHTTPService> &httpService, const char *uri, const KeyedVector<String8, String8> *headers) { Mutex::Autolock autoLock(mLock); return setDataSource_l(httpService, uri, headers);}
/frameworks/av/media/libstagefright/AwesomePlayer.cpp
status_t AwesomePlayer::setDataSource( const sp<IMediaHTTPService> &httpService, const char *uri, const KeyedVector<String8, String8> *headers) { Mutex::Autolock autoLock(mLock); return setDataSource_l(httpService, uri, headers);}status_t AwesomePlayer::setDataSource_l( const sp<IMediaHTTPService> &httpService, const char *uri, const KeyedVector<String8, String8> *headers) { reset_l(); mHTTPService = httpService; mUri = uri; if (headers) { mUriHeaders = *headers; ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log")); if (index >= 0) { // Browser is in "incognito" mode, suppress logging URLs. // This isn't something that should be passed to the server. mUriHeaders.removeItemsAt(index); modifyFlags(INCOGNITO, SET); } } ALOGI("setDataSource_l(%s)", uriDebugString(mUri, mFlags & INCOGNITO).c_str()); // The actual work will be done during preparation in the call to // ::finishSetDataSource_l to avoid blocking the calling thread in // setDataSource for any significant time. { Mutex::Autolock autoLock(mStatsLock); mStats.mFd = -1; mStats.mURI = mUri; } return OK;}
- Android MediaPlayer框架分析
- Android之MediaPlayer的框架源码分析
- android mediaplayer 分析
- android MediaPlayer深入分析
- android MediaPlayer深入分析
- android MediaPlayer surface分析
- Android MediaPlayer分析
- android mediaplayer + stagefright 框架图解
- Android MediaPlayer 框架UML图
- Android MediaPlayer 框架UML图
- Android MediaPlayer 分析- MediaPlayerService.cpp
- Android MediaPlayer 分析 - client库
- 基于android6.0 mediaplayer框架分析
- Android 源码分析之基于Stagefright的MediaPlayer播放框架[4]
- Android 源码分析之基于Stagefright的MediaPlayer播放框架[3]
- Android 的 MediaPlayer源码框架讲解
- Android MediaPlayer+Stagefright框架(音频)图解
- Android MediaPlayer 客户端框架以及消息传递
- python的random模块函数分析(一)
- 【前端】Github Pages 与域名关联简明教程
- 我们在提供api或微服务时,通常借助openresty nginx进行流量转发或者添加一些规则或功能,
- Django 学习笔记(七)数据库基本操作(增查改删)
- android长图框架
- Android MediaPlayer框架分析
- 以太坊挖矿软件反抽水-eth 免抽水破解收费小插件 (完美兼容 Claymore 原版内核,长沙矿工,圣骑士,中国矿工,ETH 超级矿工)
- Android Sensor HAL层分析
- FTPrep, 49 Anagram
- mysql开启允许远程连接
- 线程实现方法
- Java线程池原理及几种线程池类型介绍
- 关于react-native的适配与布局方式
- 【Leetcode】【python】Merge k Sorted Lists