Commit a0429d00 authored by Laurent Aimar's avatar Laurent Aimar

Added closed captions decoding/extracting from ES data. The CC tracks

are dynamically added when detected.
(Decoder/Packetizer support not yet commited)
parent 2cdbf636
...@@ -71,11 +71,20 @@ struct decoder_t ...@@ -71,11 +71,20 @@ struct decoder_t
/* Tell the decoder if it is allowed to drop frames */ /* Tell the decoder if it is allowed to drop frames */
vlc_bool_t b_pace_control; vlc_bool_t b_pace_control;
/* */
picture_t * ( * pf_decode_video )( decoder_t *, block_t ** ); picture_t * ( * pf_decode_video )( decoder_t *, block_t ** );
aout_buffer_t * ( * pf_decode_audio )( decoder_t *, block_t ** ); aout_buffer_t * ( * pf_decode_audio )( decoder_t *, block_t ** );
subpicture_t * ( * pf_decode_sub) ( decoder_t *, block_t ** ); subpicture_t * ( * pf_decode_sub) ( decoder_t *, block_t ** );
block_t * ( * pf_packetize ) ( decoder_t *, block_t ** ); block_t * ( * pf_packetize ) ( decoder_t *, block_t ** );
/* Closed Caption (CEA 608/708) extraction.
* If set, it *may* be called after pf_decode_video/pf_packetize
* returned data. It should return CC for the pictures returned by the
* last pf_packetize/pf_decode_video call only,
* pb_present will be used to known which cc channel are present (but
* globaly, not necessary for the current packet */
block_t * ( * pf_get_cc ) ( decoder_t *, vlc_bool_t pb_present[4] );
/* /*
* Buffers allocation * Buffers allocation
*/ */
......
...@@ -1679,6 +1679,7 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id ) ...@@ -1679,6 +1679,7 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id )
id->p_decoder->fmt_out.i_extra = 0; id->p_decoder->fmt_out.i_extra = 0;
id->p_decoder->fmt_out.p_extra = 0; id->p_decoder->fmt_out.p_extra = 0;
id->p_decoder->pf_decode_video = 0; id->p_decoder->pf_decode_video = 0;
id->p_decoder->pf_get_cc = 0;
id->p_decoder->pf_vout_buffer_new = video_new_buffer_decoder; id->p_decoder->pf_vout_buffer_new = video_new_buffer_decoder;
id->p_decoder->pf_vout_buffer_del = video_del_buffer_decoder; id->p_decoder->pf_vout_buffer_del = video_del_buffer_decoder;
id->p_decoder->pf_picture_link = video_link_picture_decoder; id->p_decoder->pf_picture_link = video_link_picture_decoder;
......
...@@ -89,8 +89,26 @@ struct decoder_owner_sys_t ...@@ -89,8 +89,26 @@ struct decoder_owner_sys_t
/* fifo */ /* fifo */
block_fifo_t *p_fifo; block_fifo_t *p_fifo;
/* CC */
vlc_bool_t b_cc_supported;
vlc_mutex_t lock_cc;
vlc_bool_t pb_cc_present[4];
decoder_t *pp_cc[4];
}; };
/* */
static void DecoderUnsupportedCodec( decoder_t *p_dec, vlc_fourcc_t codec )
{
msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'.\n"
"VLC probably does not support this sound or video format.",
(char*)&codec );
intf_UserFatal( p_dec, VLC_FALSE, _("No suitable decoder module "
"for format"), _("VLC probably does not support the \"%4.4s\" "
"audio or video format. Unfortunately there is no way for you "
"to fix this."), (char*)&codec );
}
/* decoder_GetInputAttachment: /* decoder_GetInputAttachment:
*/ */
input_attachment_t *decoder_GetInputAttachment( decoder_t *p_dec, input_attachment_t *decoder_GetInputAttachment( decoder_t *p_dec,
...@@ -158,13 +176,7 @@ decoder_t *input_DecoderNew( input_thread_t *p_input, ...@@ -158,13 +176,7 @@ decoder_t *input_DecoderNew( input_thread_t *p_input,
if( !p_dec->p_module ) if( !p_dec->p_module )
{ {
msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'.\n" DecoderUnsupportedCodec( p_dec, fmt->i_codec );
"VLC probably does not support this sound or video format.",
(char*)&p_dec->fmt_in.i_codec );
intf_UserFatal( p_dec, VLC_FALSE, _("No suitable decoder module "
"for format"), _("VLC probably does not support the \"%4.4s\" "
"audio or video format. Unfortunately there is no way for you "
"to fix this."), (char*)&p_dec->fmt_in.i_codec );
DeleteDecoder( p_dec ); DeleteDecoder( p_dec );
vlc_object_destroy( p_dec ); vlc_object_destroy( p_dec );
...@@ -237,6 +249,14 @@ void input_DecoderDelete( decoder_t *p_dec ) ...@@ -237,6 +249,14 @@ void input_DecoderDelete( decoder_t *p_dec )
module_Unneed( p_dec, p_dec->p_module ); module_Unneed( p_dec, p_dec->p_module );
} }
/* */
if( p_dec->p_owner->b_cc_supported )
{
int i;
for( i = 0; i < 4; i++ )
input_DecoderSetCcState( p_dec, VLC_FALSE, i );
}
/* Delete decoder configuration */ /* Delete decoder configuration */
DeleteDecoder( p_dec ); DeleteDecoder( p_dec );
...@@ -316,6 +336,89 @@ vlc_bool_t input_DecoderEmpty( decoder_t * p_dec ) ...@@ -316,6 +336,89 @@ vlc_bool_t input_DecoderEmpty( decoder_t * p_dec )
return VLC_TRUE; return VLC_TRUE;
} }
void input_DecoderIsCcPresent( decoder_t *p_dec, vlc_bool_t pb_present[4] )
{
int i;
vlc_mutex_lock( &p_dec->p_owner->lock_cc );
for( i = 0; i < 4; i++ )
pb_present[i] = p_dec->p_owner->pb_cc_present[i];
vlc_mutex_unlock( &p_dec->p_owner->lock_cc );
}
int input_DecoderSetCcState( decoder_t *p_dec, vlc_bool_t b_decode, 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 );
if( i_channel < 0 || i_channel >= 4 || !p_owner->pb_cc_present[i_channel] )
return VLC_EGENERIC;
if( b_decode )
{
static const vlc_fourcc_t fcc[4] = {
VLC_FOURCC('c', 'c', '1', ' '),
VLC_FOURCC('c', 'c', '2', ' '),
VLC_FOURCC('c', 'c', '3', ' '),
VLC_FOURCC('c', 'c', '4', ' '),
};
decoder_t *p_cc;
es_format_t fmt;
es_format_Init( &fmt, SPU_ES, fcc[i_channel] );
p_cc = CreateDecoder( p_owner->p_input, &fmt, VLC_OBJECT_DECODER );
if( !p_cc )
{
msg_Err( p_dec, "could not create decoder" );
intf_UserFatal( p_dec, VLC_FALSE, _("Streaming / Transcoding failed"),
_("VLC could not open the decoder module.") );
return VLC_EGENERIC;
}
else if( !p_cc->p_module )
{
DecoderUnsupportedCodec( p_dec, fcc[i_channel] );
DeleteDecoder( p_cc );
vlc_object_destroy( p_cc );
return VLC_EGENERIC;
}
vlc_mutex_lock( &p_owner->lock_cc );
p_dec->p_owner->pp_cc[i_channel] = p_cc;
vlc_mutex_unlock( &p_owner->lock_cc );
}
else
{
decoder_t *p_cc;
vlc_mutex_lock( &p_owner->lock_cc );
p_cc = p_dec->p_owner->pp_cc[i_channel];
p_dec->p_owner->pp_cc[i_channel] = NULL;
vlc_mutex_unlock( &p_dec->p_owner->lock_cc );
if( p_cc )
{
vlc_object_kill( p_cc );
module_Unneed( p_cc, p_cc->p_module );
DeleteDecoder( p_cc );
vlc_object_destroy( p_cc );
}
}
return VLC_SUCCESS;
}
int input_DecoderGetCcState( decoder_t *p_dec, vlc_bool_t *pb_decode, int i_channel )
{
decoder_owner_sys_t *p_owner = p_dec->p_owner;
*pb_decode = VLC_FALSE;
if( i_channel < 0 || i_channel >= 4 || !p_owner->pb_cc_present[i_channel] )
return VLC_EGENERIC;
vlc_mutex_lock( &p_owner->lock_cc );
*pb_decode = p_dec->p_owner->pp_cc[i_channel] != NULL;
vlc_mutex_unlock( &p_dec->p_owner->lock_cc );
return VLC_EGENERIC;
}
/** /**
* Create a decoder object * Create a decoder object
* *
...@@ -328,6 +431,8 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, ...@@ -328,6 +431,8 @@ static decoder_t * CreateDecoder( input_thread_t *p_input,
es_format_t *fmt, int i_object_type ) es_format_t *fmt, int i_object_type )
{ {
decoder_t *p_dec; decoder_t *p_dec;
decoder_owner_sys_t *p_owner;
int i;
p_dec = vlc_object_create( p_input, i_object_type ); p_dec = vlc_object_create( p_input, i_object_type );
if( p_dec == NULL ) if( p_dec == NULL )
...@@ -339,6 +444,7 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, ...@@ -339,6 +444,7 @@ static decoder_t * CreateDecoder( input_thread_t *p_input,
p_dec->pf_decode_audio = 0; p_dec->pf_decode_audio = 0;
p_dec->pf_decode_video = 0; p_dec->pf_decode_video = 0;
p_dec->pf_decode_sub = 0; p_dec->pf_decode_sub = 0;
p_dec->pf_get_cc = 0;
p_dec->pf_packetize = 0; p_dec->pf_packetize = 0;
/* Initialize the decoder fifo */ /* Initialize the decoder fifo */
...@@ -349,7 +455,7 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, ...@@ -349,7 +455,7 @@ static decoder_t * CreateDecoder( input_thread_t *p_input,
es_format_Copy( &p_dec->fmt_out, &null_es_format ); es_format_Copy( &p_dec->fmt_out, &null_es_format );
/* Allocate our private structure for the decoder */ /* Allocate our private structure for the decoder */
p_dec->p_owner = malloc( sizeof( decoder_owner_sys_t ) ); p_dec->p_owner = p_owner = malloc( sizeof( decoder_owner_sys_t ) );
if( p_dec->p_owner == NULL ) if( p_dec->p_owner == NULL )
{ {
msg_Err( p_dec, "out of memory" ); msg_Err( p_dec, "out of memory" );
...@@ -424,7 +530,6 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, ...@@ -424,7 +530,6 @@ static decoder_t * CreateDecoder( input_thread_t *p_input,
/* Copy ourself the input replay gain */ /* Copy ourself the input replay gain */
if( fmt->i_cat == AUDIO_ES ) if( fmt->i_cat == AUDIO_ES )
{ {
int i;
for( i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ ) for( i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ )
{ {
if( !p_dec->fmt_out.audio_replay_gain.pb_peak[i] ) if( !p_dec->fmt_out.audio_replay_gain.pb_peak[i] )
...@@ -439,6 +544,22 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, ...@@ -439,6 +544,22 @@ static decoder_t * CreateDecoder( input_thread_t *p_input,
} }
} }
} }
/* */
p_owner->b_cc_supported = VLC_FALSE;
if( i_object_type == VLC_OBJECT_DECODER )
{
if( p_owner->p_packetizer && p_owner->p_packetizer->pf_get_cc )
p_owner->b_cc_supported = VLC_TRUE;
if( p_dec->pf_get_cc )
p_owner->b_cc_supported = VLC_TRUE;
}
vlc_mutex_init( p_dec, &p_owner->lock_cc );
for( i = 0; i < 4; i++ )
{
p_owner->pb_cc_present[i] = VLC_FALSE;
p_owner->pp_cc[i] = NULL;
}
return p_dec; return p_dec;
} }
...@@ -519,6 +640,44 @@ static void DecoderDecodeAudio( decoder_t *p_dec, block_t *p_block ) ...@@ -519,6 +640,44 @@ static void DecoderDecodeAudio( decoder_t *p_dec, block_t *p_block )
p_aout_buf, i_rate ); p_aout_buf, i_rate );
} }
} }
static void DecoderGetCc( decoder_t *p_dec, decoder_t *p_dec_cc )
{
block_t *p_cc;
vlc_bool_t pb_present[4];
int i;
int i_cc_decoder;
assert( p_dec_cc->pf_get_cc != NULL );
/* Do not try retreiving CC if not wanted (sout) or cannot be retreived */
if( !p_dec->p_owner->b_cc_supported )
return;
p_cc = p_dec_cc->pf_get_cc( p_dec_cc, pb_present );
if( !p_cc )
return;
vlc_mutex_lock( &p_dec->p_owner->lock_cc );
for( i = 0, i_cc_decoder = 0; i < 4; i++ )
{
p_dec->p_owner->pb_cc_present[i] |= pb_present[i];
if( p_dec->p_owner->pp_cc[i] )
i_cc_decoder++;
}
for( i = 0; i < 4; i++ )
{
if( !p_dec->p_owner->pp_cc[i] )
continue;
if( i_cc_decoder > 1 )
DecoderDecode( p_dec->p_owner->pp_cc[i], block_Duplicate( p_cc ) );
else
DecoderDecode( p_dec->p_owner->pp_cc[i], p_cc );
i_cc_decoder--;
}
vlc_mutex_unlock( &p_dec->p_owner->lock_cc );
}
static void VoutDisplayedPicture( vout_thread_t *p_vout, picture_t *p_pic ) static void VoutDisplayedPicture( vout_thread_t *p_vout, picture_t *p_pic )
{ {
vlc_mutex_lock( &p_vout->picture_lock ); vlc_mutex_lock( &p_vout->picture_lock );
...@@ -584,6 +743,9 @@ static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block ) ...@@ -584,6 +743,9 @@ static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block )
p_dec->p_owner->i_preroll_end = -1; p_dec->p_owner->i_preroll_end = -1;
} }
if( ( !p_dec->p_owner->p_packetizer || !p_dec->p_owner->p_packetizer->pf_get_cc ) && p_dec->pf_get_cc )
DecoderGetCc( p_dec, p_dec );
vout_DatePicture( p_dec->p_owner->p_vout, p_pic, vout_DatePicture( p_dec->p_owner->p_vout, p_pic,
p_pic->date ); p_pic->date );
vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic ); vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
...@@ -731,6 +893,8 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) ...@@ -731,6 +893,8 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
es_format_Clean( &p_dec->fmt_in ); es_format_Clean( &p_dec->fmt_in );
es_format_Copy( &p_dec->fmt_in, &p_packetizer->fmt_out ); es_format_Copy( &p_dec->fmt_in, &p_packetizer->fmt_out );
} }
if( p_packetizer->pf_get_cc )
DecoderGetCc( p_dec, p_packetizer );
while( p_packetized_block ) while( p_packetized_block )
{ {
...@@ -863,6 +1027,8 @@ static void DeleteDecoder( decoder_t * p_dec ) ...@@ -863,6 +1027,8 @@ static void DeleteDecoder( decoder_t * p_dec )
vlc_object_destroy( p_dec->p_owner->p_packetizer ); vlc_object_destroy( p_dec->p_owner->p_packetizer );
} }
vlc_mutex_destroy( &p_dec->p_owner->lock_cc );
vlc_object_detach( p_dec ); vlc_object_detach( p_dec );
free( p_dec->p_owner ); free( p_dec->p_owner );
......
...@@ -78,7 +78,15 @@ struct es_out_id_t ...@@ -78,7 +78,15 @@ struct es_out_id_t
es_format_t fmt; es_format_t fmt;
char *psz_language; char *psz_language;
char *psz_language_code; char *psz_language_code;
decoder_t *p_dec; decoder_t *p_dec;
/* Fields for Video with CC */
vlc_bool_t pb_cc_present[4];
es_out_id_t *pp_cc_es[4];
/* Field for CC track from a master video */
es_out_id_t *p_master;
}; };
struct es_out_sys_t struct es_out_sys_t
...@@ -130,6 +138,7 @@ static int EsOutControl( es_out_t *, int i_query, va_list ); ...@@ -130,6 +138,7 @@ static int EsOutControl( es_out_t *, int i_query, va_list );
static void EsOutAddInfo( es_out_t *, es_out_id_t *es ); static void EsOutAddInfo( es_out_t *, es_out_id_t *es );
static vlc_bool_t EsIsSelected( es_out_t *out, es_out_id_t *es );
static void EsSelect( es_out_t *out, es_out_id_t *es ); static void EsSelect( es_out_t *out, es_out_id_t *es );
static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update ); static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update );
static char *LanguageGetName( const char *psz_code ); static char *LanguageGetName( const char *psz_code );
...@@ -380,7 +389,7 @@ vlc_bool_t input_EsOutDecodersEmpty( es_out_t *out ) ...@@ -380,7 +389,7 @@ vlc_bool_t input_EsOutDecodersEmpty( es_out_t *out )
/***************************************************************************** /*****************************************************************************
* *
*****************************************************************************/ *****************************************************************************/
static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es, static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id, es_format_t *fmt, const char *psz_language,
vlc_bool_t b_delete ) vlc_bool_t b_delete )
{ {
es_out_sys_t *p_sys = out->p_sys; es_out_sys_t *p_sys = out->p_sys;
...@@ -389,18 +398,18 @@ static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es, ...@@ -389,18 +398,18 @@ static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
const char *psz_var; const char *psz_var;
if( es->fmt.i_cat == AUDIO_ES ) if( fmt->i_cat == AUDIO_ES )
psz_var = "audio-es"; psz_var = "audio-es";
else if( es->fmt.i_cat == VIDEO_ES ) else if( fmt->i_cat == VIDEO_ES )
psz_var = "video-es"; psz_var = "video-es";
else if( es->fmt.i_cat == SPU_ES ) else if( fmt->i_cat == SPU_ES )
psz_var = "spu-es"; psz_var = "spu-es";
else else
return; return;
if( b_delete ) if( b_delete )
{ {
val.i_int = es->i_id; val.i_int = i_id;
var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL ); var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
return; return;
...@@ -419,26 +428,26 @@ static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es, ...@@ -419,26 +428,26 @@ static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
} }
/* Take care of the ES description */ /* Take care of the ES description */
if( es->fmt.psz_description && *es->fmt.psz_description ) if( fmt->psz_description && *fmt->psz_description )
{ {
if( es->psz_language && *es->psz_language ) if( psz_language && *psz_language )
{ {
text.psz_string = malloc( strlen( es->fmt.psz_description) + text.psz_string = malloc( strlen( fmt->psz_description) +
strlen( es->psz_language ) + 10 ); strlen( psz_language ) + 10 );
sprintf( text.psz_string, "%s - [%s]", es->fmt.psz_description, sprintf( text.psz_string, "%s - [%s]", fmt->psz_description,
es->psz_language ); psz_language );
} }
else text.psz_string = strdup( es->fmt.psz_description ); else text.psz_string = strdup( fmt->psz_description );
} }
else else
{ {
if( es->psz_language && *es->psz_language ) if( psz_language && *psz_language )
{ {
char *temp; char *temp;
text.psz_string = malloc( strlen( _("Track %i") )+ text.psz_string = malloc( strlen( _("Track %i") )+
strlen( es->psz_language ) + 30 ); strlen( psz_language ) + 30 );
asprintf( &temp, _("Track %i"), val.i_int ); asprintf( &temp, _("Track %i"), val.i_int );
sprintf( text.psz_string, "%s - [%s]", temp, es->psz_language ); sprintf( text.psz_string, "%s - [%s]", temp, psz_language );
free( temp ); free( temp );
} }
else else
...@@ -448,7 +457,7 @@ static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es, ...@@ -448,7 +457,7 @@ static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
} }
} }
val.i_int = es->i_id; val.i_int = i_id;
var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text ); var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
free( text.psz_string ); free( text.psz_string );
...@@ -456,6 +465,12 @@ static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es, ...@@ -456,6 +465,12 @@ static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
} }
static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
vlc_bool_t b_delete )
{
EsOutESVarUpdateGeneric( out, es->i_id, &es->fmt, es->psz_language, b_delete );
}
/* EsOutProgramSelect: /* EsOutProgramSelect:
* Select a program and update the object variable * Select a program and update the object variable
*/ */
...@@ -476,7 +491,7 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm ) ...@@ -476,7 +491,7 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
for( i = 0; i < p_sys->i_es; i++ ) for( i = 0; i < p_sys->i_es; i++ )
{ {
if( p_sys->es[i]->p_pgrm == old && p_sys->es[i]->p_dec && if( p_sys->es[i]->p_pgrm == old && EsIsSelected( out, p_sys->es[i] ) &&
p_sys->i_mode != ES_OUT_MODE_ALL ) p_sys->i_mode != ES_OUT_MODE_ALL )
EsUnselect( out, p_sys->es[i], VLC_TRUE ); EsUnselect( out, p_sys->es[i], VLC_TRUE );
} }
...@@ -932,6 +947,9 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt ) ...@@ -932,6 +947,9 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
es->psz_language = LanguageGetName( fmt->psz_language ); /* remember so we only need to do it once */ es->psz_language = LanguageGetName( fmt->psz_language ); /* remember so we only need to do it once */
es->psz_language_code = LanguageGetCode( fmt->psz_language ); es->psz_language_code = LanguageGetCode( fmt->psz_language );
es->p_dec = NULL; es->p_dec = NULL;
for( i = 0; i < 4; i++ )
es->pb_cc_present[i] = VLC_FALSE;
es->p_master = VLC_FALSE;
if( es->p_pgrm == p_sys->p_pgrm ) if( es->p_pgrm == p_sys->p_pgrm )
EsOutESVarUpdate( out, es, VLC_FALSE ); EsOutESVarUpdate( out, es, VLC_FALSE );
...@@ -960,6 +978,21 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt ) ...@@ -960,6 +978,21 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
return es; return es;
} }
static vlc_bool_t EsIsSelected( es_out_t *out, es_out_id_t *es )
{
if( es->p_master )
{
vlc_bool_t b_decode = VLC_FALSE;
if( es->p_master->p_dec )
input_DecoderGetCcState( es->p_master->p_dec, &b_decode,
es->fmt.i_codec == VLC_FOURCC('c','c','1',' ') ? 0 : 1 );
return b_decode;
}
else
{
return es->p_dec != NULL;
}
}
static void EsSelect( es_out_t *out, es_out_id_t *es ) static void EsSelect( es_out_t *out, es_out_id_t *es )
{ {
es_out_sys_t *p_sys = out->p_sys; es_out_sys_t *p_sys = out->p_sys;
...@@ -967,12 +1000,23 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) ...@@ -967,12 +1000,23 @@ static void EsSelect( es_out_t *out, es_out_id_t *es )
vlc_value_t val; vlc_value_t val;
const char *psz_var; const char *psz_var;
if( es->p_dec ) if( EsIsSelected( out, es ) )
{ {
msg_Warn( p_input, "ES 0x%x is already selected", es->i_id ); msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
return; return;
} }
if( es->p_master )
{
if( !es->p_master->p_dec )
return;
if( input_DecoderSetCcState( es->p_master->p_dec, VLC_TRUE,
es->fmt.i_codec == VLC_FOURCC('c','c','1',' ') ? 0 : 1 ) )
return;
}
else
{
if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES ) if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
{ {
if( !var_GetBool( p_input, "video" ) || if( !var_GetBool( p_input, "video" ) ||
...@@ -1010,6 +1054,7 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) ...@@ -1010,6 +1054,7 @@ static void EsSelect( es_out_t *out, es_out_id_t *es )
es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE ); es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE );
if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm ) if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
return; return;
}
if( es->fmt.i_cat == VIDEO_ES ) if( es->fmt.i_cat == VIDEO_ES )
psz_var = "video-es"; psz_var = "video-es";
...@@ -1024,7 +1069,6 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) ...@@ -1024,7 +1069,6 @@ static void EsSelect( es_out_t *out, es_out_id_t *es )
val.i_int = es->i_id; val.i_int = es->i_id;
var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL ); var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
} }
...@@ -1035,14 +1079,41 @@ static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update ) ...@@ -1035,14 +1079,41 @@ static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update )
vlc_value_t val; vlc_value_t val;
const char *psz_var; const char *psz_var;
if( es->p_dec == NULL ) if( !EsIsSelected( out, es ) )
{ {
msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id ); msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
return; return;
} }
if( es->p_master )
{
if( es->p_master->p_dec )
input_DecoderSetCcState( es->p_master->p_dec, VLC_FALSE, es->fmt.i_codec == VLC_FOURCC('c','c','1',' ') ? 0 : 1 );
}
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 */
val.i_int = -1;
var_Change( p_input, "spu-es", VLC_VAR_SETVALUE, &val, NULL );
if( !b_update )
var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
}
EsOutDel( out, es->pp_cc_es[i] );
es->pb_cc_present[i] = VLC_FALSE;
}
input_DecoderDelete( es->p_dec ); input_DecoderDelete( es->p_dec );
es->p_dec = NULL; es->p_dec = NULL;
}
if( !b_update ) if( !b_update )
return; return;
...@@ -1059,7 +1130,7 @@ static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update ) ...@@ -1059,7 +1130,7 @@ static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update )
else else
return; return;
/* Mark it as selected */ /* Mark it as unselected */
val.i_int = -1; val.i_int = -1;
var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL ); var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
...@@ -1089,7 +1160,7 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) ...@@ -1089,7 +1160,7 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force ) if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
{ {
if( !es->p_dec ) if( !EsIsSelected( out, es ) )
EsSelect( out, es ); EsSelect( out, es );
} }
else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL ) else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
...@@ -1101,7 +1172,7 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) ...@@ -1101,7 +1172,7 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
{ {
if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force ) if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force )
{ {
if( !es->p_dec ) if( !EsIsSelected( out, es ) )
EsSelect( out, es ); EsSelect( out, es );
break; break;
} }
...@@ -1202,19 +1273,19 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) ...@@ -1202,19 +1273,19 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
i_wanted = es->i_channel; i_wanted = es->i_channel;
} }
if( i_wanted == es->i_channel && es->p_dec == NULL ) if( i_wanted == es->i_channel && !EsIsSelected( out, es ) )
EsSelect( out, es ); EsSelect( out, es );
} }
/* FIXME TODO handle priority here */ /* FIXME TODO handle priority here */
if( es->p_dec ) if( EsIsSelected( out, es ) )
{ {
if( i_cat == AUDIO_ES ) if( i_cat == AUDIO_ES )
{ {
if( p_sys->i_mode == ES_OUT_MODE_AUTO && if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
p_sys->p_es_audio && p_sys->p_es_audio &&
p_sys->p_es_audio != es && p_sys->p_es_audio != es &&
p_sys->p_es_audio->p_dec ) EsIsSelected( out, p_sys->p_es_audio ) )
{ {
EsUnselect( out, p_sys->p_es_audio, VLC_FALSE ); EsUnselect( out, p_sys->p_es_audio, VLC_FALSE );
} }
...@@ -1225,7 +1296,7 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) ...@@ -1225,7 +1296,7 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
if( p_sys->i_mode == ES_OUT_MODE_AUTO && if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
p_sys->p_es_sub && p_sys->p_es_sub &&
p_sys->p_es_sub != es && p_sys->p_es_sub != es &&
p_sys->p_es_sub->p_dec ) EsIsSelected( out, p_sys->p_es_sub ) )
{ {
EsUnselect( out, p_sys->p_es_sub, VLC_FALSE ); EsUnselect( out, p_sys->p_es_sub, VLC_FALSE );
} }
...@@ -1323,7 +1394,46 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block ) ...@@ -1323,7 +1394,46 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
( p_input->p->i_rate >= INPUT_RATE_DEFAULT/AOUT_MAX_INPUT_RATE && ( p_input->p->i_rate >= INPUT_RATE_DEFAULT/AOUT_MAX_INPUT_RATE &&
p_input->p->i_rate <= INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE ) ) ) p_input->p->i_rate <= INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE ) ) )
{ {
vlc_bool_t pb_cc[4];
vlc_bool_t b_cc_new = VLC_FALSE;
int i;
input_DecoderDecode( es->p_dec, p_block ); input_DecoderDecode( es->p_dec, p_block );
/* Check CC status */
input_DecoderIsCcPresent( es->p_dec, pb_cc );
for( i = 0; i < 4; i++ )
{
static const vlc_fourcc_t fcc[4] = {
VLC_FOURCC('c', 'c', '1', ' '),
VLC_FOURCC('c', 'c', '2', ' '),
VLC_FOURCC('c', 'c', '3', ' '),
VLC_FOURCC('c', 'c', '4', ' '),
};
static const char *ppsz_description[4] = {
N_("Closed captions 1"),
N_("Closed captions 2"),
N_("Closed captions 3"),
N_("Closed captions 4"),
};
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, fcc[i] );
fmt.i_group = es->fmt.i_group;
fmt.psz_description = strdup( _(ppsz_description[i] ) );
es->pp_cc_es[i] = EsOutAdd( out, &fmt );
es->pp_cc_es[i]->p_master = es;
es_format_Clean( &fmt );
/* */
es->pb_cc_present[i] = VLC_TRUE;
b_cc_new = VLC_TRUE;
}
if( b_cc_new )
var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
} }
else else
{ {
...@@ -1424,12 +1534,12 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) ...@@ -1424,12 +1534,12 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
case ES_OUT_SET_ES_STATE: case ES_OUT_SET_ES_STATE:
es = (es_out_id_t*) va_arg( args, es_out_id_t * ); es = (es_out_id_t*) va_arg( args, es_out_id_t * );
b = (vlc_bool_t) va_arg( args, vlc_bool_t ); b = (vlc_bool_t) va_arg( args, vlc_bool_t );
if( b && es->p_dec == NULL ) if( b && !EsIsSelected( out, es ) )
{ {
EsSelect( out, es ); EsSelect( out, es );
return es->p_dec ? VLC_SUCCESS : VLC_EGENERIC; return EsIsSelected( out, es ) ? VLC_SUCCESS : VLC_EGENERIC;
} }
else if( !b && es->p_dec ) else if( !b && EsIsSelected( out, es ) )
{ {
EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm ); EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
return VLC_SUCCESS; return VLC_SUCCESS;
...@@ -1440,7 +1550,7 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) ...@@ -1440,7 +1550,7 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
es = (es_out_id_t*) va_arg( args, es_out_id_t * ); es = (es_out_id_t*) va_arg( args, es_out_id_t * );
pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * ); pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
*pb = es->p_dec ? VLC_TRUE : VLC_FALSE; *pb = EsIsSelected( out, es );
return VLC_SUCCESS; return VLC_SUCCESS;
case ES_OUT_SET_ACTIVE: case ES_OUT_SET_ACTIVE:
...@@ -1468,7 +1578,7 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) ...@@ -1468,7 +1578,7 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
/* Reapply policy mode */ /* Reapply policy mode */
for( i = 0; i < p_sys->i_es; i++ ) for( i = 0; i < p_sys->i_es; i++ )
{ {
if( p_sys->es[i]->p_dec ) if( EsIsSelected( out, p_sys->es[i] ) )
{ {
EsUnselect( out, p_sys->es[i], EsUnselect( out, p_sys->es[i],
p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
...@@ -1494,7 +1604,7 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) ...@@ -1494,7 +1604,7 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
{ {
for( i = 0; i < p_sys->i_es; i++ ) for( i = 0; i < p_sys->i_es; i++ )
{ {
if( p_sys->es[i]->p_dec ) if( EsIsSelected( out, p_sys->es[i] ) )
EsUnselect( out, p_sys->es[i], EsUnselect( out, p_sys->es[i],
p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
} }
...@@ -1503,8 +1613,8 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) ...@@ -1503,8 +1613,8 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
{ {
for( i = 0; i < p_sys->i_es; i++ ) for( i = 0; i < p_sys->i_es; i++ )
{ {
if( p_sys->es[i]->p_dec && if( p_sys->es[i]->fmt.i_cat == AUDIO_ES &&
p_sys->es[i]->fmt.i_cat == AUDIO_ES ) EsIsSelected( out, p_sys->es[i] ) )
EsUnselect( out, p_sys->es[i], EsUnselect( out, p_sys->es[i],
p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
} }
...@@ -1513,8 +1623,8 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) ...@@ -1513,8 +1623,8 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
{ {
for( i = 0; i < p_sys->i_es; i++ ) for( i = 0; i < p_sys->i_es; i++ )
{ {
if( p_sys->es[i]->p_dec && if( p_sys->es[i]->fmt.i_cat == VIDEO_ES &&
p_sys->es[i]->fmt.i_cat == VIDEO_ES ) EsIsSelected( out, p_sys->es[i] ) )
EsUnselect( out, p_sys->es[i], EsUnselect( out, p_sys->es[i],
p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
} }
...@@ -1523,8 +1633,8 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) ...@@ -1523,8 +1633,8 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
{ {
for( i = 0; i < p_sys->i_es; i++ ) for( i = 0; i < p_sys->i_es; i++ )
{ {
if( p_sys->es[i]->p_dec && if( p_sys->es[i]->fmt.i_cat == SPU_ES &&
p_sys->es[i]->fmt.i_cat == SPU_ES ) EsIsSelected( out, p_sys->es[i] ) )
EsUnselect( out, p_sys->es[i], EsUnselect( out, p_sys->es[i],
p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
} }
......
...@@ -259,6 +259,9 @@ void stream_AccessUpdate( stream_t *s ); ...@@ -259,6 +259,9 @@ void stream_AccessUpdate( stream_t *s );
/* decoder.c */ /* decoder.c */
void input_DecoderDiscontinuity( decoder_t * p_dec, vlc_bool_t b_flush ); void input_DecoderDiscontinuity( decoder_t * p_dec, vlc_bool_t b_flush );
vlc_bool_t input_DecoderEmpty( decoder_t * p_dec ); vlc_bool_t input_DecoderEmpty( decoder_t * p_dec );
int input_DecoderSetCcState( decoder_t *, vlc_bool_t b_decode, int i_channel );
int input_DecoderGetCcState( decoder_t *, vlc_bool_t *pb_decode, int i_channel );
void input_DecoderIsCcPresent( decoder_t *, vlc_bool_t pb_present[4] );
/* es_out.c */ /* es_out.c */
es_out_t *input_EsOutNew( input_thread_t * ); es_out_t *input_EsOutNew( input_thread_t * );
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment