+static void ThreadChangeAspectRatio(vout_thread_t *vout,
+ unsigned num, unsigned den)
+{
+ const video_format_t *source = &vout->p->original;
+
+ if (num > 0 && den > 0) {
+ num *= source->i_visible_height;
+ den *= source->i_visible_width;
+ vlc_ureduce(&num, &den, num, den, 0);
+ }
+ vout_SetDisplayAspect(vout->p->display.vd, num, den);
+}
+
+
+static void ThreadExecuteCropWindow(vout_thread_t *vout,
+ unsigned crop_num, unsigned crop_den,
+ unsigned x, unsigned y,
+ unsigned width, unsigned height)
+{
+ const video_format_t *source = &vout->p->original;
+
+ vout_SetDisplayCrop(vout->p->display.vd,
+ crop_num, crop_den,
+ source->i_x_offset + x,
+ source->i_y_offset + y,
+ width, height);
+}
+static void ThreadExecuteCropBorder(vout_thread_t *vout,
+ unsigned left, unsigned top,
+ unsigned right, unsigned bottom)
+{
+ const video_format_t *source = &vout->p->original;
+ ThreadExecuteCropWindow(vout, 0, 0,
+ left,
+ top,
+ /* At worst, it becomes < 0 (but unsigned) and will be rejected */
+ source->i_visible_width - (left + right),
+ source->i_visible_height - (top + bottom));
+}
+
+static void ThreadExecuteCropRatio(vout_thread_t *vout,
+ unsigned num, unsigned den)
+{
+ const video_format_t *source = &vout->p->original;
+ ThreadExecuteCropWindow(vout, num, den,
+ 0, 0,
+ source->i_visible_width,
+ source->i_visible_height);
+}
+
+static int ThreadStart(vout_thread_t *vout, const vout_display_state_t *state)
+{
+ vlc_mouse_Init(&vout->p->mouse);
+ vout->p->decoder_fifo = picture_fifo_New();
+ vout->p->decoder_pool = NULL;
+ vout->p->display_pool = NULL;
+ vout->p->private_pool = NULL;
+
+ vout->p->vfilter_chain =
+ filter_chain_New( vout, "video filter2", false,
+ VoutVideoFilterAllocationSetup, NULL, vout);
+ vout->p->vfilter_delay_index = 0;
+ for (int i = 0; i < VOUT_FILTER_DELAYS; i++)
+ vout->p->vfilter_delay[i] = 0;
+
+ 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->p->displayed.decoded = NULL;
+ vout->p->displayed.date = VLC_TS_INVALID;
+ vout->p->displayed.decoded = NULL;
+ vout->p->displayed.timestamp = VLC_TS_INVALID;
+ vout->p->displayed.qtype = QTYPE_NONE;
+ vout->p->displayed.is_interlaced = false;
+
+ vout->p->step.last = VLC_TS_INVALID;
+ vout->p->step.timestamp = VLC_TS_INVALID;
+
+ video_format_Print(VLC_OBJECT(vout), "original format", &vout->p->original);
+ return VLC_SUCCESS;
+}
+
+static void ThreadStop(vout_thread_t *vout, vout_display_state_t *state)
+{
+ /* Destroy the video filters2 */
+ filter_chain_Delete(vout->p->vfilter_chain);
+
+ /* Destroy translation tables */
+ if (vout->p->display.vd) {
+ if (vout->p->decoder_pool) {
+ ThreadFlush(vout, true, INT64_MAX);
+ vout_EndWrapper(vout);
+ }
+ vout_CloseWrapper(vout, state);
+ }
+
+ if (vout->p->decoder_fifo)
+ picture_fifo_Delete(vout->p->decoder_fifo);
+ assert(!vout->p->decoder_pool);
+}
+
+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 vout_configuration_t *cfg)
+{
+ video_format_t original;
+ if (VoutValidateFormat(&original, cfg->fmt)) {
+ ThreadStop(vout, NULL);
+ ThreadClean(vout);
+ return VLC_EGENERIC;
+ }
+ if (video_format_IsSimilar(&original, &vout->p->original)) {
+ if (cfg->dpb_size <= vout->p->dpb_size)
+ return VLC_SUCCESS;
+ msg_Warn(vout, "DPB need to be increased");
+ }
+
+ 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;
+ vout->p->dpb_size = cfg->dpb_size;
+ if (ThreadStart(vout, &state)) {
+ ThreadClean(vout);
+ return VLC_EGENERIC;
+ }
+ return VLC_SUCCESS;
+}
+