/* 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);
return VoutCreate(object, cfg);
}
-/*****************************************************************************
- * vout_Close: Close a vout created by VoutCreate.
- *****************************************************************************
- * 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.
- *****************************************************************************/
void vout_Close(vout_thread_t *vout)
{
assert(vout);
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);
/* 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);
{
int channel = SPU_DEFAULT_CHANNEL;
- vout_control_cmd_t cmd;
- vout_control_cmd_Init(&cmd, VOUT_CONTROL_REGISTER_SUBPICTURE);
- cmd.u.integer_ptr = &channel;
-
- vout_control_Push(&vout->p->control, &cmd);
- vout_control_WaitEmpty(&vout->p->control);
+ 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;
}
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)
else if (align_mask & 0x2)
cfg->align.horizontal = VOUT_DISPLAY_ALIGN_RIGHT;
if (align_mask & 0x4)
- cfg->align.horizontal = VOUT_DISPLAY_ALIGN_TOP;
+ cfg->align.vertical = VOUT_DISPLAY_ALIGN_TOP;
else if (align_mask & 0x8)
- cfg->align.horizontal = VOUT_DISPLAY_ALIGN_BOTTOM;
+ cfg->align.vertical = VOUT_DISPLAY_ALIGN_BOTTOM;
}
vout_window_t * vout_NewDisplayWindow(vout_thread_t *vout, vout_display_t *vd,
vout->p->window.object = NULL;
}
- vout_window_t *window = vout_window_New(VLC_OBJECT(vout), NULL,
+ vout_window_t *window = vout_window_New(VLC_OBJECT(vout), "$window",
&cfg_override);
if (!window)
return NULL;
}
/* */
-static int ThreadDisplayPicture(vout_thread_t *vout,
- bool now, mtime_t *deadline)
+static picture_t *ThreadDisplayGetDecodedPicture(vout_thread_t *vout,
+ int *lost_count, bool *is_forced,
+ bool now, mtime_t *deadline)
{
vout_display_t *vd = vout->p->display.vd;
- int displayed_count = 0;
- int lost_count = 0;
- for (;;) {
- const mtime_t date = mdate();
- const bool is_paused = vout->p->pause.is_on;
- bool redisplay = is_paused && !now && vout->p->displayed.decoded;
- bool is_forced;
-
- /* FIXME/XXX we must redisplay the last decoded picture (because
- * of potential vout updated, or filters update or SPU update)
- * For now a high update period is needed but it coulmd be removed
- * if and only if:
- * - vout module emits events from theselves.
- * - *and* SPU is modified to emit an event or a deadline when needed.
- *
- * So it will be done latter.
- */
- if (!redisplay) {
- picture_t *peek = picture_fifo_Peek(vout->p->decoder_fifo);
- if (peek) {
- is_forced = peek->b_force || is_paused || now;
- *deadline = (is_forced ? date : peek->date) - vout_chrono_GetHigh(&vout->p->render);
- picture_Release(peek);
- } else {
- redisplay = true;
- }
+ const mtime_t date = mdate();
+ const bool is_paused = vout->p->pause.is_on;
+ bool redisplay = is_paused && !now && vout->p->displayed.decoded;
+
+ /* FIXME/XXX we must redisplay the last decoded picture (because
+ * of potential vout updated, or filters update or SPU update)
+ * For now a high update period is needed but it coulmd be removed
+ * if and only if:
+ * - vout module emits events from theselves.
+ * - *and* SPU is modified to emit an event or a deadline when needed.
+ *
+ * So it will be done latter.
+ */
+ if (!redisplay) {
+ picture_t *peek = picture_fifo_Peek(vout->p->decoder_fifo);
+ if (peek) {
+ *is_forced = peek->b_force || is_paused || now;
+ *deadline = (*is_forced ? date : peek->date) - vout_chrono_GetHigh(&vout->p->render);
+ picture_Release(peek);
+ } else {
+ redisplay = true;
}
- if (redisplay) {
- /* FIXME a better way for this delay is needed */
- const mtime_t date_update = vout->p->displayed.date + VOUT_REDISPLAY_DELAY;
- if (date_update > date || !vout->p->displayed.decoded) {
- *deadline = vout->p->displayed.decoded ? date_update : VLC_TS_INVALID;
- break;
- }
- /* */
- is_forced = true;
- *deadline = date - vout_chrono_GetHigh(&vout->p->render);
+ }
+ if (redisplay) {
+ /* FIXME a better way for this delay is needed */
+ const mtime_t date_update = vout->p->displayed.date + VOUT_REDISPLAY_DELAY;
+ if (date_update > date || !vout->p->displayed.decoded) {
+ *deadline = vout->p->displayed.decoded ? date_update : VLC_TS_INVALID;
+ return NULL;
}
- if (*deadline > VOUT_MWAIT_TOLERANCE)
- *deadline -= VOUT_MWAIT_TOLERANCE;
+ /* */
+ *is_forced = true;
+ *deadline = date - vout_chrono_GetHigh(&vout->p->render);
+ }
+ if (*deadline > VOUT_MWAIT_TOLERANCE)
+ *deadline -= VOUT_MWAIT_TOLERANCE;
- /* If we are too early and can wait, do it */
- if (date < *deadline && !now)
- break;
+ /* If we are too early and can wait, do it */
+ if (date < *deadline && !now)
+ return NULL;
- picture_t *decoded;
- if (redisplay) {
- decoded = vout->p->displayed.decoded;
- vout->p->displayed.decoded = NULL;
- } else {
- decoded = picture_fifo_Pop(vout->p->decoder_fifo);
- assert(decoded);
- if (!is_forced && !vout->p->is_late_dropped) {
- const mtime_t predicted = date + vout_chrono_GetLow(&vout->p->render);
- const mtime_t late = predicted - decoded->date;
- if (late > 0) {
- msg_Dbg(vout, "picture might be displayed late (missing %d ms)", (int)(late/1000));
- if (late > VOUT_DISPLAY_LATE_THRESHOLD) {
- msg_Warn(vout, "rejected picture because of render time");
- /* TODO */
- picture_Release(decoded);
- lost_count++;
- break;
- }
+ picture_t *decoded;
+ if (redisplay) {
+ decoded = vout->p->displayed.decoded;
+ vout->p->displayed.decoded = NULL;
+ } else {
+ decoded = picture_fifo_Pop(vout->p->decoder_fifo);
+ assert(decoded);
+ if (!*is_forced && !vout->p->is_late_dropped) {
+ const mtime_t predicted = date + vout_chrono_GetLow(&vout->p->render);
+ const mtime_t late = predicted - decoded->date;
+ if (late > 0) {
+ msg_Dbg(vout, "picture might be displayed late (missing %d ms)", (int)(late/1000));
+ if (late > VOUT_DISPLAY_LATE_THRESHOLD) {
+ msg_Warn(vout, "rejected picture because of render time");
+ /* TODO */
+ picture_Release(decoded);
+ (*lost_count)++;
+ return NULL;
}
}
-
- vout->p->displayed.is_interlaced = !decoded->b_progressive;
- vout->p->displayed.qtype = decoded->i_qtype;
}
- vout->p->displayed.timestamp = decoded->date;
- /* */
- if (vout->p->displayed.decoded)
- picture_Release(vout->p->displayed.decoded);
- picture_Hold(decoded);
- vout->p->displayed.decoded = decoded;
+ vout->p->displayed.is_interlaced = !decoded->b_progressive;
+ vout->p->displayed.qtype = decoded->i_qtype;
+ }
+ vout->p->displayed.timestamp = decoded->date;
+
+ /* */
+ if (vout->p->displayed.decoded)
+ picture_Release(vout->p->displayed.decoded);
+ picture_Hold(decoded);
+ vout->p->displayed.decoded = decoded;
+
+ return decoded;
+}
+
+static int ThreadDisplayPicture(vout_thread_t *vout,
+ bool now, mtime_t *deadline)
+{
+ vout_display_t *vd = vout->p->display.vd;
+ int displayed_count = 0;
+ int lost_count = 0;
+
+ for (;;) {
+ bool is_forced;
+ picture_t *decoded = ThreadDisplayGetDecodedPicture(vout,
+ &lost_count, &is_forced,
+ now, deadline);
+ if (!decoded)
+ break;
/* */
vout_chrono_Start(&vout->p->render);
spu_DisplaySubpicture(vout->p->p_spu, subpicture);
}
-static void ThreadRegisterSubpicture(vout_thread_t *vout, int *channel)
-{
- *channel = spu_RegisterChannel(vout->p->p_spu);
-}
-
static void ThreadFlushSubpicture(vout_thread_t *vout, int channel)
{
spu_ClearChannel(vout->p->p_spu, channel);
{
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)
{
case VOUT_CONTROL_FLUSH_SUBPICTURE:
ThreadFlushSubpicture(vout, cmd.u.integer);
break;
- case VOUT_CONTROL_REGISTER_SUBPICTURE:
- ThreadRegisterSubpicture(vout, cmd.u.integer_ptr);
- 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;