[vlc-devel] [PATCH 08/20] vout: spu: handle secondary channel order

Roland Bewick roland.bewick at gmail.com
Fri Jun 21 11:32:44 CEST 2019


On Fri, 21 Jun 2019 at 4:21 PM, Thomas Guillem <thomas at gllm.fr> wrote:

>
> On Fri, Jun 21, 2019, at 07:09, Roland Bewick wrote:
> >
> > On 20/06/2019 10:23 PM, Thomas Guillem wrote:
> > > From: Roland Bewick <roland.bewick at gmail.com>
> > >
> > > Signed-off-by: Thomas Guillem <thomas at gllm.fr>
> > > ---
> > >   include/vlc_vout.h                  | 10 ++++
> > >   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, 86 insertions(+), 21 deletions(-)
> > >
> > > diff --git a/include/vlc_vout.h b/include/vlc_vout.h
> > > index da1a3a836c..42fdec9c26 100644
> > > --- a/include/vlc_vout.h
> > > +++ b/include/vlc_vout.h
> > > @@ -71,6 +71,16 @@ struct vout_thread_t {
> > >   #define VOUT_ALIGN_BOTTOM       0x0008
> > >   #define VOUT_ALIGN_VMASK        0x000C
> > >
> > > +/**
> > > + * SPU/Subtitle channel order
> > > + */
> > > +enum vlc_spu_channel_order
> > > +{
> > > +    VLC_SPU_CHANNEL_ORDER_NONE,
> > > +    VLC_SPU_CHANNEL_ORDER_PRIMARY,
> > > +    VLC_SPU_CHANNEL_ORDER_SECONDARY,
> > > +};
> >
> > Maybe this enum can also be used for the audio / video? tracks in the
> > future, if given a more general name.
>
> There is no such order for audio: every tracks will be mixed together,
> there won't be a primary or secondary one.
> For video: there can be an order, the first video track should be the
> video integrated in the UI.
>
> Maybe it can be VLC_VOUT_ORDER then.


True - I guess you cannot import audio tracks and therefore don’t have to
worry about individual delays for the audio.

>
>
> >
> > I was thinking it could be nice to retrieve / set delay by its order.
> > Maybe that would solve the issue of setting a category delay for
> > subtitles. Instead, set a delay for the primary / secondary order and it
> > doesn't matter if the track exists or not.
> >
> > > +
> > >
>  /*****************************************************************************
> > >    * Prototypes
> > >
> *****************************************************************************/
> > > diff --git a/src/input/decoder.c b/src/input/decoder.c
> > > index 3b19b51d66..3a47c01ddf 100644
> > > --- a/src/input/decoder.c
> > > +++ b/src/input/decoder.c
> > > @@ -630,7 +630,8 @@ static subpicture_t *spu_new_buffer( decoder_t
> *p_dec,
> > >       {
> > >           ssize_t old_spu_channel = p_owner->i_spu_channel;
> > >           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 != -1)
> > > diff --git a/src/video_output/video_output.c
> b/src/video_output/video_output.c
> > > index a3ef144da1..ab3666da81 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_spu_channel_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..699ade93ae 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_spu_channel_order *out_order );
> > > +ssize_t spu_RegisterChannelInternal( spu_t *, vlc_clock_t *, enum
> vlc_spu_channel_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..8d209bbbde 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_spu_channel_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_spu_channel_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_spu_channel_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_spu_channel_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_SPU_CHANNEL_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_SPU_CHANNEL_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_SPU_CHANNEL_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_SPU_CHANNEL_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_SPU_CHANNEL_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-spu-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_spu_channel_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_SPU_CHANNEL_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)
> > _______________________________________________
> > vlc-devel mailing list
> > To unsubscribe or modify your subscription options:
> > https://mailman.videolan.org/listinfo/vlc-devel
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20190621/b062283b/attachment.html>


More information about the vlc-devel mailing list