[vlc-devel] [PATCH] Allow the ES block fifo to store PCR
Denis Charmet
typx at dinauz.org
Sun Mar 1 16:00:23 CET 2020
---
src/Makefile.am | 2 +
src/input/decoder.c | 170 ++++++++++++++++++++++++++----------------
src/input/decoder.h | 3 +
src/input/es_fifo.c | 177 ++++++++++++++++++++++++++++++++++++++++++++
src/input/es_fifo.h | 102 +++++++++++++++++++++++++
src/input/es_out.c | 18 +++++
6 files changed, 409 insertions(+), 63 deletions(-)
create mode 100644 src/input/es_fifo.c
create mode 100644 src/input/es_fifo.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 2b4dfcb7dd..e3f4308e23 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -256,6 +256,8 @@ libvlccore_la_SOURCES = \
input/decoder_helpers.c \
input/demux.c \
input/demux_chained.c \
+ input/es_fifo.c \
+ input/es_fifo.h \
input/es_out.c \
input/es_out_source.c \
input/es_out_timeshift.c \
diff --git a/src/input/decoder.c b/src/input/decoder.c
index d868c21f23..70ab06d2d8 100644
--- a/src/input/decoder.c
+++ b/src/input/decoder.c
@@ -93,7 +93,8 @@ struct decoder_owner
atomic_int reload;
/* fifo */
- block_fifo_t *p_fifo;
+ struct vlc_es_fifo_t *p_fifo;
+ vlc_tick_t i_pcr;
/* Lock for communication with decoder thread */
vlc_mutex_t lock;
@@ -396,9 +397,9 @@ static int ModuleThread_UpdateAudioFormat( decoder_t *p_dec )
p_dec->fmt_out.audio.i_frame_length =
p_owner->fmt.audio.i_frame_length;
- vlc_fifo_Lock( p_owner->p_fifo );
+ vlc_es_fifo_Lock( p_owner->p_fifo );
p_owner->reset_out_state = true;
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
}
return 0;
}
@@ -590,9 +591,9 @@ static int CreateVoutIfNeeded(struct decoder_owner *p_owner,
return -1;
}
- vlc_fifo_Lock( p_owner->p_fifo );
+ vlc_es_fifo_Lock( p_owner->p_fifo );
p_owner->reset_out_state = true;
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
return 1; // new vout was created
}
@@ -1001,11 +1002,11 @@ static void DecoderPlayCc( struct decoder_owner *p_owner, block_t *p_cc,
if( i_bitmap > 1 )
{
- block_FifoPut( p_ccowner->p_fifo, block_Duplicate(p_cc) );
+ vlc_es_fifo_FifoPut( p_ccowner->p_fifo, block_Duplicate(p_cc) );
}
else
{
- block_FifoPut( p_ccowner->p_fifo, p_cc );
+ vlc_es_fifo_FifoPut( p_ccowner->p_fifo, p_cc );
p_cc = NULL; /* was last dec */
}
}
@@ -1100,10 +1101,10 @@ static int ModuleThread_PlayVideo( struct decoder_owner *p_owner, picture_t *p_p
/* FIXME: The *input* FIFO should not be locked here. This will not work
* properly if/when pictures are queued asynchronously. */
- vlc_fifo_Lock( p_owner->p_fifo );
+ vlc_es_fifo_Lock( p_owner->p_fifo );
if( unlikely(p_owner->paused) && likely(p_owner->frames_countdown > 0) )
p_owner->frames_countdown--;
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
/* */
if( p_vout == NULL )
@@ -1633,19 +1634,19 @@ static void *DecoderThread( void *p_data )
bool paused = false;
/* The decoder's main loop */
- vlc_fifo_Lock( p_owner->p_fifo );
+ vlc_es_fifo_Lock( p_owner->p_fifo );
while( !p_owner->aborting )
{
if( p_owner->flushing )
{ /* Flush before/regardless of pause. We do not want to resume just
* for the sake of flushing (glitches could otherwise happen). */
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
/* Flush the decoder (and the output) */
DecoderThread_Flush( p_owner );
- vlc_fifo_Lock( p_owner->p_fifo );
+ vlc_es_fifo_Lock( p_owner->p_fifo );
/* Reset flushing after DecoderThread_ProcessInput in case input_DecoderFlush
* is called again. This will avoid a second useless flush (but
@@ -1671,33 +1672,33 @@ static void *DecoderThread( void *p_data )
vlc_tick_t date = p_owner->pause_date;
paused = p_owner->paused;
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
DecoderThread_ChangePause( p_owner, paused, date );
- vlc_fifo_Lock( p_owner->p_fifo );
+ vlc_es_fifo_Lock( p_owner->p_fifo );
continue;
}
if( rate != p_owner->request_rate )
{
rate = p_owner->request_rate;
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
DecoderThread_ChangeRate( p_owner, rate );
- vlc_fifo_Lock( p_owner->p_fifo );
+ vlc_es_fifo_Lock( p_owner->p_fifo );
continue;
}
if( delay != p_owner->delay )
{
delay = p_owner->delay;
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
DecoderThread_ChangeDelay( p_owner, delay );
- vlc_fifo_Lock( p_owner->p_fifo );
+ vlc_es_fifo_Lock( p_owner->p_fifo );
continue;
}
@@ -1705,29 +1706,35 @@ static void *DecoderThread( void *p_data )
{ /* Wait for resumption from pause */
p_owner->b_idle = true;
vlc_cond_signal( &p_owner->wait_acknowledge );
- vlc_fifo_Wait( p_owner->p_fifo );
+ vlc_es_fifo_Wait( p_owner->p_fifo );
p_owner->b_idle = false;
continue;
}
vlc_cond_signal( &p_owner->wait_fifo );
- block_t *p_block = vlc_fifo_DequeueUnlocked( p_owner->p_fifo );
+ vlc_tick_t pcr;
+ block_t *p_block = vlc_es_fifo_DequeueUnlocked( p_owner->p_fifo, &pcr );
if( p_block == NULL )
{
if( likely(!p_owner->b_draining) )
{ /* Wait for a block to decode (or a request to drain) */
p_owner->b_idle = true;
vlc_cond_signal( &p_owner->wait_acknowledge );
- vlc_fifo_Wait( p_owner->p_fifo );
+ vlc_es_fifo_Wait( p_owner->p_fifo );
p_owner->b_idle = false;
continue;
}
/* We have emptied the FIFO and there is a pending request to
* drain. Pass p_block = NULL to decoder just once. */
}
+ if (pcr != p_owner->i_pcr)
+ {
+ p_owner->i_pcr = pcr;
+ /* TODO notify pcr to decoder/packetizer */
+ }
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
DecoderThread_ProcessInput( p_owner, p_block );
@@ -1740,7 +1747,7 @@ static void *DecoderThread( void *p_data )
/* TODO? Wait for draining instead of polling. */
vlc_mutex_lock( &p_owner->lock );
- vlc_fifo_Lock( p_owner->p_fifo );
+ vlc_es_fifo_Lock( p_owner->p_fifo );
if( p_owner->b_draining && (p_block == NULL) )
{
p_owner->b_draining = false;
@@ -1750,7 +1757,7 @@ static void *DecoderThread( void *p_data )
vlc_mutex_unlock( &p_owner->lock );
}
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
return NULL;
}
@@ -1861,12 +1868,13 @@ static struct decoder_owner * CreateDecoder( vlc_object_t *p_parent,
es_format_Init( &p_owner->fmt, fmt->i_cat, 0 );
/* decoder fifo */
- p_owner->p_fifo = block_FifoNew();
+ p_owner->p_fifo = vlc_es_fifo_New();
if( unlikely(p_owner->p_fifo == NULL) )
{
vlc_object_delete(p_dec);
return NULL;
}
+ p_owner->i_pcr = VLC_TICK_INVALID;
vlc_mutex_init( &p_owner->lock );
vlc_mutex_init( &p_owner->mouse_lock );
@@ -1974,7 +1982,7 @@ static void DeleteDecoder( decoder_t * p_dec )
vlc_video_context_Release( p_owner->vctx );
/* Free all packets still in the decoder fifo. */
- block_FifoRelease( p_owner->p_fifo );
+ vlc_es_fifo_Release( p_owner->p_fifo );
/* Cleanup */
#ifdef ENABLE_SOUT
@@ -2163,11 +2171,11 @@ void input_DecoderDelete( decoder_t *p_dec )
{
struct decoder_owner *p_owner = dec_get_owner( p_dec );
- vlc_fifo_Lock( p_owner->p_fifo );
+ vlc_es_fifo_Lock( p_owner->p_fifo );
p_owner->aborting = true;
p_owner->flushing = true;
- vlc_fifo_Signal( p_owner->p_fifo );
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Signal( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
/* Make sure we aren't waiting/decoding anymore */
vlc_mutex_lock( &p_owner->lock );
@@ -2212,17 +2220,17 @@ void input_DecoderDecode( decoder_t *p_dec, block_t *p_block, bool b_do_pace )
{
struct decoder_owner *p_owner = dec_get_owner( p_dec );
- vlc_fifo_Lock( p_owner->p_fifo );
+ vlc_es_fifo_Lock( p_owner->p_fifo );
if( !b_do_pace )
{
/* FIXME: ideally we would check the time amount of data
* in the FIFO instead of its size. */
/* 400 MiB, i.e. ~ 50mb/s for 60s */
- if( vlc_fifo_GetBytes( p_owner->p_fifo ) > 400*1024*1024 )
+ if( vlc_es_fifo_GetBytes( p_owner->p_fifo ) > 400*1024*1024 )
{
msg_Warn( p_dec, "decoder/packetizer fifo full (data not "
"consumed quickly enough), resetting fifo!" );
- block_ChainRelease( vlc_fifo_DequeueAllUnlocked( p_owner->p_fifo ) );
+ vlc_es_fifo_FlushUnlocked(p_owner->p_fifo);
p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
}
}
@@ -2231,12 +2239,12 @@ void input_DecoderDecode( decoder_t *p_dec, block_t *p_block, bool b_do_pace )
{ /* The FIFO is not consumed when waiting, so pacing would deadlock VLC.
* Locking is not necessary as b_waiting is only read, not written by
* the decoder thread. */
- while( vlc_fifo_GetCount( p_owner->p_fifo ) >= 10 )
- vlc_fifo_WaitCond( p_owner->p_fifo, &p_owner->wait_fifo );
+ while( vlc_es_fifo_GetCount( p_owner->p_fifo ) >= 10 )
+ vlc_es_fifo_WaitCond( p_owner->p_fifo, &p_owner->wait_fifo );
}
- vlc_fifo_QueueUnlocked( p_owner->p_fifo, p_block );
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_QueueUnlocked( p_owner->p_fifo, p_block );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
}
bool input_DecoderIsEmpty( decoder_t * p_dec )
@@ -2245,13 +2253,13 @@ bool input_DecoderIsEmpty( decoder_t * p_dec )
assert( !p_owner->b_waiting );
- vlc_fifo_Lock( p_owner->p_fifo );
- if( !vlc_fifo_IsEmpty( p_owner->p_fifo ) || p_owner->b_draining )
+ vlc_es_fifo_Lock( p_owner->p_fifo );
+ if( !vlc_es_fifo_IsEmpty( p_owner->p_fifo ) || p_owner->b_draining )
{
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
return false;
}
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
bool b_empty;
@@ -2284,10 +2292,10 @@ void input_DecoderDrain( decoder_t *p_dec )
{
struct decoder_owner *p_owner = dec_get_owner( p_dec );
- vlc_fifo_Lock( p_owner->p_fifo );
+ vlc_es_fifo_Lock( p_owner->p_fifo );
p_owner->b_draining = true;
- vlc_fifo_Signal( p_owner->p_fifo );
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Signal( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
}
/**
@@ -2298,10 +2306,10 @@ void input_DecoderFlush( decoder_t *p_dec )
{
struct decoder_owner *p_owner = dec_get_owner( p_dec );
- vlc_fifo_Lock( p_owner->p_fifo );
+ vlc_es_fifo_Lock( p_owner->p_fifo );
/* Empty the fifo */
- block_ChainRelease( vlc_fifo_DequeueAllUnlocked( p_owner->p_fifo ) );
+ vlc_es_fifo_FlushUnlocked(p_owner->p_fifo);
/* Don't need to wait for the DecoderThread to flush. Indeed, if called a
* second time, this function will clear the FIFO again before anything was
@@ -2316,9 +2324,9 @@ void input_DecoderFlush( decoder_t *p_dec )
&& p_owner->frames_countdown == 0 )
p_owner->frames_countdown++;
- vlc_fifo_Signal( p_owner->p_fifo );
+ vlc_es_fifo_Signal( p_owner->p_fifo );
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
if( p_owner->paused )
{
@@ -2449,30 +2457,30 @@ void input_DecoderChangePause( decoder_t *p_dec, bool b_paused, vlc_tick_t i_dat
/* Normally, p_owner->b_paused != b_paused here. But if a track is added
* while the input is paused (e.g. add sub file), then b_paused is
* (incorrectly) false. FIXME: This is a bug in the decoder owner. */
- vlc_fifo_Lock( p_owner->p_fifo );
+ vlc_es_fifo_Lock( p_owner->p_fifo );
p_owner->paused = b_paused;
p_owner->pause_date = i_date;
p_owner->frames_countdown = 0;
- vlc_fifo_Signal( p_owner->p_fifo );
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Signal( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
}
void input_DecoderChangeRate( decoder_t *dec, float rate )
{
struct decoder_owner *owner = dec_get_owner( dec );
- vlc_fifo_Lock( owner->p_fifo );
+ vlc_es_fifo_Lock( owner->p_fifo );
owner->request_rate = rate;
- vlc_fifo_Unlock( owner->p_fifo );
+ vlc_es_fifo_Unlock( owner->p_fifo );
}
void input_DecoderChangeDelay( decoder_t *dec, vlc_tick_t delay )
{
struct decoder_owner *owner = dec_get_owner( dec );
- vlc_fifo_Lock( owner->p_fifo );
+ vlc_es_fifo_Lock( owner->p_fifo );
owner->delay = delay;
- vlc_fifo_Unlock( owner->p_fifo );
+ vlc_es_fifo_Unlock( owner->p_fifo );
}
void input_DecoderStartWait( decoder_t *p_dec )
@@ -2514,14 +2522,14 @@ void input_DecoderWait( decoder_t *p_dec )
* owner */
if( p_owner->paused )
break;
- vlc_fifo_Lock( p_owner->p_fifo );
- if( p_owner->b_idle && vlc_fifo_IsEmpty( p_owner->p_fifo ) )
+ vlc_es_fifo_Lock( p_owner->p_fifo );
+ if( p_owner->b_idle && vlc_es_fifo_IsEmpty( p_owner->p_fifo ) )
{
msg_Err( p_dec, "buffer deadlock prevented" );
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
break;
}
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
vlc_cond_wait( &p_owner->wait_acknowledge, &p_owner->lock );
}
vlc_mutex_unlock( &p_owner->lock );
@@ -2534,10 +2542,10 @@ void input_DecoderFrameNext( decoder_t *p_dec, vlc_tick_t *pi_duration )
assert( p_owner->paused );
*pi_duration = 0;
- vlc_fifo_Lock( p_owner->p_fifo );
+ vlc_es_fifo_Lock( p_owner->p_fifo );
p_owner->frames_countdown++;
- vlc_fifo_Signal( p_owner->p_fifo );
- vlc_fifo_Unlock( p_owner->p_fifo );
+ vlc_es_fifo_Signal( p_owner->p_fifo );
+ vlc_es_fifo_Unlock( p_owner->p_fifo );
vlc_mutex_lock( &p_owner->lock );
if( p_owner->fmt.i_cat == VIDEO_ES )
@@ -2577,8 +2585,10 @@ bool input_DecoderHasFormatChanged( decoder_t *p_dec, es_format_t *p_fmt, vlc_me
size_t input_DecoderGetFifoSize( decoder_t *p_dec )
{
struct decoder_owner *p_owner = dec_get_owner( p_dec );
-
- return block_FifoSize( p_owner->p_fifo );
+ vlc_es_fifo_Lock(p_owner->p_fifo);
+ size_t bytes = vlc_es_fifo_GetBytes( p_owner->p_fifo );
+ vlc_es_fifo_Unlock(p_owner->p_fifo);
+ return bytes;
}
void input_DecoderSetVoutMouseEvent( decoder_t *dec, vlc_mouse_event mouse_event,
@@ -2667,3 +2677,37 @@ int input_DecoderSetSpuHighlight( decoder_t *dec,
vlc_mutex_unlock( &p_owner->lock );
return VLC_SUCCESS;
}
+
+int input_DecoderSetPcr(decoder_t * dec, vlc_tick_t pcr)
+{
+ struct decoder_owner *p_owner = dec_get_owner( dec );
+
+ vlc_mutex_lock( &p_owner->lock );
+
+ if (vlc_es_fifo_SetPcr(p_owner->p_fifo, pcr))
+ {
+ vlc_mutex_unlock( &p_owner->lock );
+ return 1;
+ }
+
+ /* Fanout data to all decoders. We do not know if es_out
+ selected 608 or 708. */
+ uint64_t i_bitmap = p_owner->cc.desc.i_608_channels |
+ p_owner->cc.desc.i_708_channels;
+
+ for( int i=0; i_bitmap > 0; i_bitmap >>= 1, i++ )
+ {
+ decoder_t *p_ccdec = p_owner->cc.pp_decoder[i];
+ struct decoder_owner *p_ccowner = dec_get_owner( p_ccdec );
+ if( !p_ccdec )
+ continue;
+ if (vlc_es_fifo_SetPcr(p_ccowner->p_fifo, pcr))
+ {
+ vlc_mutex_unlock( &p_owner->lock );
+ return 1;
+ }
+ }
+
+ vlc_mutex_unlock( &p_owner->lock );
+ return 0;
+}
diff --git a/src/input/decoder.h b/src/input/decoder.h
index af9f7c7bdb..2fe9b8cf44 100644
--- a/src/input/decoder.h
+++ b/src/input/decoder.h
@@ -27,6 +27,7 @@
#include <vlc_common.h>
#include <vlc_codec.h>
#include <vlc_mouse.h>
+#include "es_fifo.h"
struct input_decoder_callbacks {
/* notifications */
@@ -138,4 +139,6 @@ void input_DecoderSetVoutMouseEvent( decoder_t *, vlc_mouse_event, void * );
int input_DecoderAddVoutOverlay( decoder_t *, subpicture_t *, size_t * );
int input_DecoderDelVoutOverlay( decoder_t *, size_t );
+int input_DecoderSetPcr(decoder_t *, vlc_tick_t);
+
#endif
diff --git a/src/input/es_fifo.c b/src/input/es_fifo.c
new file mode 100644
index 0000000000..97404d2cf1
--- /dev/null
+++ b/src/input/es_fifo.c
@@ -0,0 +1,177 @@
+/*****************************************************************************
+ * es_fifo.c: Input es_out fifo functions
+ *****************************************************************************
+ * Copyright (C) 2020 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <vlc_common.h>
+#include <vlc_block.h>
+
+#include "es_fifo.h"
+
+static struct vlc_pcr_block_fifo_t *pcr_fifo_New(vlc_tick_t pcr)
+{
+ struct vlc_pcr_block_fifo_t *p_fifo = malloc(sizeof(struct vlc_pcr_block_fifo_t));
+ if (p_fifo == NULL)
+ return NULL;
+ p_fifo->i_pcr = pcr;
+ p_fifo->p_first = NULL;
+ p_fifo->pp_last = &p_fifo->p_first;
+ p_fifo->p_next = NULL;
+ return p_fifo;
+}
+
+struct vlc_es_fifo_t *vlc_es_fifo_New()
+{
+ struct vlc_es_fifo_t *p_fifo = malloc(sizeof(struct vlc_es_fifo_t));
+
+ if (p_fifo == NULL)
+ return NULL;
+
+ p_fifo->p_first = pcr_fifo_New(VLC_TICK_INVALID);
+
+ if (p_fifo->p_first == NULL)
+ {
+ free(p_fifo);
+ return NULL;
+ }
+
+ vlc_mutex_init(&p_fifo->lock);
+ vlc_cond_init(&p_fifo->wait);
+ p_fifo->p_last = p_fifo->p_first;
+ p_fifo->i_depth = p_fifo->i_size = 0;
+
+ return p_fifo;
+}
+
+int vlc_es_fifo_SetPcr(struct vlc_es_fifo_t *fifo, vlc_tick_t pcr)
+{
+ vlc_mutex_lock(&fifo->lock);
+
+ struct vlc_pcr_block_fifo_t *p_pcr_fifo = fifo->p_last;
+ if (p_pcr_fifo->p_first == NULL || p_pcr_fifo->i_pcr == pcr)
+ p_pcr_fifo->i_pcr = pcr; /* Reuse empty or same pcr_block fifo */
+ else
+ {
+ p_pcr_fifo = pcr_fifo_New(pcr);
+ if (p_pcr_fifo == NULL)
+ {
+ vlc_mutex_unlock(&fifo->lock);
+ return 1;
+ }
+ fifo->p_last->p_next = p_pcr_fifo;
+ fifo->p_last = p_pcr_fifo;
+ }
+ vlc_mutex_unlock(&fifo->lock);
+ return 0;
+}
+
+void vlc_es_fifo_Release(struct vlc_es_fifo_t *fifo)
+{
+ vlc_mutex_lock(&fifo->lock);
+ struct vlc_pcr_block_fifo_t *tmp;
+ while ((tmp = fifo->p_first) != NULL)
+ {
+ block_ChainRelease(tmp->p_first);
+ fifo->p_first = tmp->p_next;
+ free(tmp);
+ }
+ vlc_mutex_unlock(&fifo->lock);
+ free(fifo);
+}
+
+void vlc_es_fifo_FlushUnlocked(struct vlc_es_fifo_t *fifo)
+{
+ vlc_mutex_assert(&fifo->lock);
+ struct vlc_pcr_block_fifo_t *tmp, *first = fifo->p_first;
+
+ /* Reset the first element */
+ block_ChainRelease(first->p_first);
+ first->p_first = NULL;
+ first->pp_last = &first->p_first;
+ first->i_pcr = VLC_TICK_INVALID;
+
+ fifo->p_first = first->p_next;
+ first->p_next = NULL;
+
+ while ((tmp = fifo->p_first) != NULL)
+ {
+ block_ChainRelease(tmp->p_first);
+ fifo->p_first = tmp->p_next;
+ free(tmp);
+ }
+
+ fifo->p_first = fifo->p_last = first;
+ fifo->i_depth = 0;
+ fifo->i_size = 0;
+}
+
+block_t *vlc_es_fifo_DequeueUnlocked(struct vlc_es_fifo_t *fifo, vlc_tick_t * pcr)
+{
+ vlc_mutex_assert(&fifo->lock);
+
+ struct vlc_pcr_block_fifo_t * restrict first = fifo->p_first;
+ block_t * restrict block = first->p_first;
+
+ if (block == NULL)
+ return NULL;
+
+ *pcr = first->i_pcr;
+ first->p_first = block->p_next;
+ if (block->p_next == NULL)
+ {
+ if (first->p_next != NULL)
+ {
+ fifo->p_first = first->p_next;
+ free(first);
+ }
+ else
+ {
+ first->pp_last = &first->p_first;
+ //printf("%lld - %p - %p\n", first->i_pcr, first->p_first, first->pp_last);
+ }
+ }
+
+ assert(fifo->i_depth > 0);
+ fifo->i_depth--;
+ assert(fifo->i_size >= block->i_buffer);
+ fifo->i_size -= block->i_buffer;
+
+ return block;
+}
+
+void vlc_es_fifo_QueueUnlocked(struct vlc_es_fifo_t *fifo, block_t *block)
+{
+ vlc_mutex_assert(&fifo->lock);
+ struct vlc_pcr_block_fifo_t * restrict last = fifo->p_last;
+ assert(*last->pp_last == NULL);
+
+ *last->pp_last = block;
+
+ while (block != NULL)
+ {
+ last->pp_last = &block->p_next;
+ fifo->i_depth++;
+ fifo->i_size += block->i_buffer;
+ block = block->p_next;
+ }
+ vlc_cond_signal(&fifo->wait);
+}
diff --git a/src/input/es_fifo.h b/src/input/es_fifo.h
new file mode 100644
index 0000000000..38f8e6c414
--- /dev/null
+++ b/src/input/es_fifo.h
@@ -0,0 +1,102 @@
+/*****************************************************************************
+ * es_fifo.h: Input es_out fifo functions
+ *****************************************************************************
+ * Copyright (C) 2020 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef LIBVLC_INPUT_ES_FIFO_H
+#define LIBVLC_INPUT_ES_FIFO_H 1
+
+struct vlc_pcr_block_fifo_t
+{
+ vlc_tick_t i_pcr;
+ block_t *p_first;
+ block_t **pp_last;
+ struct vlc_pcr_block_fifo_t *p_next;
+};
+
+struct vlc_es_fifo_t
+{
+ vlc_mutex_t lock;
+ vlc_cond_t wait;
+ struct vlc_pcr_block_fifo_t *p_first;
+ struct vlc_pcr_block_fifo_t *p_last;
+ size_t i_depth;
+ size_t i_size;
+};
+
+struct vlc_es_fifo_t *vlc_es_fifo_New(void);
+
+void vlc_es_fifo_Release(struct vlc_es_fifo_t *fifo);
+
+void vlc_es_fifo_FlushUnlocked(struct vlc_es_fifo_t *fifo);
+
+block_t *vlc_es_fifo_DequeueUnlocked(struct vlc_es_fifo_t *fifo, vlc_tick_t * pcr);
+
+void vlc_es_fifo_QueueUnlocked(struct vlc_es_fifo_t *fifo, block_t *block);
+
+int vlc_es_fifo_SetPcr(struct vlc_es_fifo_t *fifo, vlc_tick_t pcr);
+
+static inline void vlc_es_fifo_FifoPut(struct vlc_es_fifo_t *fifo, block_t *block)
+{
+ vlc_mutex_lock(&fifo->lock);
+ vlc_es_fifo_QueueUnlocked(fifo, block);
+ vlc_mutex_unlock(&fifo->lock);
+}
+
+static inline void vlc_es_fifo_Lock(struct vlc_es_fifo_t *fifo)
+{
+ vlc_mutex_lock(&fifo->lock);
+}
+
+static inline void vlc_es_fifo_Unlock(struct vlc_es_fifo_t *fifo)
+{
+ vlc_mutex_unlock(&fifo->lock);
+}
+
+static inline void vlc_es_fifo_Signal(struct vlc_es_fifo_t *fifo)
+{
+ vlc_cond_signal(&fifo->wait);
+}
+
+static inline void vlc_es_fifo_Wait(struct vlc_es_fifo_t *fifo)
+{
+ vlc_cond_wait(&fifo->wait, &fifo->lock);
+}
+
+static inline void vlc_es_fifo_WaitCond(struct vlc_es_fifo_t *fifo, vlc_cond_t * wait)
+{
+ vlc_cond_wait(wait, &fifo->lock);
+}
+
+static inline size_t vlc_es_fifo_GetCount(const struct vlc_es_fifo_t *fifo)
+{
+ vlc_mutex_assert(&fifo->lock);
+ return fifo->i_depth;
+}
+
+static inline size_t vlc_es_fifo_GetBytes(const struct vlc_es_fifo_t *fifo)
+{
+ vlc_mutex_assert(&fifo->lock);
+ return fifo->i_size;
+}
+
+static inline bool vlc_es_fifo_IsEmpty(struct vlc_es_fifo_t *fifo)
+{
+ return vlc_es_fifo_GetCount(fifo) == 0;
+}
+#endif
diff --git a/src/input/es_out.c b/src/input/es_out.c
index 118c780c95..2c1953ecb7 100644
--- a/src/input/es_out.c
+++ b/src/input/es_out.c
@@ -3143,6 +3143,24 @@ static int EsOutVaControlLocked( es_out_t *out, input_source_t *source,
return VLC_EGENERIC;
}
+ es_out_id_t *es;
+ foreach_es_then_es_slaves( es )
+ {
+ if ( es->p_pgrm == p_pgrm )
+ {
+ if ( es->p_dec != NULL && input_DecoderSetPcr( es->p_dec, i_pcr ) )
+ {
+ EsOutControlLocked( out, source, ES_OUT_RESET_PCR );
+ return VLC_ENOMEM;
+ }
+ if ( es->p_dec_record != NULL && input_DecoderSetPcr( es->p_dec, i_pcr ) )
+ {
+ EsOutControlLocked( out, source, ES_OUT_RESET_PCR );
+ return VLC_ENOMEM;
+ }
+ }
+ }
+
/* TODO do not use vlc_tick_now() but proper stream acquisition date */
const bool b_low_delay = input_priv(p_sys->p_input)->b_low_delay;
bool b_extra_buffering_allowed = !b_low_delay && EsOutIsExtraBufferingAllowed( out );
--
2.24.1
More information about the vlc-devel
mailing list