static int UpdateWindowSize(video_format_t *p_fmt, bool b_cropped) { unsigned int i_width, i_height; unsigned int i_sar_num = 1, i_sar_den = 1; video_format_t rot_fmt; video_format_ApplyRotation(&rot_fmt, p_fmt); if (rot_fmt.i_sar_num != 0 && rot_fmt.i_sar_den != 0) { i_sar_num = rot_fmt.i_sar_num; i_sar_den = rot_fmt.i_sar_den; } if (b_cropped) { i_width = rot_fmt.i_visible_width; i_height = rot_fmt.i_visible_height; } else { i_width = rot_fmt.i_width; i_height = rot_fmt.i_height; } jni_SetSurfaceLayout(i_width, i_height, rot_fmt.i_visible_width, rot_fmt.i_visible_height, i_sar_num, i_sar_den); return 0; }
static void FixSubtitleFormat(vout_display_sys_t *sys) { video_format_t *p_subfmt = &sys->p_sub_window->fmt; video_format_t fmt; int i_width, i_height; int i_video_width, i_video_height; int i_display_width, i_display_height; double aspect; video_format_ApplyRotation(&fmt, &sys->p_window->fmt); if (fmt.i_visible_width == 0 || fmt.i_visible_height == 0) { i_video_width = fmt.i_width; i_video_height = fmt.i_height; } else { i_video_width = fmt.i_visible_width; i_video_height = fmt.i_visible_height; } if (fmt.i_sar_num > 0 && fmt.i_sar_den > 0) { if (fmt.i_sar_num >= fmt.i_sar_den) i_video_width = i_video_width * fmt.i_sar_num / fmt.i_sar_den; else i_video_height = i_video_height * fmt.i_sar_den / fmt.i_sar_num; } if (sys->p_window->i_angle == 90 || sys->p_window->i_angle == 180) { i_display_width = sys->i_display_height; i_display_height = sys->i_display_width; aspect = i_video_height / (double) i_video_width; } else { i_display_width = sys->i_display_width; i_display_height = sys->i_display_height; aspect = i_video_width / (double) i_video_height; } if (i_display_width / aspect < i_display_height) { i_width = i_display_width; i_height = i_display_width / aspect; } else { i_width = i_display_height * aspect; i_height = i_display_height; } // Use the biggest size available if (i_width * i_height < i_video_width * i_video_height) { i_width = i_video_width; i_height = i_video_height; } p_subfmt->i_width = p_subfmt->i_visible_width = i_width; p_subfmt->i_height = p_subfmt->i_visible_height = i_height; p_subfmt->i_x_offset = 0; p_subfmt->i_y_offset = 0; p_subfmt->i_sar_num = 1; p_subfmt->i_sar_den = 1; sys->b_sub_invalid = true; }
static void FmtUpdate( vout_display_t *vd ) { vout_display_sys_t *sys = vd->sys; vout_display_place_t place; video_format_t src; vout_display_PlacePicture( &place, &vd->source, vd->cfg, false ); if( sys->b_apply_rotation ) { video_format_ApplyRotation( &src, &vd->source ); vd->fmt.orientation = 0; } else src = vd->source; vd->fmt.i_width = src.i_width * place.width / src.i_visible_width; vd->fmt.i_height = src.i_height * place.height / src.i_visible_height; vd->fmt.i_visible_width = place.width; vd->fmt.i_visible_height = place.height; vd->fmt.i_x_offset = src.i_x_offset * place.width / src.i_visible_width; vd->fmt.i_y_offset = src.i_y_offset * place.height / src.i_visible_height; sys->i_width = vd->fmt.i_visible_width; sys->i_height = vd->fmt.i_visible_height; }
static int UpdateWindowSize(vout_display_sys_t *sys, video_format_t *p_fmt, bool b_cropped) { unsigned int i_width, i_height; unsigned int i_sar_num = 1, i_sar_den = 1; video_format_t rot_fmt; video_format_ApplyRotation(&rot_fmt, p_fmt); if (rot_fmt.i_sar_num != 0 && rot_fmt.i_sar_den != 0) { i_sar_num = rot_fmt.i_sar_num; i_sar_den = rot_fmt.i_sar_den; } if (b_cropped) { i_width = rot_fmt.i_visible_width; i_height = rot_fmt.i_visible_height; } else { i_width = rot_fmt.i_width; i_height = rot_fmt.i_height; } AWindowHandler_setWindowLayout(sys->p_awh, i_width, i_height, rot_fmt.i_visible_width, rot_fmt.i_visible_height, i_sar_num, i_sar_den); return 0; }
static int Control( vout_display_t *vd, int i_query, va_list ap ) { vout_display_sys_t *sys = vd->sys; switch( i_query ) { case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT: { const video_format_t *p_source; vout_display_place_t place; video_format_t fmt; msg_Dbg( vd, "VOUT_DISPLAY_CHANGE_SOURCE_ASPECT" ); p_source = va_arg( ap, const video_format_t * ); video_format_ApplyRotation( &fmt, p_source ); vout_display_PlacePicture( &place, &fmt, vd->cfg, false ); if( place.width != (unsigned) sys->i_width && place.height != (unsigned) sys->i_height ) { if( vd->info.has_pictures_invalid ) { msg_Warn( vd, "ratio changed: invalidate pictures" ); vout_display_SendEventPicturesInvalid( vd ); } else return VLC_EGENERIC; } return VLC_SUCCESS; } case VOUT_DISPLAY_CHANGE_FULLSCREEN: return VLC_SUCCESS; case VOUT_DISPLAY_RESET_PICTURES: msg_Dbg( vd, "VOUT_DISPLAY_RESET_PICTURES" ); EcoreMainLoopCallSync( vd, EvasResetMainloopCb ); BuffersClean( vd ); if( sys->p_pool ) { picture_pool_Release( sys->p_pool ); sys->p_pool = NULL; } return VLC_SUCCESS; case VOUT_DISPLAY_CHANGE_ZOOM: case VOUT_DISPLAY_CHANGE_SOURCE_CROP: case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED: case VOUT_DISPLAY_HIDE_MOUSE: return VLC_EGENERIC; default: msg_Warn( vd, "Unknown request in evas_output" ); return VLC_EGENERIC; } }
static android_window *AndroidWindow_New(vout_display_t *vd, video_format_t *p_fmt, enum AWindow_ID id, bool b_use_priv) { vout_display_sys_t *sys = vd->sys; android_window *p_window = NULL; p_window = calloc(1, sizeof(android_window)); if (!p_window) goto error; p_window->id = id; p_window->b_opaque = p_fmt->i_chroma == VLC_CODEC_ANDROID_OPAQUE; if (!p_window->b_opaque) { p_window->b_use_priv = sys->anwp && b_use_priv; p_window->i_android_hal = ChromaToAndroidHal(p_fmt->i_chroma); if (p_window->i_android_hal == -1) goto error; } switch (p_fmt->orientation) { case ORIENT_ROTATED_90: p_window->i_angle = 90; break; case ORIENT_ROTATED_180: p_window->i_angle = 180; break; case ORIENT_ROTATED_270: p_window->i_angle = 270; break; default: p_window->i_angle = 0; } if (p_window->b_use_priv) p_window->fmt = *p_fmt; else video_format_ApplyRotation(&p_window->fmt, p_fmt); p_window->i_pic_count = 1; if (AndroidWindow_ConnectSurface(sys, p_window) != 0) { if (id == AWindow_Video) msg_Err(vd, "can't get Video Surface"); else if (id == AWindow_Subtitles) msg_Err(vd, "can't get Subtitles Surface"); goto error; } return p_window; error: free(p_window); return NULL; }
static int AndroidWindow_SetupANWP(vout_display_sys_t *sys, android_window *p_window, bool b_java_configured) { unsigned int i_max_buffer_count = 0; if (!p_window->p_handle_priv) p_window->p_handle_priv = sys->anwp.connect(p_window->p_handle); if (!p_window->p_handle_priv) goto error; if (sys->anwp.setUsage(p_window->p_handle_priv, false, 0) != 0) goto error; if (!b_java_configured && sys->anwp.setBuffersGeometry(p_window->p_handle_priv, p_window->fmt.i_width, p_window->fmt.i_height, p_window->i_android_hal) != 0) goto error; sys->anwp.getMinUndequeued(p_window->p_handle_priv, &p_window->i_min_undequeued); sys->anwp.getMaxBufferCount(p_window->p_handle_priv, &i_max_buffer_count); if ((p_window->i_min_undequeued + p_window->i_pic_count) > i_max_buffer_count) p_window->i_pic_count = i_max_buffer_count - p_window->i_min_undequeued; if (sys->anwp.setBufferCount(p_window->p_handle_priv, p_window->i_pic_count + p_window->i_min_undequeued) != 0) goto error; if (sys->anwp.setOrientation(p_window->p_handle_priv, p_window->i_angle) != 0) goto error; AndroidWindow_UpdateCrop(sys, p_window); return 0; error: if (p_window->p_handle_priv) { sys->anwp.disconnect(p_window->p_handle_priv); p_window->p_handle_priv = NULL; } p_window->b_use_priv = false; if (p_window->i_angle != 0) video_format_ApplyRotation(&p_window->fmt, &p_window->fmt); return -1; }
static android_window *AndroidWindow_New(vout_display_sys_t *sys, video_format_t *p_fmt, bool b_use_priv) { android_window *p_window = calloc(1, sizeof(android_window)); if (!p_window) return NULL; p_window->b_opaque = p_fmt->i_chroma == VLC_CODEC_ANDROID_OPAQUE; if (!p_window->b_opaque) { p_window->b_use_priv = sys->b_has_anwp && b_use_priv; p_window->i_android_hal = ChromaToAndroidHal(p_fmt->i_chroma); if (p_window->i_android_hal == -1) { free(p_window); return NULL; } } switch (p_fmt->orientation) { case ORIENT_ROTATED_90: p_window->i_angle = 90; break; case ORIENT_ROTATED_180: p_window->i_angle = 180; break; case ORIENT_ROTATED_270: p_window->i_angle = 270; break; default: p_window->i_angle = 0; } if (p_window->b_use_priv) p_window->fmt = *p_fmt; else video_format_ApplyRotation(&p_window->fmt, p_fmt); p_window->i_pic_count = 1; return p_window; }
static int Open(vlc_object_t *object) { vout_display_t *vd = (vout_display_t *)object; vout_display_sys_t *sys; /* Allocate structure */ vd->sys = sys = malloc(sizeof(*sys)); if (!sys) return VLC_ENOMEM; sys->directfb = NULL; sys->primary = NULL; sys->width = 0; sys->height = 0; sys->pool = NULL; /* Init DirectFB */ if (DirectFBInit(NULL,NULL) != DFB_OK) { msg_Err(vd, "Cannot init DirectFB"); free(sys); return VLC_EGENERIC; } if (OpenDisplay(vd)) { msg_Err(vd, "Cannot create primary surface"); Close(VLC_OBJECT(vd)); return VLC_EGENERIC; } vout_display_DeleteWindow(vd, NULL); /* */ video_format_t fmt; video_format_ApplyRotation(&fmt, &vd->fmt); switch (sys->pixel_format) { case DSPF_RGB332: /* 8 bit RGB (1 byte, red 3@5, green 3@2, blue 2@0) */ fmt.i_chroma = VLC_CODEC_RGB8; fmt.i_rmask = 0x7 << 5; fmt.i_gmask = 0x7 << 2; fmt.i_bmask = 0x3 << 0; break; case DSPF_RGB16: /* 16 bit RGB (2 byte, red 5@11, green 6@5, blue 5@0) */ fmt.i_chroma = VLC_CODEC_RGB16; fmt.i_rmask = 0x1f << 11; fmt.i_gmask = 0x3f << 5; fmt.i_bmask = 0x1f << 0; break; case DSPF_RGB24: /* 24 bit RGB (3 byte, red 8@16, green 8@8, blue 8@0) */ fmt.i_chroma = VLC_CODEC_RGB24; fmt.i_rmask = 0xff << 16; fmt.i_gmask = 0xff << 8; fmt.i_bmask = 0xff << 0; break; case DSPF_RGB32: /* 24 bit RGB (4 byte, nothing@24, red 8@16, green 8@8, blue 8@0) */ fmt.i_chroma = VLC_CODEC_RGB32; fmt.i_rmask = 0xff << 16; fmt.i_gmask = 0xff << 8; fmt.i_bmask = 0xff << 0; break; default: msg_Err(vd, "unknown screen depth %i", sys->pixel_format); Close(VLC_OBJECT(vd)); return VLC_EGENERIC; } fmt.i_width = sys->width; fmt.i_height = sys->height; /* */ vout_display_info_t info = vd->info; info.has_hide_mouse = true; /* */ vd->fmt = fmt; vd->info = info; vd->pool = Pool; vd->prepare = NULL; vd->display = Display; vd->control = Control; vd->manage = Manage; /* */ vout_display_SendEventFullscreen(vd, true); vout_display_SendEventDisplaySize(vd, fmt.i_width, fmt.i_height, true); return VLC_SUCCESS; }
static int Open(vlc_object_t *p_this) { vout_display_t *vd = (vout_display_t *)p_this; video_format_t fmt; video_format_ApplyRotation(&fmt, &vd->fmt); if (fmt.i_chroma == VLC_CODEC_ANDROID_OPAQUE) return VLC_EGENERIC; if (vout_display_IsWindowed(vd)) return VLC_EGENERIC; /* Allocate structure */ vout_display_sys_t *sys = (struct vout_display_sys_t*) calloc(1, sizeof(*sys)); if (!sys) goto error; /* */ sys->p_library = InitLibrary(sys); if (!sys->p_library) { msg_Err(vd, "Could not initialize libandroid.so/libui.so/libgui.so/libsurfaceflinger_client.so!"); goto error; } /* 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_RGB16: fmt.i_bmask = 0x0000001f; fmt.i_gmask = 0x000007e0; fmt.i_rmask = 0x0000f800; break; case VLC_CODEC_YV12: case VLC_CODEC_I420: fmt.i_chroma = VLC_CODEC_RGB32; case VLC_CODEC_RGB32: fmt.i_rmask = 0x000000ff; fmt.i_gmask = 0x0000ff00; fmt.i_bmask = 0x00ff0000; break; default: return VLC_EGENERIC; } video_format_FixRgb(&fmt); msg_Dbg(vd, "Pixel format %4.4s", (char*)&fmt.i_chroma); sys->i_android_hal = ChromaToAndroidHal(fmt.i_chroma); if (sys->i_android_hal == -1) goto error; sys->fmt = fmt; UpdateLayout(sys); /* Create the associated picture */ picture_sys_t *picsys = calloc(1, sizeof(picture_sys_t)); if (unlikely(picsys == NULL)) goto error; picsys->sys = sys; picture_resource_t resource = { .p_sys = picsys }; picture_t *picture = picture_NewFromResource(&fmt, &resource); if (!picture) { free(picsys); goto error; } /* Wrap it into a picture pool */ picture_pool_configuration_t pool_cfg; memset(&pool_cfg, 0, sizeof(pool_cfg)); pool_cfg.picture_count = 1; pool_cfg.picture = &picture; pool_cfg.lock = AndroidLockSurface; pool_cfg.unlock = AndroidUnlockSurface; sys->pool = picture_pool_NewExtended(&pool_cfg); if (!sys->pool) { picture_Release(picture); goto error; } /* Setup vout_display */ vd->sys = sys; vd->fmt = fmt; vd->pool = Pool; vd->display = Display; vd->control = Control; vd->prepare = NULL; vd->manage = Manage; /* Fix initial state */ vout_display_SendEventFullscreen(vd, false); return VLC_SUCCESS; error: Close(p_this); return VLC_ENOMEM; }
static int Control (vout_display_t *vd, int query, va_list ap) { vout_display_sys_t *sys = vd->sys; switch (query) { case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: { const vout_display_cfg_t *p_cfg = (const vout_display_cfg_t*)va_arg (ap, const vout_display_cfg_t *); vout_display_place_t place; vout_display_PlacePicture (&place, &vd->source, p_cfg, false); if (place.width != vd->fmt.i_visible_width || place.height != vd->fmt.i_visible_height) { vout_display_SendEventPicturesInvalid (vd); return VLC_SUCCESS; } /* Move the picture within the window */ const uint32_t values[] = { place.x, place.y }; xcb_configure_window (sys->conn, sys->window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values); return VLC_SUCCESS; } case VOUT_DISPLAY_CHANGE_ZOOM: case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED: case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT: case VOUT_DISPLAY_CHANGE_SOURCE_CROP: /* I am not sure it is always necessary, but it is way simpler ... */ vout_display_SendEventPicturesInvalid (vd); return VLC_SUCCESS; case VOUT_DISPLAY_RESET_PICTURES: { ResetPictures (vd); vout_display_place_t place; vout_display_PlacePicture (&place, &vd->source, vd->cfg, false); video_format_t src; video_format_ApplyRotation(&src, &vd->source); vd->fmt.i_width = src.i_width * place.width / src.i_visible_width; vd->fmt.i_height = src.i_height * place.height / src.i_visible_height; vd->fmt.i_visible_width = place.width; vd->fmt.i_visible_height = place.height; vd->fmt.i_x_offset = src.i_x_offset * place.width / src.i_visible_width; vd->fmt.i_y_offset = src.i_y_offset * place.height / src.i_visible_height; return VLC_SUCCESS; } /* Hide the mouse. It will be send when * vout_display_t::info.b_hide_mouse is false */ case VOUT_DISPLAY_HIDE_MOUSE: xcb_change_window_attributes (sys->conn, sys->embed->handle.xid, XCB_CW_CURSOR, &(uint32_t){ sys->cursor }); xcb_flush (sys->conn); return VLC_SUCCESS; default: msg_Err (vd, "Unknown request in XCB vout display"); return VLC_EGENERIC; } }
/***************************************************************************** * Open: allocates video thread ***************************************************************************** * This function allocates and initializes a vout method. *****************************************************************************/ static int Open(vlc_object_t *object) { vout_display_t *vd = (vout_display_t *)object; vout_display_sys_t *sys = malloc(sizeof(*sys)); if (unlikely(!sys)) return VLC_ENOMEM; /* Get the callbacks */ vlc_format_cb setup = var_InheritAddress(vd, "vmem-setup"); sys->lock = var_InheritAddress(vd, "vmem-lock"); if (sys->lock == NULL) { msg_Err(vd, "missing lock callback"); free(sys); return VLC_EGENERIC; } sys->unlock = var_InheritAddress(vd, "vmem-unlock"); sys->display = var_InheritAddress(vd, "vmem-display"); sys->cleanup = var_InheritAddress(vd, "vmem-cleanup"); sys->opaque = var_InheritAddress(vd, "vmem-data"); sys->pool = NULL; /* Define the video format */ video_format_t fmt; video_format_ApplyRotation(&fmt, &vd->fmt); if (setup != NULL) { char chroma[5]; memcpy(chroma, &fmt.i_chroma, 4); chroma[4] = '\0'; memset(sys->pitches, 0, sizeof(sys->pitches)); memset(sys->lines, 0, sizeof(sys->lines)); sys->count = setup(&sys->opaque, chroma, &fmt.i_width, &fmt.i_height, sys->pitches, sys->lines); if (sys->count == 0) { msg_Err(vd, "video format setup failure (no pictures)"); free(sys); return VLC_EGENERIC; } fmt.i_chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, chroma); } else { char *chroma = var_InheritString(vd, "vmem-chroma"); fmt.i_chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, chroma); free(chroma); fmt.i_width = var_InheritInteger(vd, "vmem-width"); fmt.i_height = var_InheritInteger(vd, "vmem-height"); sys->pitches[0] = var_InheritInteger(vd, "vmem-pitch"); sys->lines[0] = fmt.i_height; for (size_t i = 1; i < PICTURE_PLANE_MAX; i++) { sys->pitches[i] = sys->pitches[0]; sys->lines[i] = sys->lines[0]; } sys->count = 1; sys->cleanup = NULL; } fmt.i_x_offset = fmt.i_y_offset = 0; fmt.i_visible_width = fmt.i_width; fmt.i_visible_height = fmt.i_height; if (!fmt.i_chroma) { msg_Err(vd, "vmem-chroma should be 4 characters long"); free(sys); return VLC_EGENERIC; } /* Define the bitmasks */ switch (fmt.i_chroma) { case VLC_CODEC_RGB15: fmt.i_rmask = 0x001f; fmt.i_gmask = 0x03e0; fmt.i_bmask = 0x7c00; break; case VLC_CODEC_RGB16: fmt.i_rmask = 0x001f; fmt.i_gmask = 0x07e0; fmt.i_bmask = 0xf800; break; case VLC_CODEC_RGB24: case VLC_CODEC_RGB32: fmt.i_rmask = 0xff0000; fmt.i_gmask = 0x00ff00; fmt.i_bmask = 0x0000ff; break; default: fmt.i_rmask = 0; fmt.i_gmask = 0; fmt.i_bmask = 0; break; } /* */ vout_display_info_t info = vd->info; info.has_hide_mouse = true; /* */ vd->sys = sys; vd->fmt = fmt; vd->info = info; vd->pool = Pool; vd->prepare = Prepare; vd->display = Display; vd->control = Control; vd->manage = NULL; /* */ vout_display_SendEventFullscreen(vd, false); vout_display_SendEventDisplaySize(vd, fmt.i_width, fmt.i_height); vout_display_DeleteWindow(vd, NULL); return VLC_SUCCESS; }
/** * Probe the X server. */ static int Open (vlc_object_t *obj) { vout_display_t *vd = (vout_display_t *)obj; vout_display_sys_t *sys = malloc (sizeof (*sys)); if (unlikely(sys == NULL)) return VLC_ENOMEM; vd->sys = sys; sys->pool = NULL; /* Get window, connect to X server */ xcb_connection_t *conn; const xcb_screen_t *scr; sys->embed = vlc_xcb_parent_Create(vd, &conn, &scr); if (sys->embed == NULL) { free (sys); return VLC_EGENERIC; } sys->conn = conn; const xcb_setup_t *setup = xcb_get_setup (conn); /* Determine our pixel format */ video_format_t fmt_pic; xcb_visualid_t vid = 0; sys->depth = 0; for (const xcb_format_t *fmt = xcb_setup_pixmap_formats (setup), *end = fmt + xcb_setup_pixmap_formats_length (setup); fmt < end; fmt++) { if (fmt->depth <= sys->depth) continue; /* no better than earlier format */ video_format_ApplyRotation(&fmt_pic, &vd->fmt); /* Check that the pixmap format is supported by VLC. */ switch (fmt->depth) { case 32: if (fmt->bits_per_pixel != 32) continue; fmt_pic.i_chroma = VLC_CODEC_ARGB; break; case 24: if (fmt->bits_per_pixel == 32) fmt_pic.i_chroma = VLC_CODEC_RGB32; else if (fmt->bits_per_pixel == 24) fmt_pic.i_chroma = VLC_CODEC_RGB24; else continue; break; case 16: if (fmt->bits_per_pixel != 16) continue; fmt_pic.i_chroma = VLC_CODEC_RGB16; break; case 15: if (fmt->bits_per_pixel != 16) continue; fmt_pic.i_chroma = VLC_CODEC_RGB15; break; case 8: if (fmt->bits_per_pixel != 8) continue; fmt_pic.i_chroma = VLC_CODEC_RGB8; break; default: continue; } /* Byte sex is a non-issue for 8-bits. It can be worked around with * RGB masks for 24-bits. Too bad for 15-bits and 16-bits. */ if (fmt->bits_per_pixel == 16 && setup->image_byte_order != ORDER) continue; /* Make sure the X server is sane */ assert (fmt->bits_per_pixel > 0); if (unlikely(fmt->scanline_pad % fmt->bits_per_pixel)) continue; /* Check that the selected screen supports this depth */ const xcb_depth_t *d = FindDepth (scr, fmt->depth); if (d == NULL) continue; /* Find a visual type for the selected depth */ const xcb_visualtype_t *vt = xcb_depth_visuals (d); /* First try True Color class */ for (int i = xcb_depth_visuals_length (d); i > 0; i--) { if (vt->_class == XCB_VISUAL_CLASS_TRUE_COLOR) { fmt_pic.i_rmask = vt->red_mask; fmt_pic.i_gmask = vt->green_mask; fmt_pic.i_bmask = vt->blue_mask; found_visual: vid = vt->visual_id; msg_Dbg (vd, "using X11 visual ID 0x%"PRIx32, vid); sys->depth = fmt->depth; msg_Dbg (vd, " %"PRIu8" bits depth", sys->depth); msg_Dbg (vd, " %"PRIu8" bits per pixel", fmt->bits_per_pixel); msg_Dbg (vd, " %"PRIu8" bits line pad", fmt->scanline_pad); goto found_format; } vt++; } /* Then try Static Gray class */ if (fmt->depth != 8) continue; vt = xcb_depth_visuals (d); for (int i = xcb_depth_visuals_length (d); i > 0 && !vid; i--) { if (vt->_class == XCB_VISUAL_CLASS_STATIC_GRAY) { fmt_pic.i_chroma = VLC_CODEC_GREY; goto found_visual; } vt++; } } msg_Err (obj, "no supported pixel format & visual"); goto error; found_format:; /* Create colormap (needed to select non-default visual) */ xcb_colormap_t cmap; if (vid != scr->root_visual) { cmap = xcb_generate_id (conn); xcb_create_colormap (conn, XCB_COLORMAP_ALLOC_NONE, cmap, scr->root, vid); } else cmap = scr->default_colormap; /* Create window */ sys->window = xcb_generate_id (conn); sys->gc = xcb_generate_id (conn); xcb_pixmap_t pixmap = xcb_generate_id (conn); { const uint32_t mask = XCB_CW_BACK_PIXMAP | XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXMAP | XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP; const uint32_t values[] = { /* XCB_CW_BACK_PIXMAP */ pixmap, /* XCB_CW_BACK_PIXEL */ scr->black_pixel, /* XCB_CW_BORDER_PIXMAP */ pixmap, /* XCB_CW_BORDER_PIXEL */ scr->black_pixel, /* XCB_CW_EVENT_MASK */ XCB_EVENT_MASK_VISIBILITY_CHANGE, /* XCB_CW_COLORMAP */ cmap, }; xcb_void_cookie_t c; xcb_create_pixmap (conn, sys->depth, pixmap, scr->root, 1, 1); c = xcb_create_window_checked (conn, sys->depth, sys->window, sys->embed->handle.xid, 0, 0, vd->cfg->display.width, vd->cfg->display.height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, vid, mask, values); xcb_map_window (conn, sys->window); /* Create graphic context (I wonder why the heck do we need this) */ xcb_create_gc (conn, sys->gc, sys->window, 0, NULL); if (vlc_xcb_error_Check(vd, conn, "cannot create X11 window", c)) goto error; } msg_Dbg (vd, "using X11 window %08"PRIx32, sys->window); msg_Dbg (vd, "using X11 graphic context %08"PRIx32, sys->gc); sys->cursor = vlc_xcb_cursor_Create(conn, scr); sys->visible = false; if (XCB_shm_Check (obj, conn)) { sys->seg_base = xcb_generate_id (conn); for (unsigned i = 1; i < MAX_PICTURES; i++) xcb_generate_id (conn); } else sys->seg_base = 0; /* Setup vout_display_t once everything is fine */ vd->info.has_pictures_invalid = true; vd->info.has_event_thread = true; vd->fmt = fmt_pic; vd->pool = Pool; vd->prepare = NULL; vd->display = Display; vd->control = Control; vd->manage = Manage; return VLC_SUCCESS; error: Close (obj); return VLC_EGENERIC; }
/***************************************************************************** * Control: control facility for the vout *****************************************************************************/ static int Control( vout_display_t *vd, int query, va_list args ) { vout_display_sys_t *sys = vd->sys; switch (query) { case VOUT_DISPLAY_HIDE_MOUSE: { POINTL ptl; WinQueryPointerPos( HWND_DESKTOP, &ptl ); if( !sys->is_mouse_hidden && WinWindowFromPoint( HWND_DESKTOP, &ptl, TRUE ) == sys->client ) { WinShowPointer( HWND_DESKTOP, FALSE ); sys->is_mouse_hidden = true; } return VLC_SUCCESS; } case VOUT_DISPLAY_CHANGE_FULLSCREEN: { bool fs = va_arg(args, int); WinPostMsg( sys->client, WM_VLC_FULLSCREEN_CHANGE, MPFROMLONG(fs), 0 ); return VLC_SUCCESS; } case VOUT_DISPLAY_CHANGE_WINDOW_STATE: { const unsigned state = va_arg( args, unsigned ); const bool is_on_top = (state & VOUT_WINDOW_STATE_ABOVE) != 0; if( is_on_top ) WinSetWindowPos( sys->frame, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER ); sys->is_on_top = is_on_top; return VLC_SUCCESS; } case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: case VOUT_DISPLAY_CHANGE_ZOOM: { const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t *); WinPostMsg( sys->client, WM_VLC_SIZE_CHANGE, MPFROMLONG( cfg->display.width ), MPFROMLONG( cfg->display.height )); return VLC_SUCCESS; } case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT: case VOUT_DISPLAY_CHANGE_SOURCE_CROP: { if( query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT ) { vout_display_place_t place; vout_display_PlacePicture(&place, &vd->source, vd->cfg, false); sys->kvas.ulAspectWidth = place.width; sys->kvas.ulAspectHeight = place.height; } else { video_format_t src_rot; video_format_ApplyRotation(&src_rot, &vd->source); sys->kvas.rclSrcRect.xLeft = src_rot.i_x_offset; sys->kvas.rclSrcRect.yTop = src_rot.i_y_offset; sys->kvas.rclSrcRect.xRight = src_rot.i_x_offset + src_rot.i_visible_width; sys->kvas.rclSrcRect.yBottom = src_rot.i_y_offset + src_rot.i_visible_height; } kvaSetup( &sys->kvas ); return VLC_SUCCESS; } case VOUT_DISPLAY_RESET_PICTURES: case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED: /* TODO */ break; } msg_Err(vd, "Unsupported query(=%d) in vout display KVA", query); return VLC_EGENERIC; }
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; }
/** * This function allocates and initializes a FB vout method. */ static int Open(vlc_object_t *object) { vout_display_t *vd = (vout_display_t *)object; vout_display_sys_t *sys; /* Allocate instance and initialize some members */ vd->sys = sys = calloc(1, sizeof(*sys)); if (!sys) return VLC_ENOMEM; /* Does the framebuffer uses hw acceleration? */ sys->is_hw_accel = var_InheritBool(vd, "fb-hw-accel"); /* Set tty and fb devices */ sys->tty = 0; /* 0 == /dev/tty0 == current console */ sys->is_tty = var_InheritBool(vd, "fb-tty"); #if !defined(_WIN32) && defined(HAVE_ISATTY) /* Check that stdin is a TTY */ if (sys->is_tty && !isatty(0)) { msg_Warn(vd, "standard input is not a TTY"); free(sys); return VLC_EGENERIC; } msg_Warn(vd, "disabling TTY handling, use with caution because " "there is no way to return to the TTY"); #endif const int mode = var_InheritInteger(vd, "fb-mode"); bool force_resolution = true; switch (mode) { case 0: /* QCIF */ sys->width = 176; sys->height = 144; break; case 1: /* CIF */ sys->width = 352; sys->height = 288; break; case 2: /* NTSC */ sys->width = 640; sys->height = 480; break; case 3: /* PAL */ sys->width = 704; sys->height = 576; break; case 4: default: force_resolution = false; break; } char *chroma = var_InheritString(vd, "fb-chroma"); if (chroma) { sys->chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, chroma); if (sys->chroma) msg_Dbg(vd, "forcing chroma '%s'", chroma); else msg_Warn(vd, "chroma %s invalid, using default", chroma); free(chroma); } else sys->chroma = 0; /* tty handling */ if (sys->is_tty && TtyInit(vd)) { free(sys); return VLC_EGENERIC; } /* */ sys->video_ptr = MAP_FAILED; sys->picture = NULL; sys->pool = NULL; if (OpenDisplay(vd, force_resolution)) { Close(VLC_OBJECT(vd)); return VLC_EGENERIC; } vout_display_DeleteWindow(vd, NULL); /* */ video_format_t fmt; video_format_ApplyRotation(&fmt, &vd->fmt); if (sys->chroma) { fmt.i_chroma = sys->chroma; } else { /* Assume RGB */ msg_Dbg(vd, "%d bppd", sys->var_info.bits_per_pixel); switch (sys->var_info.bits_per_pixel) { case 8: /* FIXME: set the palette */ fmt.i_chroma = VLC_CODEC_RGB8; break; case 15: fmt.i_chroma = VLC_CODEC_RGB15; break; case 16: fmt.i_chroma = VLC_CODEC_RGB16; break; case 24: fmt.i_chroma = VLC_CODEC_RGB24; break; case 32: fmt.i_chroma = VLC_CODEC_RGB32; break; default: msg_Err(vd, "unknown screendepth %i", sys->var_info.bits_per_pixel); Close(VLC_OBJECT(vd)); return VLC_EGENERIC; } if (sys->var_info.bits_per_pixel != 8) { fmt.i_rmask = ((1 << sys->var_info.red.length) - 1) << sys->var_info.red.offset; fmt.i_gmask = ((1 << sys->var_info.green.length) - 1) << sys->var_info.green.offset; fmt.i_bmask = ((1 << sys->var_info.blue.length) - 1) << sys->var_info.blue.offset; } } fmt.i_visible_width = sys->width; fmt.i_visible_height = sys->height; /* */ vout_display_info_t info = vd->info; info.has_hide_mouse = true; /* */ vd->fmt = fmt; vd->info = info; vd->pool = Pool; vd->prepare = NULL; vd->display = Display; vd->control = Control; vd->manage = NULL; /* */ vout_display_SendEventFullscreen(vd, true); vout_display_SendEventDisplaySize(vd, fmt.i_visible_width, fmt.i_visible_height, true); return VLC_SUCCESS; }
static int Control (vout_display_t *vd, int query, va_list ap) { vout_display_sys_t *sys = vd->sys; switch (query) { case VOUT_DISPLAY_CHANGE_FULLSCREEN: { const vout_display_cfg_t *c = va_arg (ap, const vout_display_cfg_t *); return vout_window_SetFullScreen (sys->embed, c->is_fullscreen); } case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: { const vout_display_cfg_t *p_cfg = (const vout_display_cfg_t*)va_arg (ap, const vout_display_cfg_t *); const bool is_forced = (bool)va_arg (ap, int); if (is_forced) { /* Changing the dimensions of the parent window takes place * asynchronously (in the X server). Also it might fail or result * in different dimensions than requested. Request the size change * and return a failure since the size is not (yet) changed. * If the change eventually succeeds, HandleParentStructure() * will trigger a non-forced display size change later. */ vout_window_SetSize (sys->embed, p_cfg->display.width, p_cfg->display.height); return VLC_EGENERIC; } vout_display_place_t place; vout_display_PlacePicture (&place, &vd->source, p_cfg, false); if (place.width != vd->fmt.i_visible_width || place.height != vd->fmt.i_visible_height) { vout_display_SendEventPicturesInvalid (vd); return VLC_SUCCESS; } /* Move the picture within the window */ const uint32_t values[] = { place.x, place.y }; xcb_configure_window (sys->conn, sys->window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values); return VLC_SUCCESS; } case VOUT_DISPLAY_CHANGE_WINDOW_STATE: { unsigned state = va_arg (ap, unsigned); return vout_window_SetState (sys->embed, state); } case VOUT_DISPLAY_CHANGE_ZOOM: case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED: case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT: case VOUT_DISPLAY_CHANGE_SOURCE_CROP: /* I am not sure it is always necessary, but it is way simpler ... */ vout_display_SendEventPicturesInvalid (vd); return VLC_SUCCESS; case VOUT_DISPLAY_RESET_PICTURES: { ResetPictures (vd); vout_display_place_t place; vout_display_PlacePicture (&place, &vd->source, vd->cfg, false); video_format_t src; video_format_ApplyRotation(&src, &vd->source); vd->fmt.i_width = src.i_width * place.width / src.i_visible_width; vd->fmt.i_height = src.i_height * place.height / src.i_visible_height; vd->fmt.i_visible_width = place.width; vd->fmt.i_visible_height = place.height; vd->fmt.i_x_offset = src.i_x_offset * place.width / src.i_visible_width; vd->fmt.i_y_offset = src.i_y_offset * place.height / src.i_visible_height; return VLC_SUCCESS; } /* Hide the mouse. It will be send when * vout_display_t::info.b_hide_mouse is false */ case VOUT_DISPLAY_HIDE_MOUSE: xcb_change_window_attributes (sys->conn, sys->embed->handle.xid, XCB_CW_CURSOR, &(uint32_t) { sys->cursor }); xcb_flush (sys->conn); return VLC_SUCCESS; default: msg_Err (vd, "Unknown request in XCB vout display"); 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; /* XXX: android_window use a surface created by VideoPlayerActivity to * alloc pictures. Don't try to open the vout if this activity is not * created. This need to be replaced by something like var_CreateGetAddress * (vd, "drawable-android") in the future. */ if (!jni_IsVideoPlayerActivityCreated()) return VLC_EGENERIC; /* Allocate structure */ vd->sys = sys = (struct vout_display_sys_t*)calloc(1, sizeof(*sys)); if (!sys) return VLC_ENOMEM; sys->p_library = LoadNativeWindowAPI(&sys->anw); if (!sys->p_library) { msg_Err(vd, "Could not initialize NativeWindow API."); goto error; } #ifdef USE_ANWP if (LoadNativeWindowPrivAPI(&sys->anwp) == 0) sys->b_has_anwp = true; else 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(sys, &vd->fmt, true); if (!sys->p_window) goto error; if (SetupWindowSurface(sys, 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(sys, &sub_fmt, false); if (!sys->p_sub_window) goto error; 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; }
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; }
static int Open(vlc_object_t *object) { vout_display_t *vd = (vout_display_t *)object; vout_display_sys_t *sys; /* Allocate instance and initialize some members */ vd->sys = sys = malloc(sizeof(*sys)); if (!sys) return VLC_ENOMEM; sys->is_first = false; sys->is_yuv4mpeg2 = var_InheritBool(vd, CFG_PREFIX "yuv4mpeg2"); sys->pool = NULL; /* */ char *psz_fcc = var_InheritString(vd, CFG_PREFIX "chroma"); const vlc_fourcc_t requested_chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, psz_fcc); free(psz_fcc); const vlc_fourcc_t chroma = requested_chroma ? requested_chroma : VLC_CODEC_I420; if (sys->is_yuv4mpeg2) { switch (chroma) { case VLC_CODEC_YV12: case VLC_CODEC_I420: case VLC_CODEC_J420: break; default: msg_Err(vd, "YUV4MPEG2 mode needs chroma YV12 not %4.4s as requested", (char *)&chroma); free(sys); return VLC_EGENERIC; } } msg_Dbg(vd, "Using chroma %4.4s", (char *)&chroma); /* */ char *name = var_InheritString(vd, CFG_PREFIX "file"); if (!name) { msg_Err(vd, "Empty file name"); free(sys); return VLC_EGENERIC; } sys->f = vlc_fopen(name, "wb"); if (!sys->f) { msg_Err(vd, "Failed to open %s", name); free(name); free(sys); return VLC_EGENERIC; } msg_Dbg(vd, "Writing data to %s", name); free(name); /* */ video_format_t fmt; video_format_ApplyRotation(&fmt, &vd->fmt); fmt.i_chroma = chroma; video_format_FixRgb(&fmt); /* */ vout_display_info_t info = vd->info; info.has_hide_mouse = true; /* */ vd->fmt = fmt; vd->info = info; vd->pool = Pool; vd->prepare = NULL; vd->display = Display; vd->control = Control; vd->manage = NULL; vout_display_SendEventFullscreen(vd, false); vout_display_DeleteWindow(vd, NULL); return VLC_SUCCESS; }
/** * This function initializes SDL vout method. */ static int Open(vlc_object_t *object) { vout_display_t *vd = (vout_display_t *)object; vout_display_sys_t *sys; if (vout_display_IsWindowed(vd)) return VLC_EGENERIC; #if !defined(_WIN32) && !defined(__OS2__) if (!vlc_xlib_init (object)) return VLC_EGENERIC; #endif /* XXX: check for conflicts with the SDL audio output */ vlc_mutex_lock(&sdl_lock); /* Check if SDL video module has been initialized */ if (SDL_WasInit(SDL_INIT_VIDEO) != 0) { vlc_mutex_unlock(&sdl_lock); return VLC_EGENERIC; } vd->sys = sys = calloc(1, sizeof(*sys)); if (!sys) { vlc_mutex_unlock(&sdl_lock); return VLC_ENOMEM; } /* */ int sdl_flags = SDL_INIT_VIDEO; #ifndef _WIN32 /* Win32 SDL implementation doesn't support SDL_INIT_EVENTTHREAD yet*/ sdl_flags |= SDL_INIT_EVENTTHREAD; #endif /* In debug mode you may want vlc to dump a core instead of staying stuck */ sdl_flags |= SDL_INIT_NOPARACHUTE; /* Initialize library */ if (SDL_Init(sdl_flags) < 0) { vlc_mutex_unlock(&sdl_lock); msg_Err(vd, "cannot initialize SDL (%s)", SDL_GetError()); free(sys); return VLC_EGENERIC; } vlc_mutex_unlock(&sdl_lock); /* Translate keys into unicode */ SDL_EnableUNICODE(1); /* Get the desktop resolution */ /* FIXME: SDL has a problem with virtual desktop */ sys->desktop_width = SDL_GetVideoInfo()->current_w; sys->desktop_height = SDL_GetVideoInfo()->current_h; /* */ video_format_t fmt; video_format_ApplyRotation(&fmt, &vd->fmt); /* */ vout_display_info_t info = vd->info; info.needs_event_thread = true; /* Set main window's size */ int display_width; int display_height; if (vd->cfg->is_fullscreen) { display_width = sys->desktop_width; display_height = sys->desktop_height; } else { display_width = vd->cfg->display.width; display_height = vd->cfg->display.height; } /* Initialize flags and cursor */ sys->display_flags = SDL_ANYFORMAT | SDL_HWPALETTE | SDL_HWSURFACE | SDL_DOUBLEBUF; sys->display_flags |= vd->cfg->is_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE; sys->display_bpp = SDL_VideoModeOK(display_width, display_height, 16, sys->display_flags); if (sys->display_bpp == 0) { msg_Err(vd, "no video mode available"); goto error; } sys->display = SDL_SetVideoMode(display_width, display_height, sys->display_bpp, sys->display_flags); if (!sys->display) { msg_Err(vd, "cannot set video mode"); goto error; } /* We keep the surface locked forever */ SDL_LockSurface(sys->display); /* */ vlc_fourcc_t forced_chroma = 0; char *psz_chroma = var_InheritString(vd, "sdl-chroma"); if (psz_chroma) { forced_chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, psz_chroma); if (forced_chroma) msg_Dbg(vd, "Forcing chroma to 0x%.8x (%4.4s)", forced_chroma, (const char*)&forced_chroma); free(psz_chroma); } /* Try to open an overlay if requested */ sys->overlay = NULL; const bool is_overlay = var_InheritBool(vd, "sdl-overlay"); if (is_overlay) { static const struct { vlc_fourcc_t vlc; uint32_t sdl; } vlc_to_sdl[] = { { VLC_CODEC_YV12, SDL_YV12_OVERLAY }, { VLC_CODEC_I420, SDL_IYUV_OVERLAY }, { VLC_CODEC_YUYV, SDL_YUY2_OVERLAY }, { VLC_CODEC_UYVY, SDL_UYVY_OVERLAY }, { VLC_CODEC_YVYU, SDL_YVYU_OVERLAY }, { 0, 0 } }; const vlc_fourcc_t forced_chromas[] = { forced_chroma, 0 }; const vlc_fourcc_t *fallback_chromas = vlc_fourcc_GetYUVFallback(fmt.i_chroma); const vlc_fourcc_t *chromas = forced_chroma ? forced_chromas : fallback_chromas; for (int pass = forced_chroma ? 1 : 0; pass < 2 && !sys->overlay; pass++) { for (int i = 0; chromas[i] != 0; i++) { const vlc_fourcc_t vlc = chromas[i]; uint32_t sdl = 0; for (int j = 0; vlc_to_sdl[j].vlc != 0 && !sdl; j++) { if (vlc_to_sdl[j].vlc == vlc) sdl = vlc_to_sdl[j].sdl; } if (!sdl) continue; sys->overlay = SDL_CreateYUVOverlay(fmt.i_width, fmt.i_height, sdl, sys->display); if (sys->overlay && !sys->overlay->hw_overlay && pass == 0) { /* Ignore non hardware overlay surface in first pass */ SDL_FreeYUVOverlay(sys->overlay); sys->overlay = NULL; } if (sys->overlay) { /* We keep the surface locked forever */ SDL_LockYUVOverlay(sys->overlay); fmt.i_chroma = vlc; sys->is_uv_swapped = vlc_fourcc_AreUVPlanesSwapped(fmt.i_chroma, vd->fmt.i_chroma); if (sys->is_uv_swapped) fmt.i_chroma = vd->fmt.i_chroma; break; } } } } else { msg_Warn(vd, "SDL overlay disabled by the user"); } /* */ vout_display_cfg_t place_cfg = *vd->cfg; place_cfg.display.width = display_width; place_cfg.display.height = display_height; vout_display_PlacePicture(&sys->place, &vd->source, &place_cfg, !sys->overlay); /* If no overlay, fallback to software output */ if (!sys->overlay) { /* */ switch (sys->display->format->BitsPerPixel) { case 8: fmt.i_chroma = VLC_CODEC_RGB8; break; case 15: fmt.i_chroma = VLC_CODEC_RGB15; break; case 16: fmt.i_chroma = VLC_CODEC_RGB16; break; case 24: fmt.i_chroma = VLC_CODEC_RGB24; break; case 32: fmt.i_chroma = VLC_CODEC_RGB32; break; default: msg_Err(vd, "unknown screen depth %i", sys->display->format->BitsPerPixel); goto error; } /* All we have is an RGB image with square pixels */ fmt.i_width = display_width; fmt.i_height = display_height; fmt.i_rmask = sys->display->format->Rmask; fmt.i_gmask = sys->display->format->Gmask; fmt.i_bmask = sys->display->format->Bmask; info.has_pictures_invalid = true; } if (vd->cfg->display.title) SDL_WM_SetCaption(vd->cfg->display.title, vd->cfg->display.title); else if (!sys->overlay) SDL_WM_SetCaption(VOUT_TITLE " (software RGB SDL output)", VOUT_TITLE " (software RGB SDL output)"); else if (sys->overlay->hw_overlay) SDL_WM_SetCaption(VOUT_TITLE " (hardware YUV SDL output)", VOUT_TITLE " (hardware YUV SDL output)"); else SDL_WM_SetCaption(VOUT_TITLE " (software YUV SDL output)", VOUT_TITLE " (software YUV SDL output)"); /* Setup events */ SDL_EventState(SDL_KEYUP, SDL_IGNORE); /* ignore keys up */ /* Setup vout_display now that everything is fine */ vd->fmt = fmt; vd->info = info; vd->pool = Pool; vd->prepare = NULL; vd->display = PictureDisplay; vd->control = Control; vd->manage = Manage; /* */ vout_display_SendEventDisplaySize(vd, display_width, display_height); return VLC_SUCCESS; error: msg_Err(vd, "cannot set up SDL (%s)", SDL_GetError()); if (sys->display) { SDL_UnlockSurface(sys->display); SDL_FreeSurface(sys->display); } vlc_mutex_lock(&sdl_lock); SDL_QuitSubSystem(SDL_INIT_VIDEO); vlc_mutex_unlock(&sdl_lock); free(sys); return VLC_EGENERIC; }
static int Control(vout_display_t *vd, int query, va_list ap) { vout_display_sys_t *sys = vd->sys; switch (query) { case VOUT_DISPLAY_RESET_PICTURES: { const vout_display_cfg_t *cfg = va_arg(ap, const vout_display_cfg_t *); video_format_t *fmt = va_arg(ap, video_format_t *); vout_display_place_t place; video_format_t src; assert(sys->viewport == NULL); vout_display_PlacePicture(&place, &vd->source, cfg); video_format_ApplyRotation(&src, &vd->source); fmt->i_width = src.i_width * place.width / src.i_visible_width; fmt->i_height = src.i_height * place.height / src.i_visible_height; fmt->i_visible_width = place.width; fmt->i_visible_height = place.height; fmt->i_x_offset = src.i_x_offset * place.width / src.i_visible_width; fmt->i_y_offset = src.i_y_offset * place.height / src.i_visible_height; break; } case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED: case VOUT_DISPLAY_CHANGE_ZOOM: case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT: case VOUT_DISPLAY_CHANGE_SOURCE_CROP: { const vout_display_cfg_t *cfg = va_arg(ap, const vout_display_cfg_t *); sys->display_width = cfg->display.width; sys->display_height = cfg->display.height; if (sys->viewport != NULL) { video_format_t fmt; vout_display_place_t place; video_format_ApplyRotation(&fmt, &vd->source); vout_display_PlacePicture(&place, &vd->source, cfg); wp_viewport_set_source(sys->viewport, wl_fixed_from_int(fmt.i_x_offset), wl_fixed_from_int(fmt.i_y_offset), wl_fixed_from_int(fmt.i_visible_width), wl_fixed_from_int(fmt.i_visible_height)); wp_viewport_set_destination(sys->viewport, place.width, place.height); } else return VLC_EGENERIC; break; } default: msg_Err(vd, "unknown request %d", query); return VLC_EGENERIC; } return VLC_SUCCESS; }
static void PMThread( void *arg ) { vout_display_t *vd = ( vout_display_t * )arg; vout_display_sys_t * sys = vd->sys; ULONG i_frame_flags; QMSG qm; char *psz_mode; ULONG i_kva_mode; /* */ video_format_t fmt; video_format_ApplyRotation(&fmt, &vd->fmt); /* */ vout_display_info_t info = vd->info; info.is_slow = false; info.has_double_click = true; info.needs_hide_mouse = true; info.has_pictures_invalid = false; MorphToPM(); sys->hab = WinInitialize( 0 ); sys->hmq = WinCreateMsgQueue( sys->hab, 0); WinRegisterClass( sys->hab, WC_VLC_KVA, WndProc, CS_SIZEREDRAW | CS_MOVENOTIFY, sizeof( PVOID )); sys->b_fixt23 = var_CreateGetBool( vd, "kva-fixt23"); if( !sys->b_fixt23 ) /* If an external window was specified, we'll draw in it. */ sys->parent_window = vout_display_NewWindow( vd, VOUT_WINDOW_TYPE_HWND ); if( sys->parent_window ) { sys->parent = ( HWND )sys->parent_window->handle.hwnd; ULONG i_style = WinQueryWindowULong( sys->parent, QWL_STYLE ); WinSetWindowULong( sys->parent, QWL_STYLE, i_style | WS_CLIPCHILDREN ); i_frame_flags = FCF_TITLEBAR; } else { sys->parent = HWND_DESKTOP; i_frame_flags = FCF_SYSMENU | FCF_TITLEBAR | FCF_MINMAX | FCF_SIZEBORDER | FCF_TASKLIST; } sys->frame = WinCreateStdWindow( sys->parent, /* parent window handle */ WS_VISIBLE, /* frame window style */ &i_frame_flags, /* window style */ WC_VLC_KVA, /* class name */ "", /* window title */ 0L, /* default client style */ NULLHANDLE, /* resource in exe file */ 1, /* frame window id */ &sys->client ); /* client window handle */ if( sys->frame == NULLHANDLE ) { msg_Err( vd, "cannot create a frame window"); goto exit_frame; } WinSetWindowPtr( sys->client, 0, vd ); if( !sys->parent_window ) { WinSetWindowPtr( sys->frame, 0, vd ); sys->p_old_frame = WinSubclassWindow( sys->frame, MyFrameWndProc ); } psz_mode = var_CreateGetString( vd, "kva-video-mode" ); i_kva_mode = KVAM_AUTO; if( strcmp( psz_mode, "snap" ) == 0 ) i_kva_mode = KVAM_SNAP; else if( strcmp( psz_mode, "wo" ) == 0 ) i_kva_mode = KVAM_WO; else if( strcmp( psz_mode, "vman" ) == 0 ) i_kva_mode = KVAM_VMAN; else if( strcmp( psz_mode, "dive" ) == 0 ) i_kva_mode = KVAM_DIVE; free( psz_mode ); if( kvaInit( i_kva_mode, sys->client, COLOR_KEY )) { msg_Err( vd, "cannot initialize KVA"); goto exit_kva_init; } kvaCaps( &sys->kvac ); msg_Dbg( vd, "selected video mode = %s", psz_video_mode[ sys->kvac.ulMode - 1 ]); if( OpenDisplay( vd, &fmt ) ) { msg_Err( vd, "cannot open display"); goto exit_open_display; } if( vd->cfg->is_fullscreen && !sys->parent_window ) WinPostMsg( sys->client, WM_VLC_FULLSCREEN_CHANGE, MPFROMLONG( true ), 0 ); kvaDisableScreenSaver(); /* Setup vout_display now that everything is fine */ vd->fmt = fmt; vd->info = info; vd->pool = Pool; vd->prepare = NULL; vd->display = Display; vd->control = Control; vd->manage = Manage; /* Prevent SIG_FPE */ _control87(MCW_EM, MCW_EM); sys->i_result = VLC_SUCCESS; DosPostEventSem( sys->ack_event ); if( !sys->parent_window ) WinSetVisibleRegionNotify( sys->frame, TRUE ); while( WinGetMsg( sys->hab, &qm, NULLHANDLE, 0, 0 )) WinDispatchMsg( sys->hab, &qm ); if( !sys->parent_window ) WinSetVisibleRegionNotify( sys->frame, FALSE ); kvaEnableScreenSaver(); CloseDisplay( vd ); /* fall through */ exit_open_display : kvaDone(); exit_kva_init : if( !sys->parent_window ) WinSubclassWindow( sys->frame, sys->p_old_frame ); WinDestroyWindow( sys->frame ); exit_frame : vout_display_DeleteWindow( vd, sys->parent_window ); if( sys->is_mouse_hidden ) WinShowPointer( HWND_DESKTOP, TRUE ); WinDestroyMsgQueue( sys->hmq ); WinTerminate( sys->hab ); sys->i_result = VLC_EGENERIC; DosPostEventSem( sys->ack_event ); }