[vlc-devel] [PATCH 2/2] codec/esout: enable both 608 and 708 captions
Francois Cartegnie
fcvlcdev at free.fr
Tue Sep 26 22:59:51 CEST 2017
Extends the get_cc hack to make embedded captions work
also with CEA708.
CEA708 replaces EIA608 when it's possible and set in prefs.
(as long as CEA708 is not stable)
---
include/vlc_codec.h | 26 ++++---
modules/codec/avcodec/video.c | 6 +-
modules/codec/cc.h | 16 ++---
modules/codec/libmpeg2.c | 6 +-
modules/demux/ty.c | 8 ++-
modules/packetizer/h264.c | 6 +-
modules/packetizer/hevc.c | 6 +-
modules/packetizer/hxxx_common.c | 17 +++--
modules/packetizer/hxxx_common.h | 3 +-
modules/packetizer/mpegvideo.c | 13 ++--
modules/packetizer/vc1.c | 12 ++--
src/input/decoder.c | 118 ++++++++++++++++++-------------
src/input/decoder.h | 9 ++-
src/input/es_out.c | 145 +++++++++++++++++++++++++--------------
src/libvlc-module.c | 9 +++
15 files changed, 244 insertions(+), 156 deletions(-)
diff --git a/include/vlc_codec.h b/include/vlc_codec.h
index c62ccd0..3499ede 100644
--- a/include/vlc_codec.h
+++ b/include/vlc_codec.h
@@ -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,15 @@ 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 */
+ uint64_t i_708_channels; /* 708 */
+ int i_reorder_depth; /* reorder depth, -1 for no reorder, 0 for old P/B flag based */
+};
+
/**
* @}
*/
@@ -311,21 +322,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 );
}
/**
diff --git a/modules/codec/avcodec/video.c b/modules/codec/avcodec/video.c
index e243191..02af2ae 100644
--- a/modules/codec/avcodec/video.c
+++ b/modules/codec/avcodec/video.c
@@ -864,7 +864,11 @@ 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_708_channels = p_sys->cc.i_708channels;
+ desc.i_reorder_depth = 4;
+ decoder_QueueCc( p_dec, p_cc, &desc );
}
cc_Flush( &p_sys->cc );
}
diff --git a/modules/codec/cc.h b/modules/codec/cc.h
index 4562e53..fb80d17 100644
--- a/modules/codec/cc.h
+++ b/modules/codec/cc.h
@@ -42,8 +42,8 @@ enum cc_payload_type_e
typedef struct
{
/* Which channel are present */
- bool pb_present[4];
- int64_t i_708_flags;
+ uint64_t i_708channels;
+ uint8_t i_608channels;
/* */
bool b_reorder;
@@ -63,9 +63,8 @@ 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_708_flags = 0;
+ c->i_608channels = 0;
+ c->i_708channels = 0;
c->i_data = 0;
c->b_reorder = false;
c->i_payload_type = CC_PAYLOAD_NONE;
@@ -85,10 +84,9 @@ 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));
+ else
+ c->i_708channels |= 1;
c->p_data[c->i_data++] = cc_preamble;
c->p_data[c->i_data++] = cc[0];
diff --git a/modules/codec/libmpeg2.c b/modules/codec/libmpeg2.c
index 2cbc96c..f58972a 100644
--- a/modules/codec/libmpeg2.c
+++ b/modules/codec/libmpeg2.c
@@ -717,7 +717,11 @@ 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_708_channels = p_sys->cc.i_708channels;
+ desc.i_reorder_depth = p_sys->cc.b_reorder ? 0 : -1;
+ decoder_QueueCc( p_dec, p_cc, &desc );
}
cc_Flush( &p_sys->cc );
return;
diff --git a/modules/demux/ty.c b/modules/demux/ty.c
index 67f7aca..d96ea13 100644
--- a/modules/demux/ty.c
+++ b/modules/demux/ty.c
@@ -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;
diff --git a/modules/packetizer/h264.c b/modules/packetizer/h264.c
index a681422..8cca41f 100644
--- a/modules/packetizer/h264.c
+++ b/modules/packetizer/h264.c
@@ -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 );
}
/****************************************************************************
diff --git a/modules/packetizer/hevc.c b/modules/packetizer/hevc.c
index 9bdca10..40cc79e 100644
--- a/modules/packetizer/hevc.c
+++ b/modules/packetizer/hevc.c
@@ -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 );
}
/****************************************************************************
diff --git a/modules/packetizer/hxxx_common.c b/modules/packetizer/hxxx_common.c
index 0eecf9a..45b33fd 100644
--- a/modules/packetizer/hxxx_common.c
+++ b/modules/packetizer/hxxx_common.c
@@ -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,10 @@ 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_708_channels = p_ccs->current.i_708channels;
+ p_desc->i_reorder_depth = p_ccs->current.b_reorder ? 4 : -1;
}
cc_Flush( &p_ccs->current );
diff --git a/modules/packetizer/hxxx_common.h b/modules/packetizer/hxxx_common.h
index 6e7cd09..eff2f0b 100644
--- a/modules/packetizer/hxxx_common.h
+++ b/modules/packetizer/hxxx_common.h
@@ -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 * );
/* */
diff --git a/modules/packetizer/mpegvideo.c b/modules/packetizer/mpegvideo.c
index 71126d8..703b1d7 100644
--- a/modules/packetizer/mpegvideo.c
+++ b/modules/packetizer/mpegvideo.c
@@ -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,10 @@ 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_708_channels = p_sys->cc.i_708channels;
+ p_desc->i_reorder_depth = p_sys->cc.b_reorder ? 0 : -1;
}
cc_Flush( &p_sys->cc );
return p_cc;
diff --git a/modules/packetizer/vc1.c b/modules/packetizer/vc1.c
index b075299..901e2c0 100644
--- a/modules/packetizer/vc1.c
+++ b/modules/packetizer/vc1.c
@@ -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,10 @@ 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_708_channels = p_sys->cc.i_708channels;
+ p_desc->i_reorder_depth = p_sys->cc.b_reorder ? 4 : -1;
}
cc_Flush( &p_sys->cc );
return p_cc;
diff --git a/src/input/decoder.c b/src/input/decoder.c
index 54eec0f..f5aaefb 100644
--- a/src/input/decoder.c
+++ b/src/input/decoder.c
@@ -131,12 +131,12 @@ struct decoder_owner_sys_t
bool b_idle;
/* CC */
+#define MAX_CC_DECODERS 64 /* 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,39 @@ 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. 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++ )
{
- 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 +947,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 +955,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 +970,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 +1470,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 )
@@ -1773,12 +1776,10 @@ 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;
+ p_owner->cc.desc.i_708_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;
}
@@ -1994,8 +1995,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_CEA708, i, false );
}
/* Delete decoder */
@@ -2121,23 +2122,46 @@ 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;
+
+ 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 if( codec == VLC_CODEC_CEA708 )
+ {
+ i_max_channels = 64;
+ i_bitmap = p_owner->cc.desc.i_708_channels;
+ }
+ else return false;
+
+ return ( i_channel >= 0 && i_channel < i_max_channels &&
+ ( i_bitmap & ((uint64_t)1 << 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 @%d", b_decode, i_channel );
+ //msg_Warn( p_dec, "input_DecoderSetCcState: %d @%x", b_decode, i_channel );
- 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;
if( b_decode )
@@ -2145,9 +2169,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 )
@@ -2185,18 +2209,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 )
diff --git a/src/input/decoder.h b/src/input/decoder.h
index 226ecde..ccfe8ec 100644
--- a/src/input/decoder.h
+++ b/src/input/decoder.h
@@ -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
diff --git a/src/input/es_out.c b/src/input/es_out.c
index b19c500..a081e60 100644
--- a/src/input/es_out.c
+++ b/src/input/es_out.c
@@ -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;
@@ -209,6 +213,8 @@ static inline int EsOutGetClosedCaptionsChannel( const es_format_t *p_fmt )
int i_channel;
if( p_fmt->i_codec == VLC_CODEC_CEA608 && p_fmt->subs.cc.i_channel < 4 )
i_channel = p_fmt->subs.cc.i_channel;
+ else if( p_fmt->i_codec == VLC_CODEC_CEA708 && p_fmt->subs.cc.i_channel < 64 )
+ i_channel = p_fmt->subs.cc.i_channel;
else
i_channel = -1;
return i_channel;
@@ -1624,8 +1630,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 +1666,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 +1733,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 +1780,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 +1825,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 +1987,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 +2122,14 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
}
/* Check CC status */
- bool pb_cc[4];
-
- input_DecoderIsCcPresent( es->p_dec, pb_cc );
- for( int i = 0; i < 4; i++ )
- {
- es_format_t fmt;
-
- if( es->pb_cc_present[i] || !pb_cc[i] )
- continue;
- msg_Dbg( p_input, "Adding CC track %d for es[%d]", 1+i, es->i_id );
-
- es_format_Init( &fmt, SPU_ES, VLC_CODEC_CEA608 );
- fmt.subs.cc.i_channel = i;
- fmt.i_group = es->fmt.i_group;
- if( asprintf( &fmt.psz_description,
- _("Closed captions %u"), 1 + i ) == -1 )
- fmt.psz_description = NULL;
- es->pp_cc_es[i] = EsOutAddSlave( out, &fmt, es );
- es_format_Clean( &fmt );
-
- /* */
- es->pb_cc_present[i] = true;
-
- /* Enable if user specified on command line */
- if (p_sys->sub.i_channel == i)
- EsOutSelect(out, es->pp_cc_es[i], true);
- }
+ decoder_cc_desc_t desc;
+
+ input_DecoderGetCcDesc( es->p_dec, &desc );
+ if( var_InheritInteger( p_input, "captions" ) == 708 )
+ EsOutCreateCCChannels( out, VLC_CODEC_CEA708, desc.i_708_channels,
+ _("DTVCC Closed captions %u"), es );
+ EsOutCreateCCChannels( out, VLC_CODEC_CEA608, desc.i_608_channels,
+ _("Closed captions %u"), es );
vlc_mutex_unlock( &p_sys->lock );
diff --git a/src/libvlc-module.c b/src/libvlc-module.c
index ae6825f..24712fee 100644
--- a/src/libvlc-module.c
+++ b/src/libvlc-module.c
@@ -611,6 +611,11 @@ static const char *const ppsz_clock_descriptions[] =
#define INPUT_SUBTRACK_ID_LONGTEXT N_( \
"Stream ID of the subtitle track to use.")
+#define INPUT_CAPTIONS_TEXT N_(N_("Closed Captions decoder"))
+#define INPUT_CAPTIONS_LONGTEXT N_("Preferred closed captions decoder")
+static const int pi_captions[] = { 608, 708 };
+static const char *const ppsz_captions[] = { N_("EIA/CEA 608"), N_("CEA 708") };
+
#define INPUT_PREFERREDRESOLUTION_TEXT N_("Preferred video resolution")
#define INPUT_PREFERREDRESOLUTION_LONGTEXT N_( \
"When several video formats are available, select one whose " \
@@ -1728,6 +1733,10 @@ vlc_module_begin ()
add_integer( "sub-track-id", -1,
INPUT_SUBTRACK_ID_TEXT, INPUT_SUBTRACK_ID_LONGTEXT, true )
change_safe ()
+ add_integer( "captions", 608,
+ INPUT_CAPTIONS_TEXT, INPUT_CAPTIONS_LONGTEXT, true )
+ change_integer_list( pi_captions, ppsz_captions )
+ change_safe ()
add_integer( "preferred-resolution", -1, INPUT_PREFERREDRESOLUTION_TEXT,
INPUT_PREFERREDRESOLUTION_LONGTEXT, false )
change_safe ()
--
2.9.5
More information about the vlc-devel
mailing list