[vlc-devel] [PATCH 09/15] Add support for multiple SPU clocks

Roland Bewick roland.bewick at gmail.com
Tue May 14 11:40:08 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    |  21 ++++---
 src/video_output/vout_subpictures.c | 115 +++++++++++++++++++++++++++++-------
 6 files changed, 131 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 fbdacc55f6..e6dc3c9e06 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);
 }
 
@@ -1940,10 +1947,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 129d0993cf..915639acf9 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 */
@@ -261,14 +260,17 @@ 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);
+
 int spu_ProcessMouse(spu_t *, const vlc_mouse_t *, const video_format_t *);
 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*);
 
@@ -296,10 +298,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 9fdbf0dc94..4050e9ea09 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;
 
@@ -539,15 +545,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];
@@ -556,17 +584,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;
@@ -580,9 +613,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++;
         }
     }
@@ -1400,7 +1436,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;
@@ -1512,21 +1552,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