您的位置:首页 > 其它

初探MeidaPlayer底层实现(二)

2017-01-22 21:54 483 查看
接着上一篇文章继续研究MeidaPlayer三个入手点:
1private static native final void native_init();
2private native final void native_setup(Object mediaplayer_this);
3private native void nativeSetDataSource(
IBinder httpServiceBinder, String path, String[] keys, String[] values)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
jni实现在frameworks\base\media\jni\android_media_MediaPlayer.cpp
jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
JNIEnv* env = NULL;
jint result = -1;
。。。
    if (register_android_media_MediaPlayer(env) < 0) {
ALOGE("ERROR: MediaPlayer native registration failed\n");
goto bail;}
}if语句会调用如下函数
// This function only registers the native methods
static int register_android_media_MediaPlayer(JNIEnv *env)
{
return AndroidRuntime::registerNativeMethods(env,
"android/media/MediaPlayer", gMethods, NELEM(gMethods));
}
static JNINativeMethod gMethods[] = {
{
"nativeSetDataSource",//对应java文件中的本地方法名
"(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
"[Ljava/lang/String;)V",//未知
(void *)android_media_MediaPlayer_setDataSourceAndHeaders//JNI方法名
},

{"_setDataSource",      "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
{"_setDataSource",      "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback },
{"_setVideoSurface",    "(Landroid/view/Surface;)V",        (void *)android_media_MediaPlayer_setVideoSurface},
。。。
{"native_init",         "()V",                              (void *)android_media_MediaPlayer_native_init},
{"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer_native_setup},
};从上面知道native_init、native_setup、nativeSetDataSource分别对应的JNI方法名1、native_init()
// This function gets some field IDs, which in turn causes class initialization.
// It is called from a static block in MediaPlayer, which won't run until the
<
4000
/span>// first time an instance of this class is used.
static void
android_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);
}
//todo 具体实现暂时先不研究
2、native_setup()
static void
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);
}
接下来一句一句分析上述代码
sp<MediaPlayer> mp = new MediaPlayer();
这里创建一个MediaPlayer强指针对象。(此处涉及智能指针相关知识,另具体研究)
sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
mp->setListener(listener);
JNIMediaPlayerListener是android_media_MediaPlayer.cpp中的内部类
class JNIMediaPlayerListener: public MediaPlayerListener
{
public:
JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
~JNIMediaPlayerListener();
virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
private:
JNIMediaPlayerListener();
jclass      mClass;     // Reference to MediaPlayer class
jobject     mObject;    // Weak ref to MediaPlayer Java object to call on
};

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(weak_thiz);
}
JNIMediaPlayerListener继承自MediaPlayerListener类,MediaPlayerListener类是frameworks\av\include\media\mediaplayer.h文件中的内部类。
class MediaPlayerListener: virtual public RefBase{public:virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;};
只有一个纯虚函数,在JNIMediaPlayerListener中实现,如下 
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();}}//todo 暂不分析
继续
setMediaPlayer(env, thiz, mp);
static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player){//mz2Mutex::Autolock l(sLock);//同步锁sp<MediaPlayer> old = (MediaPlayer*)env->GetLongField(thiz, fields.context);//获取旧指针if (player.get()) {//刚开始不为NULL,计数+1player->incStrong((void*)setMediaPlayer);}if (old != 0) {//刚开始应该为0old->decStrong((void*)setMediaPlayer);}env->SetLongField(thiz, fields.context, (jlong)player.get());//存入MediaPlayerreturn old;}
3、nativeSetDataSource()
httpServiceBinderObj在java层的类型是IBinder  值为:MediaHTTPService.createHttpServiceBinderIfNecessary(path)
path是String传入的URL
keys是String[] 默认为null
values是String[] 默认为null
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 ) {//此时不为nulljniThrowException(env, "java/lang/IllegalStateException", NULL);return;}if (path == NULL) {//此时不为nulljniThrowException(env, "java/lang/IllegalArgumentException", NULL);return;}const char *tmp = env->GetStringUTFChars(path, NULL);if (tmp == NULL) {  // Out of memoryreturn;}ALOGV("setDataSource: path %s", tmp);String8 pathStr(tmp);env->ReleaseStringUTFChars(path, tmp);tmp = NULL;// We build a KeyedVector out of the key and val arraysKeyedVector<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." );}
继续
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
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);}
继续
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);
这里调用的是MediaPlayer类中的setDataSource
继续
process_media_player_call(env, thiz, opStatus, "java/io/IOException","setDataSource failed." );
// If exception is NULL and opStatus is not OK, this method sends an error// event to the client application; otherwise, if exception is not NULL and// opStatus is not OK, this method throws the given exception to the client// application.static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message){if (exception == NULL) {  // Don't throw exception. Instead, send an event.if (opStatus != (status_t) OK) {sp<MediaPlayer> mp = getMediaPlayer(env, thiz);if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0);}} else {  // Throw exception!if ( opStatus == (status_t) INVALID_OPERATION ) {jniThrowException(env, "java/lang/IllegalStateException", NULL);} else if ( opStatus == (status_t) BAD_VALUE ) {jniThrowException(env, "java/lang/IllegalArgumentException", NULL);} else if ( opStatus == (status_t) PERMISSION_DENIED ) {jniThrowException(env, "java/lang/SecurityException", NULL);} else if ( opStatus != (status_t) OK ) {if (strlen(message) > 230) {// if the message is too long, don't bother displaying the status codejniThrowException( env, exception, message);} else {char msg[256];// append the status code to the messagesprintf(msg, "%s: status=0x%X", message, opStatus);jniThrowException( env, exception, msg);}}}}//todo 初步看是个异常处理的功能,具体另分析
总结,本章主要分析JNI层源码,下一章开始分析c++源码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: