vlc | branch: master | Roland Bewick <[email protected]> | Wed May 22 01:08:31 2019 +0700| [eb10f0b60edf5ac22d1b843ba794a67bed269fcd] | committer: Thomas Guillem
vout: spu: handle secondary channel order Signed-off-by: Thomas Guillem <[email protected]> > 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) _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
