[vlc-commits] vout: spu: handle secondary channel order

Roland Bewick git at videolan.org
Tue Jun 25 20:55:22 CEST 2019


vlc | branch: master | Roland Bewick <roland.bewick at gmail.com> | Wed May 22 01:08:31 2019 +0700| [eb10f0b60edf5ac22d1b843ba794a67bed269fcd] | committer: Thomas Guillem

vout: spu: handle secondary channel order

Signed-off-by: Thomas Guillem <thomas at gllm.fr>

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=eb10f0b60edf5ac22d1b843ba794a67bed269fcd
---

 include/vlc_vout.h                  | 22 ++++++++++
 src/input/decoder.c                 |  3 +-
 src/video_output/video_output.c     |  5 ++-
 src/video_output/vout_internal.h    |  6 ++-
 src/video_output/vout_subpictures.c | 83 ++++++++++++++++++++++++++++++-------
 5 files changed, 98 insertions(+), 21 deletions(-)

diff --git a/include/vlc_vout.h b/include/vlc_vout.h
index da1a3a836c..5d66131825 100644
--- a/include/vlc_vout.h
+++ b/include/vlc_vout.h
@@ -71,6 +71,28 @@ struct vout_thread_t {
 #define VOUT_ALIGN_BOTTOM       0x0008
 #define VOUT_ALIGN_VMASK        0x000C
 
+/**
+ * vout or spu_channel order
+ */
+enum vlc_vout_order
+{
+    VLC_VOUT_ORDER_NONE,
+    /**
+     * There is only one primary vout/spu_channel
+     * For vouts: this is the first vout, probably embedded in the UI.
+     * For spu channels: main and first SPU channel.
+     */
+    VLC_VOUT_ORDER_PRIMARY,
+    /**
+     * There can be several secondary vouts or spu_channels
+     * For vouts: a secondary vout using its own window.
+     * For spu channels: a secondary spu channel that is placed in function of
+     * the primary one. See "secondary-sub-margin" and
+     * "secondary-sub-alignment".
+     */
+    VLC_VOUT_ORDER_SECONDARY,
+};
+
 /*****************************************************************************
  * Prototypes
  *****************************************************************************/
diff --git a/src/input/decoder.c b/src/input/decoder.c
index 160150b671..9877703122 100644
--- a/src/input/decoder.c
+++ b/src/input/decoder.c
@@ -637,7 +637,8 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec,
         }
 
         p_owner->i_spu_channel =
-            vout_RegisterSubpictureChannelInternal(p_vout, p_owner->p_clock);
+            vout_RegisterSubpictureChannelInternal(p_vout, p_owner->p_clock,
+                                                   NULL);
         p_owner->i_spu_order = 0;
 
         if (p_owner->i_spu_channel == VOUT_SPU_CHANNEL_INVALID)
diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c
index 834521b877..11ed7c3eac 100644
--- a/src/video_output/video_output.c
+++ b/src/video_output/video_output.c
@@ -276,13 +276,14 @@ ssize_t vout_RegisterSubpictureChannel( vout_thread_t *vout )
 }
 
 ssize_t vout_RegisterSubpictureChannelInternal(vout_thread_t *vout,
-                                               vlc_clock_t *clock)
+                                               vlc_clock_t *clock,
+                                               enum vlc_vout_order *out_order)
 {
     assert(!vout->p->dummy);
     ssize_t channel = VOUT_SPU_CHANNEL_INVALID;
 
     if (vout->p->spu)
-        channel = spu_RegisterChannelInternal(vout->p->spu, clock);
+        channel = spu_RegisterChannelInternal(vout->p->spu, clock, out_order);
 
     return channel;
 }
diff --git a/src/video_output/vout_internal.h b/src/video_output/vout_internal.h
index 5490b2b12c..bd25a244d6 100644
--- a/src/video_output/vout_internal.h
+++ b/src/video_output/vout_internal.h
@@ -261,8 +261,10 @@ vout_display_t *vout_OpenWrapper(vout_thread_t *, const char *,
 void vout_CloseWrapper(vout_thread_t *, vout_display_t *vd);
 
 /* */
-ssize_t vout_RegisterSubpictureChannelInternal( vout_thread_t *, vlc_clock_t *clock );
-ssize_t spu_RegisterChannelInternal( spu_t *, vlc_clock_t * );
+ssize_t vout_RegisterSubpictureChannelInternal( vout_thread_t *,
+                                                vlc_clock_t *clock,
+                                                enum vlc_vout_order *out_order );
+ssize_t spu_RegisterChannelInternal( spu_t *, vlc_clock_t *, enum vlc_vout_order * );
 void spu_Attach( spu_t *, input_thread_t *input );
 void spu_Detach( spu_t * );
 void spu_SetClockDelay(spu_t *spu, size_t channel_id, vlc_tick_t delay);
diff --git a/src/video_output/vout_subpictures.c b/src/video_output/vout_subpictures.c
index 18a40f51a8..24f1a0c6f0 100644
--- a/src/video_output/vout_subpictures.c
+++ b/src/video_output/vout_subpictures.c
@@ -54,6 +54,7 @@ typedef struct {
     vlc_tick_t start;
     vlc_tick_t stop;
     bool is_late;
+    enum vlc_vout_order channel_order;
 } spu_render_entry_t;
 
 typedef struct VLC_VECTOR(spu_render_entry_t) spu_render_vector;
@@ -61,6 +62,7 @@ typedef struct VLC_VECTOR(spu_render_entry_t) spu_render_vector;
 struct spu_channel {
     spu_render_vector entries;
     size_t id;
+    enum vlc_vout_order order;
     vlc_clock_t *clock;
     vlc_tick_t delay;
     float rate;
@@ -87,6 +89,13 @@ struct spu_private_t {
     } crop;                                                  /**< cropping */
 
     int margin;                        /**< force position of a subpicture */
+    /**
+     * Move the secondary subtites vertically.
+     * Note: Primary sub margin is applied to all sub tracks and is absolute.
+     * Secondary sub margin is not absolute to enable overlap detection.
+     */
+    int secondary_margin;
+    int secondary_alignment;       /**< Force alignment for secondary subs */
     video_palette_t palette;              /**< force palette of subpicture */
 
     /* Subpiture filters */
@@ -104,12 +113,13 @@ struct spu_private_t {
 };
 
 static void spu_channel_Init(struct spu_channel *channel, size_t id,
-                             vlc_clock_t *clock)
+                             enum vlc_vout_order order, vlc_clock_t *clock)
 {
     channel->id = id;
     channel->clock = clock;
     channel->delay = 0;
     channel->rate = 1.f;
+    channel->order = order;
 
     vlc_vector_init(&channel->entries);
 }
@@ -167,7 +177,7 @@ static struct spu_channel *spu_GetChannel(spu_t *spu, size_t channel_id)
     vlc_assert_unreachable();
 }
 
-static ssize_t spu_GetFreeChannelId(spu_t *spu)
+static ssize_t spu_GetFreeChannelId(spu_t *spu, enum vlc_vout_order *order)
 {
     spu_private_t *sys = spu->p;
 
@@ -175,6 +185,8 @@ static ssize_t spu_GetFreeChannelId(spu_t *spu)
         return VOUT_SPU_CHANNEL_INVALID;
 
     size_t id;
+    if (order)
+        *order = VLC_VOUT_ORDER_PRIMARY;
     for (id = VOUT_SPU_CHANNEL_OSD_COUNT; id < sys->channels.size + 1; ++id)
     {
         bool used = false;
@@ -183,6 +195,8 @@ static ssize_t spu_GetFreeChannelId(spu_t *spu)
             if (sys->channels.data[i].id == id)
             {
                 used = true;
+                if (order)
+                    *order = VLC_VOUT_ORDER_SECONDARY;
                 break;
             }
         }
@@ -500,23 +514,24 @@ static void SpuAreaFitInside(spu_area_t *area, const spu_area_t *boundary)
  */
 static void SpuRegionPlace(int *x, int *y,
                            const subpicture_t *subpic,
-                           const subpicture_region_t *region)
+                           const subpicture_region_t *region,
+                           int i_align)
 {
     assert(region->i_x != INT_MAX && region->i_y != INT_MAX);
     if (subpic->b_absolute) {
         *x = region->i_x;
         *y = region->i_y;
     } else {
-        if (region->i_align & SUBPICTURE_ALIGN_TOP)
-            *y = region->i_y;
-        else if (region->i_align & SUBPICTURE_ALIGN_BOTTOM)
+        if (i_align & SUBPICTURE_ALIGN_TOP)
+            *y = region->i_y + ( subpic->b_subtitle ? region->fmt.i_visible_height : 0 );
+        else if (i_align & SUBPICTURE_ALIGN_BOTTOM)
             *y = subpic->i_original_picture_height - region->fmt.i_visible_height - region->i_y;
         else
             *y = subpic->i_original_picture_height / 2 - region->fmt.i_visible_height / 2;
 
-        if (region->i_align & SUBPICTURE_ALIGN_LEFT)
+        if (i_align & SUBPICTURE_ALIGN_LEFT)
             *x = region->i_x;
-        else if (region->i_align & SUBPICTURE_ALIGN_RIGHT)
+        else if (i_align & SUBPICTURE_ALIGN_RIGHT)
             *x = subpic->i_original_picture_width - region->fmt.i_visible_width - region->i_x;
         else
             *x = subpic->i_original_picture_width / 2 - region->fmt.i_visible_width / 2;
@@ -743,7 +758,10 @@ spu_SelectSubpictures(spu_t *spu, vlc_tick_t system_now,
             if (is_rejeted)
                 spu_channel_DeleteSubpicture(channel, current);
             else
+            {
+                render_entry->channel_order = channel->order;
                 subpicture_array[(*subpicture_count)++] = *render_entry;
+            }
         }
     }
 
@@ -815,15 +833,41 @@ static void SpuRenderRegion(spu_t *spu,
 
     /* Compute the margin which is expressed in destination pixel unit
      * The margin is applied only to subtitle and when no forced crop is
-     * requested (dvd menu) */
+     * requested (dvd menu).
+     * Note: Margin will also be applied to secondary subtitles if they exist
+     * to ensure that overlap does not occur. */
     int y_margin = 0;
     if (!crop_requested && subpic->b_subtitle)
         y_margin = spu_invscale_h(sys->margin, scale_size);
 
     /* Place the picture
      * We compute the position in the rendered size */
+
+    int i_align = region->i_align;
+    if (entry->channel_order == VLC_VOUT_ORDER_SECONDARY)
+        i_align = sys->secondary_alignment >= 0 ? sys->secondary_alignment : i_align;
+
     SpuRegionPlace(&x_offset, &y_offset,
-                   subpic, region);
+                   subpic, region, i_align);
+
+    if (entry->channel_order == VLC_VOUT_ORDER_SECONDARY)
+    {
+        int secondary_margin =
+            spu_invscale_h(sys->secondary_margin, scale_size);
+        if (!subpic->b_absolute)
+        {
+            /* Move the secondary subtitles by the secondary margin before
+             * overlap detection. This way, overlaps will be resolved if they
+             * still exist.  */
+            y_offset -= secondary_margin;
+        }
+        else
+        {
+            /* Use an absolute margin for secondary subpictures that have
+             * already been placed but have been moved by the user */
+            y_margin += secondary_margin;
+        }
+    }
 
     /* Save this position for subtitle overlap support
      * it is really important that there are given without scale_size applied */
@@ -835,7 +879,7 @@ static void SpuRenderRegion(spu_t *spu,
     /* Handle overlapping subtitles when possible */
     if (subpic->b_subtitle && !subpic->b_absolute)
         SpuAreaFixOverlap(dst_area, subtitle_area, subtitle_area_count,
-                          region->i_align);
+                          i_align);
 
     /* we copy the area: for the subtitle overlap support we want
      * to only save the area without margin applied */
@@ -1415,7 +1459,7 @@ spu_t *spu_Create(vlc_object_t *object, vout_thread_t *vout)
     for (size_t i = 0; i < VOUT_SPU_CHANNEL_OSD_COUNT; ++i)
     {
         struct spu_channel channel;
-        spu_channel_Init(&channel, i, NULL);
+        spu_channel_Init(&channel, i, VLC_VOUT_ORDER_PRIMARY, NULL);
         vlc_vector_push(&sys->channels, channel);
     }
 
@@ -1423,6 +1467,10 @@ spu_t *spu_Create(vlc_object_t *object, vout_thread_t *vout)
     vlc_mutex_init(&sys->lock);
 
     sys->margin = var_InheritInteger(spu, "sub-margin");
+    sys->secondary_margin = var_InheritInteger(spu, "secondary-sub-margin");
+
+    sys->secondary_alignment = var_InheritInteger(spu,
+                                                  "secondary-sub-alignment");
 
     sys->source_chain_update = NULL;
     sys->filter_chain_update = NULL;
@@ -1761,18 +1809,20 @@ subpicture_t *spu_Render(spu_t *spu,
     return render;
 }
 
-ssize_t spu_RegisterChannelInternal(spu_t *spu, vlc_clock_t *clock)
+ssize_t spu_RegisterChannelInternal(spu_t *spu, vlc_clock_t *clock,
+                                    enum vlc_vout_order *order)
 {
     spu_private_t *sys = spu->p;
 
     vlc_mutex_lock(&sys->lock);
 
-    ssize_t channel_id = spu_GetFreeChannelId(spu);
+    ssize_t channel_id = spu_GetFreeChannelId(spu, order);
 
     if (channel_id != VOUT_SPU_CHANNEL_INVALID)
     {
         struct spu_channel channel;
-        spu_channel_Init(&channel, channel_id, clock);
+        spu_channel_Init(&channel, channel_id,
+                         order ? *order : VLC_VOUT_ORDER_PRIMARY, clock);
         if (vlc_vector_push(&sys->channels, channel))
         {
             vlc_mutex_unlock(&sys->lock);
@@ -1787,7 +1837,8 @@ ssize_t spu_RegisterChannelInternal(spu_t *spu, vlc_clock_t *clock)
 
 ssize_t spu_RegisterChannel(spu_t *spu)
 {
-    return spu_RegisterChannelInternal(spu, NULL);
+    /* Public call, order is always primary (used for OSD or dvd/bluray spus) */
+    return spu_RegisterChannelInternal(spu, NULL, NULL);
 }
 
 static void spu_channel_Clear(struct spu_channel *channel)



More information about the vlc-commits mailing list