X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fvideo_output%2Fdisplay.c;h=600fedf846fdfd95e45144944ce378ce44956ad7;hb=12ade3e3bc975d5426ba4af155b7372c31093b31;hp=877efd0932a22557102a2fa47a3bae6048be2022;hpb=9744c6016f14b54985c220f3e71dfeff3b565d9a;p=vlc diff --git a/src/video_output/display.c b/src/video_output/display.c index 877efd0932..600fedf846 100644 --- a/src/video_output/display.c +++ b/src/video_output/display.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include @@ -58,7 +60,7 @@ static picture_t *VideoBufferNew(filter_t *filter) vd->fmt.i_width == fmt->i_width && vd->fmt.i_height == fmt->i_height); - picture_pool_t *pool = vout_display_Pool(vd, 1); + picture_pool_t *pool = vout_display_Pool(vd, 3); if (!pool) return NULL; return picture_pool_Get(pool); @@ -112,6 +114,7 @@ static vout_display_t *vout_display_New(vlc_object_t *obj, vd->info.has_double_click = false; vd->info.has_hide_mouse = false; vd->info.has_pictures_invalid = false; + vd->info.has_event_thread = false; vd->cfg = cfg; vd->pool = NULL; @@ -253,7 +256,7 @@ void vout_display_PlacePicture(vout_display_place_t *place, place->x = cfg->display.width - place->width; break; default: - place->x = (cfg->display.width - place->width) / 2; + place->x = ((int)cfg->display.width - (int)place->width) / 2; break; } @@ -265,7 +268,7 @@ void vout_display_PlacePicture(vout_display_place_t *place, place->y = cfg->display.height - place->height; break; default: - place->y = (cfg->display.height - place->height) / 2; + place->y = ((int)cfg->display.height - (int)place->height) / 2; break; } } @@ -284,8 +287,8 @@ struct vout_display_owner_sys_t { } sar_initial; /* */ - int width_saved; - int height_saved; + unsigned width_saved; + unsigned height_saved; struct { unsigned num; @@ -354,6 +357,13 @@ struct vout_display_owner_sys_t { bool display_is_fullscreen; bool display_is_forced; + int fit_window; + + struct { + vlc_thread_t thread; + block_fifo_t *fifo; + } event; + #ifdef ALLOW_DUMMY_VOUT vlc_mouse_t vout_mouse; #endif @@ -457,15 +467,12 @@ static void VoutDisplayEventMouse(vout_display_t *vd, int event, va_list args) case VOUT_DISPLAY_EVENT_MOUSE_MOVED: { const int x = (int)va_arg(args, int); const int y = (int)va_arg(args, int); - if (x != osys->mouse.state.i_x || y != osys->mouse.state.i_y) { - //msg_Dbg(vd, "VoutDisplayEvent 'mouse' @%d,%d", x, y); - m.i_x = x; - m.i_y = y; - m.b_double_click = false; - } else { - is_ignored = true; - } + //msg_Dbg(vd, "VoutDisplayEvent 'mouse' @%d,%d", x, y); + + m.i_x = x; + m.i_y = y; + m.b_double_click = false; break; } case VOUT_DISPLAY_EVENT_MOUSE_PRESSED: @@ -525,9 +532,6 @@ static void VoutDisplayEventMouse(vout_display_t *vd, int event, va_list args) if (!vd->info.has_hide_mouse) osys->mouse.last_moved = mdate(); - /* */ - vlc_mutex_unlock(&osys->lock); - /* */ vout_SendEventMouseVisible(osys->vout); #ifdef ALLOW_DUMMY_VOUT @@ -535,6 +539,47 @@ static void VoutDisplayEventMouse(vout_display_t *vd, int event, va_list args) #else vout_SendDisplayEventMouse(osys->vout, &m); #endif + vlc_mutex_unlock(&osys->lock); +} + +static void *VoutDisplayEventKeyDispatch(void *data) +{ + vout_display_owner_sys_t *osys = data; + + for (;;) { + block_t *event = block_FifoGet(osys->event.fifo); + + int cancel = vlc_savecancel(); + + int key; + memcpy(&key, event->p_buffer, sizeof(key)); + vout_SendEventKey(osys->vout, key); + block_Release(event); + + vlc_restorecancel(cancel); + } +} + +static void VoutDisplayEventKey(vout_display_t *vd, int key) +{ + vout_display_owner_sys_t *osys = vd->owner.sys; + + if (!osys->event.fifo) { + osys->event.fifo = block_FifoNew(); + if (!osys->event.fifo) + return; + if (vlc_clone(&osys->event.thread, VoutDisplayEventKeyDispatch, + osys, VLC_THREAD_PRIORITY_LOW)) { + block_FifoRelease(osys->event.fifo); + osys->event.fifo = NULL; + return; + } + } + block_t *event = block_Alloc(sizeof(key)); + if (event) { + memcpy(event->p_buffer, &key, sizeof(key)); + block_FifoPut(osys->event.fifo, event); + } } static void VoutDisplayEvent(vout_display_t *vd, int event, va_list args) @@ -550,7 +595,10 @@ static void VoutDisplayEvent(vout_display_t *vd, int event, va_list args) case VOUT_DISPLAY_EVENT_KEY: { const int key = (int)va_arg(args, int); msg_Dbg(vd, "VoutDisplayEvent 'key' 0x%2.2x", key); - vout_SendEventKey(osys->vout, key); + if (vd->info.has_event_thread) + vout_SendEventKey(osys->vout, key); + else + VoutDisplayEventKey(vd, key); break; } case VOUT_DISPLAY_EVENT_MOUSE_STATE: @@ -631,15 +679,88 @@ static vout_window_t *VoutDisplayNewWindow(vout_display_t *vd, const vout_window { vout_display_owner_sys_t *osys = vd->owner.sys; +#ifdef ALLOW_DUMMY_VOUT + if (!osys->vout->p) { + vout_window_cfg_t cfg_override = *cfg; + + if (!var_InheritBool(osys->vout, "embedded-video")) + cfg_override.is_standalone = true; + + return vout_window_New(VLC_OBJECT(osys->vout), NULL, &cfg_override); + } +#endif return vout_NewDisplayWindow(osys->vout, vd, cfg); } static void VoutDisplayDelWindow(vout_display_t *vd, vout_window_t *window) { vout_display_owner_sys_t *osys = vd->owner.sys; +#ifdef ALLOW_DUMMY_VOUT + if (!osys->vout->p) { + if( window) + vout_window_Delete(window); + return; + } +#endif vout_DeleteDisplayWindow(osys->vout, vd, window); } +static void VoutDisplayFitWindow(vout_display_t *vd, bool default_size) +{ + vout_display_owner_sys_t *osys = vd->owner.sys; + vout_display_cfg_t cfg = osys->cfg; + + if (!cfg.is_display_filled) + return; + + cfg.display.width = 0; + if (default_size) { + cfg.display.height = 0; + } else { + cfg.display.height = osys->height_saved; + cfg.zoom.num = 1; + cfg.zoom.den = 1; + } + + unsigned display_width; + unsigned display_height; + vout_display_GetDefaultDisplaySize(&display_width, &display_height, + &vd->source, &cfg); + + vlc_mutex_lock(&osys->lock); + + osys->ch_display_size = true; + osys->display_width = display_width; + osys->display_height = display_height; + osys->display_is_fullscreen = osys->cfg.is_fullscreen; + osys->display_is_forced = true; + + vlc_mutex_unlock(&osys->lock); +} + +static void VoutDisplayCropRatio(unsigned *x, unsigned *y, + unsigned *width, unsigned *height, + const video_format_t *source, + unsigned num, unsigned den) +{ + unsigned scaled_width = (uint64_t)source->i_visible_height * num * source->i_sar_den / den / source->i_sar_num; + unsigned scaled_height = (uint64_t)source->i_visible_width * den * source->i_sar_num / num / source->i_sar_den; + + if (scaled_width < source->i_visible_width) { + *x = (source->i_visible_width - scaled_width) / 2; + *y = 0; + *width = scaled_width; + *height = source->i_visible_height; + } else { + *x = 0; + *y = (source->i_visible_height - scaled_height) / 2; + *width = source->i_visible_width; + *height = scaled_height; + } + *x += source->i_x_offset; + *y += source->i_y_offset; +} + void vout_ManageDisplay(vout_display_t *vd, bool allow_reset_pictures) { vout_display_owner_sys_t *osys = vd->owner.sys; @@ -663,7 +784,7 @@ void vout_ManageDisplay(vout_display_t *vd, bool allow_reset_pictures) if (hide_mouse) { if (!vd->info.has_hide_mouse) { - msg_Dbg(vd, "auto hidding mouse"); + msg_Dbg(vd, "auto hiding mouse"); vout_display_Control(vd, VOUT_DISPLAY_HIDE_MOUSE); } vout_SendEventMouseHidden(osys->vout); @@ -706,8 +827,15 @@ void vout_ManageDisplay(vout_display_t *vd, bool allow_reset_pictures) !osys->ch_zoom && !ch_wm_state && !osys->ch_sar && - !osys->ch_crop) + !osys->ch_crop) { + + if (!osys->cfg.is_fullscreen && osys->fit_window != 0) { + VoutDisplayFitWindow(vd, osys->fit_window == -1); + osys->fit_window = 0; + continue; + } break; + } /* */ if (ch_fullscreen) { @@ -720,6 +848,8 @@ void vout_ManageDisplay(vout_display_t *vd, bool allow_reset_pictures) if (vout_display_Control(vd, VOUT_DISPLAY_CHANGE_FULLSCREEN, &cfg)) { msg_Err(vd, "Failed to set fullscreen"); is_fullscreen = osys->cfg.is_fullscreen; + } else if (!is_fullscreen) { + vout_display_Control(vd, VOUT_DISPLAY_CHANGE_DISPLAY_SIZE, &cfg, true); } osys->cfg.is_fullscreen = is_fullscreen; @@ -784,19 +914,8 @@ void vout_ManageDisplay(vout_display_t *vd, bool allow_reset_pictures) msg_Err(vd, "Failed to change zoom"); osys->zoom.num = osys->cfg.zoom.num; osys->zoom.den = osys->cfg.zoom.den; - } else if (cfg.is_display_filled) { - const int display_width = (int64_t)vd->source.i_width * osys->zoom.num / osys->zoom.den; - const int display_height = (int64_t)vd->source.i_height * osys->zoom.num / osys->zoom.den; - - vlc_mutex_lock(&osys->lock); - - osys->ch_display_size = true; - osys->display_width = display_width; - osys->display_height = display_height; - osys->display_is_fullscreen = osys->cfg.is_fullscreen; - osys->display_is_forced = true; - - vlc_mutex_unlock(&osys->lock); + } else { + osys->fit_window = -1; } osys->cfg.zoom.num = osys->zoom.num; @@ -836,6 +955,8 @@ void vout_ManageDisplay(vout_display_t *vd, bool allow_reset_pictures) */ msg_Err(vd, "Failed to change source AR"); source = vd->source; + } else if (!osys->fit_window) { + osys->fit_window = 1; } vd->source = source; osys->sar.num = source.i_sar_num; @@ -857,12 +978,24 @@ void vout_ManageDisplay(vout_display_t *vd, bool allow_reset_pictures) 65536); vout_SendEventSourceAspect(osys->vout, dar_num, dar_den); } + /* If a crop ratio is requested, recompute the parameters */ + if (osys->crop.num > 0 && osys->crop.den > 0) + osys->ch_crop = true; } /* */ if (osys->ch_crop) { video_format_t source = vd->source; + unsigned crop_num = osys->crop.num; unsigned crop_den = osys->crop.den; + if (crop_num > 0 && crop_den > 0) { + video_format_t fmt = osys->source; + fmt.i_sar_num = source.i_sar_num; + fmt.i_sar_den = source.i_sar_den; + VoutDisplayCropRatio(&osys->crop.x, &osys->crop.y, + &osys->crop.width, &osys->crop.height, + &fmt, crop_num, crop_den); + } source.i_x_offset = osys->crop.x; source.i_y_offset = osys->crop.y; @@ -888,6 +1021,8 @@ void vout_ManageDisplay(vout_display_t *vd, bool allow_reset_pictures) /* FIXME implement cropping in the core if not supported by the * vout module (easy) */ + } else if (!osys->fit_window) { + osys->fit_window = 1; } vd->source = source; osys->crop.x = source.i_x_offset; @@ -1010,7 +1145,9 @@ void vout_SetDisplayCrop(vout_display_t *vd, vout_display_owner_sys_t *osys = vd->owner.sys; if (osys->crop.x != x || osys->crop.y != y || - osys->crop.width != width || osys->crop.height != height) { + osys->crop.width != width || osys->crop.height != height || + (crop_num > 0 && crop_den > 0 && + (crop_num != osys->crop.num || crop_den != osys->crop.den))) { osys->crop.x = x; osys->crop.y = y; @@ -1044,8 +1181,7 @@ static vout_display_t *DisplayNew(vout_thread_t *vout, vout_display_cfg_t *cfg = &osys->cfg; *cfg = state->cfg; - osys->wm_state_initial = state->is_on_top - ? VOUT_WINDOW_STATE_ABOVE : VOUT_WINDOW_STATE_NORMAL; + osys->wm_state_initial = -1; osys->sar_initial.num = state->sar.num; osys->sar_initial.den = state->sar.den; vout_display_GetDefaultDisplaySize(&cfg->display.width, &cfg->display.height, @@ -1062,13 +1198,25 @@ static vout_display_t *DisplayNew(vout_thread_t *vout, osys->mouse.double_click_timeout = double_click_timeout; osys->mouse.hide_timeout = hide_timeout; osys->is_fullscreen = cfg->is_fullscreen; - osys->width_saved = osys->display_width = cfg->display.width; - osys->height_saved = osys->display_height = cfg->display.height; osys->is_display_filled = cfg->is_display_filled; + osys->width_saved = cfg->display.width; + osys->height_saved = cfg->display.height; + if (osys->is_fullscreen) { + vout_display_cfg_t cfg_windowed = *cfg; + cfg_windowed.is_fullscreen = false; + cfg_windowed.display.width = 0; + cfg_windowed.display.height = 0; + vout_display_GetDefaultDisplaySize(&osys->width_saved, + &osys->height_saved, + source_org, &cfg_windowed); + } osys->zoom.num = cfg->zoom.num; osys->zoom.den = cfg->zoom.den; + osys->wm_state = state->wm_state; + osys->fit_window = 0; + osys->event.fifo = NULL; osys->source = *source_org; @@ -1118,7 +1266,7 @@ static vout_display_t *DisplayNew(vout_thread_t *vout, if (osys->sar.num != source_org->i_sar_num || osys->sar.den != source_org->i_sar_den) osys->ch_sar = true; - if (osys->wm_state != VOUT_WINDOW_STATE_NORMAL) + if (osys->wm_state != osys->wm_state_initial) osys->ch_wm_state = true; if (osys->crop.x != source_org->i_x_offset || osys->crop.y != source_org->i_y_offset || @@ -1136,15 +1284,20 @@ void vout_DeleteDisplay(vout_display_t *vd, vout_display_state_t *state) if (state) { if (!osys->is_wrapper ) state->cfg = osys->cfg; - state->is_on_top = (osys->wm_state & VOUT_WINDOW_STATE_ABOVE) != 0; - state->sar.num = osys->sar_initial.num; - state->sar.den = osys->sar_initial.den; + state->wm_state = osys->wm_state; + state->sar.num = osys->sar_initial.num; + state->sar.den = osys->sar_initial.den; } VoutDisplayDestroyRender(vd); if (osys->is_wrapper) SplitterClose(vd); vout_display_Delete(vd); + if (osys->event.fifo) { + vlc_cancel(osys->event.thread); + vlc_join(osys->event.thread, NULL); + block_FifoRelease(osys->event.fifo); + } vlc_mutex_destroy(&osys->lock); free(osys); } @@ -1163,17 +1316,11 @@ vout_display_t *vout_NewDisplay(vout_thread_t *vout, double_click_timeout, hide_timeout, NULL); } -static void SplitterClose(vout_display_t *vd) -{ - VLC_UNUSED(vd); - assert(0); -} - -#if 0 /***************************************************************************** * *****************************************************************************/ struct vout_display_sys_t { + picture_pool_t *pool; video_splitter_t *splitter; /* */ @@ -1204,7 +1351,7 @@ static void SplitterDelWindow(vout_display_t *vd, vout_window_t *window) } static void SplitterEvent(vout_display_t *vd, int event, va_list args) { - vout_display_owner_sys_t *osys = vd->owner.sys; + //vout_display_owner_sys_t *osys = vd->owner.sys; switch (event) { #if 0 @@ -1230,10 +1377,12 @@ static void SplitterEvent(vout_display_t *vd, int event, va_list args) } } -static picture_t *SplitterGet(vout_display_t *vd) +static picture_pool_t *SplitterPool(vout_display_t *vd, unsigned count) { - /* TODO pool ? */ - return picture_NewFromFormat(&vd->fmt); + vout_display_sys_t *sys = vd->sys; + if (!sys->pool) + sys->pool = picture_pool_NewFromFormat(&vd->fmt, count); + return sys->pool; } static void SplitterPrepare(vout_display_t *vd, picture_t *picture) { @@ -1249,27 +1398,10 @@ static void SplitterPrepare(vout_display_t *vd, picture_t *picture) } for (int i = 0; i < sys->count; i++) { - /* */ - /* FIXME now vout_FilterDisplay already return a direct buffer FIXME */ - sys->picture[i] = vout_FilterDisplay(sys->display[i], sys->picture[i]); - if (!sys->picture[i]) - continue; - - /* */ - picture_t *direct = vout_display_Get(sys->display[i]); - if (!direct) { - msg_Err(vd, "Failed to get a direct buffer"); - picture_Release(sys->picture[i]); - sys->picture[i] = NULL; - continue; - } - - /* FIXME not always needed (easy when there is a osys->filters) */ - picture_Copy(direct, sys->picture[i]); - picture_Release(sys->picture[i]); - sys->picture[i] = direct; - - vout_display_Prepare(sys->display[i], sys->picture[i]); + if (vout_IsDisplayFiltered(sys->display[i])) + sys->picture[i] = vout_FilterDisplay(sys->display[i], sys->picture[i]); + if (sys->picture[i]) + vout_display_Prepare(sys->display[i], sys->picture[i]); } } static void SplitterDisplay(vout_display_t *vd, picture_t *picture) @@ -1291,7 +1423,7 @@ static void SplitterManage(vout_display_t *vd) vout_display_sys_t *sys = vd->sys; for (int i = 0; i < sys->count; i++) - vout_ManageDisplay(sys->display[i]); + vout_ManageDisplay(sys->display[i], true); } static int SplitterPictureNew(video_splitter_t *splitter, picture_t *picture[]) @@ -1299,8 +1431,13 @@ static int SplitterPictureNew(video_splitter_t *splitter, picture_t *picture[]) vout_display_sys_t *wsys = splitter->p_owner->wrapper->sys; for (int i = 0; i < wsys->count; i++) { - /* TODO pool ? */ - picture[i] = picture_NewFromFormat(&wsys->display[i]->source); + if (vout_IsDisplayFiltered(wsys->display[i])) { + /* TODO use a pool ? */ + picture[i] = picture_NewFromFormat(&wsys->display[i]->source); + } else { + picture_pool_t *pool = vout_display_Pool(wsys->display[i], 1); + picture[i] = pool ? picture_pool_Get(pool) : NULL; + } if (!picture[i]) { for (int j = 0; j < i; j++) picture_Release(picture[j]); @@ -1325,6 +1462,9 @@ static void SplitterClose(vout_display_t *vd) free(splitter->p_owner); video_splitter_Delete(splitter); + if (sys->pool) + picture_pool_Delete(sys->pool); + /* */ for (int i = 0; i < sys->count; i++) vout_DeleteDisplay(sys->display[i], NULL); @@ -1362,8 +1502,9 @@ vout_display_t *vout_NewSplitter(vout_thread_t *vout, if (!sys->picture ) abort(); sys->splitter = splitter; + sys->pool = NULL; - wrapper->get = SplitterGet; + wrapper->pool = SplitterPool; wrapper->prepare = SplitterPrepare; wrapper->display = SplitterDisplay; wrapper->control = SplitterControl; @@ -1413,7 +1554,6 @@ vout_display_t *vout_NewSplitter(vout_thread_t *vout, return wrapper; } -#endif /***************************************************************************** * TODO move out @@ -1421,6 +1561,21 @@ vout_display_t *vout_NewSplitter(vout_thread_t *vout, #include "vout_internal.h" void vout_SendDisplayEventMouse(vout_thread_t *vout, const vlc_mouse_t *m) { + vlc_mouse_t tmp1, tmp2; + + /* The check on p_spu is needed as long as ALLOW_DUMMY_VOUT is defined */ + if (vout->p->p_spu && spu_ProcessMouse( vout->p->p_spu, m, &vout->p->display.vd->source)) + return; + + vlc_mutex_lock( &vout->p->filter.lock ); + if (vout->p->filter.chain_static && vout->p->filter.chain_interactive) { + if (!filter_chain_MouseFilter(vout->p->filter.chain_interactive, &tmp1, m)) + m = &tmp1; + if (!filter_chain_MouseFilter(vout->p->filter.chain_static, &tmp2, m)) + m = &tmp2; + } + vlc_mutex_unlock( &vout->p->filter.lock ); + if (vlc_mouse_HasMoved(&vout->p->mouse, m)) { vout_SendEventMouseMoved(vout, m->i_x, m->i_y); } @@ -1452,29 +1607,18 @@ static void DummyVoutSendDisplayEventMouse(vout_thread_t *vout, vlc_mouse_t *fal if (!vout->p) { p.mouse = *fallback; + vlc_mutex_init(&p.filter.lock); + p.filter.chain_static = NULL; + p.filter.chain_interactive = NULL; + p.p_spu = NULL; vout->p = &p; } vout_SendDisplayEventMouse(vout, m); if (vout->p == &p) { + vlc_mutex_destroy(&p.filter.lock); *fallback = p.mouse; vout->p = NULL; } } #endif -vout_window_t * vout_NewDisplayWindow(vout_thread_t *vout, vout_display_t *vd, const vout_window_cfg_t *cfg) -{ - VLC_UNUSED(vd); - vout_window_cfg_t cfg_override = *cfg; - - if( !var_InheritBool( vout, "embedded-video" ) ) - cfg_override.is_standalone = true; - - return vout_window_New(VLC_OBJECT(vout), NULL, &cfg_override); -} -void vout_DeleteDisplayWindow(vout_thread_t *vout, vout_display_t *vd, vout_window_t *window) -{ - VLC_UNUSED(vout); - VLC_UNUSED(vd); - vout_window_Delete(window); -}