Commit 1618a00d authored by Laurent Aimar's avatar Laurent Aimar

Added API to simplify/clean up vout controls.

parent 3624290f
......@@ -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 \
......
/*****************************************************************************
* control.c : vout internal control
*****************************************************************************
* Copyright (C) 2009 Laurent Aimar
* $Id$
*
* Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
*
* 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 <vlc_common.h>
#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;
}
/*****************************************************************************
* control.h : vout internal control
*****************************************************************************
* Copyright (C) 2009-2010 Laurent Aimar
* $Id$
*
* Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
*
* 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
......@@ -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;
}
......
......@@ -34,6 +34,7 @@
#include <vlc_picture_pool.h>
#include <vlc_vout_display.h>
#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 {
......
......@@ -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);
}
/**
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment