[vlc-devel] [PATCH 10/16] Add support for multiple SPU clocks
Roland Bewick
roland.bewick at gmail.com
Tue May 21 20:08:34 CEST 2019
---
include/vlc_subpicture.h | 1 +
src/input/decoder.c | 12 ++--
src/misc/subpicture.c | 1 +
src/video_output/video_output.c | 24 +++++---
src/video_output/vout_internal.h | 20 ++++---
src/video_output/vout_subpictures.c | 115 +++++++++++++++++++++++++++++-------
6 files changed, 130 insertions(+), 43 deletions(-)
diff --git a/include/vlc_subpicture.h b/include/vlc_subpicture.h
index 5dc07d4d3b..4a646dc936 100644
--- a/include/vlc_subpicture.h
+++ b/include/vlc_subpicture.h
@@ -193,6 +193,7 @@ struct subpicture_t
/**@{*/
bool b_subtitle; /**< the picture is a movie subtitle */
unsigned int i_spu_id; /**< use spu-specific settings */
+ void *p_clock; /** controls when this picture will be displayed */
bool b_absolute; /**< position is absolute */
int i_original_picture_width; /**< original width of the movie */
int i_original_picture_height;/**< original height of the movie */
diff --git a/src/input/decoder.c b/src/input/decoder.c
index c26db520a3..1435bf2496 100644
--- a/src/input/decoder.c
+++ b/src/input/decoder.c
@@ -613,7 +613,7 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec,
if( p_owner->p_vout )
{
vlc_mutex_lock( &p_owner->lock );
- vout_SetSubpictureClock(p_owner->p_vout, NULL);
+ vout_RemoveSubpictureClock(p_owner->p_vout, p_owner->p_clock);
vout_Release(p_owner->p_vout);
p_owner->p_vout = NULL;
vlc_mutex_unlock( &p_owner->lock );
@@ -629,13 +629,13 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec,
vlc_mutex_lock( &p_owner->lock );
if( p_owner->p_vout )
{
- vout_SetSubpictureClock(p_owner->p_vout, NULL);
+ vout_RemoveSubpictureClock(p_owner->p_vout, p_owner->p_clock);
vout_Release(p_owner->p_vout);
}
p_owner->p_vout = p_vout;
vlc_mutex_unlock( &p_owner->lock );
- vout_SetSubpictureClock( p_vout, p_owner->p_clock );
+ vout_AddSubpictureClock( p_vout, p_owner->p_clock);
}
else
vout_Release(p_vout);
@@ -647,6 +647,7 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec,
p_subpic->i_order = p_owner->i_spu_order++;
p_subpic->b_subtitle = true;
p_subpic->i_spu_id = p_owner->i_spu_id;
+ p_subpic->p_clock = p_owner->p_clock;
}
return p_subpic;
@@ -1557,7 +1558,8 @@ static void OutputChangeDelay( decoder_t *p_dec, vlc_tick_t delay )
break;
case SPU_ES:
if( p_owner->p_vout != NULL )
- vout_ChangeSpuDelay( p_owner->p_vout, delay );
+ vout_ChangeSpuDelay( p_owner->p_vout, delay,
+ p_owner->p_clock );
break;
default:
vlc_assert_unreachable();
@@ -1971,7 +1973,7 @@ static void DeleteDecoder( decoder_t * p_dec )
{
vout_FlushSubpictureChannel( p_owner->p_vout,
p_owner->i_spu_channel );
- vout_SetSubpictureClock(p_owner->p_vout, NULL);
+ vout_RemoveSubpictureClock(p_owner->p_vout, p_owner->p_clock);
vout_Release(p_owner->p_vout);
}
break;
diff --git a/src/misc/subpicture.c b/src/misc/subpicture.c
index 3e2535492a..8c1ae51797 100644
--- a/src/misc/subpicture.c
+++ b/src/misc/subpicture.c
@@ -52,6 +52,7 @@ subpicture_t *subpicture_New( const subpicture_updater_t *p_upd )
p_subpic->b_subtitle = false;
p_subpic->i_alpha = 0xFF;
p_subpic->p_region = NULL;
+ p_subpic->p_clock = NULL;
if( p_upd )
{
diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c
index c941a3ded9..16e4be8f6b 100644
--- a/src/video_output/video_output.c
+++ b/src/video_output/video_output.c
@@ -280,12 +280,20 @@ int vout_RegisterSubpictureChannel( vout_thread_t *vout )
return channel;
}
-void vout_SetSubpictureClock( vout_thread_t *vout, vlc_clock_t *clock )
+void vout_AddSubpictureClock( vout_thread_t *vout, vlc_clock_t *clock )
{
assert(!vout->p->dummy);
vlc_mutex_lock(&vout->p->spu_lock);
if (vout->p->spu)
- spu_clock_Set(vout->p->spu, clock);
+ spu_clock_Add(vout->p->spu, clock);
+ vlc_mutex_unlock(&vout->p->spu_lock);
+}
+
+void vout_RemoveSubpictureClock( vout_thread_t *vout, vlc_clock_t *clock )
+{
+ vlc_mutex_lock(&vout->p->spu_lock);
+ if (vout->p->spu)
+ spu_clock_Remove(vout->p->spu, clock);
vlc_mutex_unlock(&vout->p->spu_lock);
}
@@ -1309,8 +1317,7 @@ static void vout_FlushUnlocked(vout_thread_t *vout, bool below,
vlc_mutex_lock(&vout->p->spu_lock);
if (vout->p->spu)
{
- spu_clock_Reset(vout->p->spu);
- spu_clock_SetDelay(vout->p->spu, vout->p->spu_delay);
+ spu_clock_ResetAll(vout->p->spu);
}
vlc_mutex_unlock(&vout->p->spu_lock);
}
@@ -1370,13 +1377,13 @@ void vout_ChangeRate(vout_thread_t *vout, float rate)
vout_control_Release(&sys->control);
}
-void vout_ChangeSpuDelay(vout_thread_t *vout, vlc_tick_t delay)
+void vout_ChangeSpuDelay(vout_thread_t *vout, vlc_tick_t delay,
+ vlc_clock_t *clock)
{
assert(!vout->p->dummy);
vlc_mutex_lock(&vout->p->spu_lock);
if (vout->p->spu)
- spu_clock_SetDelay(vout->p->spu, delay);
- vout->p->spu_delay = delay;
+ spu_clock_SetDelay(vout->p->spu, delay, clock);
vlc_mutex_unlock(&vout->p->spu_lock);
}
@@ -1935,10 +1942,9 @@ int vout_Request(const vout_configuration_t *cfg, input_thread_t *input)
} else
vout_UpdateWindowSize(vout);
- sys->delay = sys->spu_delay = 0;
+ sys->delay = 0;
sys->rate = sys->spu_rate = 1.f;
sys->clock = cfg->clock;
- sys->delay = sys->spu_delay = 0;
vlc_mutex_unlock(&sys->window_lock);
diff --git a/src/video_output/vout_internal.h b/src/video_output/vout_internal.h
index ac2feebe93..3a37f8e85d 100644
--- a/src/video_output/vout_internal.h
+++ b/src/video_output/vout_internal.h
@@ -71,9 +71,8 @@ struct vout_thread_sys_t
vlc_clock_t *clock;
float rate;
- float spu_rate;
+ float spu_rate; /* TODO: Move to spu_private_t */
vlc_tick_t delay;
- vlc_tick_t spu_delay;
/* */
video_format_t original; /* Original format ie coming from the decoder */
@@ -260,13 +259,15 @@ int vout_OpenWrapper(vout_thread_t *, const char *,
const vout_display_cfg_t *);
void vout_CloseWrapper(vout_thread_t *);
-/* */
-void vout_SetSubpictureClock(vout_thread_t *vout, vlc_clock_t *clock);
+/* TODO: https://trac.videolan.org/vlc/ticket/22273#ticket */
+void vout_AddSubpictureClock(vout_thread_t *vout, vlc_clock_t *clock);
+void vout_RemoveSubpictureClock(vout_thread_t *vout, vlc_clock_t *clock);
void spu_Attach( spu_t *, input_thread_t *input );
void spu_Detach( spu_t * );
-void spu_clock_Set(spu_t *, vlc_clock_t *);
-void spu_clock_Reset(spu_t *);
-void spu_clock_SetDelay(spu_t *spu, vlc_tick_t delay);
+void spu_clock_Add(spu_t *, vlc_clock_t *);
+void spu_clock_Remove(spu_t *, vlc_clock_t *);
+void spu_clock_ResetAll(spu_t *);
+void spu_clock_SetDelay(spu_t *spu, vlc_tick_t delay, vlc_clock_t *clock);
void spu_ChangeMargin(spu_t *, int);
void spu_SetHighlight(spu_t *, const vlc_spu_highlight_t*);
@@ -294,10 +295,11 @@ void vout_ChangeDelay( vout_thread_t *, vlc_tick_t delay );
*/
void vout_ChangeSpuRate( vout_thread_t *, float rate );
/**
- * This function will change the delay of the spu channel
+ * This function will change the delay of an spu clock
* It is thread safe
*/
-void vout_ChangeSpuDelay( vout_thread_t *, vlc_tick_t delay );
+void vout_ChangeSpuDelay( vout_thread_t *, vlc_tick_t delay,
+ vlc_clock_t *clock );
/**
diff --git a/src/video_output/vout_subpictures.c b/src/video_output/vout_subpictures.c
index 2e6087ca1f..808e144c00 100644
--- a/src/video_output/vout_subpictures.c
+++ b/src/video_output/vout_subpictures.c
@@ -55,6 +55,10 @@
/* ID of the primary SPU. Secondary SPU IDs will be higher. */
#define SPU_ID_PRIMARY 1
+/* How many SPU clocks can be used simultaneously. Secondary
+ SPUs may have different delay therefore require their own clock. */
+#define SPU_MAX_CLOCKS 2
+
/* Hold of subpicture with converted ts */
typedef struct {
subpicture_t *subpicture;
@@ -75,7 +79,9 @@ struct spu_private_t {
vlc_mutex_t lock; /* lock to protect all followings fields */
input_thread_t *input;
- vlc_clock_t *clock;
+ /* TODO: Extract primary/secondary dependent members to a new object? */
+ vlc_clock_t *clocks[SPU_MAX_CLOCKS]; /* one for each selected sub track */
+ vlc_tick_t delays[SPU_MAX_CLOCKS]; /* delays applied to clocks above */
spu_heap_t heap;
@@ -538,15 +544,37 @@ static int SpuRenderCmp(const void *s0, const void *s1)
return r;
}
+static int SpuGetClockIndex(spu_t *spu, vlc_clock_t *spu_clock)
+{
+ spu_private_t *sys = spu->p;
+ int index = 0; /* If no clock found, use the first clock index */
+ for (int i = 1; i < SPU_MAX_CLOCKS; i++)
+ {
+ if (sys->clocks[i] && spu_clock == sys->clocks[i])
+ {
+ index = i;
+ break;
+ }
+ }
+ return index;
+}
+
static int SpuConvertDates(spu_t *spu, vlc_tick_t system_now,
spu_render_entry_t *render_entries, float rate)
{
spu_private_t *sys = spu->p;
- /* Put every spu start and stop ts into the same array to convert them in
- * one shot */
- vlc_tick_t date_array[VOUT_MAX_SUBPICTURES *2];
+ /* Put every spu start and stop ts into an array based on which
+ * clock the spu entry belongs to.
+ * All start and stop times for the same clock can then be converted together */
+ vlc_tick_t date_array[SPU_MAX_CLOCKS][VOUT_MAX_SUBPICTURES *2];
size_t entry_count = 0;
+ bool hasEntry[SPU_MAX_CLOCKS];
+ for (int i = 0; i < SPU_MAX_CLOCKS; i++)
+ {
+ hasEntry[i] = false;
+ }
+
for (size_t index = 0; index < VOUT_MAX_SUBPICTURES; index++)
{
spu_heap_entry_t *entry = &sys->heap.entry[index];
@@ -555,17 +583,22 @@ static int SpuConvertDates(spu_t *spu, vlc_tick_t system_now,
if (!current)
continue;
- date_array[entry_count * 2] = current->i_start;
- date_array[entry_count * 2 + 1] = current->i_stop;
+ int clock_index = SpuGetClockIndex(spu, current->p_clock);
+ hasEntry[clock_index] = true;
+ date_array[clock_index][entry_count * 2] = current->i_start;
+ date_array[clock_index][entry_count * 2 + 1] = current->i_stop;
entry_count++;
}
if (entry_count == 0)
return 0;
/* Convert all spu ts */
- if (sys->clock)
- vlc_clock_ConvertArrayToSystem(sys->clock, system_now, date_array,
- entry_count * 2, rate);
+ for (int i = 0; i < SPU_MAX_CLOCKS; i++)
+ {
+ if (hasEntry[i] && sys->clocks[i])
+ vlc_clock_ConvertArrayToSystem(sys->clocks[i], system_now,
+ date_array[i], entry_count * 2, rate);
+ }
/* Put back the converted ts into the output spu_render_entry_t struct */
entry_count = 0;
@@ -579,9 +612,12 @@ static int SpuConvertDates(spu_t *spu, vlc_tick_t system_now,
render_entry->subpicture = NULL;
else
{
+ int clock_index = SpuGetClockIndex(spu, current->p_clock);
render_entry->subpicture = current;
- render_entry->start = date_array[entry_count * 2];
- render_entry->stop = date_array[entry_count * 2 + 1];
+ render_entry->start =
+ date_array[clock_index][entry_count * 2];
+ render_entry->stop =
+ date_array[clock_index][entry_count * 2 + 1];
entry_count++;
}
}
@@ -1399,7 +1435,11 @@ spu_t *spu_Create(vlc_object_t *object, vout_thread_t *vout)
SpuHeapInit(&sys->heap);
- sys->clock = NULL;
+ for (int i = 0; i < SPU_MAX_CLOCKS; i++)
+ {
+ sys->clocks[i] = NULL;
+ sys->delays[i] = 0;
+ }
sys->text = NULL;
sys->scale = NULL;
sys->scale_yuvp = NULL;
@@ -1509,21 +1549,56 @@ void spu_Detach(spu_t *spu)
vlc_mutex_unlock(&spu->p->lock);
}
-void spu_clock_Set(spu_t *spu, vlc_clock_t *clock)
+void spu_clock_Add(spu_t *spu, vlc_clock_t *clock)
+{
+ for (int i = 0; i < SPU_MAX_CLOCKS; i++)
+ {
+ if (spu->p->clocks[i] == NULL)
+ {
+ spu->p->clocks[i] = clock;
+ return;
+ }
+ }
+ msg_Err(spu, "Maximum SPU clock count exceeded");
+}
+
+void spu_clock_Remove(spu_t *spu, vlc_clock_t *clock)
{
- spu->p->clock = clock;
+ for (int i = 0; i < SPU_MAX_CLOCKS; i++)
+ {
+ if (spu->p->clocks[i] == clock)
+ {
+ spu->p->clocks[i] = NULL;
+ return;
+ }
+ }
+ msg_Err(spu, "Clock not in SPU clocks list: %p", clock);
}
-void spu_clock_Reset(spu_t *spu)
+void spu_clock_ResetAll(spu_t *spu)
{
- if (spu->p->clock)
- vlc_clock_Reset(spu->p->clock);
+ for (int i = 0; i < SPU_MAX_CLOCKS; i++)
+ {
+ if (spu->p->clocks[i])
+ {
+ vlc_clock_Reset(spu->p->clocks[i]);
+ vlc_clock_SetDelay(spu->p->clocks[i], spu->p->delays[i]);
+ }
+ }
}
-void spu_clock_SetDelay(spu_t *spu, vlc_tick_t delay)
+void spu_clock_SetDelay(spu_t *spu, vlc_tick_t delay, vlc_clock_t *clock)
{
- if (spu->p->clock)
- vlc_clock_SetDelay(spu->p->clock, delay);
+ for (int i = 0; i < SPU_MAX_CLOCKS; i++)
+ {
+ if (spu->p->clocks[i] == clock)
+ {
+ vlc_clock_SetDelay(spu->p->clocks[i], delay);
+ spu->p->delays[i] = delay;
+ return;
+ }
+ }
+ msg_Err(spu, "Clock not in SPU clocks list: %p", clock);
}
/**
--
2.11.0
More information about the vlc-devel
mailing list