初探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[] 默认为nullvalues是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++源码。
相关文章推荐
- TCP三次握手与四次挥手最简洁易懂的解释
- Python库安装
- vi命令使用
- Glide进阶详解(七)
- Spring 注释 Autowired 和@Resource 的区别
- Unity LineRender画线+计算空间距离+实时更新数据
- 零基础学编程
- java并发编程实践学习(1)线程安全
- hibernate常见错误
- MVC C# 页面跳转
- [置顶] ESP-TOUCH编码规则及解码
- JSTL标签的<c:forEach>用法示例
- zs/rz 命令
- Jquery中$.get(),$.post(),$.ajax(),$.getJSON()的用法总结
- android如何设置listview点击后的item背景颜色的变换
- mesa3d代码阅读
- 文档总结
- Linux I/O文件open函数
- Glide进阶详解(六)
- 多进程编程的优缺点