有第十章中分析,在android设备上,通过模块组件搜索可知android设备上加载window如下:
window.c (vlc\modules\video_output\android) line 54 : set_capability("vout window", 10)
1、其模块初始化分析:
// [vlc/modules/video_output/android/window.c]
vlc_module_begin()
set_shortname(N_("Android Window"))
set_description(N_("Android native window"))
set_category(CAT_VIDEO)
set_subcategory(SUBCAT_VIDEO_VOUT)
set_capability("vout window", 10)
set_callbacks(Open, Close)
vlc_module_end()
// [vlc/modules/video_output/android/window.c]
/**
* Create an Android native window.
*/
static int Open(vout_window_t *wnd, const vout_window_cfg_t *cfg)
{
// 检查设置的window类型
if (cfg->type != VOUT_WINDOW_TYPE_INVALID
&& cfg->type != VOUT_WINDOW_TYPE_ANDROID_NATIVE)
return VLC_EGENERIC;
vout_window_sys_t *p_sys = malloc(sizeof (*p_sys));
if (p_sys == NULL)
return VLC_ENOMEM;
wnd->sys = p_sys;
// 创建【AWindowHandler】android window handler处理者对象,
// 并赋值控制window大小、鼠标坐标事件的方法指针【android设备中可不用】
// 见1.1小节分析
p_sys->p_awh = AWindowHandler_new(wnd,
&(awh_events_t) { OnNewWindowSize, OnNewMouseCoords });
if (!p_sys->p_awh)
goto error;
// 初始化window类型、保存【AWindowHandler】对象
wnd->type = VOUT_WINDOW_TYPE_ANDROID_NATIVE;
wnd->handle.anativewindow = p_sys->p_awh;
// window控制方法指针赋值
// 但是主要:该方法在android native window实现中是空实现!
// 即此模块不需要改功能
wnd->control = Control;
return VLC_SUCCESS;
error:
Close(wnd);
return VLC_EGENERIC;
}
1.1、AWindowHandler_new实现分析:
// 【vlc/modules/video_output/android/utils.c】
AWindowHandler *
AWindowHandler_new(vout_window_t *wnd, awh_events_t *p_events)
{
#define AWINDOW_REGISTER_FLAGS_SUCCESS 0x1
#define AWINDOW_REGISTER_FLAGS_HAS_VIDEO_LAYOUT_LISTENER 0x2
AWindowHandler *p_awh;
JNIEnv *p_env;
// 初始化播放器时保存的对应对象地址值
// 后续分析 TODO
JavaVM *p_jvm = var_InheritAddress(wnd, "android-jvm");
jobject jobj = var_InheritAddress(wnd, "drawable-androidwindow");
if (!p_jvm || !jobj)
{
msg_Err(wnd, "libvlc_media_player options not set");
return NULL;
}
// 获取缓存的jvm环境信息对象
p_env = android_getEnvCommon(NULL, p_jvm, "AWindowHandler");
if (!p_env)
{
msg_Err(wnd, "can't get JNIEnv");
return NULL;
}
// 初始化JNI层jfilds结构体对应java层的【AndroidNativeWindow】和【SurfaceTexture】对象转换
// 及其相关方法赋值、注册java回调jni方法事件等
if (InitJNIFields(p_env, VLC_OBJECT(wnd), jobj) != VLC_SUCCESS)
{
msg_Err(wnd, "InitJNIFields failed");
return NULL;
}
msg_Dbg(wnd, "InitJNIFields success");
p_awh = calloc(1, sizeof(AWindowHandler));
if (!p_awh)
return NULL;
p_awh->p_jvm = p_jvm;
p_awh->jobj = (*p_env)->NewGlobalRef(p_env, jobj);
p_awh->wnd = wnd;
// 窗口大小控制方法赋值给cb,对应接收来自JAVA端的对应方法的调用
p_awh->event.cb = *p_events;
jfloatArray jarray = (*p_env)->NewFloatArray(p_env, 16);
if ((*p_env)->ExceptionCheck(p_env))
{
(*p_env)->ExceptionClear(p_env);
free(p_awh);
return NULL;
}
p_awh->stex.jtransform_mtx_array = (*p_env)->NewGlobalRef(p_env, jarray);
(*p_env)->DeleteLocalRef(p_env, jarray);
p_awh->stex.jtransform_mtx = NULL;
// 此方法为宏定义,实现为:调用了jvm中的jfields.AndroidNativeWindow.registerNative方法,
// 其对应的是java层该对象的该方法,即将native层的【AWindowHandler】对象指针值传递给java层保存,用于对应关系
const jint flags = JNI_ANWCALL(CallIntMethod, registerNative,
(jlong)(intptr_t)p_awh);
if ((flags & AWINDOW_REGISTER_FLAGS_SUCCESS) == 0)
{
msg_Err(wnd, "AWindow already registered");
(*p_env)->DeleteGlobalRef(p_env, p_awh->jobj);
(*p_env)->DeleteGlobalRef(p_env, p_awh->stex.jtransform_mtx_array);
free(p_awh);
return NULL;
}
// 加载android native window模块功能,见该小节下面分析
LoadNativeWindowAPI(p_awh);
// 根据java层到反馈flags值,判断java层是否组成了视频布局变化监听事件
p_awh->b_has_video_layout_listener =
flags & AWINDOW_REGISTER_FLAGS_HAS_VIDEO_LAYOUT_LISTENER;
return p_awh;
}
// 【vlc/modules/video_output/android/utils.c】
static void
LoadNativeWindowAPI(AWindowHandler *p_awh)
{
// 首先加载判断是否有android so库,若无则加载android native Surface对象
void *p_library = dlopen("libandroid.so", RTLD_NOW);
if (!p_library)
{
// 目前只分析该情况
// 见该小节下面分析
LoadNativeSurfaceAPI(p_awh);
return;
}
p_awh->pf_winFromSurface = dlsym(p_library, "ANativeWindow_fromSurface");
p_awh->pf_winRelease = dlsym(p_library, "ANativeWindow_release");
p_awh->anw_api.winLock = dlsym(p_library, "ANativeWindow_lock");
p_awh->anw_api.unlockAndPost = dlsym(p_library, "ANativeWindow_unlockAndPost");
p_awh->anw_api.setBuffersGeometry = dlsym(p_library, "ANativeWindow_setBuffersGeometry");
if (p_awh->pf_winFromSurface && p_awh->pf_winRelease
&& p_awh->anw_api.winLock && p_awh->anw_api.unlockAndPost
&& p_awh->anw_api.setBuffersGeometry)
{
p_awh->p_anw_dl = p_library;
}
else
{
dlclose(p_library);
LoadNativeSurfaceAPI(p_awh);
}
}
// 【vlc/modules/video_output/android/utils.c】
static void
LoadNativeSurfaceAPI(AWindowHandler *p_awh)
{
// android native Surface创建等操作相关的方法指针赋值
// 见第2小节分析,正常情况下加载的是【"libsurfaceflinger_client.so"】中的Surface对象
p_awh->pf_winFromSurface = NativeSurface_fromSurface;
p_awh->pf_winRelease = NativeSurface_release;
// 见第3小节分析
p_awh->anw_api.winLock = NativeSurface_lock;
p_awh->anw_api.unlockAndPost = NativeSurface_unlockAndPost;
p_awh->anw_api.setBuffersGeometry = NULL;
}
2、NativeSurface_fromSurface实现分析:
// 【vlc/modules/video_output/android/utils.c】
// 创建android native Surface 对象
static ANativeWindow*
NativeSurface_fromSurface(JNIEnv *p_env, jobject jsurf)
{
void *p_surface_handle;
NativeSurface *p_ns;
// 从以下顺序的三个so库中尝试获取android native window对象,
// 最先加载Surfaceflinger模块的ANativeWindow对象句柄
static const char *libs[] = {
"libsurfaceflinger_client.so",
"libgui.so",
"libui.so"
};
// 备注:从第十章后续分析【WindowHandler_NewSurfaceEnv】可知,
// jsurf参数为java层【android.view.Surface】对象对应的JNI层对象实例。
// 此处返回的是:对应的是native层Surface的对象指针
// 见本小节下面的分析
p_surface_handle = NativeSurface_getHandle(p_env, jsurf);
if (!p_surface_handle)
return NULL;
p_ns = malloc(sizeof(NativeSurface));
if (!p_ns)
return NULL;
// 保存native surface对象指针
p_ns->p_surface_handle = p_surface_handle;
for (size_t i = 0; i < sizeof(libs) / sizeof(*libs); i++)
{
// 按so库顺序,先加载Surfaceflinger so模块的ANativeWindow对象及其方法句柄指针
// 见本小节下面的分析
void *p_dl_handle = NativeSurface_Load(libs[i], p_ns);
if (p_dl_handle)
{
p_ns->p_dl_handle = p_dl_handle;
// 然后将其强转为【ANativeWindow】对象指针
return (ANativeWindow*)p_ns;
}
}
free(p_ns);
return NULL;
}
// 【vlc/modules/video_output/android/utils.c】
static void *
NativeSurface_getHandle(JNIEnv *p_env, jobject jsurf)
{
jclass clz;
jfieldID fid;
intptr_t p_surface_handle = 0;
// 获取JVM中【android.view.Surface】该对象的class实例
clz = (*p_env)->GetObjectClass(p_env, jsurf);
if ((*p_env)->ExceptionCheck(p_env))
{
(*p_env)->ExceptionClear(p_env);
return NULL;
}
// 获取该变量在该对象中的值【Int值,其实对应的是native层Surface的对象指针值】
fid = (*p_env)->GetFieldID(p_env, clz, "mSurface", "I");
if (fid == NULL)
{
if ((*p_env)->ExceptionCheck(p_env))
(*p_env)->ExceptionClear(p_env);
fid = (*p_env)->GetFieldID(p_env, clz, "mNativeSurface", "I");
if (fid == NULL)
{
if ((*p_env)->ExceptionCheck(p_env))
(*p_env)->ExceptionClear(p_env);
}
}
if (fid != NULL)
// 获取native层surface的指针int值
p_surface_handle = (intptr_t)(*p_env)->GetIntField(p_env, jsurf, fid);
(*p_env)->DeleteLocalRef(p_env, clz);
return (void *)p_surface_handle;
}
// 【vlc/modules/video_output/android/utils.c】
// 该方法实现:加载对应so库中的ANativeWindow对象及其方法句柄指针
static inline void *
NativeSurface_Load(const char *psz_lib, NativeSurface *p_ns)
{
void *p_lib = dlopen(psz_lib, RTLD_NOW);
if (!p_lib)
return NULL;
p_ns->pf_lock = (AndroidSurface_lock)(dlsym(p_lib, ANDROID_SYM_S_LOCK));
p_ns->pf_lock2 = (AndroidSurface_lock2)(dlsym(p_lib, ANDROID_SYM_S_LOCK2));
p_ns->pf_unlockAndPost =
(AndroidSurface_unlockAndPost)(dlsym(p_lib, ANDROID_SYM_S_UNLOCK));
if ((p_ns->pf_lock || p_ns->pf_lock2) && p_ns->pf_unlockAndPost)
return p_lib;
dlclose(p_lib);
return NULL;
}
3、NativeSurface_lock实现分析:
// 【vlc/modules/video_output/android/utils.c】
static int32_t
NativeSurface_lock(ANativeWindow *p_anw, ANativeWindow_Buffer *p_anb,
ARect *p_rect)
{
(void) p_rect;
NativeSurface *p_ns = (NativeSurface *)p_anw;
struct {
uint32_t w;
uint32_t h;
uint32_t s;
uint32_t usage;
uint32_t format;
uint32_t* bits;
uint32_t reserved[2];
} info = { 0 };
// 此处可知直接调用的android Surface的lock/lock2方法请求lock图像
if (p_ns->pf_lock)
p_ns->pf_lock(p_ns->p_surface_handle, &info, 1);
else
p_ns->pf_lock2(p_ns->p_surface_handle, &info, NULL);
if (!info.w || !info.h) {
p_ns->pf_unlockAndPost(p_ns->p_surface_handle);
return -1;
}
// 获取到图像格式及其数据信息
if (p_anb) {
p_anb->bits = info.bits;
p_anb->width = info.w;
p_anb->height = info.h;
p_anb->stride = info.s;
p_anb->format = info.format;
}
return 0;
}
本章节结束,其他源码分析请查看后续章节分析