static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture, vlc_tick_t date) { vout_display_sys_t *sys = vd->sys; VLC_UNUSED(picture); if (subpicture && sys->p_sub_window) { if (sys->b_sub_invalid) { sys->b_sub_invalid = false; if (sys->p_sub_pic) { picture_Release(sys->p_sub_pic); sys->p_sub_pic = NULL; } if (sys->p_spu_blend) { filter_DeleteBlend(sys->p_spu_blend); sys->p_spu_blend = NULL; } free(sys->p_sub_buffer_bounds); sys->p_sub_buffer_bounds = NULL; } if (!sys->p_sub_pic && AndroidWindow_Setup(sys, sys->p_sub_window, 1) == 0) sys->p_sub_pic = PictureAlloc(sys, &sys->p_sub_window->fmt, false); if (!sys->p_spu_blend && sys->p_sub_pic) sys->p_spu_blend = filter_NewBlend(VLC_OBJECT(vd), &sys->p_sub_pic->format); if (sys->p_sub_pic && sys->p_spu_blend) sys->b_has_subpictures = true; } /* As long as no subpicture was received, do not call SubpictureDisplay since JNI calls and clearing the subtitles surface are expensive operations. */ if (sys->b_has_subpictures) { SubpicturePrepare(vd, subpicture); if (!subpicture) { /* The surface has been cleared and there is no new subpicture to upload, do not clear again until a new subpicture is received. */ sys->b_has_subpictures = false; } } if (sys->p_window->b_opaque && AndroidOpaquePicture_CanReleaseAtTime(picture->p_sys)) { vlc_tick_t now = vlc_tick_now(); if (date > now) { if (date - now <= VLC_TICK_FROM_SEC(1)) AndroidOpaquePicture_ReleaseAtTime(picture->p_sys, date); else /* The picture will be displayed from the Display callback */ msg_Warn(vd, "picture way too early to release at time"); } } }
static int SetupWindowSubtitleSurface(vout_display_sys_t *sys) { int err; jobject jsurf = jni_LockAndGetSubtitlesSurface(); err = AndroidWindow_SetSurface(sys, sys->p_sub_window, jsurf); jni_UnlockAndroidSurface(); err = err == 0 ? AndroidWindow_Setup(sys, sys->p_sub_window, 1) : err; return err; }
static int SetupWindowSurface(vout_display_sys_t *sys, unsigned i_pic_count) { int err; jobject jsurf = jni_LockAndGetAndroidJavaSurface(); err = AndroidWindow_SetSurface(sys, sys->p_window, jsurf); jni_UnlockAndroidSurface(); err = err == 0 ? AndroidWindow_Setup(sys, sys->p_window, i_pic_count) : err; return err; }
static picture_pool_t *PoolAlloc(vout_display_t *vd, unsigned requested_count) { vout_display_sys_t *sys = vd->sys; picture_pool_t *pool = NULL; picture_t **pp_pics = NULL; unsigned int i = 0; msg_Dbg(vd, "PoolAlloc: request %d frames", requested_count); if (AndroidWindow_Setup(sys, sys->p_window, requested_count) != 0) goto error; requested_count = sys->p_window->i_pic_count; msg_Dbg(vd, "PoolAlloc: got %d frames", requested_count); UpdateVideoSize(sys, &sys->p_window->fmt); pp_pics = calloc(requested_count, sizeof(picture_t)); for (i = 0; i < requested_count; i++) { picture_t *p_pic = PictureAlloc(sys, &sys->p_window->fmt, sys->p_window->b_opaque); if (!p_pic) goto error; pp_pics[i] = p_pic; } picture_pool_configuration_t pool_cfg; memset(&pool_cfg, 0, sizeof(pool_cfg)); pool_cfg.picture_count = requested_count; pool_cfg.picture = pp_pics; if (sys->p_window->b_opaque) { pool_cfg.lock = PoolLockOpaquePicture; pool_cfg.unlock = PoolUnlockOpaquePicture; } else { pool_cfg.lock = PoolLockPicture; pool_cfg.unlock = PoolUnlockPicture; } pool = picture_pool_NewExtended(&pool_cfg); error: if (!pool && pp_pics) { for (unsigned j = 0; j < i; j++) picture_Release(pp_pics[j]); } free(pp_pics); return pool; }
static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture) { vout_display_sys_t *sys = vd->sys; VLC_UNUSED(picture); SendEventDisplaySize(vd); if (subpicture && sys->p_sub_window) { if (sys->b_sub_invalid) { sys->b_sub_invalid = false; if (sys->p_sub_pic) { picture_Release(sys->p_sub_pic); sys->p_sub_pic = NULL; } if (sys->p_spu_blend) { filter_DeleteBlend(sys->p_spu_blend); sys->p_spu_blend = NULL; } free(sys->p_sub_buffer_bounds); sys->p_sub_buffer_bounds = NULL; } if (!sys->p_sub_pic && AndroidWindow_Setup(sys, sys->p_sub_window, 1) == 0) sys->p_sub_pic = PictureAlloc(sys, &sys->p_sub_window->fmt, false); if (!sys->p_spu_blend && sys->p_sub_pic) sys->p_spu_blend = filter_NewBlend(VLC_OBJECT(vd), &sys->p_sub_pic->format); if (sys->p_sub_pic && sys->p_spu_blend) sys->b_has_subpictures = true; } /* As long as no subpicture was received, do not call SubpictureDisplay since JNI calls and clearing the subtitles surface are expensive operations. */ if (sys->b_has_subpictures) { SubpicturePrepare(vd, subpicture); if (!subpicture) { /* The surface has been cleared and there is no new subpicture to upload, do not clear again until a new subpicture is received. */ sys->b_has_subpictures = false; } } }
static int OpenCommon(vout_display_t *vd, const vout_display_cfg_t *cfg, video_format_t *fmtp) { vout_display_sys_t *sys; video_format_t fmt, sub_fmt; vout_window_t *embed = cfg->window; if (embed->type != VOUT_WINDOW_TYPE_ANDROID_NATIVE) return VLC_EGENERIC; fmt = *fmtp; if (embed == NULL) return VLC_EGENERIC; assert(embed->handle.anativewindow); AWindowHandler *p_awh = embed->handle.anativewindow; if (!AWindowHandler_canSetVideoLayout(p_awh)) { /* It's better to use gles2 if we are not able to change the video * layout */ return VLC_EGENERIC; } /* Allocate structure */ vd->sys = sys = (struct vout_display_sys_t*)calloc(1, sizeof(*sys)); if (!sys) return VLC_ENOMEM; sys->embed = embed; sys->p_awh = p_awh; sys->anw = AWindowHandler_getANativeWindowAPI(sys->p_awh); sys->i_display_width = cfg->display.width; sys->i_display_height = cfg->display.height; if (fmt.i_chroma != VLC_CODEC_ANDROID_OPAQUE) { /* Setup chroma */ char *psz_fcc = var_InheritString(vd, CFG_PREFIX "chroma"); if (psz_fcc) { fmt.i_chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, psz_fcc); free(psz_fcc); } else fmt.i_chroma = VLC_CODEC_RGB32; switch(fmt.i_chroma) { case VLC_CODEC_YV12: /* avoid swscale usage by asking for I420 instead since the * vout already has code to swap the buffers */ fmt.i_chroma = VLC_CODEC_I420; case VLC_CODEC_I420: break; case VLC_CODEC_RGB16: case VLC_CODEC_RGB32: case VLC_CODEC_RGBA: SetRGBMask(&fmt); video_format_FixRgb(&fmt); break; default: goto error; } } sys->p_window = AndroidWindow_New(vd, &fmt, AWindow_Video); if (!sys->p_window) goto error; if (AndroidWindow_Setup(sys, sys->p_window, 0) != 0) goto error; /* use software rotation if we don't do opaque */ if (!sys->p_window->b_opaque) video_format_TransformTo(&fmt, ORIENT_NORMAL); msg_Dbg(vd, "using %s", sys->p_window->b_opaque ? "opaque" : "ANW"); video_format_ApplyRotation(&sub_fmt, &fmt); sub_fmt.i_chroma = subpicture_chromas[0]; SetRGBMask(&sub_fmt); video_format_FixRgb(&sub_fmt); sys->p_sub_window = AndroidWindow_New(vd, &sub_fmt, AWindow_Subtitles); if (sys->p_sub_window) { FixSubtitleFormat(sys); sys->i_sub_last_order = -1; /* Export the subpicture capability of this vout. */ vd->info.subpicture_chromas = subpicture_chromas; } else if (!vd->obj.force && sys->p_window->b_opaque) { msg_Warn(vd, "cannot blend subtitles with an opaque surface, " "trying next vout"); goto error; } *fmtp = fmt; /* Setup vout_display */ vd->pool = Pool; vd->prepare = Prepare; vd->display = Display; vd->control = Control; vd->info.is_slow = !sys->p_window->b_opaque; return VLC_SUCCESS; error: Close(vd); return VLC_EGENERIC; }
static int Open(vlc_object_t *p_this) { vout_display_t *vd = (vout_display_t*)p_this; vout_display_sys_t *sys; video_format_t sub_fmt; if (vout_display_IsWindowed(vd)) return VLC_EGENERIC; /* Allocate structure */ vd->sys = sys = (struct vout_display_sys_t*)calloc(1, sizeof(*sys)); if (!sys) return VLC_ENOMEM; sys->p_awh = AWindowHandler_new(p_this); if (!sys->p_awh) { free(sys); msg_Err(vd, "AWindowHandler_new failed"); return VLC_EGENERIC; } sys->anw = AWindowHandler_getANativeWindowAPI(sys->p_awh); #ifdef USE_ANWP sys->anwp = AWindowHandler_getANativeWindowPrivAPI(sys->p_awh); if (!sys->anwp) msg_Warn(vd, "Could not initialize NativeWindow Priv API."); #endif sys->i_display_width = vd->cfg->display.width; sys->i_display_height = vd->cfg->display.height; if (vd->fmt.i_chroma != VLC_CODEC_ANDROID_OPAQUE) { /* Setup chroma */ char *psz_fcc = var_InheritString(vd, CFG_PREFIX "chroma"); if (psz_fcc) { vd->fmt.i_chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, psz_fcc); free(psz_fcc); } else vd->fmt.i_chroma = VLC_CODEC_RGB32; switch(vd->fmt.i_chroma) { case VLC_CODEC_YV12: /* avoid swscale usage by asking for I420 instead since the * vout already has code to swap the buffers */ vd->fmt.i_chroma = VLC_CODEC_I420; case VLC_CODEC_I420: break; case VLC_CODEC_RGB16: case VLC_CODEC_RGB32: case VLC_CODEC_RGBA: SetRGBMask(&vd->fmt); video_format_FixRgb(&vd->fmt); break; default: goto error; } } sys->p_window = AndroidWindow_New(vd, &vd->fmt, AWindow_Video, true); if (!sys->p_window) goto error; if (AndroidWindow_Setup(sys, sys->p_window, 0) != 0) goto error; /* use software rotation if we don't use private anw */ if (!sys->p_window->b_opaque && !sys->p_window->b_use_priv) video_format_ApplyRotation(&vd->fmt, &vd->fmt); msg_Dbg(vd, "using %s", sys->p_window->b_opaque ? "opaque" : (sys->p_window->b_use_priv ? "ANWP" : "ANW")); video_format_ApplyRotation(&sub_fmt, &vd->fmt); sub_fmt.i_chroma = subpicture_chromas[0]; SetRGBMask(&sub_fmt); video_format_FixRgb(&sub_fmt); sys->p_sub_window = AndroidWindow_New(vd, &sub_fmt, AWindow_Subtitles, false); if (sys->p_sub_window) { FixSubtitleFormat(sys); sys->i_sub_last_order = -1; /* Export the subpicture capability of this vout. */ vd->info.subpicture_chromas = subpicture_chromas; } /* Setup vout_display */ vd->pool = Pool; vd->prepare = Prepare; vd->display = Display; vd->control = Control; vd->manage = Manage; /* Fix initial state */ vout_display_SendEventFullscreen(vd, true); SendEventDisplaySize(vd); return VLC_SUCCESS; error: Close(p_this); return VLC_ENOMEM; }