From: Laurent Aimar Date: Sun, 25 Apr 2010 17:18:02 +0000 (+0200) Subject: Added API to simplify/clean up vout controls. X-Git-Tag: 1.2.0-pre1~6881 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=1618a00d42eb5573d142a8568a0d13b4379e88ab;p=vlc Added API to simplify/clean up vout controls. --- diff --git a/src/Makefile.am b/src/Makefile.am index bc93824fac..e8ed0d5e91 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -356,6 +356,8 @@ SOURCES_libvlc_common = \ input/subtitles.c \ input/var.c \ video_output/chrono.h \ + video_output/control.c \ + video_output/control.h \ video_output/display.c \ video_output/display.h \ video_output/event.h \ diff --git a/src/video_output/control.c b/src/video_output/control.c new file mode 100644 index 0000000000..6e4e3abda9 --- /dev/null +++ b/src/video_output/control.c @@ -0,0 +1,205 @@ +/***************************************************************************** + * control.c : vout internal control + ***************************************************************************** + * Copyright (C) 2009 Laurent Aimar + * $Id$ + * + * Authors: Laurent Aimar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include "control.h" + +/* */ +void vout_control_cmd_Init(vout_control_cmd_t *cmd, int type) +{ + memset(cmd, 0, sizeof(*cmd)); + cmd->type = type; +} + +void vout_control_cmd_Clean(vout_control_cmd_t *cmd) +{ + switch (cmd->type) { + //case VOUT_CONTROL_OSD_MESSAGE: + case VOUT_CONTROL_OSD_TITLE: + free(cmd->u.message.string); + break; +#if 0 + case VOUT_CONTROL_OSD_TEXT: + free(cmd->text.string); + if (cmd->text.style) + text_style_Delete(cmd->text.style); + break; + case VOUT_CONTROL_OSD_SUBPICTURE: + if (cmd->subpicture) + subpicture_Delete(cmd->subpicture); + break; +#endif + default: + break; + } +} + +/* */ +void vout_control_Init(vout_control_t *ctrl) +{ + vlc_mutex_init(&ctrl->lock); + vlc_cond_init(&ctrl->wait_request); + vlc_cond_init(&ctrl->wait_acknowledge); + + ctrl->is_dead = false; + ctrl->is_sleeping = false; + ctrl->can_sleep = true; + ctrl->is_processing = false; + ARRAY_INIT(ctrl->cmd); +} + +void vout_control_Clean(vout_control_t *ctrl) +{ + /* */ + for (int i = 0; i < ctrl->cmd.i_size; i++) { + vout_control_cmd_t cmd = ARRAY_VAL(ctrl->cmd, i); + vout_control_cmd_Clean(&cmd); + } + ARRAY_RESET(ctrl->cmd); + + vlc_mutex_destroy(&ctrl->lock); + vlc_cond_destroy(&ctrl->wait_request); + vlc_cond_destroy(&ctrl->wait_acknowledge); +} + +void vout_control_Dead(vout_control_t *ctrl) +{ + vlc_mutex_lock(&ctrl->lock); + ctrl->is_dead = true; + vlc_cond_broadcast(&ctrl->wait_acknowledge); + vlc_mutex_unlock(&ctrl->lock); + +} + +void vout_control_WaitEmpty(vout_control_t *ctrl) +{ + vlc_mutex_lock(&ctrl->lock); + while ((ctrl->cmd.i_size > 0 || ctrl->is_processing) && !ctrl->is_dead) + vlc_cond_wait(&ctrl->wait_acknowledge, &ctrl->lock); + vlc_mutex_unlock(&ctrl->lock); +} + +void vout_control_Push(vout_control_t *ctrl, vout_control_cmd_t *cmd) +{ + vlc_mutex_lock(&ctrl->lock); + if (!ctrl->is_dead) { + ARRAY_APPEND(ctrl->cmd, *cmd); + vlc_cond_signal(&ctrl->wait_request); + } else { + vout_control_cmd_Clean(cmd); + } + vlc_mutex_unlock(&ctrl->lock); +} + +void vout_control_Wake(vout_control_t *ctrl) +{ + vlc_mutex_lock(&ctrl->lock); + ctrl->can_sleep = false; + if (ctrl->is_sleeping) + vlc_cond_signal(&ctrl->wait_request); + vlc_mutex_unlock(&ctrl->lock); +} + +void vout_control_PushVoid(vout_control_t *ctrl, int type) +{ + vout_control_cmd_t cmd; + + vout_control_cmd_Init(&cmd, type); + vout_control_Push(ctrl, &cmd); +} +void vout_control_PushBool(vout_control_t *ctrl, int type, bool boolean) +{ + vout_control_cmd_t cmd; + + vout_control_cmd_Init(&cmd, type); + cmd.u.boolean = boolean; + vout_control_Push(ctrl, &cmd); +} +void vout_control_PushTime(vout_control_t *ctrl, int type, mtime_t time) +{ + vout_control_cmd_t cmd; + + vout_control_cmd_Init(&cmd, type); + cmd.u.time = time; + vout_control_Push(ctrl, &cmd); +} +void vout_control_PushMessage(vout_control_t *ctrl, int type, int channel, const char *string) +{ + vout_control_cmd_t cmd; + + vout_control_cmd_Init(&cmd, type); + cmd.u.message.channel = channel; + cmd.u.message.string = strdup(string); + vout_control_Push(ctrl, &cmd); +} +void vout_control_PushPair(vout_control_t *ctrl, int type, int a, int b) +{ + vout_control_cmd_t cmd; + + vout_control_cmd_Init(&cmd, type); + cmd.u.pair.a = a; + cmd.u.pair.b = b; + vout_control_Push(ctrl, &cmd); +} + +int vout_control_Pop(vout_control_t *ctrl, vout_control_cmd_t *cmd, + mtime_t deadline, mtime_t timeout) +{ + vlc_mutex_lock(&ctrl->lock); + if (ctrl->cmd.i_size <= 0) { + ctrl->is_processing = false; + vlc_cond_broadcast(&ctrl->wait_acknowledge); + + const mtime_t max_deadline = mdate() + timeout; + + /* Supurious wake up are perfectly fine */ + if (deadline <= VLC_TS_INVALID) { + ctrl->is_sleeping = true; + if (ctrl->can_sleep) + vlc_cond_timedwait(&ctrl->wait_request, &ctrl->lock, max_deadline); + ctrl->is_sleeping = false; + } else { + vlc_cond_timedwait(&ctrl->wait_request, &ctrl->lock, __MIN(deadline, max_deadline)); + } + } + + bool has_cmd; + if (ctrl->cmd.i_size > 0) { + has_cmd = true; + *cmd = ARRAY_VAL(ctrl->cmd, 0); + ARRAY_REMOVE(ctrl->cmd, 0); + + ctrl->is_processing = true; + } else { + has_cmd = false; + ctrl->can_sleep = true; + } + vlc_mutex_unlock(&ctrl->lock); + + return has_cmd ? VLC_SUCCESS : VLC_EGENERIC; +} + diff --git a/src/video_output/control.h b/src/video_output/control.h new file mode 100644 index 0000000000..4949f4e30b --- /dev/null +++ b/src/video_output/control.h @@ -0,0 +1,159 @@ +/***************************************************************************** + * control.h : vout internal control + ***************************************************************************** + * Copyright (C) 2009-2010 Laurent Aimar + * $Id$ + * + * Authors: Laurent Aimar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#if defined(__PLUGIN__) || defined(__BUILTIN__) || !defined(__LIBVLC__) +# error This header file can only be included from LibVLC. +#endif + +#ifndef _VOUT_INTERNAL_CONTROL_H +#define _VOUT_INTERNAL_CONTROL_H + +/* */ +enum { +#if 0 + VOUT_CONTROL_INIT, + VOUT_CONTROL_EXIT, + + /* */ + VOUT_CONTROL_START, + VOUT_CONTROL_STOP, + + /* */ + VOUT_CONTROL_RESET, + VOUT_CONTROL_FLUSH, + VOUT_CONTROL_PAUSE, + VOUT_CONTROL_STEP, + + /* Controls */ + VOUT_CONTROL_FULLSCREEN, + VOUT_CONTROL_DISPLAY_FILLED, + VOUT_CONTROL_ZOOM, + VOUT_CONTROL_ON_TOP, + + VOUT_CONTROL_SOURCE_ASPECT, + VOUT_CONTROL_SOURCE_CROP_BORDER, + VOUT_CONTROL_SOURCE_CROP_RATIO, + VOUT_CONTROL_SOURCE_CROP_WINDOW, + + /* OSD */ + VOUT_CONTROL_OSD_MESSAGE, + VOUT_CONTROL_OSD_TEXT, + VOUT_CONTROL_OSD_SLIDER, + VOUT_CONTROL_OSD_ICON, + VOUT_CONTROL_OSD_SUBPICTURE, +#endif + VOUT_CONTROL_OSD_TITLE, +}; + +typedef struct { + int type; + + union { + bool boolean; + mtime_t time; + struct { + int a; + int b; + } pair; + struct { + bool is_on; + mtime_t date; + } pause; + struct { + int channel; + char *string; + } message; +#if 0 + struct { + int channel; + char *string; + text_style_t *style; + int flags; + int hmargin; + int vmargin; + mtime_t start; + mtime_t stop; + } text; + struct { + unsigned left; + unsigned top; + unsigned right; + unsigned bottom; + } border; + struct { + unsigned x; + unsigned y; + unsigned width; + unsigned height; + } window; + struct { + int channel; + int type; + float position; + } slider; + struct { + int channel; + int icon; + } icon; + subpicture_t *subpicture; +#endif + } u; +} vout_control_cmd_t; + +void vout_control_cmd_Init(vout_control_cmd_t *, int type); +void vout_control_cmd_Clean(vout_control_cmd_t *); + +typedef struct { + vlc_mutex_t lock; + vlc_cond_t wait_request; + vlc_cond_t wait_acknowledge; + + /* */ + bool is_dead; + bool is_sleeping; + bool can_sleep; + bool is_processing; + DECL_ARRAY(vout_control_cmd_t) cmd; +} vout_control_t; + +/* */ +void vout_control_Init(vout_control_t *); +void vout_control_Clean(vout_control_t *); + +/* controls outside of the vout thread */ +void vout_control_WaitEmpty(vout_control_t *); + +void vout_control_Push(vout_control_t *, vout_control_cmd_t *); +void vout_control_PushVoid(vout_control_t *, int type); +void vout_control_PushBool(vout_control_t *, int type, bool boolean); +void vout_control_PushTime(vout_control_t *, int type, mtime_t time); +void vout_control_PushMessage(vout_control_t *, int type, int channel, const char *string); +void vout_control_PushPair(vout_control_t *, int type, int a, int b); +void vout_control_Wake(vout_control_t *); + +/* control inside of the vout thread */ +int vout_control_Pop(vout_control_t *, vout_control_cmd_t *, mtime_t deadline, mtime_t timeout); +void vout_control_Dead(vout_control_t *); + +#endif + diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c index 39f4257b1e..06533f544f 100644 --- a/src/video_output/video_output.c +++ b/src/video_output/video_output.c @@ -281,6 +281,7 @@ vout_thread_t * (vout_Create)( vlc_object_t *p_parent, video_format_t *p_fmt ) video_format_FixRgb( &p_vout->fmt_in ); /* Initialize misc stuff */ + vout_control_Init( &p_vout->p->control ); p_vout->p->i_changes = 0; p_vout->p->b_fullscreen = 0; vout_chrono_Init( &p_vout->p->render, 5, 10000 ); /* Arbitrary initial time */ @@ -468,6 +469,7 @@ static void vout_Destructor( vlc_object_t * p_this ) vlc_mutex_destroy( &p_vout->p->picture_lock ); vlc_mutex_destroy( &p_vout->p->change_lock ); vlc_mutex_destroy( &p_vout->p->vfilter_lock ); + vout_control_Clean( &p_vout->p->control ); /* */ vout_statistic_Clean( &p_vout->p->statistic ); @@ -506,9 +508,10 @@ void vout_ChangePause( vout_thread_t *p_vout, bool b_paused, mtime_t i_date ) if (p_vout->p->displayed.decoded) p_vout->p->displayed.decoded->date += i_duration; - vlc_cond_signal( &p_vout->p->picture_wait ); vlc_mutex_unlock( &p_vout->p->picture_lock ); + vout_control_Wake( &p_vout->p->control ); + spu_OffsetSubtitleDate( p_vout->p->p_spu, i_duration ); } else @@ -554,8 +557,8 @@ void vout_Flush(vout_thread_t *vout, mtime_t date) Flush(vout, date, false, false); - vlc_cond_signal(&vout->p->picture_wait); vlc_mutex_unlock(&vout->p->picture_lock); + vout_control_Wake(&vout->p->control); } void vout_Reset(vout_thread_t *vout) @@ -568,8 +571,8 @@ void vout_Reset(vout_thread_t *vout) vout->p->pause.is_on = false; vout->p->pause.date = mdate(); - vlc_cond_signal( &vout->p->picture_wait ); vlc_mutex_unlock(&vout->p->picture_lock); + vout_control_Wake(&vout->p->control); } void vout_FixLeaks( vout_thread_t *vout ) @@ -596,8 +599,8 @@ void vout_FixLeaks( vout_thread_t *vout ) /* */ picture_pool_NonEmpty(vout->p->decoder_pool, false); - vlc_cond_signal(&vout->p->picture_wait); vlc_mutex_unlock(&vout->p->picture_lock); + vout_control_Wake(&vout->p->control); } void vout_NextPicture(vout_thread_t *vout, mtime_t *duration) { @@ -606,9 +609,11 @@ void vout_NextPicture(vout_thread_t *vout, mtime_t *duration) vout->p->b_picture_empty = false; vout->p->step.is_requested = true; - /* FIXME I highly doubt that it can works with only one cond_t FIXME */ - vlc_cond_signal(&vout->p->picture_wait); + vlc_mutex_unlock(&vout->p->picture_lock); + + vout_control_Wake(&vout->p->control); + vlc_mutex_lock(&vout->p->picture_lock); while (vout->p->step.is_requested && !vout->p->b_picture_empty) vlc_cond_wait(&vout->p->picture_wait, &vout->p->picture_lock); @@ -1017,9 +1022,23 @@ static void *Thread(void *object) * Main loop - it is not executed if an error occurred during * initialization */ + mtime_t deadline = VLC_TS_INVALID; while (!vout->p->b_done && !vout->p->b_error) { + vout_control_cmd_t cmd; + + vlc_mutex_unlock(&vout->p->change_lock); + /* FIXME remove thoses ugly timeouts + */ + while (!vout_control_Pop(&vout->p->control, &cmd, deadline, 100000)) { + switch(cmd.type) { + default: + break; + } + vout_control_cmd_Clean(&cmd); + } + vlc_mutex_lock(&vout->p->change_lock); + /* */ - mtime_t deadline; if (ThreadManage(vout, &deadline, &interlacing, &postprocessing)) { vout->p->b_error = true; @@ -1028,16 +1047,6 @@ static void *Thread(void *object) ThreadDisplayOsdTitle(vout); ThreadChangeFilter(vout); - - vlc_mutex_unlock(&vout->p->change_lock); - - if (deadline > VLC_TS_INVALID) { - vlc_mutex_lock(&vout->p->picture_lock); - vlc_cond_timedwait(&vout->p->picture_wait, &vout->p->picture_lock, deadline); - vlc_mutex_unlock(&vout->p->picture_lock); - } - - vlc_mutex_lock(&vout->p->change_lock); } /* @@ -1064,6 +1073,7 @@ exit_thread: if (has_wrapper) vout_CloseWrapper(vout); + vout_control_Dead(&vout->p->control); return NULL; } diff --git a/src/video_output/vout_internal.h b/src/video_output/vout_internal.h index 21b358eaed..ee08763bc6 100644 --- a/src/video_output/vout_internal.h +++ b/src/video_output/vout_internal.h @@ -34,6 +34,7 @@ #include #include #include "vout_control.h" +#include "control.h" #include "snapshot.h" #include "statistic.h" #include "chrono.h" @@ -56,6 +57,7 @@ struct vout_thread_sys_t bool b_ready; bool b_done; bool b_error; + vout_control_t control; /* */ struct { diff --git a/src/video_output/vout_pictures.c b/src/video_output/vout_pictures.c index 5376a3faf8..3519caa70d 100644 --- a/src/video_output/vout_pictures.c +++ b/src/video_output/vout_pictures.c @@ -82,8 +82,9 @@ void vout_PutPicture( vout_thread_t *p_vout, picture_t *p_pic ) p_pic->p_next = NULL; picture_fifo_Push(p_vout->p->decoder_fifo, p_pic); - vlc_cond_signal( &p_vout->p->picture_wait ); vlc_mutex_unlock( &p_vout->p->picture_lock ); + + vout_control_Wake( &p_vout->p->control); } /** @@ -95,8 +96,9 @@ void vout_ReleasePicture( vout_thread_t *p_vout, picture_t *p_pic ) picture_Release( p_pic ); - vlc_cond_signal( &p_vout->p->picture_wait ); vlc_mutex_unlock( &p_vout->p->picture_lock ); + + vout_control_Wake( &p_vout->p->control); } /**