return VLC_SUCCESS;
}
-/*****************************************************************************
- * vout_Request: find a video output thread, create one, or destroy one.
- *****************************************************************************
- * This function looks for a video output thread matching the current
- * properties. If not found, it spawns a new one.
- *****************************************************************************/
-vout_thread_t *(vout_Request)(vlc_object_t *object, vout_thread_t *vout,
- const video_format_t *fmt)
-{
- if (!fmt) {
- if (vout)
- vout_CloseAndRelease(vout);
- return NULL;
- }
-
- /* If a vout is provided, try reusing it */
- if (vout) {
- spu_Attach(vout->p->p_spu, VLC_OBJECT(vout), false);
- vlc_object_detach(vout);
-
- vout_control_cmd_t cmd;
- vout_control_cmd_Init(&cmd, VOUT_CONTROL_REINIT);
- cmd.u.reinit.fmt = fmt;
-
- vout_control_Push(&vout->p->control, &cmd);
- vout_control_WaitEmpty(&vout->p->control);
- if (!vout->p->dead) {
- vlc_object_attach(vout, object);
- spu_Attach(vout->p->p_spu, VLC_OBJECT(vout), true);
-
- msg_Dbg(object, "reusing provided vout");
- return vout;
- }
- vout_CloseAndRelease(vout);
-
- msg_Warn(object, "cannot reuse provided vout");
- }
- return vout_Create(object, fmt);
-}
-
-/*****************************************************************************
- * vout_Create: creates a new video output thread
- *****************************************************************************
- * This function creates a new video output thread, and returns a pointer
- * to its description. On error, it returns NULL.
- *****************************************************************************/
-vout_thread_t *(vout_Create)(vlc_object_t *object, const video_format_t *fmt)
+static vout_thread_t *VoutCreate(vlc_object_t *object,
+ const vout_configuration_t *cfg)
{
video_format_t original;
- if (VoutValidateFormat(&original, fmt))
+ if (VoutValidateFormat(&original, cfg->fmt))
return NULL;
/* Allocate descriptor */
return vout;
}
+vout_thread_t *(vout_Request)(vlc_object_t *object,
+ const vout_configuration_t *cfg)
+{
+ vout_thread_t *vout = cfg->vout;
+ if (!cfg->fmt) {
+ if (vout)
+ vout_CloseAndRelease(vout);
+ return NULL;
+ }
+
+ /* If a vout is provided, try reusing it */
+ if (vout) {
+ spu_Attach(vout->p->p_spu, VLC_OBJECT(vout), false);
+ vlc_object_detach(vout);
+ vlc_object_attach(vout, object);
+ spu_Attach(vout->p->p_spu, VLC_OBJECT(vout), true);
+
+ vout_control_cmd_t cmd;
+ vout_control_cmd_Init(&cmd, VOUT_CONTROL_REINIT);
+ cmd.u.cfg = cfg;
+
+ vout_control_Push(&vout->p->control, &cmd);
+ vout_control_WaitEmpty(&vout->p->control);
+ if (!vout->p->dead) {
+ msg_Dbg(object, "reusing provided vout");
+ return vout;
+ }
+ vout_CloseAndRelease(vout);
+
+ msg_Warn(object, "cannot reuse provided vout");
+ }
+ return VoutCreate(object, cfg);
+}
+
/*****************************************************************************
- * vout_Close: Close a vout created by vout_Create.
+ * vout_Close: Close a vout created by VoutCreate.
*****************************************************************************
- * You HAVE to call it on vout created by vout_Create before vlc_object_release.
- * You should NEVER call it on vout not obtained through vout_Create
+ * You HAVE to call it on vout created by VoutCreate before vlc_object_release.
+ * You should NEVER call it on vout not obtained through VoutCreate
* (like with vout_Request or vlc_object_find.)
* You can use vout_CloseAndRelease() as a convenience method.
*****************************************************************************/
assert(vout);
spu_Attach(vout->p->p_spu, VLC_OBJECT(vout), false);
+ vlc_object_detach(vout->p->p_spu);
vout_snapshot_End(&vout->p->snapshot);
filters);
}
+/* */
+static void VoutGetDisplayCfg(vout_thread_t *vout, vout_display_cfg_t *cfg, const char *title)
+{
+ /* Load configuration */
+ cfg->is_fullscreen = var_CreateGetBool(vout, "fullscreen");
+ cfg->display.title = title;
+ const int display_width = var_CreateGetInteger(vout, "width");
+ const int display_height = var_CreateGetInteger(vout, "height");
+ cfg->display.width = display_width > 0 ? display_width : 0;
+ cfg->display.height = display_height > 0 ? display_height : 0;
+ cfg->is_display_filled = var_CreateGetBool(vout, "autoscale");
+ cfg->display.sar.num = 1; /* TODO monitor AR */
+ cfg->display.sar.den = 1;
+ unsigned zoom_den = 1000;
+ unsigned zoom_num = zoom_den * var_CreateGetFloat(vout, "scale");
+ vlc_ureduce(&zoom_num, &zoom_den, zoom_num, zoom_den, 0);
+ cfg->zoom.num = zoom_num;
+ cfg->zoom.den = zoom_den;
+ cfg->align.vertical = VOUT_DISPLAY_ALIGN_CENTER;
+ cfg->align.horizontal = VOUT_DISPLAY_ALIGN_CENTER;
+ const int align_mask = var_CreateGetInteger(vout, "align");
+ if (align_mask & 0x1)
+ cfg->align.horizontal = VOUT_DISPLAY_ALIGN_LEFT;
+ else if (align_mask & 0x2)
+ cfg->align.horizontal = VOUT_DISPLAY_ALIGN_RIGHT;
+ if (align_mask & 0x4)
+ cfg->align.horizontal = VOUT_DISPLAY_ALIGN_TOP;
+ else if (align_mask & 0x8)
+ cfg->align.horizontal = VOUT_DISPLAY_ALIGN_BOTTOM;
+}
+
+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;
+
+ if (vout->p->window.is_unused && vout->p->window.object) {
+ assert(!vout->p->splitter_name);
+ if (!cfg_override.is_standalone == !vout->p->window.cfg.is_standalone &&
+ cfg_override.type == vout->p->window.cfg.type) {
+ /* Reuse the stored window */
+ msg_Dbg(vout, "Reusing previous vout window");
+ vout_window_t *window = vout->p->window.object;
+ if (cfg_override.width != vout->p->window.cfg.width ||
+ cfg_override.height != vout->p->window.cfg.height)
+ vout_window_SetSize(window,
+ cfg_override.width, cfg_override.height);
+ vout->p->window.is_unused = false;
+ vout->p->window.cfg = cfg_override;
+ return window;
+ }
+
+ vout_window_Delete(vout->p->window.object);
+ vout->p->window.is_unused = true;
+ vout->p->window.object = NULL;
+ }
+
+ vout_window_t *window = vout_window_New(VLC_OBJECT(vout), NULL,
+ &cfg_override);
+ if (!window)
+ return NULL;
+ if (!vout->p->splitter_name) {
+ vout->p->window.is_unused = false;
+ vout->p->window.cfg = cfg_override;
+ vout->p->window.object = window;
+ }
+ return window;
+}
+
+void vout_DeleteDisplayWindow(vout_thread_t *vout, vout_display_t *vd,
+ vout_window_t *window)
+{
+ VLC_UNUSED(vd);
+ if (!vout->p->window.is_unused && vout->p->window.object == window) {
+ vout->p->window.is_unused = true;
+ } else if (vout->p->window.is_unused && vout->p->window.object && !window) {
+ vout_window_Delete(vout->p->window.object);
+ vout->p->window.is_unused = true;
+ vout->p->window.object = NULL;
+ } else if (window) {
+ vout_window_Delete(window);
+ }
+}
+
/* */
static picture_t *VoutVideoFilterNewPicture(filter_t *filter)
{
source->i_visible_height);
}
-static int ThreadInit(vout_thread_t *vout)
+static int ThreadStart(vout_thread_t *vout, const vout_display_state_t *state)
{
- vout->p->dead = false;
- vout->p->is_late_dropped = var_InheritBool(vout, "drop-late-frames");
vlc_mouse_Init(&vout->p->mouse);
vout->p->decoder_fifo = picture_fifo_New();
vout->p->decoder_pool = NULL;
filter_chain_New( vout, "video filter2", false,
VoutVideoFilterAllocationSetup, NULL, vout);
- if (vout_OpenWrapper(vout, vout->p->splitter_name))
+ vout_display_state_t state_default;
+ if (!state) {
+ VoutGetDisplayCfg(vout, &state_default.cfg, vout->p->display.title);
+ state_default.wm_state = var_CreateGetBool(vout, "video-on-top") ? VOUT_WINDOW_STATE_ABOVE :
+ VOUT_WINDOW_STATE_NORMAL;
+ state_default.sar.num = 0;
+ state_default.sar.den = 0;
+
+ state = &state_default;
+ }
+
+ if (vout_OpenWrapper(vout, vout->p->splitter_name, state))
return VLC_EGENERIC;
if (vout_InitWrapper(vout))
return VLC_EGENERIC;
assert(vout->p->decoder_pool);
- vout_chrono_Init(&vout->p->render, 5, 10000); /* Arbitrary initial time */
-
vout->p->displayed.decoded = NULL;
vout->p->displayed.date = VLC_TS_INVALID;
vout->p->displayed.decoded = NULL;
vout->p->step.last = VLC_TS_INVALID;
vout->p->step.timestamp = VLC_TS_INVALID;
- vout->p->pause.is_on = false;
- vout->p->pause.date = VLC_TS_INVALID;
-
video_format_Print(VLC_OBJECT(vout), "original format", &vout->p->original);
return VLC_SUCCESS;
}
-static void ThreadClean(vout_thread_t *vout)
+static void ThreadStop(vout_thread_t *vout, vout_display_state_t *state)
{
/* Destroy the video filters2 */
filter_chain_Delete(vout->p->vfilter_chain);
ThreadFlush(vout, true, INT64_MAX);
vout_EndWrapper(vout);
}
- vout_CloseWrapper(vout);
+ vout_CloseWrapper(vout, state);
}
- /* Detach subpicture unit from vout */
- vlc_object_detach(vout->p->p_spu);
-
if (vout->p->decoder_fifo)
picture_fifo_Delete(vout->p->decoder_fifo);
assert(!vout->p->decoder_pool);
- vout_chrono_Clean(&vout->p->render);
+}
+
+static void ThreadInit(vout_thread_t *vout)
+{
+ vout->p->window.is_unused = true;
+ vout->p->window.object = NULL;
+ vout->p->dead = false;
+ vout->p->is_late_dropped = var_InheritBool(vout, "drop-late-frames");
+ vout->p->pause.is_on = false;
+ vout->p->pause.date = VLC_TS_INVALID;
+
+ vout_chrono_Init(&vout->p->render, 5, 10000); /* Arbitrary initial time */
+}
+static void ThreadClean(vout_thread_t *vout)
+{
+ if (vout->p->window.object) {
+ assert(vout->p->window.is_unused);
+ vout_window_Delete(vout->p->window.object);
+ }
+ vout_chrono_Clean(&vout->p->render);
vout->p->dead = true;
vout_control_Dead(&vout->p->control);
}
+
static int ThreadReinit(vout_thread_t *vout,
- const video_format_t *fmt)
+ const vout_configuration_t *cfg)
{
video_format_t original;
- if (VoutValidateFormat(&original, fmt))
+ if (VoutValidateFormat(&original, cfg->fmt)) {
+ ThreadStop(vout, NULL);
+ ThreadClean(vout);
return VLC_EGENERIC;
+ }
if (video_format_IsSimilar(&original, &vout->p->original))
return VLC_SUCCESS;
- /* TODO */
- return VLC_EGENERIC;
+ vout_display_state_t state;
+ memset(&state, 0, sizeof(state));
+
+ ThreadStop(vout, &state);
+
+ if (!state.cfg.is_fullscreen) {
+ state.cfg.display.width = 0;
+ state.cfg.display.height = 0;
+ }
+ state.sar.num = 0;
+ state.sar.den = 0;
+ /* FIXME current vout "variables" are not in sync here anymore
+ * and I am not sure what to do */
+
+ vout->p->original = original;
+ if (ThreadStart(vout, &state)) {
+ ThreadClean(vout);
+ return VLC_EGENERIC;
+ }
+ return VLC_SUCCESS;
}
/*****************************************************************************
while (!vout_control_Pop(&vout->p->control, &cmd, deadline, 100000)) {
switch(cmd.type) {
case VOUT_CONTROL_INIT:
- if (ThreadInit(vout)) {
+ ThreadInit(vout);
+ if (ThreadStart(vout, NULL)) {
+ ThreadStop(vout, NULL);
ThreadClean(vout);
return NULL;
}
break;
case VOUT_CONTROL_CLEAN:
+ ThreadStop(vout, NULL);
ThreadClean(vout);
return NULL;
case VOUT_CONTROL_REINIT:
- if (ThreadReinit(vout, cmd.u.reinit.fmt)) {
- ThreadClean(vout);
+ if (ThreadReinit(vout, cmd.u.cfg))
return NULL;
- }
break;
case VOUT_CONTROL_OSD_TITLE:
ThreadDisplayOsdTitle(vout, cmd.u.string);