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; }
/** * Return a direct buffer */ static picture_pool_t *Pool (vout_display_t *vd, unsigned requested_count) { vout_display_sys_t *sys = vd->sys; (void)requested_count; if (sys->pool) return sys->pool; vout_display_place_t place; vout_display_PlacePicture (&place, &vd->source, vd->cfg, false); /* */ const uint32_t values[] = { place.x, place.y, place.width, place.height }; xcb_configure_window (sys->conn, sys->window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); picture_t *pic = picture_NewFromFormat (&vd->fmt); if (!pic) return NULL; assert (pic->i_planes == 1); picture_resource_t res = { .p = { [0] = { .i_lines = pic->p->i_lines, .i_pitch = pic->p->i_pitch, }, }, }; picture_Release (pic); unsigned count; picture_t *pic_array[MAX_PICTURES]; const size_t size = res.p->i_pitch * res.p->i_lines; for (count = 0; count < MAX_PICTURES; count++) { xcb_shm_seg_t seg = (sys->seg_base != 0) ? (sys->seg_base + count) : 0; if (XCB_picture_Alloc (vd, &res, size, sys->conn, seg)) break; pic_array[count] = XCB_picture_NewFromResource (&vd->fmt, &res, sys->conn); if (unlikely(pic_array[count] == NULL)) break; } xcb_flush (sys->conn); if (count == 0) return NULL; sys->pool = picture_pool_New (count, pic_array); if (unlikely(sys->pool == NULL)) while (count > 0) picture_Release(pic_array[--count]); return sys->pool; }
event_thread_t *EventThreadCreate( vout_display_t *vd) { /* Create the Vout EventThread, this thread is created by us to isolate * the Win32 PeekMessage function calls. We want to do this because * Windows can stay blocked inside this call for a long time, and when * this happens it thus blocks vlc's video_output thread. * Vout EventThread will take care of the creation of the video * window (because PeekMessage has to be called from the same thread which * created the window). */ msg_Dbg( vd, "creating Vout EventThread" ); event_thread_t *p_event = malloc( sizeof(*p_event) ); if( !p_event ) return NULL; p_event->vd = vd; vlc_mutex_init( &p_event->lock ); vlc_cond_init( &p_event->wait ); p_event->is_cursor_hidden = false; p_event->button_pressed = 0; p_event->psz_title = NULL; p_event->source = vd->source; vout_display_PlacePicture(&p_event->place, &vd->source, vd->cfg, false); _snprintf( p_event->class_main, sizeof(p_event->class_main)/sizeof(*p_event->class_main), _T("VLC MSW %p"), p_event ); _snprintf( p_event->class_video, sizeof(p_event->class_video)/sizeof(*p_event->class_video), _T("VLC MSW video %p"), p_event ); return p_event; }
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; } }
/** * Return a direct buffer */ static picture_pool_t *Pool (vout_display_t *vd, unsigned requested_count) { vout_display_sys_t *p_sys = vd->sys; (void)requested_count; if (!p_sys->pool) { vout_display_place_t place; vout_display_PlacePicture (&place, &vd->source, vd->cfg, false); /* */ const uint32_t values[] = { place.x, place.y, place.width, place.height }; xcb_configure_window (p_sys->conn, p_sys->window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); picture_t *pic = picture_NewFromFormat (&vd->fmt); if (!pic) return NULL; assert (pic->i_planes == 1); memset (p_sys->resource, 0, sizeof(p_sys->resource)); unsigned count; picture_t *pic_array[MAX_PICTURES]; for (count = 0; count < MAX_PICTURES; count++) { picture_resource_t *res = &p_sys->resource[count]; res->p->i_lines = pic->p->i_lines; res->p->i_pitch = pic->p->i_pitch; if (PictureResourceAlloc (vd, res, res->p->i_pitch * res->p->i_lines, p_sys->conn, p_sys->shm)) break; pic_array[count] = picture_NewFromResource (&vd->fmt, res); if (!pic_array[count]) { PictureResourceFree (res, p_sys->conn); memset (res, 0, sizeof(*res)); break; } } picture_Release (pic); if (count == 0) return NULL; p_sys->pool = picture_pool_New (count, pic_array); /* TODO release picture resources if NULL */ xcb_flush (p_sys->conn); } return p_sys->pool; }
/** * Move or resize overlay surface on video display. * * This function is used to move or resize an overlay surface on the screen. * Ususally the overlay is moved by the user and thus, by a move or resize * event. */ static int DirectXUpdateOverlay(vout_display_t *vd, LPDIRECTDRAWSURFACE2 surface) { vout_display_sys_t *sys = vd->sys; RECT src = sys->rect_src_clipped; RECT dst = sys->rect_dest_clipped; if (sys->use_wallpaper) { src.left = vd->source.i_x_offset; src.top = vd->source.i_y_offset; src.right = vd->source.i_x_offset + vd->source.i_visible_width; src.bottom = vd->source.i_y_offset + vd->source.i_visible_height; AlignRect(&src, sys->i_align_src_boundary, sys->i_align_src_size); vout_display_cfg_t cfg = *vd->cfg; cfg.display.width = sys->rect_display.right; cfg.display.height = sys->rect_display.bottom; vout_display_place_t place; vout_display_PlacePicture(&place, &vd->source, &cfg, true); dst.left = sys->rect_display.left + place.x; dst.top = sys->rect_display.top + place.y; dst.right = dst.left + place.width; dst.bottom = dst.top + place.height; AlignRect(&dst, sys->i_align_dest_boundary, sys->i_align_dest_size); } if (!surface) { if (!sys->pool) return VLC_EGENERIC; surface = sys->resource.p_sys->front_surface; } /* The new window dimensions should already have been computed by the * caller of this function */ /* Position and show the overlay */ DDOVERLAYFX ddofx; ZeroMemory(&ddofx, sizeof(ddofx)); ddofx.dwSize = sizeof(ddofx); ddofx.dckDestColorkey.dwColorSpaceLowValue = sys->i_colorkey; ddofx.dckDestColorkey.dwColorSpaceHighValue = sys->i_colorkey; HRESULT hr = IDirectDrawSurface2_UpdateOverlay(surface, &src, sys->display, &dst, DDOVER_SHOW | DDOVER_KEYDESTOVERRIDE, &ddofx); sys->restore_overlay = hr != DD_OK; if (hr != DD_OK) { msg_Warn(vd, "DirectDrawUpdateOverlay cannot move/resize overlay"); return VLC_EGENERIC; } return VLC_SUCCESS; }
static void HandleMotionNotify (vout_display_t *vd, xcb_motion_notify_event_t *ev) { vout_display_place_t place; /* TODO it could be saved */ vout_display_PlacePicture (&place, &vd->source, vd->cfg, false); if (place.width <= 0 || place.height <= 0) return; const int x = vd->source.i_x_offset + (int64_t)(ev->event_x -0*place.x) * vd->source.i_visible_width / place.width; const int y = vd->source.i_y_offset + (int64_t)(ev->event_y -0*place.y) * vd->source.i_visible_height/ place.height; /* TODO show the cursor ? */ if (x >= vd->source.i_x_offset && x < vd->source.i_x_offset + vd->source.i_visible_width && y >= vd->source.i_y_offset && y < vd->source.i_y_offset + vd->source.i_visible_height) vout_display_SendEventMouseMoved (vd, x, y); }
/***************************************************************************** * UpdateRects: update clipping rectangles ***************************************************************************** * This function is called when the window position or size are changed, and * its job is to update the source and destination RECTs used to display the * picture. *****************************************************************************/ void CommonPlacePicture(vlc_object_t *obj, display_win32_area_t *area, vout_display_sys_win32_t *sys) { /* Update the window position and size */ vout_display_cfg_t place_cfg = area->vdcfg; #if (defined(MODULE_NAME_IS_glwin32)) /* Reverse vertical alignment as the GL tex are Y inverted */ if (place_cfg.align.vertical == VLC_VIDEO_ALIGN_TOP) place_cfg.align.vertical = VLC_VIDEO_ALIGN_BOTTOM; else if (place_cfg.align.vertical == VLC_VIDEO_ALIGN_BOTTOM) place_cfg.align.vertical = VLC_VIDEO_ALIGN_TOP; #endif vout_display_place_t before_place = area->place; vout_display_PlacePicture(&area->place, &area->texture_source, &place_cfg); /* Signal the change in size/position */ if (!vout_display_PlaceEquals(&before_place, &area->place)) { area->place_changed |= true; #ifndef NDEBUG msg_Dbg(obj, "UpdateRects source offset: %i,%i visible: %ix%i decoded: %ix%i", area->texture_source.i_x_offset, area->texture_source.i_y_offset, area->texture_source.i_visible_width, area->texture_source.i_visible_height, area->texture_source.i_width, area->texture_source.i_height); msg_Dbg(obj, "UpdateRects image_dst coords: %i,%i %ix%i", area->place.x, area->place.y, area->place.width, area->place.height); #endif #if !VLC_WINSTORE_APP if (sys->event != NULL) { CommonChangeThumbnailClip(obj, sys, true); } #endif } }
/** * Compute the place in canvas unit. */ static void Place(vout_display_t *vd, vout_display_place_t *place) { vout_display_sys_t *sys = vd->sys; vout_display_PlacePicture(place, &vd->source, vd->cfg, false); const int canvas_width = cucul_get_canvas_width(sys->cv); const int canvas_height = cucul_get_canvas_height(sys->cv); const int display_width = caca_get_display_width(sys->dp); const int display_height = caca_get_display_height(sys->dp); if (display_width > 0 && display_height > 0) { place->x = place->x * canvas_width / display_width; place->y = place->y * canvas_height / display_height; place->width = (place->width * canvas_width + display_width/2) / display_width; place->height = (place->height * canvas_height + display_height/2) / display_height; } else { place->x = 0; place->y = 0; place->width = canvas_width; place->height = display_height; } }
/** * Control for vout display */ 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: SDL_ShowCursor(0); return VLC_SUCCESS; case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: { const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t *); /* */ sys->display = SDL_SetVideoMode(cfg->display.width, cfg->display.height, sys->display_bpp, sys->display_flags); if (!sys->display) { sys->display = SDL_SetVideoMode(vd->cfg->display.width, vd->cfg->display.height, sys->display_bpp, sys->display_flags); return VLC_EGENERIC; } if (sys->overlay) vout_display_PlacePicture(&sys->place, &vd->source, cfg, !sys->overlay); else vout_display_SendEventPicturesInvalid(vd); return VLC_SUCCESS; } case VOUT_DISPLAY_CHANGE_FULLSCREEN: { vout_display_cfg_t cfg = *va_arg(args, const vout_display_cfg_t *); /* Fix flags */ sys->display_flags &= ~(SDL_FULLSCREEN | SDL_RESIZABLE); sys->display_flags |= cfg.is_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE; if (cfg.is_fullscreen) { cfg.display.width = sys->desktop_width; cfg.display.height = sys->desktop_height; } if (sys->overlay) { sys->display = SDL_SetVideoMode(cfg.display.width, cfg.display.height, sys->display_bpp, sys->display_flags); vout_display_PlacePicture(&sys->place, &vd->source, &cfg, !sys->overlay); } vout_display_SendEventDisplaySize(vd, cfg.display.width, cfg.display.height, cfg.is_fullscreen); return VLC_SUCCESS; } case VOUT_DISPLAY_CHANGE_ZOOM: case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED: case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT: { const vout_display_cfg_t *cfg; const video_format_t *source; if (query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT) { source = va_arg(args, const video_format_t *); cfg = vd->cfg; } else { source = &vd->source; cfg = va_arg(args, const vout_display_cfg_t *); } if (sys->overlay) { sys->display = SDL_SetVideoMode(cfg->display.width, cfg->display.height, sys->display_bpp, sys->display_flags); vout_display_PlacePicture(&sys->place, source, cfg, !sys->overlay); } else { vout_display_SendEventPicturesInvalid(vd); } 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; /* 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; } #ifdef HAVE_SETENV char *psz_driver = var_CreateGetNonEmptyString(vd, "sdl-video-driver"); if (psz_driver) { setenv("SDL_VIDEODRIVER", psz_driver, 1); free(psz_driver); } #endif /* */ int sdl_flags = SDL_INIT_VIDEO; #ifndef WIN32 /* Win32 SDL implementation doesn't support SDL_INIT_EVENTTHREAD yet*/ sdl_flags |= SDL_INIT_EVENTTHREAD; #endif #ifndef NDEBUG /* In debug mode you may want vlc to dump a core instead of staying stuck */ sdl_flags |= SDL_INIT_NOPARACHUTE; #endif /* 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 = vd->fmt; /* */ vout_display_info_t info = vd->info; /* 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_CreateGetNonEmptyString(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_CreateGetBool(vd, "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->get = Get; vd->prepare = NULL; vd->display = Display; vd->control = Control; vd->manage = Manage; /* */ vout_display_SendEventDisplaySize(vd, display_width, display_height, vd->cfg->is_fullscreen); 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; }
/** * ProjectM update thread which do the rendering * @param p_this: the p_thread object */ static void *Thread( void *p_data ) { filter_t *p_filter = (filter_t*)p_data; filter_sys_t *p_sys = p_filter->p_sys; video_format_t fmt; vlc_gl_t *gl; unsigned int i_last_width = 0; unsigned int i_last_height = 0; locale_t loc; locale_t oldloc; projectM *p_projectm; #ifndef HAVE_PROJECTM2 char *psz_config; #else char *psz_preset_path; char *psz_title_font; char *psz_menu_font; projectM::Settings settings; #endif vlc_savecancel(); /* Create the openGL provider */ p_sys->p_vout = (vout_thread_t *)vlc_object_create( p_filter, sizeof(vout_thread_t) ); if( !p_sys->p_vout ) goto error; /* */ video_format_Init( &fmt, 0 ); video_format_Setup( &fmt, VLC_CODEC_RGB32, p_sys->i_width, p_sys->i_height, 0, 1 ); fmt.i_sar_num = 1; fmt.i_sar_den = 1; vout_display_state_t state; memset( &state, 0, sizeof(state) ); state.cfg.display.sar.num = 1; state.cfg.display.sar.den = 1; state.cfg.is_display_filled = true; state.cfg.zoom.num = 1; state.cfg.zoom.den = 1; state.sar.num = 1; state.sar.den = 1; p_sys->p_vd = vout_NewDisplay( p_sys->p_vout, &fmt, &state, "opengl", 300000, 1000000 ); if( !p_sys->p_vd ) { vlc_object_release( p_sys->p_vout ); goto error; } var_Create( p_sys->p_vout, "fullscreen", VLC_VAR_BOOL ); var_AddCallback( p_sys->p_vout, "fullscreen", VoutCallback, p_sys->p_vd ); gl = vout_GetDisplayOpengl( p_sys->p_vd ); if( !gl ) { vout_DeleteDisplay( p_sys->p_vd, NULL ); vlc_object_release( p_sys->p_vout ); goto error; } /* Work-around the projectM locale bug */ loc = newlocale (LC_NUMERIC_MASK, "C", NULL); oldloc = uselocale (loc); /* Create the projectM object */ #ifndef HAVE_PROJECTM2 psz_config = var_InheritString( p_filter, "projectm-config" ); p_projectm = new projectM( psz_config ); free( psz_config ); #else psz_preset_path = var_InheritString( p_filter, "projectm-preset-path" ); #ifdef WIN32 if ( psz_preset_path == NULL ) { char *psz_data_path = config_GetDataDir( p_filter ); asprintf( &psz_preset_path, "%s" DIR_SEP "visualization", psz_data_path ); free( psz_data_path ); } #endif psz_title_font = var_InheritString( p_filter, "projectm-title-font" ); psz_menu_font = var_InheritString( p_filter, "projectm-menu-font" ); settings.meshX = var_InheritInteger( p_filter, "projectm-meshx" ); settings.meshY = var_InheritInteger( p_filter, "projectm-meshy" ); settings.fps = 35; settings.textureSize = var_InheritInteger( p_filter, "projectm-texture-size" ); settings.windowWidth = p_sys->i_width; settings.windowHeight = p_sys->i_height; settings.presetURL = psz_preset_path; settings.titleFontURL = psz_title_font; settings.menuFontURL = psz_menu_font; settings.smoothPresetDuration = 5; settings.presetDuration = 30; settings.beatSensitivity = 10; settings.aspectCorrection = 1; settings.easterEgg = 1; settings.shuffleEnabled = 1; p_projectm = new projectM( settings ); free( psz_menu_font ); free( psz_title_font ); free( psz_preset_path ); #endif /* HAVE_PROJECTM2 */ p_sys->i_buffer_size = p_projectm->pcm()->maxsamples; p_sys->p_buffer = (float*)calloc( p_sys->i_buffer_size, sizeof( float ) ); vlc_sem_post( &p_sys->ready ); /* Choose a preset randomly or projectM will always show the first one */ if ( p_projectm->getPlaylistSize() > 0 ) p_projectm->selectPreset( (unsigned)vlc_mrand48() % p_projectm->getPlaylistSize() ); /* */ for( ;; ) { const mtime_t i_deadline = mdate() + CLOCK_FREQ / 50; /* 50 fps max */ /* Manage the events */ vout_ManageDisplay( p_sys->p_vd, true ); if( p_sys->p_vd->cfg->display.width != i_last_width || p_sys->p_vd->cfg->display.height != i_last_height ) { /* FIXME it is not perfect as we will have black bands */ vout_display_place_t place; vout_display_PlacePicture( &place, &p_sys->p_vd->source, p_sys->p_vd->cfg, false ); p_projectm->projectM_resetGL( place.width, place.height ); i_last_width = p_sys->p_vd->cfg->display.width; i_last_height = p_sys->p_vd->cfg->display.height; } /* Render the image and swap the buffers */ vlc_mutex_lock( &p_sys->lock ); if( p_sys->i_nb_samples > 0 ) { p_projectm->pcm()->addPCMfloat( p_sys->p_buffer, p_sys->i_nb_samples ); p_sys->i_nb_samples = 0; } if( p_sys->b_quit ) { vlc_mutex_unlock( &p_sys->lock ); delete p_projectm; vout_DeleteDisplay( p_sys->p_vd, NULL ); vlc_object_release( p_sys->p_vout ); if (loc != (locale_t)0) { uselocale (oldloc); freelocale (loc); } return NULL; } vlc_mutex_unlock( &p_sys->lock ); p_projectm->renderFrame(); /* */ mwait( i_deadline ); if( !vlc_gl_Lock(gl) ) { vlc_gl_Swap( gl ); vlc_gl_Unlock( gl ); } } abort(); error: p_sys->b_error = true; vlc_sem_post( &p_sys->ready ); return NULL; }
static int configure_display(vout_display_t *vd, const vout_display_cfg_t *cfg, const video_format_t *fmt) { vout_display_sys_t *sys = vd->sys; vout_display_place_t place; MMAL_DISPLAYREGION_T display_region; MMAL_STATUS_T status; if (!cfg && !fmt) return -EINVAL; if (fmt) { sys->input->format->es->video.par.num = fmt->i_sar_num; sys->input->format->es->video.par.den = fmt->i_sar_den; status = mmal_port_format_commit(sys->input); if (status != MMAL_SUCCESS) { msg_Err(vd, "Failed to commit format for input port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); return -EINVAL; } } else { fmt = &vd->source; } if (!cfg) cfg = vd->cfg; vout_display_PlacePicture(&place, fmt, cfg, false); display_region.hdr.id = MMAL_PARAMETER_DISPLAYREGION; display_region.hdr.size = sizeof(MMAL_DISPLAYREGION_T); display_region.fullscreen = MMAL_FALSE; display_region.src_rect.x = fmt->i_x_offset; display_region.src_rect.y = fmt->i_y_offset; display_region.src_rect.width = fmt->i_visible_width; display_region.src_rect.height = fmt->i_visible_height; display_region.dest_rect.x = place.x; display_region.dest_rect.y = place.y; display_region.dest_rect.width = place.width; display_region.dest_rect.height = place.height; display_region.layer = sys->layer; display_region.set = MMAL_DISPLAY_SET_FULLSCREEN | MMAL_DISPLAY_SET_SRC_RECT | MMAL_DISPLAY_SET_DEST_RECT | MMAL_DISPLAY_SET_LAYER; status = mmal_port_parameter_set(sys->input, &display_region.hdr); if (status != MMAL_SUCCESS) { msg_Err(vd, "Failed to set display region (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); return -EINVAL; } show_background(vd, cfg->is_fullscreen); sys->adjust_refresh_rate = var_InheritBool(vd, MMAL_ADJUST_REFRESHRATE_NAME); sys->native_interlaced = var_InheritBool(vd, MMAL_NATIVE_INTERLACED); if (sys->adjust_refresh_rate) { adjust_refresh_rate(vd, fmt); set_latency_target(vd, true); } return 0; }
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; } }
/** * ProjectM update thread which do the rendering * @param p_this: the p_thread object */ static void *Thread( void *p_data ) { filter_t *p_filter = (filter_t*)p_data; filter_sys_t *p_sys = p_filter->p_sys; int cancel = vlc_savecancel(); video_format_t fmt; vout_opengl_t *gl; int i_last_width = 0; int i_last_height = 0; #ifdef HAVE_PROJECTM2 projectM::Settings settings; #endif /* Create the openGL provider */ p_sys->p_vout = (vout_thread_t *)vlc_object_create( p_filter, sizeof(vout_thread_t) ); if( !p_sys->p_vout ) goto error; vlc_object_attach( p_sys->p_vout, p_filter ); /* */ video_format_Init( &fmt, 0 ); video_format_Setup( &fmt, VLC_CODEC_RGB32, p_sys->i_width, p_sys->i_height, 0, 1 ); fmt.i_sar_num = 1; fmt.i_sar_den = 1; vout_display_state_t state; memset( &state, 0, sizeof(state) ); state.cfg.display.sar.num = 1; state.cfg.display.sar.den = 1; state.cfg.is_display_filled = true; state.cfg.zoom.num = 1; state.cfg.zoom.den = 1; state.sar.num = 1; state.sar.den = 1; p_sys->p_vd = vout_NewDisplay( p_sys->p_vout, &fmt, &state, "opengl", 300000, 1000000 ); if( !p_sys->p_vd ) { vlc_object_release( p_sys->p_vout ); goto error; } var_Create( p_sys->p_vout, "fullscreen", VLC_VAR_BOOL ); var_AddCallback( p_sys->p_vout, "fullscreen", VoutCallback, p_sys->p_vd ); gl = vout_GetDisplayOpengl( p_sys->p_vd ); if( !gl ) { vout_DeleteDisplay( p_sys->p_vd, NULL ); vlc_object_release( p_sys->p_vout ); goto error; } /* Create the projectM object */ #ifndef HAVE_PROJECTM2 p_sys->p_projectm = new projectM( p_sys->psz_config ); #else settings.meshX = 32; settings.meshY = 24; settings.fps = 35; settings.textureSize = 1024; settings.windowWidth = p_sys->i_width; settings.windowHeight = p_sys->i_height; settings.presetURL = p_sys->psz_preset_path; settings.titleFontURL = p_sys->psz_title_font; settings.menuFontURL = p_sys->psz_menu_font; settings.smoothPresetDuration = 5; settings.presetDuration = 30; settings.beatSensitivity = 10; settings.aspectCorrection = 1; settings.easterEgg = 1; settings.shuffleEnabled = 1; p_sys->p_projectm = new projectM( settings ); #endif p_sys->i_buffer_size = p_sys->p_projectm->pcm()->maxsamples; p_sys->p_buffer = (float*)calloc( p_sys->i_buffer_size, sizeof( float ) ); vlc_sem_post( &p_sys->ready ); /* TODO: Give to projectm the name of the input p_sys->p_projectm->projectM_setTitle( "" ); */ /* */ for( ;; ) { const mtime_t i_deadline = mdate() + CLOCK_FREQ / 50; /* 50 fps max */ /* Manage the events */ vout_ManageDisplay( p_sys->p_vd, true ); if( p_sys->p_vd->cfg->display.width != i_last_width || p_sys->p_vd->cfg->display.height != i_last_height ) { /* FIXME it is not perfect as we will have black bands */ vout_display_place_t place; vout_display_PlacePicture( &place, &p_sys->p_vd->source, p_sys->p_vd->cfg, false ); p_sys->p_projectm->projectM_resetGL( place.width, place.height ); i_last_width = p_sys->p_vd->cfg->display.width; i_last_height = p_sys->p_vd->cfg->display.height; } /* Render the image and swap the buffers */ vlc_mutex_lock( &p_sys->lock ); if( p_sys->i_nb_samples > 0 ) { p_sys->p_projectm->pcm()->addPCMfloat( p_sys->p_buffer, p_sys->i_nb_samples ); p_sys->i_nb_samples = 0; } if( p_sys->b_quit ) { vlc_mutex_unlock( &p_sys->lock ); delete p_sys->p_projectm; vout_DeleteDisplay( p_sys->p_vd, NULL ); vlc_object_release( p_sys->p_vout ); return NULL; } vlc_mutex_unlock( &p_sys->lock ); p_sys->p_projectm->renderFrame(); /* */ mwait( i_deadline ); if( !vout_opengl_Lock(gl) ) { vout_opengl_Swap( gl ); vout_opengl_Unlock( gl ); } } abort(); error: p_sys->b_error = true; vlc_sem_post( &p_sys->ready ); return NULL; }
static int Control (vout_display_t *vd, int query, va_list ap) { vout_display_sys_t *p_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 (p_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 && vout_window_SetSize (p_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 (p_sys->conn, p_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 (p_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); vd->fmt.i_width = vd->source.i_width * place.width / vd->source.i_visible_width; vd->fmt.i_height = vd->source.i_height * place.height / vd->source.i_visible_height; vd->fmt.i_visible_width = place.width; vd->fmt.i_visible_height = place.height; vd->fmt.i_x_offset = vd->source.i_x_offset * place.width / vd->source.i_visible_width; vd->fmt.i_y_offset = vd->source.i_y_offset * place.height / vd->source.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 (p_sys->conn, p_sys->embed->handle.xid, XCB_CW_CURSOR, &(uint32_t){ p_sys->cursor }); xcb_flush (p_sys->conn); return VLC_SUCCESS; default: msg_Err (vd, "Unknown request in XCB vout display"); 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 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); vd->fmt.i_width = vd->source.i_width * place.width / vd->source.i_visible_width; vd->fmt.i_height = vd->source.i_height * place.height / vd->source.i_visible_height; vd->fmt.i_visible_width = place.width; vd->fmt.i_visible_height = place.height; vd->fmt.i_x_offset = vd->source.i_x_offset * place.width / vd->source.i_visible_width; vd->fmt.i_y_offset = vd->source.i_y_offset * place.height / vd->source.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 Control (vout_display_t *vd, int query, va_list ap) { vout_display_sys_t *sys = vd->sys; switch (query) { case VOUT_DISPLAY_HIDE_MOUSE: /* FIXME TODO */ break; #ifndef NDEBUG case VOUT_DISPLAY_RESET_PICTURES: // not needed assert(0); #endif case VOUT_DISPLAY_CHANGE_FULLSCREEN: { const vout_display_cfg_t *cfg = va_arg (ap, const vout_display_cfg_t *); return vout_window_SetFullScreen (sys->window, cfg->is_fullscreen); } case VOUT_DISPLAY_CHANGE_WINDOW_STATE: { unsigned state = va_arg (ap, unsigned); return vout_window_SetState (sys->window, state); } case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED: case VOUT_DISPLAY_CHANGE_ZOOM: { const vout_display_cfg_t *cfg = va_arg (ap, const vout_display_cfg_t *); const video_format_t *src = &vd->source; if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE) { bool force = false; force = va_arg (ap, int); if (force && (cfg->display.width != vd->cfg->display.width || cfg->display.height != vd->cfg->display.height) && vout_window_SetSize (sys->window, cfg->display.width, cfg->display.height)) return VLC_EGENERIC; } vout_display_place_t place; vout_display_PlacePicture (&place, src, cfg, false); glViewport (0, 0, place.width, place.height); return VLC_SUCCESS; } case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT: case VOUT_DISPLAY_CHANGE_SOURCE_CROP: { const vout_display_cfg_t *cfg = vd->cfg; const video_format_t *src = va_arg (ap, const video_format_t *); vout_display_place_t place; vout_display_PlacePicture (&place, src, cfg, false); glViewport (0, 0, place.width, place.height); return VLC_SUCCESS; } case VOUT_DISPLAY_GET_OPENGL: { vlc_gl_t **pgl = va_arg (ap, vlc_gl_t **); *pgl = sys->gl; return VLC_SUCCESS; } default: msg_Err (vd, "Unknown request %d", query); }
/***************************************************************************** * UpdateRects: update clipping rectangles ***************************************************************************** * This function is called when the window position or size are changed, and * its job is to update the source and destination RECTs used to display the * picture. *****************************************************************************/ void UpdateRects(vout_display_t *vd, const vout_display_cfg_t *cfg, const video_format_t *source, bool is_forced) { vout_display_sys_t *sys = vd->sys; #define rect_src sys->rect_src #define rect_src_clipped sys->rect_src_clipped #define rect_dest sys->rect_dest #define rect_dest_clipped sys->rect_dest_clipped RECT rect; POINT point; /* */ if (!cfg) cfg = vd->cfg; if (!source) source = &vd->source; /* Retrieve the window size */ GetClientRect(sys->hwnd, &rect); /* Retrieve the window position */ point.x = point.y = 0; ClientToScreen(sys->hwnd, &point); /* If nothing changed, we can return */ bool has_moved; bool is_resized; EventThreadUpdateWindowPosition(sys->event, &has_moved, &is_resized, point.x, point.y, rect.right, rect.bottom); if (is_resized) vout_display_SendEventDisplaySize(vd, rect.right, rect.bottom, cfg->is_fullscreen); if (!is_forced && !has_moved && !is_resized ) return; /* Update the window position and size */ vout_display_cfg_t place_cfg = *cfg; place_cfg.display.width = rect.right; place_cfg.display.height = rect.bottom; vout_display_place_t place; vout_display_PlacePicture(&place, source, &place_cfg, false); EventThreadUpdateSourceAndPlace(sys->event, source, &place); if (sys->hvideownd) SetWindowPos(sys->hvideownd, 0, place.x, place.y, place.width, place.height, SWP_NOCOPYBITS|SWP_NOZORDER|SWP_ASYNCWINDOWPOS); /* Destination image position and dimensions */ #if defined(MODULE_NAME_IS_direct3d) || defined(MODULE_NAME_IS_direct2d) rect_dest.left = 0; rect_dest.right = place.width; rect_dest.top = 0; rect_dest.bottom = place.height; #else rect_dest.left = point.x + place.x; rect_dest.right = rect_dest.left + place.width; rect_dest.top = point.y + place.y; rect_dest.bottom = rect_dest.top + place.height; #ifdef MODULE_NAME_IS_directdraw /* Apply overlay hardware constraints */ if (sys->use_overlay) AlignRect(&rect_dest, sys->i_align_dest_boundary, sys->i_align_dest_size); #endif #endif #if defined(MODULE_NAME_IS_directdraw) /* UpdateOverlay directdraw function doesn't automatically clip to the * display size so we need to do it otherwise it will fail */ /* Clip the destination window */ if (!IntersectRect(&rect_dest_clipped, &rect_dest, &sys->rect_display)) { SetRectEmpty(&rect_src_clipped); goto exit; } #ifndef NDEBUG msg_Dbg(vd, "DirectXUpdateRects image_dst_clipped coords:" " %li,%li,%li,%li", rect_dest_clipped.left, rect_dest_clipped.top, rect_dest_clipped.right, rect_dest_clipped.bottom); #endif #else /* AFAIK, there are no clipping constraints in Direct3D, OpenGL and GDI */ rect_dest_clipped = rect_dest; #endif /* the 2 following lines are to fix a bug when clicking on the desktop */ if ((rect_dest_clipped.right - rect_dest_clipped.left) == 0 || (rect_dest_clipped.bottom - rect_dest_clipped.top) == 0) { SetRectEmpty(&rect_src_clipped); goto exit; } /* src image dimensions */ rect_src.left = 0; rect_src.top = 0; rect_src.right = source->i_width; rect_src.bottom = source->i_height; /* Clip the source image */ rect_src_clipped.left = source->i_x_offset + (rect_dest_clipped.left - rect_dest.left) * source->i_visible_width / (rect_dest.right - rect_dest.left); rect_src_clipped.right = source->i_x_offset + source->i_visible_width - (rect_dest.right - rect_dest_clipped.right) * source->i_visible_width / (rect_dest.right - rect_dest.left); rect_src_clipped.top = source->i_y_offset + (rect_dest_clipped.top - rect_dest.top) * source->i_visible_height / (rect_dest.bottom - rect_dest.top); rect_src_clipped.bottom = source->i_y_offset + source->i_visible_height - (rect_dest.bottom - rect_dest_clipped.bottom) * source->i_visible_height / (rect_dest.bottom - rect_dest.top); #ifdef MODULE_NAME_IS_directdraw /* Apply overlay hardware constraints */ if (sys->use_overlay) AlignRect(&rect_src_clipped, sys->i_align_src_boundary, sys->i_align_src_size); #elif defined(MODULE_NAME_IS_direct3d) || defined(MODULE_NAME_IS_direct2d) /* Needed at least with YUV content */ rect_src_clipped.left &= ~1; rect_src_clipped.right &= ~1; rect_src_clipped.top &= ~1; rect_src_clipped.bottom &= ~1; #endif #ifndef NDEBUG msg_Dbg(vd, "DirectXUpdateRects image_src_clipped" " coords: %li,%li,%li,%li", rect_src_clipped.left, rect_src_clipped.top, rect_src_clipped.right, rect_src_clipped.bottom); #endif #ifdef MODULE_NAME_IS_directdraw /* The destination coordinates need to be relative to the current * directdraw primary surface (display) */ rect_dest_clipped.left -= sys->rect_display.left; rect_dest_clipped.right -= sys->rect_display.left; rect_dest_clipped.top -= sys->rect_display.top; rect_dest_clipped.bottom -= sys->rect_display.top; #endif CommonChangeThumbnailClip(vd, true); exit: /* Signal the change in size/position */ sys->changes |= DX_POSITION_CHANGE; #undef rect_src #undef rect_src_clipped #undef rect_dest #undef rect_dest_clipped }
static int Open(vlc_object_t *object) { vout_display_t *vd = (vout_display_t *)object; vout_display_sys_t *sys; uint32_t buffer_pitch, buffer_height; vout_display_place_t place; MMAL_DISPLAYREGION_T display_region; uint32_t offsets[3]; MMAL_STATUS_T status; int ret = VLC_SUCCESS; unsigned i; if (vout_display_IsWindowed(vd)) return VLC_EGENERIC; sys = calloc(1, sizeof(struct vout_display_sys_t)); if (!sys) return VLC_ENOMEM; vd->sys = sys; sys->layer = var_InheritInteger(vd, MMAL_LAYER_NAME); bcm_host_init(); vd->info.has_hide_mouse = true; sys->opaque = vd->fmt.i_chroma == VLC_CODEC_MMAL_OPAQUE; status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &sys->component); if (status != MMAL_SUCCESS) { msg_Err(vd, "Failed to create MMAL component %s (status=%"PRIx32" %s)", MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->component->control->userdata = (struct MMAL_PORT_USERDATA_T *)vd; status = mmal_port_enable(sys->component->control, control_port_cb); if (status != MMAL_SUCCESS) { msg_Err(vd, "Failed to enable control port %s (status=%"PRIx32" %s)", sys->component->control->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->input = sys->component->input[0]; sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)vd; if (sys->opaque) { sys->input->format->encoding = MMAL_ENCODING_OPAQUE; sys->i_planes = 1; sys->buffer_size = sys->input->buffer_size_recommended; } else { sys->input->format->encoding = MMAL_ENCODING_I420; vd->fmt.i_chroma = VLC_CODEC_I420; buffer_pitch = align(vd->fmt.i_width, 32); buffer_height = align(vd->fmt.i_height, 16); sys->i_planes = 3; sys->buffer_size = 3 * buffer_pitch * buffer_height / 2; } sys->input->format->es->video.width = vd->fmt.i_width; sys->input->format->es->video.height = vd->fmt.i_height; sys->input->format->es->video.crop.x = 0; sys->input->format->es->video.crop.y = 0; sys->input->format->es->video.crop.width = vd->fmt.i_width; sys->input->format->es->video.crop.height = vd->fmt.i_height; sys->input->format->es->video.par.num = vd->source.i_sar_num; sys->input->format->es->video.par.den = vd->source.i_sar_den; status = mmal_port_format_commit(sys->input); if (status != MMAL_SUCCESS) { msg_Err(vd, "Failed to commit format for input port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->input->buffer_size = sys->input->buffer_size_recommended; vout_display_PlacePicture(&place, &vd->source, vd->cfg, false); display_region.hdr.id = MMAL_PARAMETER_DISPLAYREGION; display_region.hdr.size = sizeof(MMAL_DISPLAYREGION_T); display_region.fullscreen = MMAL_FALSE; display_region.src_rect.x = vd->fmt.i_x_offset; display_region.src_rect.y = vd->fmt.i_y_offset; display_region.src_rect.width = vd->fmt.i_visible_width; display_region.src_rect.height = vd->fmt.i_visible_height; display_region.dest_rect.x = place.x; display_region.dest_rect.y = place.y; display_region.dest_rect.width = place.width; display_region.dest_rect.height = place.height; display_region.layer = sys->layer; display_region.set = MMAL_DISPLAY_SET_FULLSCREEN | MMAL_DISPLAY_SET_SRC_RECT | MMAL_DISPLAY_SET_DEST_RECT | MMAL_DISPLAY_SET_LAYER; status = mmal_port_parameter_set(sys->input, &display_region.hdr); if (status != MMAL_SUCCESS) { msg_Err(vd, "Failed to set display region (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } offsets[0] = 0; for (i = 0; i < sys->i_planes; ++i) { sys->planes[i].i_lines = buffer_height; sys->planes[i].i_pitch = buffer_pitch; sys->planes[i].i_visible_lines = vd->fmt.i_visible_height; sys->planes[i].i_visible_pitch = vd->fmt.i_visible_width; if (i > 0) { offsets[i] = offsets[i - 1] + sys->planes[i - 1].i_pitch * sys->planes[i - 1].i_lines; sys->planes[i].i_lines /= 2; sys->planes[i].i_pitch /= 2; sys->planes[i].i_visible_lines /= 2; sys->planes[i].i_visible_pitch /= 2; } sys->planes[i].p_pixels = (uint8_t *)offsets[i]; } vlc_mutex_init(&sys->buffer_mutex); vlc_cond_init(&sys->buffer_cond); vlc_mutex_init(&sys->manage_mutex); vd->pool = vd_pool; vd->prepare = vd_prepare; vd->display = vd_display; vd->control = vd_control; vd->manage = vd_manage; vc_tv_register_callback(tvservice_cb, vd); if (query_resolution(vd, &sys->display_width, &sys->display_height) >= 0) { vout_display_SendEventDisplaySize(vd, sys->display_width, sys->display_height); } else { sys->display_width = vd->cfg->display.width; sys->display_height = vd->cfg->display.height; } sys->dmx_handle = vc_dispmanx_display_open(0); vd->info.subpicture_chromas = subpicture_chromas; out: if (ret != VLC_SUCCESS) Close(object); return ret; }
static void CreateBuffers(vout_display_t *vd, const vout_display_cfg_t *cfg) { const video_format_t *fmt = &vd->source; vout_display_sys_t *sys = vd->sys; xcb_connection_t *conn = sys->conn; xcb_create_pixmap(conn, 32, sys->drawable.crop, sys->root, fmt->i_visible_width, fmt->i_visible_height); xcb_create_pixmap(conn, 32, sys->drawable.scale, sys->root, cfg->display.width, cfg->display.height); xcb_render_create_picture(conn, sys->picture.crop, sys->drawable.crop, sys->format.argb, 0, NULL); xcb_render_create_picture(conn, sys->picture.scale, sys->drawable.scale, sys->format.argb, 0, NULL); vout_display_place_t *place = &sys->place; vout_display_PlacePicture(place, fmt, cfg); /* Homogeneous coordinates transform from destination(place) * to source(fmt) */ int32_t ax = place->height; /* multiply x instead of dividing y */ int32_t ay = place->width; /* multiply y instead of dividing x */ int32_t bx = 0; int32_t by = 0; switch (fmt->orientation) { case ORIENT_TOP_LEFT: case ORIENT_LEFT_TOP: break; case ORIENT_TOP_RIGHT: case ORIENT_RIGHT_TOP: ax *= -1; bx -= place->width; break; case ORIENT_BOTTOM_LEFT: case ORIENT_LEFT_BOTTOM: ay *= -1; by -= place->height; break; case ORIENT_BOTTOM_RIGHT: case ORIENT_RIGHT_BOTTOM: ax *= -1; ay *= -1; bx -= place->width; by -= place->height; break; } sys->src_x = bx; sys->src_y = by; xcb_render_transform_t transform = { 0, 0, 0, 0, 0, 0, /* Multiply z by width and height to compensate for x and y above */ 0, 0, place->width * place->height, }; if (ORIENT_IS_SWAP(fmt->orientation)) { transform.matrix12 = ay * fmt->i_visible_width; transform.matrix21 = ax * fmt->i_visible_height; } else { transform.matrix11 = ax * fmt->i_visible_width; transform.matrix22 = ay * fmt->i_visible_height; } xcb_render_set_picture_transform(conn, sys->picture.crop, transform); if (likely(sys->filter != NULL)) xcb_render_set_picture_filter(conn, sys->picture.crop, strlen(sys->filter), sys->filter, 0, NULL); }
/** * VSXu update thread which do the rendering * @param p_this: the p_thread object */ static void *Thread( void *p_data ) { filter_t *p_filter = (filter_t*)p_data; filter_sys_t *p_sys = p_filter->p_sys; // our abstract manager holder vsx_manager_abs* manager = 0; // temp audio buffer for sending to vsxu through manager float f_sample_buf[512]; // vsxu logo intro vsx_logo_intro* intro = 0; vout_display_t *p_vd; video_format_t fmt; vlc_gl_t *gl; unsigned int i_last_width = 0; unsigned int i_last_height = 0; bool first = true; bool run = true; /* Create the openGL provider */ vout_thread_t *p_vout; p_vout = (vout_thread_t *)vlc_object_create( p_filter, sizeof(vout_thread_t) ); if( !p_vout ) goto error; video_format_Init( &fmt, 0 ); video_format_Setup( &fmt, VLC_CODEC_RGB32, p_sys->i_width, p_sys->i_height, 0, 1 ); fmt.i_sar_num = 1; fmt.i_sar_den = 1; vout_display_state_t state; memset( &state, 0, sizeof(state) ); state.cfg.display.sar.num = 1; state.cfg.display.sar.den = 1; state.cfg.is_display_filled = true; state.cfg.zoom.num = 1; state.cfg.zoom.den = 1; state.sar.num = 1; state.sar.den = 1; p_vd = vout_NewDisplay( p_vout, &fmt, &state, "opengl", 300000, 1000000 ); if( !p_vd ) { vlc_object_release( p_vout ); goto error; } var_Create( p_vout, "fullscreen", VLC_VAR_BOOL ); var_AddCallback( p_vout, "fullscreen", VoutCallback, p_vd ); gl = vout_GetDisplayOpengl( p_vd ); if( !gl ) { var_DelCallback( p_vout, "fullscreen", VoutCallback, p_vd ); vout_DeleteDisplay( p_vd, NULL ); vlc_object_release( p_vout ); goto error; } // tell main thread we are ready vlc_sem_post( &p_sys->ready ); while ( run ) { /* Manage the events */ vout_ManageDisplay( p_vd, true ); if( p_vd->cfg->display.width != i_last_width || p_vd->cfg->display.height != i_last_height ) { /* FIXME it is not perfect as we will have black bands */ vout_display_place_t place; vout_display_PlacePicture( &place, &p_vd->source, p_vd->cfg, false ); i_last_width = p_vd->cfg->display.width; i_last_height = p_vd->cfg->display.height; } // look for control commands from outside the thread vlc_mutex_lock( &p_sys->lock ); if( p_sys->b_quit ) { run = false; } vlc_mutex_unlock( &p_sys->lock ); if (first) { // only run this once first = false; // create a new manager manager = manager_factory(); // init manager with the shared path and sound input type. manager->init( 0, "media_player" ); // only show logo once // keep track of iterations static int i_iterations = 0; if ( i_iterations++ < 1 ) { intro = new vsx_logo_intro(); intro->set_destroy_textures( false ); } } // lock cyclic buffer mutex and copy floats vlc_mutex_lock( &p_sys->cyclic_block_mutex ); block_holder* bh = p_sys->vsxu_cyclic_buffer->consume(); memcpy( &f_sample_buf[0], (void*)(&bh->data[0]), sizeof(float) * 512 ); vlc_mutex_unlock( &p_sys->cyclic_block_mutex ); // send sound pointer to vsxu manager->set_sound_wave( &f_sample_buf[0] ); // render vsxu engine if (manager) manager->render(); // render intro if (intro) intro->draw(); // swap buffers etc. if( !vlc_gl_Lock(gl) ) { vlc_gl_Swap( gl ); vlc_gl_Unlock( gl ); } } // stop vsxu nicely (unloads textures and frees memory) if (manager) manager->stop(); // call manager factory to destruct our manager object if (manager) manager_destroy( manager ); // delete the intro (if ever allocated) if (intro) delete intro; var_DelCallback( p_vout, "fullscreen", VoutCallback, p_vd ); // clean out vlc opengl stuff vout_DeleteDisplay( p_vd, NULL ); vlc_object_release( p_vout ); // clean up the cyclic buffer vlc_mutex_lock( &p_sys->cyclic_block_mutex ); p_sys->vsxu_cyclic_buffer->reset(); vlc_mutex_unlock( &p_sys->cyclic_block_mutex ); // die return NULL; error: p_sys->b_error = true; vlc_sem_post( &p_sys->ready ); return NULL; }
/** * Update thread which do the rendering * @param p_this: the p_thread object */ static void *Thread( void *p_data ) { filter_t *p_filter = (filter_t*)p_data; filter_sys_t *p_sys = p_filter->p_sys; video_format_t fmt; vlc_gl_t *gl; unsigned int i_last_width = 0; unsigned int i_last_height = 0; /* Create the openGL provider */ p_sys->p_vout = (vout_thread_t *)vlc_object_create(p_filter, sizeof(vout_thread_t)); if (!p_sys->p_vout) goto error; /* Configure the video format for the opengl provider. */ video_format_Init(&fmt, 0); video_format_Setup(&fmt, VLC_CODEC_RGB32, p_sys->i_width, p_sys->i_height, 0, 1 ); fmt.i_sar_num = 1; fmt.i_sar_den = 1; /* Init vout state. */ vout_display_state_t state; memset(&state, 0, sizeof(state)); state.cfg.display.sar.num = 1; state.cfg.display.sar.den = 1; state.cfg.is_display_filled = true; state.cfg.zoom.num = 1; state.cfg.zoom.den = 1; state.sar.num = 1; state.sar.den = 1; p_sys->p_vd = vout_NewDisplay(p_sys->p_vout, &fmt, &state, "opengl", 1000000, 1000000); if (!p_sys->p_vd) { vlc_object_release(p_sys->p_vout); goto error; } gl = vout_GetDisplayOpengl(p_sys->p_vd); if (!gl) { vout_DeleteDisplay(p_sys->p_vd, NULL); vlc_object_release(p_sys->p_vout); goto error; } vlc_sem_post(&p_sys->ready); initOpenGLScene(); float height[NB_BANDS] = {0}; while (1) { block_t *block = block_FifoGet(p_sys->fifo); int canc = vlc_savecancel(); /* Manage the events */ vout_ManageDisplay(p_sys->p_vd, true); if (p_sys->p_vd->cfg->display.width != i_last_width || p_sys->p_vd->cfg->display.height != i_last_height) { /* FIXME it is not perfect as we will have black bands */ vout_display_place_t place; vout_display_PlacePicture(&place, &p_sys->p_vd->source, p_sys->p_vd->cfg, false); i_last_width = p_sys->p_vd->cfg->display.width; i_last_height = p_sys->p_vd->cfg->display.height; } /* Horizontal scale for 20-band equalizer */ const unsigned xscale[] = {0,1,2,3,4,5,6,7,8,11,15,20,27, 36,47,62,82,107,141,184,255}; fft_state *p_state; /* internal FFT data */ unsigned i, j; float p_output[FFT_BUFFER_SIZE]; /* Raw FFT Result */ int16_t p_buffer1[FFT_BUFFER_SIZE]; /* Buffer on which we perform the FFT (first channel) */ int16_t p_dest[FFT_BUFFER_SIZE]; /* Adapted FFT result */ float *p_buffl = (float*)block->p_buffer; /* Original buffer */ int16_t *p_buffs; /* int16_t converted buffer */ int16_t *p_s16_buff; /* int16_t converted buffer */ /* Allocate the buffer only if the number of samples change */ if (block->i_nb_samples != p_sys->i_prev_nb_samples) { free(p_sys->p_prev_s16_buff); p_sys->p_prev_s16_buff = malloc(block->i_nb_samples * p_sys->i_channels * sizeof(int16_t)); if (!p_sys->p_prev_s16_buff) goto release; p_sys->i_prev_nb_samples = block->i_nb_samples; } p_buffs = p_s16_buff = p_sys->p_prev_s16_buff; /* Convert the buffer to int16_t Pasted from float32tos16.c */ for (i = block->i_nb_samples * p_sys->i_channels; i--;) { union {float f; int32_t i;} u; u.f = *p_buffl + 384.0; if (u.i > 0x43c07fff) *p_buffs = 32767; else if (u.i < 0x43bf8000) *p_buffs = -32768; else *p_buffs = u.i - 0x43c00000; p_buffl++; p_buffs++; } p_state = visual_fft_init(); if (!p_state) { msg_Err(p_filter,"unable to initialize FFT transform"); goto release; } p_buffs = p_s16_buff; for (i = 0 ; i < FFT_BUFFER_SIZE; i++) { p_output[i] = 0; p_buffer1[i] = *p_buffs; p_buffs += p_sys->i_channels; if (p_buffs >= &p_s16_buff[block->i_nb_samples * p_sys->i_channels]) p_buffs = p_s16_buff; } fft_perform (p_buffer1, p_output, p_state); for (i = 0; i< FFT_BUFFER_SIZE; ++i) p_dest[i] = p_output[i] * (2 ^ 16) / ((FFT_BUFFER_SIZE / 2 * 32768) ^ 2); for (i = 0 ; i < NB_BANDS; i++) { /* Decrease the previous size of the bar. */ height[i] -= BAR_DECREMENT; if (height[i] < 0) height[i] = 0; int y = 0; /* We search the maximum on one scale to determine the current size of the bar. */ for (j = xscale[i]; j < xscale[i + 1]; j++) { if (p_dest[j] > y) y = p_dest[j]; } /* Calculate the height of the bar */ float new_height = y != 0 ? log(y) * 0.4 : 0; height[i] = new_height > height[i] ? new_height : height[i]; } /* Determine the camera rotation angle. */ p_sys->f_rotationAngle += p_sys->f_rotationIncrement; if (p_sys->f_rotationAngle <= -ROTATION_MAX) p_sys->f_rotationIncrement = ROTATION_INCREMENT; else if (p_sys->f_rotationAngle >= ROTATION_MAX) p_sys->f_rotationIncrement = -ROTATION_INCREMENT; /* Render the frame. */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glRotatef(p_sys->f_rotationAngle, 0, 1, 0); drawBars(height); glPopMatrix(); /* Wait to swapp the frame on time. */ mwait(block->i_pts + (block->i_length / 2)); if (!vlc_gl_Lock(gl)) { vlc_gl_Swap(gl); vlc_gl_Unlock(gl); } release: block_Release(block); vlc_restorecancel(canc); } assert(0); error: p_sys->b_error = true; vlc_sem_post(&p_sys->ready); return NULL; }
/***************************************************************************** * 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; }