Commit 5ac1ca3f authored by François Cartegnie's avatar François Cartegnie 🤞

codec/esout: use bitmap for cc channels and refactor channel creation

parent ef281573
......@@ -45,6 +45,8 @@
typedef struct decoder_owner_sys_t decoder_owner_sys_t;
typedef struct decoder_cc_desc_t decoder_cc_desc_t;
/*
* BIG FAT WARNING : the code relies in the first 4 members of filter_t
* and decoder_t to be the same, so if you have anything to add, do it
......@@ -127,10 +129,10 @@ struct decoder_t
/* Closed Caption (CEA 608/708) extraction.
* If set, it *may* be called after pf_packetize returned data. It should
* return CC for the pictures returned by the last pf_packetize call only,
* pb_present will be used to known which cc channel are present (but
* channel bitmaps will be used to known which cc channel are present (but
* globaly, not necessary for the current packet. Video decoders should use
* the decoder_QueueCc() function to pass closed captions. */
block_t * ( * pf_get_cc ) ( decoder_t *, bool pb_present[4], int * );
block_t * ( * pf_get_cc ) ( decoder_t *, decoder_cc_desc_t * );
/* Meta data at codec level
* The decoder owner set it back to NULL once it has retreived what it needs.
......@@ -178,7 +180,7 @@ struct decoder_t
/* XXX use decoder_QueueAudio */
int (*pf_queue_audio)( decoder_t *, block_t * );
/* XXX use decoder_QueueCC */
int (*pf_queue_cc)( decoder_t *, block_t *, bool p_cc_present[4], int );
int (*pf_queue_cc)( decoder_t *, block_t *, const decoder_cc_desc_t * );
/* XXX use decoder_QueueSub */
int (*pf_queue_sub)( decoder_t *, subpicture_t *);
void *p_queue_ctx;
......@@ -187,6 +189,14 @@ struct decoder_t
decoder_owner_sys_t *p_owner;
};
/* struct for packetizer get_cc polling/decoder queue_cc
* until we have a proper metadata way */
struct decoder_cc_desc_t
{
uint8_t i_608_channels; /* 608 channels bitmap */
int i_reorder_depth; /* reorder depth, -1 for no reorder, 0 for old P/B flag based */
};
/**
* @}
*/
......@@ -311,21 +321,18 @@ static inline int decoder_QueueVideo( decoder_t *dec, picture_t *p_pic )
*
* \param dec the decoder object
* \param p_cc the closed-caption to queue
* \param p_cc_present array-of-bool where each entry indicates whether the
* given channel is present or not
* \param i_depth the closed-caption to queue reorder depth, or simply 0
* if using the old mpgv block flag tagging
* \param p_desc decoder_cc_desc_t description structure
* \return 0 if queued, -1 on error
*/
static inline int decoder_QueueCc( decoder_t *dec, block_t *p_cc,
bool p_cc_present[4], int i_depth )
const decoder_cc_desc_t *p_desc )
{
if( dec->pf_queue_cc == NULL )
{
block_Release( p_cc );
return -1;
}
return dec->pf_queue_cc( dec, p_cc, p_cc_present, i_depth );
return dec->pf_queue_cc( dec, p_cc, p_desc );
}
/**
......
......@@ -864,7 +864,10 @@ static void DecodeSidedata( decoder_t *p_dec, const AVFrame *frame, picture_t *p
p_cc->i_dts = p_cc->i_pts = p_pic->date;
else
p_cc->i_pts = p_cc->i_dts;
decoder_QueueCc( p_dec, p_cc, p_sys->cc.pb_present, 4 );
decoder_cc_desc_t desc;
desc.i_608_channels = p_sys->cc.i_608channels;
desc.i_reorder_depth = 4;
decoder_QueueCc( p_dec, p_cc, &desc );
}
cc_Flush( &p_sys->cc );
}
......
......@@ -42,7 +42,7 @@ enum cc_payload_type_e
typedef struct
{
/* Which channel are present */
bool pb_present[4];
uint8_t i_608channels;
/* */
bool b_reorder;
......@@ -62,8 +62,7 @@ typedef struct
static inline void cc_Init( cc_data_t *c )
{
for( int i = 0; i < 4; i++ )
c->pb_present[i] = false;
c->i_608channels = 0;
c->i_data = 0;
c->b_reorder = false;
c->i_payload_type = CC_PAYLOAD_NONE;
......@@ -83,10 +82,7 @@ static inline void cc_AppendData( cc_data_t *c, uint8_t cc_preamble, const uint8
{
uint8_t i_field = cc_preamble & 0x03;
if( i_field == 0 || i_field == 1 )
{
c->pb_present[2*i_field+0] =
c->pb_present[2*i_field+1] = true;
}
c->i_608channels |= (3 << (2 * i_field));
c->p_data[c->i_data++] = cc_preamble;
c->p_data[c->i_data++] = cc[0];
......
......@@ -717,7 +717,10 @@ static void SendCc( decoder_t *p_dec )
p_cc->i_dts =
p_cc->i_pts = p_sys->cc.b_reorder ? p_sys->i_cc_pts : p_sys->i_cc_dts;
p_cc->i_flags = p_sys->i_cc_flags & BLOCK_FLAG_TYPE_MASK;
decoder_QueueCc( p_dec, p_cc, p_sys->cc.pb_present, p_sys->cc.b_reorder ? 0 : -1 );
decoder_cc_desc_t desc;
desc.i_608_channels = p_sys->cc.i_608channels;
desc.i_reorder_depth = p_sys->cc.b_reorder ? 0 : -1;
decoder_QueueCc( p_dec, p_cc, &desc );
}
cc_Flush( &p_sys->cc );
return;
......
......@@ -759,8 +759,12 @@ static int DemuxRecVideo( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_bl
}
/* Register the CC decoders when needed */
for( i = 0; i < 4; i++ )
uint64_t i_chans = p_sys->cc.i_608channels;
for( i = 0; i_chans > 0; i++, i_chans >>= 1 )
{
if( (i_chans & 1) == 0 || p_sys->p_cc[i] )
continue;
static const char *ppsz_description[4] = {
N_("Closed captions 1"),
N_("Closed captions 2"),
......@@ -770,8 +774,6 @@ static int DemuxRecVideo( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_bl
es_format_t fmt;
if( !p_sys->cc.pb_present[i] || p_sys->p_cc[i] )
continue;
es_format_Init( &fmt, SPU_ES, VLC_CODEC_CEA608 );
fmt.subs.cc.i_channel = i;
......
......@@ -135,7 +135,7 @@ struct decoder_sys_t
static block_t *Packetize( decoder_t *, block_t ** );
static block_t *PacketizeAVC1( decoder_t *, block_t ** );
static block_t *GetCc( decoder_t *p_dec, bool pb_present[4], int * );
static block_t *GetCc( decoder_t *p_dec, decoder_cc_desc_t * );
static void PacketizeFlush( decoder_t * );
static void PacketizeReset( void *p_private, bool b_broken );
......@@ -486,9 +486,9 @@ static block_t *PacketizeAVC1( decoder_t *p_dec, block_t **pp_block )
/*****************************************************************************
* GetCc:
*****************************************************************************/
static block_t *GetCc( decoder_t *p_dec, bool pb_present[4], int *pi_reorder_depth )
static block_t *GetCc( decoder_t *p_dec, decoder_cc_desc_t *p_desc )
{
return cc_storage_get_current( p_dec->p_sys->p_ccs, pb_present, pi_reorder_depth );
return cc_storage_get_current( p_dec->p_sys->p_ccs, p_desc );
}
/****************************************************************************
......
......@@ -71,7 +71,7 @@ static block_t *PacketizeParse(void *p_private, bool *pb_ts_used, block_t *);
static block_t *ParseNALBlock(decoder_t *, bool *pb_ts_used, block_t *);
static int PacketizeValidate(void *p_private, block_t *);
static bool ParseSEICallback( const hxxx_sei_data_t *, void * );
static block_t *GetCc( decoder_t *, bool pb_present[4], int * );
static block_t *GetCc( decoder_t *, decoder_cc_desc_t * );
struct decoder_sys_t
{
......@@ -304,9 +304,9 @@ static void PacketizeFlush( decoder_t *p_dec )
/*****************************************************************************
* GetCc:
*****************************************************************************/
static block_t *GetCc( decoder_t *p_dec, bool pb_present[4], int *pi_reorder_depth )
static block_t *GetCc( decoder_t *p_dec, decoder_cc_desc_t *p_desc )
{
return cc_storage_get_current( p_dec->p_sys->p_ccs, pb_present, pi_reorder_depth );
return cc_storage_get_current( p_dec->p_sys->p_ccs, p_desc );
}
/****************************************************************************
......
......@@ -21,10 +21,11 @@
# include "config.h"
#endif
#include "hxxx_common.h"
#include <vlc_common.h>
#include <vlc_block.h>
#include <vlc_codec.h>
#include "hxxx_common.h"
#include "../codec/cc.h"
/****************************************************************************
......@@ -80,16 +81,10 @@ void cc_storage_commit( cc_storage_t *p_ccs, block_t *p_pic )
cc_Flush( &p_ccs->next );
}
block_t * cc_storage_get_current( cc_storage_t *p_ccs, bool pb_present[4],
int *pi_reorder_depth )
block_t * cc_storage_get_current( cc_storage_t *p_ccs, decoder_cc_desc_t *p_desc )
{
block_t *p_block;
*pi_reorder_depth = p_ccs->current.b_reorder ? 4 : -1;
for( int i = 0; i < 4; i++ )
pb_present[i] = p_ccs->current.pb_present[i];
if( !p_ccs->current.b_reorder && p_ccs->current.i_data <= 0 )
return NULL;
......@@ -100,6 +95,9 @@ block_t * cc_storage_get_current( cc_storage_t *p_ccs, bool pb_present[4],
p_block->i_dts =
p_block->i_pts = p_ccs->current.b_reorder ? p_ccs->i_pts : p_ccs->i_dts;
p_block->i_flags = p_ccs->i_flags & BLOCK_FLAG_TYPE_MASK;
p_desc->i_608_channels = p_ccs->current.i_608channels;
p_desc->i_reorder_depth = p_ccs->current.b_reorder ? 4 : -1;
}
cc_Flush( &p_ccs->current );
......
......@@ -33,8 +33,7 @@ void cc_storage_append( cc_storage_t *p_ccs, bool b_top_field_first,
const uint8_t *p_buf, size_t i_buf );
void cc_storage_commit( cc_storage_t *p_ccs, block_t *p_pic );
block_t * cc_storage_get_current( cc_storage_t *p_ccs, bool pb_present[4],
int *pi_reorder_depth );
block_t * cc_storage_get_current( cc_storage_t *p_ccs, decoder_cc_desc_t * );
/* */
......
......@@ -177,7 +177,7 @@ struct decoder_sys_t
static block_t *Packetize( decoder_t *, block_t ** );
static void PacketizeFlush( decoder_t * );
static block_t *GetCc( decoder_t *p_dec, bool pb_present[4], int * );
static block_t *GetCc( decoder_t *p_dec, decoder_cc_desc_t * );
static void PacketizeReset( void *p_private, bool b_broken );
static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t * );
......@@ -312,15 +312,10 @@ static void PacketizeFlush( decoder_t *p_dec )
/*****************************************************************************
* GetCc:
*****************************************************************************/
static block_t *GetCc( decoder_t *p_dec, bool pb_present[4], int *pi_reorder_depth )
static block_t *GetCc( decoder_t *p_dec, decoder_cc_desc_t *p_desc )
{
decoder_sys_t *p_sys = p_dec->p_sys;
block_t *p_cc;
int i;
*pi_reorder_depth = p_sys->cc.b_reorder ? 0 : -1;
for( i = 0; i < 4; i++ )
pb_present[i] = p_sys->cc.pb_present[i];
if( !p_sys->cc.b_reorder && p_sys->cc.i_data <= 0 )
return NULL;
......@@ -332,6 +327,9 @@ static block_t *GetCc( decoder_t *p_dec, bool pb_present[4], int *pi_reorder_dep
p_cc->i_dts =
p_cc->i_pts = p_sys->cc.b_reorder ? p_sys->i_cc_pts : p_sys->i_cc_dts;
p_cc->i_flags = p_sys->i_cc_flags & BLOCK_FLAG_TYPE_MASK;
p_desc->i_608_channels = p_sys->cc.i_608channels;
p_desc->i_reorder_depth = p_sys->cc.b_reorder ? 0 : -1;
}
cc_Flush( &p_sys->cc );
return p_cc;
......
......@@ -129,7 +129,7 @@ static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t * );
static int PacketizeValidate( void *p_private, block_t * );
static block_t *ParseIDU( decoder_t *p_dec, bool *pb_ts_used, block_t *p_frag );
static block_t *GetCc( decoder_t *p_dec, bool pb_present[4], int * );
static block_t *GetCc( decoder_t *p_dec, decoder_cc_desc_t * );
static const uint8_t p_vc1_startcode[3] = { 0x00, 0x00, 0x01 };
/*****************************************************************************
......@@ -762,14 +762,10 @@ static block_t *ParseIDU( decoder_t *p_dec, bool *pb_ts_used, block_t *p_frag )
/*****************************************************************************
* GetCc:
*****************************************************************************/
static block_t *GetCc( decoder_t *p_dec, bool pb_present[4], int *pi_reorder_depth )
static block_t *GetCc( decoder_t *p_dec, decoder_cc_desc_t *p_desc )
{
decoder_sys_t *p_sys = p_dec->p_sys;
block_t *p_cc;
*pi_reorder_depth = p_sys->cc.b_reorder ? 4 : -1;
for( int i = 0; i < 4; i++ )
pb_present[i] = p_sys->cc.pb_present[i];
p_cc = block_Alloc( p_sys->cc.i_data);
if( p_cc )
......@@ -778,6 +774,9 @@ static block_t *GetCc( decoder_t *p_dec, bool pb_present[4], int *pi_reorder_dep
p_cc->i_dts =
p_cc->i_pts = p_sys->cc.b_reorder ? p_sys->i_cc_pts : p_sys->i_cc_dts;
p_cc->i_flags = p_sys->i_cc_flags & BLOCK_FLAG_TYPE_MASK;
p_desc->i_608_channels = p_sys->cc.i_608channels;
p_desc->i_reorder_depth = p_sys->cc.b_reorder ? 4 : -1;
}
cc_Flush( &p_sys->cc );
return p_cc;
......
......@@ -131,12 +131,12 @@ struct decoder_owner_sys_t
bool b_idle;
/* CC */
#define MAX_CC_DECODERS 4 /* The es_out only creates one type of es */
struct
{
bool b_supported;
bool pb_present[4];
uint8_t i_reorder_depth;
decoder_t *pp_decoder[4];
decoder_cc_desc_t desc;
decoder_t *pp_decoder[MAX_CC_DECODERS];
} cc;
/* Delay */
......@@ -907,35 +907,37 @@ static void DecoderProcessSout( decoder_t *p_dec, block_t *p_block )
#endif
static void DecoderPlayCc( decoder_t *p_dec, block_t *p_cc,
bool pb_present[4], int i_reorder_depth )
const decoder_cc_desc_t *p_desc )
{
decoder_owner_sys_t *p_owner = p_dec->p_owner;
bool b_processed = false;
int i_cc_decoder = 0;
vlc_mutex_lock( &p_owner->lock );
for( int i = 0; i < 4; i++ )
{
p_owner->cc.pb_present[i] |= pb_present[i];
if( p_owner->cc.pp_decoder[i] )
i_cc_decoder++;
}
p_owner->cc.i_reorder_depth = i_reorder_depth;
for( int i = 0; i < 4; i++ )
p_owner->cc.desc = *p_desc;
/* Fanout data to all decoders. */
uint64_t i_bitmap = p_owner->cc.desc.i_608_channels;
for( int i=0; i_bitmap > 0; i_bitmap >>= 1, i++ )
{
if( !p_owner->cc.pp_decoder[i] )
decoder_t *p_ccdec = p_owner->cc.pp_decoder[i];
if( !p_ccdec )
continue;
block_FifoPut( p_owner->cc.pp_decoder[i]->p_owner->p_fifo,
(i_cc_decoder > 1) ? block_Duplicate(p_cc) : p_cc);
i_cc_decoder--;
b_processed = true;
if( i_bitmap > 1 )
{
block_FifoPut( p_ccdec->p_owner->p_fifo, block_Duplicate(p_cc) );
}
else
{
block_FifoPut( p_ccdec->p_owner->p_fifo, p_cc );
p_cc = NULL; /* was last dec */
}
}
vlc_mutex_unlock( &p_owner->lock );
if( !b_processed )
if( p_cc ) /* can have bitmap set but no created decs */
block_Release( p_cc );
}
......@@ -943,7 +945,7 @@ static void PacketizerGetCc( decoder_t *p_dec, decoder_t *p_dec_cc )
{
decoder_owner_sys_t *p_owner = p_dec->p_owner;
block_t *p_cc;
bool pb_present[4];
decoder_cc_desc_t desc;
/* Do not try retreiving CC if not wanted (sout) or cannot be retreived */
if( !p_owner->cc.b_supported )
......@@ -951,15 +953,14 @@ static void PacketizerGetCc( decoder_t *p_dec, decoder_t *p_dec_cc )
assert( p_dec_cc->pf_get_cc != NULL );
int i_reorder_depth;
p_cc = p_dec_cc->pf_get_cc( p_dec_cc, pb_present, &i_reorder_depth );
p_cc = p_dec_cc->pf_get_cc( p_dec_cc, &desc );
if( !p_cc )
return;
DecoderPlayCc( p_dec, p_cc, pb_present, i_reorder_depth );
DecoderPlayCc( p_dec, p_cc, &desc );
}
static int DecoderQueueCc( decoder_t *p_videodec, block_t *p_cc,
bool p_cc_present[4], int i_reorder_depth )
const decoder_cc_desc_t *p_desc )
{
decoder_owner_sys_t *p_owner = p_videodec->p_owner;
......@@ -967,7 +968,7 @@ static int DecoderQueueCc( decoder_t *p_videodec, block_t *p_cc,
{
if( p_owner->cc.b_supported &&
( !p_owner->p_packetizer || !p_owner->p_packetizer->pf_get_cc ) )
DecoderPlayCc( p_videodec, p_cc, p_cc_present, i_reorder_depth );
DecoderPlayCc( p_videodec, p_cc, p_desc );
else
block_Release( p_cc );
}
......@@ -1467,7 +1468,7 @@ static void DecoderProcessFlush( decoder_t *p_dec )
/* flush CC sub decoders */
if( p_owner->cc.b_supported )
{
for( int i=0; i<4; i++ )
for( int i=0; i<MAX_CC_DECODERS; i++ )
{
decoder_t *p_subdec = p_owner->cc.pp_decoder[i];
if( p_subdec && p_subdec->pf_flush )
......@@ -1775,12 +1776,9 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
/* */
p_owner->cc.b_supported = ( p_sout == NULL );
for( unsigned i = 0; i < 4; i++ )
{
p_owner->cc.pb_present[i] = false;
p_owner->cc.desc.i_608_channels = 0;
for( unsigned i = 0; i < MAX_CC_DECODERS; i++ )
p_owner->cc.pp_decoder[i] = NULL;
}
p_owner->cc.i_reorder_depth = 0;
p_owner->i_ts_delay = 0;
return p_dec;
}
......@@ -1996,8 +1994,8 @@ void input_DecoderDelete( decoder_t *p_dec )
/* */
if( p_dec->p_owner->cc.b_supported )
{
for( int i = 0; i < 4; i++ )
input_DecoderSetCcState( p_dec, false, i );
for( int i = 0; i < MAX_CC_DECODERS; i++ )
input_DecoderSetCcState( p_dec, VLC_CODEC_CEA608, i, false );
}
/* Delete decoder */
......@@ -2123,23 +2121,41 @@ void input_DecoderFlush( decoder_t *p_dec )
vlc_fifo_Unlock( p_owner->p_fifo );
}
void input_DecoderIsCcPresent( decoder_t *p_dec, bool pb_present[4] )
void input_DecoderGetCcDesc( decoder_t *p_dec, decoder_cc_desc_t *p_desc )
{
decoder_owner_sys_t *p_owner = p_dec->p_owner;
vlc_mutex_lock( &p_owner->lock );
for( int i = 0; i < 4; i++ )
pb_present[i] = p_owner->cc.pb_present[i];
*p_desc = p_owner->cc.desc;
vlc_mutex_unlock( &p_owner->lock );
}
int input_DecoderSetCcState( decoder_t *p_dec, bool b_decode, int i_channel )
static bool input_DecoderHasCCChanFlag( decoder_t *p_dec,
vlc_fourcc_t codec, int i_channel )
{
decoder_owner_sys_t *p_owner = p_dec->p_owner;
//msg_Warn( p_dec, "input_DecoderSetCcState: %d @%d", b_decode, i_channel );
int i_max_channels;
uint64_t i_bitmap;
if( codec == VLC_CODEC_CEA608 )
{
i_max_channels = 4;
i_bitmap = p_owner->cc.desc.i_608_channels;
}
else return false;
return ( i_channel >= 0 && i_channel < i_max_channels &&
( i_bitmap & ((uint64_t)1 << i_channel) ) );
}
if( i_channel < 0 || i_channel >= 4 || !p_owner->cc.pb_present[i_channel] )
int input_DecoderSetCcState( decoder_t *p_dec, vlc_fourcc_t codec,
int i_channel, bool b_decode )
{
decoder_owner_sys_t *p_owner = p_dec->p_owner;
//msg_Warn( p_dec, "input_DecoderSetCcState: %d @%x", b_decode, i_channel );
if( !input_DecoderHasCCChanFlag( p_dec, codec, i_channel ) )
return VLC_EGENERIC;
if( b_decode )
......@@ -2147,9 +2163,9 @@ int input_DecoderSetCcState( decoder_t *p_dec, bool b_decode, int i_channel )
decoder_t *p_cc;
es_format_t fmt;
es_format_Init( &fmt, SPU_ES, VLC_CODEC_CEA608 );
es_format_Init( &fmt, SPU_ES, codec );
fmt.subs.cc.i_channel = i_channel;
fmt.subs.cc.i_reorder_depth = p_owner->cc.i_reorder_depth;
fmt.subs.cc.i_reorder_depth = p_owner->cc.desc.i_reorder_depth;
p_cc = input_DecoderNew( p_owner->p_input, &fmt,
p_dec->p_owner->p_clock, p_owner->p_sout );
if( !p_cc )
......@@ -2187,18 +2203,18 @@ int input_DecoderSetCcState( decoder_t *p_dec, bool b_decode, int i_channel )
return VLC_SUCCESS;
}
int input_DecoderGetCcState( decoder_t *p_dec, bool *pb_decode, int i_channel )
int input_DecoderGetCcState( decoder_t *p_dec, vlc_fourcc_t codec,
int i_channel, bool *pb_decode )
{
decoder_owner_sys_t *p_owner = p_dec->p_owner;
*pb_decode = false;
if( i_channel < 0 || i_channel >= 4 || !p_owner->cc.pb_present[i_channel] )
if( !input_DecoderHasCCChanFlag( p_dec, codec, i_channel ) )
return VLC_EGENERIC;
vlc_mutex_lock( &p_owner->lock );
*pb_decode = p_owner->cc.pp_decoder[i_channel] != NULL;
vlc_mutex_unlock( &p_owner->lock );
return VLC_EGENERIC;
return VLC_SUCCESS;
}
void input_DecoderChangePause( decoder_t *p_dec, bool b_paused, mtime_t i_date )
......
......@@ -66,19 +66,18 @@ bool input_DecoderIsEmpty( decoder_t * );
/**
* This function activates the request closed caption channel.
*/
int input_DecoderSetCcState( decoder_t *, bool b_decode, int i_channel );
int input_DecoderSetCcState( decoder_t *, vlc_fourcc_t, int i_channel, bool b_decode );
/**
* This function returns an error if the requested channel does not exist and
* set pb_decode to the channel status(active or not) otherwise.
*/
int input_DecoderGetCcState( decoder_t *, bool *pb_decode, int i_channel );
int input_DecoderGetCcState( decoder_t *, vlc_fourcc_t, int i_channel, bool *pb_decode );
/**
* This function set each pb_present entry to true if the corresponding channel
* exists or false otherwise.
* This function get cc channels descriptions
*/
void input_DecoderIsCcPresent( decoder_t *, bool pb_present[4] );
void input_DecoderGetCcDesc( decoder_t *, decoder_cc_desc_t * );
/**
* This function force the display of the next picture and fills the stream
......
......@@ -93,8 +93,12 @@ struct es_out_id_t
decoder_t *p_dec_record;
/* Fields for Video with CC */
bool pb_cc_present[4];
es_out_id_t *pp_cc_es[4];
struct
{
vlc_fourcc_t type;
uint64_t i_bitmap; /* channels bitmap */
es_out_id_t *pp_es[64]; /* a max of 64 chans for CEA708 */
} cc;
/* Field for CC track from a master video */
es_out_id_t *p_master;
......@@ -1624,8 +1628,8 @@ static es_out_id_t *EsOutAddSlave( es_out_t *out, const es_format_t *fmt, es_out
es->psz_language_code = LanguageGetCode( es->fmt.psz_language );
es->p_dec = NULL;
es->p_dec_record = NULL;
for( i = 0; i < 4; i++ )
es->pb_cc_present[i] = false;
es->cc.type = 0;
es->cc.i_bitmap = 0;
es->p_master = p_master;
TAB_APPEND( p_sys->i_es, p_sys->es, es );
......@@ -1660,8 +1664,8 @@ static bool EsIsSelected( es_out_id_t *es )
if( es->p_master->p_dec )
{
int i_channel = EsOutGetClosedCaptionsChannel( &es->fmt );
if( i_channel != -1 )
input_DecoderGetCcState( es->p_master->p_dec, &b_decode, i_channel );
input_DecoderGetCcState( es->p_master->p_dec, es->fmt.i_codec,
i_channel, &b_decode );
}
return b_decode;
}
......@@ -1727,7 +1731,9 @@ static void EsSelect( es_out_t *out, es_out_id_t *es )
i_channel = EsOutGetClosedCaptionsChannel( &es->fmt );
if( i_channel == -1 || input_DecoderSetCcState( es->p_master->p_dec, true, i_channel ) )
if( i_channel == -1 ||
input_DecoderSetCcState( es->p_master->p_dec, es->fmt.i_codec,
i_channel, true ) )
return;
}
else
......@@ -1772,6 +1778,34 @@ static void EsSelect( es_out_t *out, es_out_id_t *es )
input_SendEventTeletextSelect( p_input, EsFmtIsTeletext( &es->fmt ) ? es->i_id : -1 );
}
static void EsDeleteCCChannels( es_out_t *out, es_out_id_t *parent )
{
es_out_sys_t *p_sys = out->p_sys;
input_thread_t *p_input = p_sys->p_input;
if( parent->cc.type == 0 )
return;
const int i_spu_id = var_GetInteger( p_input, "spu-es");
uint64_t i_bitmap = parent->cc.i_bitmap;
for( int i = 0; i_bitmap > 0; i++, i_bitmap >>= 1 )
{
if( (i_bitmap & 1) == 0 || !parent->cc.pp_es[i] )
continue;
if( i_spu_id == parent->cc.pp_es[i]->i_id )
{
/* Force unselection of the CC */
input_SendEventEsSelect( p_input, SPU_ES, -1 );
}
EsOutDel( out, parent->cc.pp_es[i] );
}
parent->cc.i_bitmap = 0;
parent->cc.type = 0;
}
static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update )
{
es_out_sys_t *p_sys = out->p_sys;
......@@ -1789,27 +1823,13 @@ static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update )
{
int i_channel = EsOutGetClosedCaptionsChannel( &es->fmt );
if( i_channel != -1 )
input_DecoderSetCcState( es->p_master->p_dec, false, i_channel );
input_DecoderSetCcState( es->p_master->p_dec, es->fmt.i_codec,
i_channel, false );
}
}
else
{
const int i_spu_id = var_GetInteger( p_input, "spu-es");
int i;
for( i = 0; i < 4; i++ )
{
if( !es->pb_cc_present[i] || !es->pp_cc_es[i] )
continue;
if( i_spu_id == es->pp_cc_es[i]->i_id )
{
/* Force unselection of the CC */
input_SendEventEsSelect( p_input, SPU_ES, -1 );
}
EsOutDel( out, es->pp_cc_es[i] );
es->pb_cc_present[i] = false;
}
EsDeleteCCChannels( out, es );
EsDestroyDecoder( out, es );
}
......@@ -1965,6 +1985,46 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, bool b_force )
}
}
static void EsOutCreateCCChannels( es_out_t *out, vlc_fourcc_t codec, uint64_t i_bitmap,
const char *psz_descfmt, es_out_id_t *parent )
{
es_out_sys_t *p_sys = out->p_sys;
input_thread_t *p_input = p_sys->p_input;
/* Only one type of captions is allowed ! */
if( parent->cc.type && parent->cc.type != codec )
return;
uint64_t i_existingbitmap = parent->cc.i_bitmap;
for( int i = 0; i_bitmap > 0; i++, i_bitmap >>= 1, i_existingbitmap >>= 1 )
{
es_format_t fmt;
if( (i_bitmap & 1) == 0 || (i_existingbitmap & 1) )
continue;
msg_Dbg( p_input, "Adding CC track %d for es[%d]", 1+i, parent->i_id );
es_format_Init( &fmt, SPU_ES, codec );
fmt.subs.cc.i_channel = i;
fmt.i_group = parent->fmt.i_group;
if( asprintf( &fmt.psz_description, psz_descfmt, 1 + i ) == -1 )
fmt.psz_description = NULL;
es_out_id_t **pp_es = &parent->cc.pp_es[i];
*pp_es = EsOutAddSlave( out, &fmt, parent );
es_format_Clean( &fmt );
/* */
parent->cc.i_bitmap |= (1ULL << i);
parent->cc.type = codec;
/* Enable if user specified on command line */
if (p_sys->sub.i_channel == i)
EsOutSelect(out, *pp_es, true);
}
}
/**
* Send a block for the given es_out
*
......@@ -2060,33 +2120,11 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
}