[vlc-devel] [RFC PATCH 08/13] FIXUP: convert SPU dates
Thomas Guillem
thomas at gllm.fr
Wed Jun 27 14:41:30 CEST 2018
SpuSelectSubpictures will now return all selected spus with start/stop
converted. New date are converted in a new struct since we don't want to
override original SPU (that can be re-used later with a different clock
reference).
---
src/input/decoder.c | 4 +
src/video_output/video_output.c | 10 +-
src/video_output/vout_internal.h | 2 +
src/video_output/vout_subpictures.c | 160 ++++++++++++++++++++--------
4 files changed, 131 insertions(+), 45 deletions(-)
diff --git a/src/input/decoder.c b/src/input/decoder.c
index 161b159cb1..4650850e17 100644
--- a/src/input/decoder.c
+++ b/src/input/decoder.c
@@ -591,6 +591,7 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec,
if( p_owner->p_vout != p_vout )
{
p_owner->i_spu_channel = vout_RegisterSubpictureChannel( p_vout );
+ vout_SetSubpictureClock( p_vout, p_owner->p_clock );
p_owner->i_spu_order = 0;
p_owner->p_vout = p_vout;
}
@@ -1784,7 +1785,10 @@ static void DeleteDecoder( decoder_t * p_dec )
if( p_vout )
{
if( p_owner->p_vout == p_vout )
+ {
vout_FlushSubpictureChannel( p_vout, p_owner->i_spu_channel );
+ vout_SetSubpictureClock( p_vout, NULL );
+ }
vlc_object_release( p_vout );
}
break;
diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c
index 545aaff94c..67858b1a91 100644
--- a/src/video_output/video_output.c
+++ b/src/video_output/video_output.c
@@ -404,6 +404,13 @@ int vout_RegisterSubpictureChannel( vout_thread_t *vout )
return channel;
}
+void vout_SetSubpictureClock( vout_thread_t *vout, vlc_clock_t *clock )
+{
+ vlc_mutex_lock(&vout->p->spu_lock);
+ if (vout->p->spu)
+ spu_SetClock(vout->p->spu, clock);
+ vlc_mutex_unlock(&vout->p->spu_lock);
+}
void vout_FlushSubpictureChannel( vout_thread_t *vout, int channel )
{
vout_control_PushInteger(&vout->p->control, VOUT_CONTROL_FLUSH_SUBPICTURE,
@@ -988,6 +995,7 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
* Get the subpicture to be displayed
*/
const bool do_snapshot = vout_snapshot_IsRequested(&vout->p->snapshot);
+ vlc_tick_t system_now = vlc_tick_now();
vlc_tick_t render_subtitle_date;
if (vout->p->pause.is_on)
render_subtitle_date = vout->p->pause.date;
@@ -1058,7 +1066,7 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
subpicture_t *subpic = spu_Render(vout->p->spu,
subpicture_chromas, &fmt_spu_rot,
&vd->source,
- render_subtitle_date, render_osd_date,
+ render_subtitle_date, system_now,
do_snapshot);
/*
* Perform rendering
diff --git a/src/video_output/vout_internal.h b/src/video_output/vout_internal.h
index 6cafe05667..2f0d52c44e 100644
--- a/src/video_output/vout_internal.h
+++ b/src/video_output/vout_internal.h
@@ -223,6 +223,8 @@ void vout_ManageWrapper(vout_thread_t *);
/* */
int spu_ProcessMouse(spu_t *, const vlc_mouse_t *, const video_format_t *);
void spu_Attach( spu_t *, vlc_object_t *input, bool );
+void vout_SetSubpictureClock( vout_thread_t *vout, vlc_clock_t *clock ); /* FIXME */
+void spu_SetClock( spu_t *, vlc_clock_t * );
void spu_ChangeMargin(spu_t *, int);
/**
diff --git a/src/video_output/vout_subpictures.c b/src/video_output/vout_subpictures.c
index e5bcc1555d..dc3e83ede3 100644
--- a/src/video_output/vout_subpictures.c
+++ b/src/video_output/vout_subpictures.c
@@ -52,6 +52,12 @@
#define VOUT_MAX_SUBPICTURES (__MAX(VOUT_MAX_PICTURES, SPU_MAX_PREPARE_TIME/5000))
/* */
+typedef struct {
+ subpicture_t *subpicture;
+ vlc_tick_t start;
+ vlc_tick_t stop;
+} spu_render_entry_t;
+
typedef struct {
subpicture_t *subpicture;
bool reject;
@@ -65,6 +71,8 @@ struct spu_private_t {
vlc_mutex_t lock; /* lock to protect all followings fields */
vlc_object_t *input;
+ vlc_clock_t *clock;
+
spu_heap_t heap;
int channel; /**< number of subpicture channels registered */
@@ -498,15 +506,17 @@ static int IntegerCmp(int64_t i0, int64_t i1)
*
* XXX spu_RenderSubpictures depends heavily on this order.
*/
-static int SubpictureCmp(const void *s0, const void *s1)
+static int SpuRenderCmp(const void *s0, const void *s1)
{
- subpicture_t *subpic0 = *(subpicture_t**)s0;
- subpicture_t *subpic1 = *(subpicture_t**)s1;
+ const spu_render_entry_t *render_entry0 = s0;
+ const spu_render_entry_t *render_entry1 = s1;
+ subpicture_t *subpic0 = render_entry0->subpicture;
+ subpicture_t *subpic1 = render_entry1->subpicture;
int r;
r = IntegerCmp(!subpic0->b_absolute, !subpic1->b_absolute);
if (!r)
- r = IntegerCmp(subpic0->i_start, subpic1->i_start);
+ r = IntegerCmp(render_entry0->start, render_entry1->start);
if (!r)
r = IntegerCmp(subpic0->i_channel, subpic1->i_channel);
if (!r)
@@ -514,6 +524,54 @@ static int SubpictureCmp(const void *s0, const void *s1)
return r;
}
+static int SpuConvertDates(spu_t *spu, vlc_tick_t system_now,
+ spu_render_entry_t *render_entries)
+{
+ spu_private_t *sys = spu->p;
+
+ if (!sys->clock)
+ return 0;
+
+ vlc_tick_t date_array[VOUT_MAX_SUBPICTURES *2];
+ size_t entry_count = 0;
+ for (size_t index = 0; index < VOUT_MAX_SUBPICTURES; index++)
+ {
+ spu_heap_entry_t *entry = &sys->heap.entry[index];
+ subpicture_t *current = entry->subpicture;
+
+ if (!current)
+ continue;
+
+ date_array[entry_count * 2] = current->i_start;
+ date_array[entry_count * 2 + 1] = current->i_stop;
+ entry_count++;
+ }
+ if (entry_count == 0)
+ return 0;
+
+ vlc_clock_ConvertArrayToSystem(sys->clock, system_now, date_array,
+ entry_count * 2);
+
+ entry_count = 0;
+ for (size_t index = 0; index < VOUT_MAX_SUBPICTURES; index++)
+ {
+ spu_render_entry_t *render_entry = &render_entries[index];
+ spu_heap_entry_t *entry = &sys->heap.entry[index];
+ subpicture_t *current = entry->subpicture;
+
+ if (!current)
+ render_entry->subpicture = NULL;
+ else
+ {
+ render_entry->subpicture = current;
+ render_entry->start = date_array[entry_count * 2];
+ render_entry->stop = date_array[entry_count * 2 + 1];
+ entry_count++;
+ }
+ }
+ return entry_count;
+}
+
/*****************************************************************************
* SpuSelectSubpictures: find the subpictures to display
*****************************************************************************
@@ -526,9 +584,9 @@ static int SubpictureCmp(const void *s0, const void *s1)
*****************************************************************************/
static void SpuSelectSubpictures(spu_t *spu,
size_t *subpicture_count,
- subpicture_t **subpicture_array,
+ spu_render_entry_t *subpicture_array,
vlc_tick_t render_subtitle_date,
- vlc_tick_t render_osd_date,
+ vlc_tick_t system_now,
bool ignore_osd)
{
spu_private_t *sys = spu->p;
@@ -536,6 +594,10 @@ static void SpuSelectSubpictures(spu_t *spu,
/* */
*subpicture_count = 0;
+ spu_render_entry_t render_entries[VOUT_MAX_SUBPICTURES];
+ if (SpuConvertDates(spu, system_now, render_entries) == 0)
+ return;
+
/* Create a list of channels */
int channel[VOUT_MAX_SUBPICTURES];
int channel_count = 0;
@@ -556,7 +618,7 @@ static void SpuSelectSubpictures(spu_t *spu,
/* Fill up the subpicture_array arrays with relevant pictures */
for (int i = 0; i < channel_count; i++) {
- subpicture_t *available_subpic[VOUT_MAX_SUBPICTURES];
+ spu_render_entry_t available_entries[VOUT_MAX_SUBPICTURES];
bool is_available_late[VOUT_MAX_SUBPICTURES];
size_t available_count = 0;
@@ -569,6 +631,7 @@ static void SpuSelectSubpictures(spu_t *spu,
/* Select available pictures */
for (int index = 0; index < VOUT_MAX_SUBPICTURES; index++) {
spu_heap_entry_t *entry = &sys->heap.entry[index];
+ spu_render_entry_t *render_entry = &render_entries[index];
subpicture_t *current = entry->subpicture;
bool is_stop_valid;
bool is_late;
@@ -583,33 +646,33 @@ static void SpuSelectSubpictures(spu_t *spu,
(ignore_osd && !current->b_subtitle))
continue;
- const vlc_tick_t render_date = current->b_subtitle ? render_subtitle_date : render_osd_date;
+ const vlc_tick_t render_date = current->b_subtitle ? render_subtitle_date : system_now;
if (render_date &&
- render_date < current->i_start) {
+ render_date < render_entry->start) {
/* Too early, come back next monday */
continue;
}
vlc_tick_t *ephemer_date_ptr = current->b_subtitle ? &ephemer_subtitle_date : &ephemer_osd_date;
int64_t *ephemer_order_ptr = current->b_subtitle ? &ephemer_subtitle_order : &ephemer_system_order;
- if (current->i_start >= *ephemer_date_ptr) {
- *ephemer_date_ptr = current->i_start;
+ if (render_entry->start >= *ephemer_date_ptr) {
+ *ephemer_date_ptr = render_entry->start;
if (current->i_order > *ephemer_order_ptr)
*ephemer_order_ptr = current->i_order;
}
- is_stop_valid = !current->b_ephemer || current->i_stop > current->i_start;
+ is_stop_valid = !current->b_ephemer || render_entry->stop > render_entry->start;
- is_late = is_stop_valid && current->i_stop <= render_date;
+ is_late = is_stop_valid && render_entry->stop <= render_date;
/* start_date will be used for correct automatic overlap support
* in case picture that should not be displayed anymore (display_time)
- * overlap with a picture to be displayed (current->i_start) */
+ * overlap with a picture to be displayed (render_entry->start) */
if (current->b_subtitle && !is_late && !current->b_ephemer)
- start_date = current->i_start;
+ start_date = render_entry->start;
/* */
- available_subpic[available_count] = current;
+ available_entries[available_count] = *render_entry;
is_available_late[available_count] = is_late;
available_count++;
}
@@ -622,19 +685,20 @@ static void SpuSelectSubpictures(spu_t *spu,
/* Select pictures to be displayed */
for (size_t index = 0; index < available_count; index++) {
- subpicture_t *current = available_subpic[index];
+ spu_render_entry_t *render_entry = &available_entries[index];
+ subpicture_t *current = render_entry->subpicture;
bool is_late = is_available_late[index];
- const vlc_tick_t stop_date = current->b_subtitle ? __MAX(start_date, sys->last_sort_date) : render_osd_date;
+ const vlc_tick_t stop_date = current->b_subtitle ? __MAX(start_date, sys->last_sort_date) : system_now;
const vlc_tick_t ephemer_date = current->b_subtitle ? ephemer_subtitle_date : ephemer_osd_date;
const int64_t ephemer_order = current->b_subtitle ? ephemer_subtitle_order : ephemer_system_order;
/* Destroy late and obsolete ephemer subpictures */
- bool is_rejeted = is_late && current->i_stop <= stop_date;
+ bool is_rejeted = is_late && render_entry->stop <= stop_date;
if (current->b_ephemer) {
- if (current->i_start < ephemer_date)
+ if (render_entry->start < ephemer_date)
is_rejeted = true;
- else if (current->i_start == ephemer_date &&
+ else if (render_entry->start == ephemer_date &&
current->i_order < ephemer_order)
is_rejeted = true;
}
@@ -642,7 +706,7 @@ static void SpuSelectSubpictures(spu_t *spu,
if (is_rejeted)
SpuHeapDeleteSubpicture(&sys->heap, current);
else
- subpicture_array[(*subpicture_count)++] = current;
+ subpicture_array[(*subpicture_count)++] = *render_entry;
}
}
@@ -656,13 +720,14 @@ static void SpuSelectSubpictures(spu_t *spu,
*/
static void SpuRenderRegion(spu_t *spu,
subpicture_region_t **dst_ptr, spu_area_t *dst_area,
- subpicture_t *subpic, subpicture_region_t *region,
+ const spu_render_entry_t *entry, subpicture_region_t *region,
const spu_scale_t scale_size,
const vlc_fourcc_t *chroma_list,
const video_format_t *fmt,
const spu_area_t *subtitle_area, int subtitle_area_count,
vlc_tick_t render_date)
{
+ subpicture_t *subpic = entry->subpicture;
spu_private_t *sys = spu->p;
video_format_t fmt_original = region->fmt;
@@ -681,7 +746,7 @@ static void SpuRenderRegion(spu_t *spu,
if (region->fmt.i_chroma == VLC_CODEC_TEXT) {
SpuRenderText(spu, &restore_text, region,
chroma_list,
- render_date - subpic->i_start);
+ render_date - entry->start);
/* Check if the rendering has failed ... */
if (region->fmt.i_chroma == VLC_CODEC_TEXT)
@@ -963,11 +1028,11 @@ static void SpuRenderRegion(spu_t *spu,
dst->p_picture = picture_Hold(region_picture);
int fade_alpha = 255;
if (subpic->b_fade) {
- vlc_tick_t fade_start = subpic->i_start + 3 * (subpic->i_stop - subpic->i_start) / 4;
+ vlc_tick_t fade_start = entry->start + 3 * (entry->stop - entry->start) / 4;
- if (fade_start <= render_date && fade_start < subpic->i_stop)
- fade_alpha = 255 * (subpic->i_stop - render_date) /
- (subpic->i_stop - fade_start);
+ if (fade_start <= render_date && fade_start < entry->stop)
+ fade_alpha = 255 * (entry->stop - render_date) /
+ (entry->stop - fade_start);
}
dst->i_alpha = fade_alpha * subpic->i_alpha * region->i_alpha / 65025;
}
@@ -996,12 +1061,12 @@ exit:
*/
static subpicture_t *SpuRenderSubpictures(spu_t *spu,
size_t i_subpicture,
- subpicture_t **pp_subpicture,
+ const spu_render_entry_t *p_entries,
const vlc_fourcc_t *chroma_list,
const video_format_t *fmt_dst,
const video_format_t *fmt_src,
vlc_tick_t render_subtitle_date,
- vlc_tick_t render_osd_date)
+ vlc_tick_t system_now)
{
spu_private_t *sys = spu->p;
@@ -1009,7 +1074,7 @@ static subpicture_t *SpuRenderSubpictures(spu_t *spu,
unsigned int subtitle_region_count = 0;
unsigned int region_count = 0;
for (unsigned i = 0; i < i_subpicture; i++) {
- const subpicture_t *subpic = pp_subpicture[i];
+ const subpicture_t *subpic = p_entries[i].subpicture;
unsigned count = 0;
for (subpicture_region_t *r = subpic->p_region; r != NULL; r = r->p_next)
@@ -1026,7 +1091,7 @@ static subpicture_t *SpuRenderSubpictures(spu_t *spu,
subpicture_t *output = subpicture_New(NULL);
if (!output)
return NULL;
- output->i_order = pp_subpicture[i_subpicture - 1]->i_order;
+ output->i_order = p_entries[i_subpicture - 1].subpicture->i_order;
output->i_original_picture_width = fmt_dst->i_visible_width;
output->i_original_picture_height = fmt_dst->i_visible_height;
subpicture_region_t **output_last_ptr = &output->p_region;
@@ -1042,8 +1107,9 @@ static subpicture_t *SpuRenderSubpictures(spu_t *spu,
subtitle_area = calloc(subtitle_region_count, sizeof(*subtitle_area));
/* Process all subpictures and regions (in the right order) */
- for (unsigned int index = 0; index < i_subpicture; index++) {
- subpicture_t *subpic = pp_subpicture[index];
+ for (size_t index = 0; index < i_subpicture; index++) {
+ const spu_render_entry_t *entry = &p_entries[index];
+ subpicture_t *subpic = entry->subpicture;
subpicture_region_t *region;
if (!subpic->p_region)
@@ -1107,10 +1173,10 @@ static subpicture_t *SpuRenderSubpictures(spu_t *spu,
/* */
SpuRenderRegion(spu, output_last_ptr, &area,
- subpic, region, scale,
+ entry, region, scale,
chroma_list, fmt_dst,
subtitle_area, subtitle_area_count,
- subpic->b_subtitle ? render_subtitle_date : render_osd_date);
+ subpic->b_subtitle ? render_subtitle_date : system_now);
if (*output_last_ptr)
output_last_ptr = &(*output_last_ptr)->p_next;
@@ -1303,6 +1369,7 @@ spu_t *spu_Create(vlc_object_t *object, vout_thread_t *vout)
SpuHeapInit(&sys->heap);
+ sys->clock = NULL;
sys->text = NULL;
sys->scale = NULL;
sys->scale_yuvp = NULL;
@@ -1413,6 +1480,11 @@ void spu_Attach(spu_t *spu, vlc_object_t *input, bool attach)
}
}
+void spu_SetClock(spu_t *spu, vlc_clock_t *clock)
+{
+ spu->p->clock = clock;
+}
+
/**
* Inform the SPU filters of mouse event
*/
@@ -1524,7 +1596,7 @@ subpicture_t *spu_Render(spu_t *spu,
const video_format_t *fmt_dst,
const video_format_t *fmt_src,
vlc_tick_t render_subtitle_date,
- vlc_tick_t render_osd_date,
+ vlc_tick_t system_now,
bool ignore_osd)
{
spu_private_t *sys = spu->p;
@@ -1553,7 +1625,7 @@ subpicture_t *spu_Render(spu_t *spu,
free(chain_update);
}
/* Run subpicture sources */
- filter_chain_SubSource(sys->source_chain, spu, render_osd_date);
+ filter_chain_SubSource(sys->source_chain, spu, system_now);
vlc_mutex_unlock(&sys->source_chain_lock);
static const vlc_fourcc_t chroma_list_default_yuv[] = {
@@ -1580,11 +1652,11 @@ subpicture_t *spu_Render(spu_t *spu,
vlc_mutex_lock(&sys->lock);
size_t subpicture_count;
- subpicture_t *subpicture_array[VOUT_MAX_SUBPICTURES];
+ spu_render_entry_t subpicture_array[VOUT_MAX_SUBPICTURES];
/* Get an array of subpictures to render */
SpuSelectSubpictures(spu, &subpicture_count, subpicture_array,
- render_subtitle_date, render_osd_date, ignore_osd);
+ render_subtitle_date, system_now, ignore_osd);
if (subpicture_count == 0) {
vlc_mutex_unlock(&sys->lock);
return NULL;
@@ -1592,15 +1664,15 @@ subpicture_t *spu_Render(spu_t *spu,
/* Updates the subpictures */
for (size_t i = 0; i < subpicture_count; i++) {
- subpicture_t *subpic = subpicture_array[i];
+ subpicture_t *subpic = subpicture_array[i].subpicture;
subpicture_Update(subpic,
fmt_src, fmt_dst,
- subpic->b_subtitle ? render_subtitle_date : render_osd_date);
+ subpic->b_subtitle ? render_subtitle_date : system_now);
}
/* Now order the subpicture array
* XXX The order is *really* important for overlap subtitles positionning */
- qsort(subpicture_array, subpicture_count, sizeof(*subpicture_array), SubpictureCmp);
+ qsort(subpicture_array, subpicture_count, sizeof(*subpicture_array), SpuRenderCmp);
/* Render the subpictures */
subpicture_t *render = SpuRenderSubpictures(spu,
@@ -1609,7 +1681,7 @@ subpicture_t *spu_Render(spu_t *spu,
fmt_dst,
fmt_src,
render_subtitle_date,
- render_osd_date);
+ system_now);
vlc_mutex_unlock(&sys->lock);
return render;
--
2.18.0
More information about the vlc-devel
mailing list