<div><br></div><div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, 21 Jun 2019 at 4:21 PM, Thomas Guillem <<a href="mailto:thomas@gllm.fr">thomas@gllm.fr</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
On Fri, Jun 21, 2019, at 07:09, Roland Bewick wrote:<br>
> <br>
> On 20/06/2019 10:23 PM, Thomas Guillem wrote:<br>
> > From: Roland Bewick <<a href="mailto:roland.bewick@gmail.com" target="_blank">roland.bewick@gmail.com</a>><br>
> ><br>
> > Signed-off-by: Thomas Guillem <<a href="mailto:thomas@gllm.fr" target="_blank">thomas@gllm.fr</a>><br>
> > ---<br>
> >   include/vlc_vout.h                  | 10 ++++<br>
> >   src/input/decoder.c                 |  3 +-<br>
> >   src/video_output/video_output.c     |  5 +-<br>
> >   src/video_output/vout_internal.h    |  6 ++-<br>
> >   src/video_output/vout_subpictures.c | 83 +++++++++++++++++++++++------<br>
> >   5 files changed, 86 insertions(+), 21 deletions(-)<br>
> ><br>
> > diff --git a/include/vlc_vout.h b/include/vlc_vout.h<br>
> > index da1a3a836c..42fdec9c26 100644<br>
> > --- a/include/vlc_vout.h<br>
> > +++ b/include/vlc_vout.h<br>
> > @@ -71,6 +71,16 @@ struct vout_thread_t {<br>
> >   #define VOUT_ALIGN_BOTTOM       0x0008<br>
> >   #define VOUT_ALIGN_VMASK        0x000C<br>
> >   <br>
> > +/**<br>
> > + * SPU/Subtitle channel order<br>
> > + */<br>
> > +enum vlc_spu_channel_order<br>
> > +{<br>
> > +    VLC_SPU_CHANNEL_ORDER_NONE,<br>
> > +    VLC_SPU_CHANNEL_ORDER_PRIMARY,<br>
> > +    VLC_SPU_CHANNEL_ORDER_SECONDARY,<br>
> > +};<br>
> <br>
> Maybe this enum can also be used for the audio / video? tracks in the <br>
> future, if given a more general name.<br>
<br>
There is no such order for audio: every tracks will be mixed together, there won't be a primary or secondary one.<br>
For video: there can be an order, the first video track should be the video integrated in the UI.<br>
<br>
Maybe it can be VLC_VOUT_ORDER then.</blockquote><div dir="auto"><br></div><div dir="auto">True - I guess you cannot import audio tracks and therefore don’t have to worry about individual delays for the audio.</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
<br>
> <br>
> I was thinking it could be nice to retrieve / set delay by its order. <br>
> Maybe that would solve the issue of setting a category delay for <br>
> subtitles. Instead, set a delay for the primary / secondary order and it <br>
> doesn't matter if the track exists or not.<br>
> <br>
> > +<br>
> >   /*****************************************************************************<br>
> >    * Prototypes<br>
> >    *****************************************************************************/<br>
> > diff --git a/src/input/decoder.c b/src/input/decoder.c<br>
> > index 3b19b51d66..3a47c01ddf 100644<br>
> > --- a/src/input/decoder.c<br>
> > +++ b/src/input/decoder.c<br>
> > @@ -630,7 +630,8 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec,<br>
> >       {<br>
> >           ssize_t old_spu_channel = p_owner->i_spu_channel;<br>
> >           p_owner->i_spu_channel =<br>
> > -            vout_RegisterSubpictureChannelInternal(p_vout, p_owner->p_clock);<br>
> > +            vout_RegisterSubpictureChannelInternal(p_vout, p_owner->p_clock,<br>
> > +                                                   NULL);<br>
> >           p_owner->i_spu_order = 0;<br>
> >   <br>
> >           if (p_owner->i_spu_channel != -1)<br>
> > diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c<br>
> > index a3ef144da1..ab3666da81 100644<br>
> > --- a/src/video_output/video_output.c<br>
> > +++ b/src/video_output/video_output.c<br>
> > @@ -276,13 +276,14 @@ ssize_t vout_RegisterSubpictureChannel( vout_thread_t *vout )<br>
> >   }<br>
> >   <br>
> >   ssize_t vout_RegisterSubpictureChannelInternal(vout_thread_t *vout,<br>
> > -                                               vlc_clock_t *clock)<br>
> > +                                               vlc_clock_t *clock,<br>
> > +                                               enum vlc_spu_channel_order *out_order)<br>
> >   {<br>
> >       assert(!vout->p->dummy);<br>
> >       ssize_t channel = VOUT_SPU_CHANNEL_INVALID;<br>
> >   <br>
> >       if (vout->p->spu)<br>
> > -        channel = spu_RegisterChannelInternal(vout->p->spu, clock);<br>
> > +        channel = spu_RegisterChannelInternal(vout->p->spu, clock, out_order);<br>
> >   <br>
> >       return channel;<br>
> >   }<br>
> > diff --git a/src/video_output/vout_internal.h b/src/video_output/vout_internal.h<br>
> > index 5490b2b12c..699ade93ae 100644<br>
> > --- a/src/video_output/vout_internal.h<br>
> > +++ b/src/video_output/vout_internal.h<br>
> > @@ -261,8 +261,10 @@ vout_display_t *vout_OpenWrapper(vout_thread_t *, const char *,<br>
> >   void vout_CloseWrapper(vout_thread_t *, vout_display_t *vd);<br>
> >   <br>
> >   /* */<br>
> > -ssize_t vout_RegisterSubpictureChannelInternal( vout_thread_t *, vlc_clock_t *clock );<br>
> > -ssize_t spu_RegisterChannelInternal( spu_t *, vlc_clock_t * );<br>
> > +ssize_t vout_RegisterSubpictureChannelInternal( vout_thread_t *,<br>
> > +                                                vlc_clock_t *clock,<br>
> > +                                                enum vlc_spu_channel_order *out_order );<br>
> > +ssize_t spu_RegisterChannelInternal( spu_t *, vlc_clock_t *, enum vlc_spu_channel_order * );<br>
> >   void spu_Attach( spu_t *, input_thread_t *input );<br>
> >   void spu_Detach( spu_t * );<br>
> >   void spu_SetClockDelay(spu_t *spu, size_t channel_id, vlc_tick_t delay);<br>
> > diff --git a/src/video_output/vout_subpictures.c b/src/video_output/vout_subpictures.c<br>
> > index 18a40f51a8..8d209bbbde 100644<br>
> > --- a/src/video_output/vout_subpictures.c<br>
> > +++ b/src/video_output/vout_subpictures.c<br>
> > @@ -54,6 +54,7 @@ typedef struct {<br>
> >       vlc_tick_t start;<br>
> >       vlc_tick_t stop;<br>
> >       bool is_late;<br>
> > +    enum vlc_spu_channel_order channel_order;<br>
> >   } spu_render_entry_t;<br>
> >   <br>
> >   typedef struct VLC_VECTOR(spu_render_entry_t) spu_render_vector;<br>
> > @@ -61,6 +62,7 @@ typedef struct VLC_VECTOR(spu_render_entry_t) spu_render_vector;<br>
> >   struct spu_channel {<br>
> >       spu_render_vector entries;<br>
> >       size_t id;<br>
> > +    enum vlc_spu_channel_order order;<br>
> >       vlc_clock_t *clock;<br>
> >       vlc_tick_t delay;<br>
> >       float rate;<br>
> > @@ -87,6 +89,13 @@ struct spu_private_t {<br>
> >       } crop;                                                  /**< cropping */<br>
> >   <br>
> >       int margin;                        /**< force position of a subpicture */<br>
> > +    /**<br>
> > +     * Move the secondary subtites vertically.<br>
> > +     * Note: Primary sub margin is applied to all sub tracks and is absolute.<br>
> > +     * Secondary sub margin is not absolute to enable overlap detection.<br>
> > +     */<br>
> > +    int secondary_margin;<br>
> > +    int secondary_alignment;       /**< Force alignment for secondary subs */<br>
> >       video_palette_t palette;              /**< force palette of subpicture */<br>
> >   <br>
> >       /* Subpiture filters */<br>
> > @@ -104,12 +113,13 @@ struct spu_private_t {<br>
> >   };<br>
> >   <br>
> >   static void spu_channel_Init(struct spu_channel *channel, size_t id,<br>
> > -                             vlc_clock_t *clock)<br>
> > +                             enum vlc_spu_channel_order order, vlc_clock_t *clock)<br>
> >   {<br>
> >       channel->id = id;<br>
> >       channel->clock = clock;<br>
> >       channel->delay = 0;<br>
> >       channel->rate = 1.f;<br>
> > +    channel->order = order;<br>
> >   <br>
> >       vlc_vector_init(&channel->entries);<br>
> >   }<br>
> > @@ -167,7 +177,7 @@ static struct spu_channel *spu_GetChannel(spu_t *spu, size_t channel_id)<br>
> >       vlc_assert_unreachable();<br>
> >   }<br>
> >   <br>
> > -static ssize_t spu_GetFreeChannelId(spu_t *spu)<br>
> > +static ssize_t spu_GetFreeChannelId(spu_t *spu, enum vlc_spu_channel_order *order)<br>
> >   {<br>
> >       spu_private_t *sys = spu->p;<br>
> >   <br>
> > @@ -175,6 +185,8 @@ static ssize_t spu_GetFreeChannelId(spu_t *spu)<br>
> >           return VOUT_SPU_CHANNEL_INVALID;<br>
> >   <br>
> >       size_t id;<br>
> > +    if (order)<br>
> > +        *order = VLC_SPU_CHANNEL_ORDER_PRIMARY;<br>
> >       for (id = VOUT_SPU_CHANNEL_OSD_COUNT; id < sys->channels.size + 1; ++id)<br>
> >       {<br>
> >           bool used = false;<br>
> > @@ -183,6 +195,8 @@ static ssize_t spu_GetFreeChannelId(spu_t *spu)<br>
> >               if (sys->channels.data[i].id == id)<br>
> >               {<br>
> >                   used = true;<br>
> > +                if (order)<br>
> > +                    *order = VLC_SPU_CHANNEL_ORDER_SECONDARY;<br>
> >                   break;<br>
> >               }<br>
> >           }<br>
> > @@ -500,23 +514,24 @@ static void SpuAreaFitInside(spu_area_t *area, const spu_area_t *boundary)<br>
> >    */<br>
> >   static void SpuRegionPlace(int *x, int *y,<br>
> >                              const subpicture_t *subpic,<br>
> > -                           const subpicture_region_t *region)<br>
> > +                           const subpicture_region_t *region,<br>
> > +                           int i_align)<br>
> >   {<br>
> >       assert(region->i_x != INT_MAX && region->i_y != INT_MAX);<br>
> >       if (subpic->b_absolute) {<br>
> >           *x = region->i_x;<br>
> >           *y = region->i_y;<br>
> >       } else {<br>
> > -        if (region->i_align & SUBPICTURE_ALIGN_TOP)<br>
> > -            *y = region->i_y;<br>
> > -        else if (region->i_align & SUBPICTURE_ALIGN_BOTTOM)<br>
> > +        if (i_align & SUBPICTURE_ALIGN_TOP)<br>
> > +            *y = region->i_y + ( subpic->b_subtitle ? region->fmt.i_visible_height : 0 );<br>
> > +        else if (i_align & SUBPICTURE_ALIGN_BOTTOM)<br>
> >               *y = subpic->i_original_picture_height - region->fmt.i_visible_height - region->i_y;<br>
> >           else<br>
> >               *y = subpic->i_original_picture_height / 2 - region->fmt.i_visible_height / 2;<br>
> >   <br>
> > -        if (region->i_align & SUBPICTURE_ALIGN_LEFT)<br>
> > +        if (i_align & SUBPICTURE_ALIGN_LEFT)<br>
> >               *x = region->i_x;<br>
> > -        else if (region->i_align & SUBPICTURE_ALIGN_RIGHT)<br>
> > +        else if (i_align & SUBPICTURE_ALIGN_RIGHT)<br>
> >               *x = subpic->i_original_picture_width - region->fmt.i_visible_width - region->i_x;<br>
> >           else<br>
> >               *x = subpic->i_original_picture_width / 2 - region->fmt.i_visible_width / 2;<br>
> > @@ -743,7 +758,10 @@ spu_SelectSubpictures(spu_t *spu, vlc_tick_t system_now,<br>
> >               if (is_rejeted)<br>
> >                   spu_channel_DeleteSubpicture(channel, current);<br>
> >               else<br>
> > +            {<br>
> > +                render_entry->channel_order = channel->order;<br>
> >                   subpicture_array[(*subpicture_count)++] = *render_entry;<br>
> > +            }<br>
> >           }<br>
> >       }<br>
> >   <br>
> > @@ -815,15 +833,41 @@ static void SpuRenderRegion(spu_t *spu,<br>
> >   <br>
> >       /* Compute the margin which is expressed in destination pixel unit<br>
> >        * The margin is applied only to subtitle and when no forced crop is<br>
> > -     * requested (dvd menu) */<br>
> > +     * requested (dvd menu).<br>
> > +     * Note: Margin will also be applied to secondary subtitles if they exist<br>
> > +     * to ensure that overlap does not occur. */<br>
> >       int y_margin = 0;<br>
> >       if (!crop_requested && subpic->b_subtitle)<br>
> >           y_margin = spu_invscale_h(sys->margin, scale_size);<br>
> >   <br>
> >       /* Place the picture<br>
> >        * We compute the position in the rendered size */<br>
> > +<br>
> > +    int i_align = region->i_align;<br>
> > +    if (entry->channel_order == VLC_SPU_CHANNEL_ORDER_SECONDARY)<br>
> > +        i_align = sys->secondary_alignment >= 0 ? sys->secondary_alignment : i_align;<br>
> > +<br>
> >       SpuRegionPlace(&x_offset, &y_offset,<br>
> > -                   subpic, region);<br>
> > +                   subpic, region, i_align);<br>
> > +<br>
> > +    if (entry->channel_order == VLC_SPU_CHANNEL_ORDER_SECONDARY)<br>
> > +    {<br>
> > +        int secondary_margin =<br>
> > +            spu_invscale_h(sys->secondary_margin, scale_size);<br>
> > +        if (!subpic->b_absolute)<br>
> > +        {<br>
> > +            /* Move the secondary subtitles by the secondary margin before<br>
> > +             * overlap detection. This way, overlaps will be resolved if they<br>
> > +             * still exist.  */<br>
> > +            y_offset -= secondary_margin;<br>
> > +        }<br>
> > +        else<br>
> > +        {<br>
> > +            /* Use an absolute margin for secondary subpictures that have<br>
> > +             * already been placed but have been moved by the user */<br>
> > +            y_margin += secondary_margin;<br>
> > +        }<br>
> > +    }<br>
> >   <br>
> >       /* Save this position for subtitle overlap support<br>
> >        * it is really important that there are given without scale_size applied */<br>
> > @@ -835,7 +879,7 @@ static void SpuRenderRegion(spu_t *spu,<br>
> >       /* Handle overlapping subtitles when possible */<br>
> >       if (subpic->b_subtitle && !subpic->b_absolute)<br>
> >           SpuAreaFixOverlap(dst_area, subtitle_area, subtitle_area_count,<br>
> > -                          region->i_align);<br>
> > +                          i_align);<br>
> >   <br>
> >       /* we copy the area: for the subtitle overlap support we want<br>
> >        * to only save the area without margin applied */<br>
> > @@ -1415,7 +1459,7 @@ spu_t *spu_Create(vlc_object_t *object, vout_thread_t *vout)<br>
> >       for (size_t i = 0; i < VOUT_SPU_CHANNEL_OSD_COUNT; ++i)<br>
> >       {<br>
> >           struct spu_channel channel;<br>
> > -        spu_channel_Init(&channel, i, NULL);<br>
> > +        spu_channel_Init(&channel, i, VLC_SPU_CHANNEL_ORDER_PRIMARY, NULL);<br>
> >           vlc_vector_push(&sys->channels, channel);<br>
> >       }<br>
> >   <br>
> > @@ -1423,6 +1467,10 @@ spu_t *spu_Create(vlc_object_t *object, vout_thread_t *vout)<br>
> >       vlc_mutex_init(&sys->lock);<br>
> >   <br>
> >       sys->margin = var_InheritInteger(spu, "sub-margin");<br>
> > +    sys->secondary_margin = var_InheritInteger(spu, "secondary-sub-margin");<br>
> > +<br>
> > +    sys->secondary_alignment = var_InheritInteger(spu,<br>
> > +                                                  "secondary-spu-alignment");<br>
> >   <br>
> >       sys->source_chain_update = NULL;<br>
> >       sys->filter_chain_update = NULL;<br>
> > @@ -1761,18 +1809,20 @@ subpicture_t *spu_Render(spu_t *spu,<br>
> >       return render;<br>
> >   }<br>
> >   <br>
> > -ssize_t spu_RegisterChannelInternal(spu_t *spu, vlc_clock_t *clock)<br>
> > +ssize_t spu_RegisterChannelInternal(spu_t *spu, vlc_clock_t *clock,<br>
> > +                                    enum vlc_spu_channel_order *order)<br>
> >   {<br>
> >       spu_private_t *sys = spu->p;<br>
> >   <br>
> >       vlc_mutex_lock(&sys->lock);<br>
> >   <br>
> > -    ssize_t channel_id = spu_GetFreeChannelId(spu);<br>
> > +    ssize_t channel_id = spu_GetFreeChannelId(spu, order);<br>
> >   <br>
> >       if (channel_id != VOUT_SPU_CHANNEL_INVALID)<br>
> >       {<br>
> >           struct spu_channel channel;<br>
> > -        spu_channel_Init(&channel, channel_id, clock);<br>
> > +        spu_channel_Init(&channel, channel_id,<br>
> > +                         order ? *order : VLC_SPU_CHANNEL_ORDER_PRIMARY, clock);<br>
> >           if (vlc_vector_push(&sys->channels, channel))<br>
> >           {<br>
> >               vlc_mutex_unlock(&sys->lock);<br>
> > @@ -1787,7 +1837,8 @@ ssize_t spu_RegisterChannelInternal(spu_t *spu, vlc_clock_t *clock)<br>
> >   <br>
> >   ssize_t spu_RegisterChannel(spu_t *spu)<br>
> >   {<br>
> > -    return spu_RegisterChannelInternal(spu, NULL);<br>
> > +    /* Public call, order is always primary (used for OSD or dvd/bluray spus) */<br>
> > +    return spu_RegisterChannelInternal(spu, NULL, NULL);<br>
> >   }<br>
> >   <br>
> >   static void spu_channel_Clear(struct spu_channel *channel)<br>
> _______________________________________________<br>
> vlc-devel mailing list<br>
> To unsubscribe or modify your subscription options:<br>
> <a href="https://mailman.videolan.org/listinfo/vlc-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/vlc-devel</a><br>
_______________________________________________<br>
vlc-devel mailing list<br>
To unsubscribe or modify your subscription options:<br>
<a href="https://mailman.videolan.org/listinfo/vlc-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/vlc-devel</a></blockquote></div></div>