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);
- 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.reinit.fmt = fmt;
-
- 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 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 */
vout->p = (vout_thread_sys_t*)&vout[1];
vout->p->original = original;
+ vout->p->dpb_size = cfg->dpb_size;
vout_control_Init(&vout->p->control);
vout_control_PushVoid(&vout->p->control, VOUT_CONTROL_INIT);
/* Initialize locks */
vlc_mutex_init(&vout->p->picture_lock);
vlc_mutex_init(&vout->p->vfilter_lock);
+ vlc_mutex_init(&vout->p->spu_lock);
/* Attach the new object now so we can use var inheritance below */
vlc_object_attach(vout, object);
/* */
if (vlc_clone(&vout->p->thread, Thread, vout,
VLC_THREAD_PRIORITY_OUTPUT)) {
+ spu_Destroy(vout->p->p_spu);
vlc_object_release(vout);
return NULL;
}
- spu_Attach(vout->p->p_spu, VLC_OBJECT(vout), true);
vout_control_WaitEmpty(&vout->p->control);
return NULL;
}
+ vout->p->input = cfg->input;
+ if (vout->p->input)
+ spu_Attach(vout->p->p_spu, vout->p->input, true);
+
return vout;
}
-/*****************************************************************************
- * vout_Close: Close a vout created by vout_Create.
- *****************************************************************************
- * 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
- * (like with vout_Request or vlc_object_find.)
- * You can use vout_CloseAndRelease() as a convenience method.
- *****************************************************************************/
+vout_thread_t *(vout_Request)(vlc_object_t *object,
+ const vout_configuration_t *cfg)
+{
+ vout_thread_t *vout = cfg->vout;
+ if (cfg->change_fmt && !cfg->fmt) {
+ if (vout)
+ vout_CloseAndRelease(vout);
+ return NULL;
+ }
+
+ /* If a vout is provided, try reusing it */
+ if (vout) {
+ if (vout->p->input != cfg->input) {
+ if (vout->p->input)
+ spu_Attach(vout->p->p_spu, vout->p->input, false);
+ vout->p->input = cfg->input;
+ if (vout->p->input)
+ spu_Attach(vout->p->p_spu, vout->p->input, true);
+ }
+
+ if (cfg->change_fmt) {
+ 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);
+}
+
void vout_Close(vout_thread_t *vout)
{
assert(vout);
- spu_Attach(vout->p->p_spu, VLC_OBJECT(vout), false);
- vlc_object_detach(vout->p->p_spu);
+ if (vout->p->input)
+ spu_Attach(vout->p->p_spu, vout->p->input, false);
vout_snapshot_End(&vout->p->snapshot);
vout_control_PushVoid(&vout->p->control, VOUT_CONTROL_CLEAN);
vlc_join(vout->p->thread, NULL);
+
+ vlc_mutex_lock(&vout->p->spu_lock);
+ spu_Destroy(vout->p->p_spu);
+ vout->p->p_spu = NULL;
+ vlc_mutex_unlock(&vout->p->spu_lock);
}
/* */
free(vout->p->splitter_name);
- /* */
- spu_Destroy(vout->p->p_spu);
-
/* Destroy the locks */
+ vlc_mutex_destroy(&vout->p->spu_lock);
vlc_mutex_destroy(&vout->p->picture_lock);
vlc_mutex_destroy(&vout->p->vfilter_lock);
vout_control_Clean(&vout->p->control);
void vout_PutSubpicture( vout_thread_t *vout, subpicture_t *subpic )
{
- spu_DisplaySubpicture(vout->p->p_spu, subpic);
+ vout_control_cmd_t cmd;
+ vout_control_cmd_Init(&cmd, VOUT_CONTROL_SUBPICTURE);
+ cmd.u.subpicture = subpic;
+
+ vout_control_Push(&vout->p->control, &cmd);
}
int vout_RegisterSubpictureChannel( vout_thread_t *vout )
{
- return spu_RegisterChannel(vout->p->p_spu);
+ int channel = SPU_DEFAULT_CHANNEL;
+
+ vlc_mutex_lock(&vout->p->spu_lock);
+ if (vout->p->p_spu)
+ channel = spu_RegisterChannel(vout->p->p_spu);
+ vlc_mutex_unlock(&vout->p->spu_lock);
+
+ return channel;
}
void vout_FlushSubpictureChannel( vout_thread_t *vout, int channel )
{
- spu_ClearChannel(vout->p->p_spu, channel);
+ vout_control_PushInteger(&vout->p->control, VOUT_CONTROL_FLUSH_SUBPICTURE,
+ channel);
}
/* vout_Control* are usable by anyone at anytime */
vout_control_PushString(&vout->p->control, VOUT_CONTROL_CHANGE_SUB_FILTERS,
filters);
}
+void vout_ControlChangeSubMargin(vout_thread_t *vout, int margin)
+{
+ vout_control_PushInteger(&vout->p->control, VOUT_CONTROL_CHANGE_SUB_MARGIN,
+ margin);
+}
/* */
static void VoutGetDisplayCfg(vout_thread_t *vout, vout_display_cfg_t *cfg, const char *title)
vout_ManageWrapper(vout);
}
+static void ThreadDisplaySubpicture(vout_thread_t *vout,
+ subpicture_t *subpicture)
+{
+ spu_DisplaySubpicture(vout->p->p_spu, subpicture);
+}
+
+static void ThreadFlushSubpicture(vout_thread_t *vout, int channel)
+{
+ spu_ClearChannel(vout->p->p_spu, channel);
+}
+
static void ThreadDisplayOsdTitle(vout_thread_t *vout, const char *string)
{
if (!vout->p->title.show)
{
spu_ChangeFilters(vout->p->p_spu, filters);
}
+static void ThreadChangeSubMargin(vout_thread_t *vout, int margin)
+{
+ spu_ChangeMargin(vout->p->p_spu, margin);
+}
static void ThreadChangePause(vout_thread_t *vout, bool is_paused, mtime_t date)
{
}
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;
+ 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));
* 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;
ThreadClean(vout);
return NULL;
case VOUT_CONTROL_REINIT:
- if (ThreadReinit(vout, cmd.u.reinit.fmt))
+ if (ThreadReinit(vout, cmd.u.cfg))
return NULL;
break;
+ case VOUT_CONTROL_SUBPICTURE:
+ ThreadDisplaySubpicture(vout, cmd.u.subpicture);
+ cmd.u.subpicture = NULL;
+ break;
+ case VOUT_CONTROL_FLUSH_SUBPICTURE:
+ ThreadFlushSubpicture(vout, cmd.u.integer);
+ break;
case VOUT_CONTROL_OSD_TITLE:
ThreadDisplayOsdTitle(vout, cmd.u.string);
break;
case VOUT_CONTROL_CHANGE_SUB_FILTERS:
ThreadChangeSubFilters(vout, cmd.u.string);
break;
+ case VOUT_CONTROL_CHANGE_SUB_MARGIN:
+ ThreadChangeSubMargin(vout, cmd.u.integer);
+ break;
case VOUT_CONTROL_PAUSE:
ThreadChangePause(vout, cmd.u.pause.is_on, cmd.u.pause.date);
break;