X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Finput%2Fes_out.c;h=ca6780b6bcd57eee576f084cdcc22e8a48559313;hb=c35c18a622dad4f768370aacd1cbcd2b59c7204d;hp=c7dac8e5177460848284f14e5f9d84c73b5953ca;hpb=b2fcbc3a4a8f49b258b6f10cdf21da7723ac4981;p=vlc diff --git a/src/input/es_out.c b/src/input/es_out.c index c7dac8e517..ca6780b6bc 100644 --- a/src/input/es_out.c +++ b/src/input/es_out.c @@ -29,9 +29,9 @@ # include "config.h" #endif -#include - #include +#include +#include #include #include @@ -40,6 +40,8 @@ #include "input_internal.h" +#include "../stream_output/stream_output.h" + #include /* FIXME we should find a better way than including that */ #include "../text/iso-639_def.h" @@ -83,6 +85,7 @@ struct es_out_id_t char *psz_language_code; decoder_t *p_dec; + decoder_t *p_dec_record; /* Fields for Video with CC */ bool pb_cc_present[4]; @@ -134,6 +137,9 @@ struct es_out_sys_t /* Rate used to rescale ES ts */ int i_rate; + + /* Record */ + sout_instance_t *p_sout_record; }; static es_out_id_t *EsOutAdd ( es_out_t *, es_format_t * ); @@ -266,6 +272,8 @@ es_out_t *input_EsOutNew( input_thread_t *p_input, int i_rate ) p_sys->i_rate = i_rate; + p_sys->p_sout_record = NULL; + return out; } @@ -277,12 +285,14 @@ void input_EsOutDelete( es_out_t *out ) es_out_sys_t *p_sys = out->p_sys; int i; + if( p_sys->p_sout_record ) + input_EsOutSetRecord( out, false ); + for( i = 0; i < p_sys->i_es; i++ ) { if( p_sys->es[i]->p_dec ) - { input_DecoderDelete( p_sys->es[i]->p_dec ); - } + free( p_sys->es[i]->psz_language ); free( p_sys->es[i]->psz_language_code ); es_format_Clean( &p_sys->es[i]->fmt ); @@ -301,7 +311,6 @@ void input_EsOutDelete( es_out_t *out ) free( p_sys->ppsz_sub_language[i] ); free( p_sys->ppsz_sub_language ); } - free( p_sys->es ); /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */ @@ -351,7 +360,11 @@ static void EsOutDiscontinuity( es_out_t *out, bool b_flush, bool b_audio ) /* Send a dummy block to let decoder know that * there is a discontinuity */ if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) ) + { input_DecoderDiscontinuity( es->p_dec, b_flush ); + if( es->p_dec_record ) + input_DecoderDiscontinuity( es->p_dec_record, b_flush ); + } } } void input_EsOutChangeRate( es_out_t *out, int i_rate ) @@ -366,6 +379,77 @@ void input_EsOutChangeRate( es_out_t *out, int i_rate ) input_ClockSetRate( &p_sys->pgrm[i]->clock, i_rate ); } +int input_EsOutSetRecord( es_out_t *out, bool b_record ) +{ + es_out_sys_t *p_sys = out->p_sys; + input_thread_t *p_input = p_sys->p_input; + + assert( ( b_record && !p_sys->p_sout_record ) || ( !b_record && p_sys->p_sout_record ) ); + + if( b_record ) + { + char *psz_path = var_CreateGetString( p_input, "input-record-path" ); + if( !psz_path || *psz_path == '\0' ) + { + free( psz_path ); + psz_path = strdup( config_GetHomeDir() ); + } + + char *psz_sout = NULL; // TODO conf + + if( !psz_sout && psz_path ) + { + char *psz_file = input_CreateFilename( VLC_OBJECT(p_input), psz_path, INPUT_RECORD_PREFIX, NULL ); + if( psz_file ) + { + if( asprintf( &psz_sout, "#record{dst-prefix='%s'}", psz_file ) < 0 ) + psz_sout = NULL; + free( psz_file ); + } + } + free( psz_path ); + + if( !psz_sout ) + return VLC_EGENERIC; + +#ifdef ENABLE_SOUT + p_sys->p_sout_record = sout_NewInstance( p_input, psz_sout ); +#endif + free( psz_sout ); + + if( !p_sys->p_sout_record ) + return VLC_EGENERIC; + + for( int i = 0; i < p_sys->i_es; i++ ) + { + es_out_id_t *p_es = p_sys->es[i]; + + if( !p_es->p_dec || p_es->p_master ) + continue; + + p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, p_sys->p_sout_record ); + } + } + else + { + for( int i = 0; i < p_sys->i_es; i++ ) + { + es_out_id_t *p_es = p_sys->es[i]; + + if( !p_es->p_dec_record ) + continue; + + input_DecoderDelete( p_es->p_dec_record ); + p_es->p_dec_record = NULL; + } +#ifdef ENABLE_SOUT + sout_DeleteInstance( p_sys->p_sout_record ); +#endif + p_sys->p_sout_record = NULL; + } + + return VLC_SUCCESS; +} void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay ) { es_out_sys_t *p_sys = out->p_sys; @@ -411,6 +495,8 @@ bool input_EsOutDecodersEmpty( es_out_t *out ) if( es->p_dec && !input_DecoderEmpty( es->p_dec ) ) return false; + if( es->p_dec_record && !input_DecoderEmpty( es->p_dec_record ) ) + return false; } return true; } @@ -669,9 +755,15 @@ static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm ) { char *psz = NULL; if( p_pgrm->psz_name ) - asprintf( &psz, _("%s [%s %d]"), p_pgrm->psz_name, _("Program"), p_pgrm->i_id ); + { + if( asprintf( &psz, _("%s [%s %d]"), p_pgrm->psz_name, _("Program"), p_pgrm->i_id ) == -1 ) + return NULL; + } else - asprintf( &psz, "%s %d", _("Program"), p_pgrm->i_id ); + { + if( asprintf( &psz, "%s %d", _("Program"), p_pgrm->i_id ) == -1 ) + return NULL; + } return psz; } @@ -735,9 +827,11 @@ static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta ) if( psz_provider && *psz_provider ) { - asprintf( &text.psz_string, "%s [%s]", psz_title, psz_provider ); - var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text ); - free( text.psz_string ); + if( asprintf( &text.psz_string, "%s [%s]", psz_title, psz_provider ) != -1 ) + { + var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text ); + free( text.psz_string ); + } } else { @@ -945,8 +1039,8 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt ) es->i_channel = p_sys->i_audio; - vlc_mutex_lock( &p_input->p->input.p_item->lock ); memset( &rg, 0, sizeof(rg) ); + vlc_mutex_lock( &p_input->p->input.p_item->lock ); vlc_audio_replay_gain_MergeFromMeta( &rg, p_input->p->input.p_item->p_meta ); vlc_mutex_unlock( &p_input->p->input.p_item->lock ); @@ -986,9 +1080,10 @@ 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_code = LanguageGetCode( 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->p_master = false; + es->p_master = NULL; if( es->p_pgrm == p_sys->p_pgrm ) EsOutESVarUpdate( out, es, false ); @@ -1035,6 +1130,32 @@ static bool EsIsSelected( es_out_id_t *es ) return es->p_dec != NULL; } } +static void EsCreateDecoder( es_out_t *out, es_out_id_t *p_es ) +{ + es_out_sys_t *p_sys = out->p_sys; + input_thread_t *p_input = p_sys->p_input; + + p_es->p_dec = input_DecoderNew( p_input, &p_es->fmt, p_input->p->p_sout ); + if( p_es->p_dec && !p_es->p_master && p_sys->p_sout_record ) + p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, p_sys->p_sout_record ); +} +static void EsDestroyDecoder( es_out_t *out, es_out_id_t *p_es ) +{ + es_out_sys_t *p_sys = out->p_sys; + + if( !p_es->p_dec ) + return; + + input_DecoderDelete( p_es->p_dec ); + p_es->p_dec = NULL; + + if( p_es->p_dec_record ) + { + input_DecoderDelete( p_es->p_dec_record ); + p_es->p_dec_record = NULL; + } +} + static void EsSelect( es_out_t *out, es_out_id_t *es ) { es_out_sys_t *p_sys = out->p_sys; @@ -1091,7 +1212,8 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) } es->i_preroll_end = -1; - es->p_dec = input_DecoderNew( p_input, &es->fmt, false ); + EsCreateDecoder( out, es ); + if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm ) return; } @@ -1155,8 +1277,7 @@ static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update ) es->pb_cc_present[i] = false; } - input_DecoderDelete( es->p_dec ); - es->p_dec = NULL; + EsDestroyDecoder( out, es ); } if( !b_update ) @@ -1442,6 +1563,12 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block ) bool pb_cc[4]; bool b_cc_new = false; int i; + if( es->p_dec_record ) + { + block_t *p_dup = block_Duplicate( p_block ); + if( p_dup ) + input_DecoderDecode( es->p_dec_record, p_dup ); + } input_DecoderDecode( es->p_dec, p_block ); /* Check CC status */ @@ -1502,7 +1629,8 @@ static void EsOutDel( es_out_t *out, es_out_id_t *es ) { while( !out->p_sys->p_input->b_die && es->p_dec ) { - if( input_DecoderEmpty( es->p_dec ) ) + if( input_DecoderEmpty( es->p_dec ) && + ( !es->p_dec_record || input_DecoderEmpty( es->p_dec_record ) )) break; msleep( 20*1000 ); } @@ -1641,50 +1769,26 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) return VLC_SUCCESS; case ES_OUT_SET_ES: + case ES_OUT_RESTART_ES: + { + int i_cat; + es = (es_out_id_t*) va_arg( args, es_out_id_t * ); - /* Special case NULL, NULL+i_cat */ + if( es == NULL ) - { - for( i = 0; i < p_sys->i_es; i++ ) - { - if( EsIsSelected( p_sys->es[i] ) ) - EsUnselect( out, p_sys->es[i], - p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); - } - } + i_cat = UNKNOWN_ES; else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) ) - { - for( i = 0; i < p_sys->i_es; i++ ) - { - if( p_sys->es[i]->fmt.i_cat == AUDIO_ES && - EsIsSelected( p_sys->es[i] ) ) - EsUnselect( out, p_sys->es[i], - p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); - } - } + i_cat = AUDIO_ES; else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) ) - { - for( i = 0; i < p_sys->i_es; i++ ) - { - if( p_sys->es[i]->fmt.i_cat == VIDEO_ES && - EsIsSelected( p_sys->es[i] ) ) - EsUnselect( out, p_sys->es[i], - p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); - } - } + i_cat = VIDEO_ES; else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) ) - { - for( i = 0; i < p_sys->i_es; i++ ) - { - if( p_sys->es[i]->fmt.i_cat == SPU_ES && - EsIsSelected( p_sys->es[i] ) ) - EsUnselect( out, p_sys->es[i], - p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); - } - } + i_cat = SPU_ES; else + i_cat = -1; + + for( i = 0; i < p_sys->i_es; i++ ) { - for( i = 0; i < p_sys->i_es; i++ ) + if( i_cat == -1 ) { if( es == p_sys->es[i] ) { @@ -1692,13 +1796,37 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) break; } } + else + { + if( i_cat == UNKNOWN_ES || p_sys->es[i]->fmt.i_cat == i_cat ) + { + if( EsIsSelected( p_sys->es[i] ) ) + { + if( i_query == ES_OUT_RESTART_ES ) + { + if( p_sys->es[i]->p_dec ) + { + EsDestroyDecoder( out, p_sys->es[i] ); + EsCreateDecoder( out, p_sys->es[i] ); + } + } + else + { + EsUnselect( out, p_sys->es[i], + p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); + } + } + } + } } + if( i_query == ES_OUT_SET_ES ) { vlc_event_t event; event.type = vlc_InputSelectedStreamChanged; vlc_event_send( &p_sys->p_input->p->event_manager, &event ); } return VLC_SUCCESS; + } case ES_OUT_SET_DEFAULT: { @@ -1816,7 +1944,8 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) es_format_t *p_fmt; es = (es_out_id_t*) va_arg( args, es_out_id_t * ); p_fmt = (es_format_t*) va_arg( args, es_format_t * ); - if( es == NULL ) return VLC_EGENERIC; + if( es == NULL ) + return VLC_EGENERIC; if( p_fmt->i_extra ) { @@ -1824,13 +1953,12 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra ); memcpy( es->fmt.p_extra, p_fmt->p_extra, p_fmt->i_extra ); - if( !es->p_dec ) return VLC_SUCCESS; - + if( !es->p_dec ) + return VLC_SUCCESS; #if 1 - input_DecoderDelete( es->p_dec ); - es->p_dec = input_DecoderNew( p_sys->p_input, - &es->fmt, false ); + EsDestroyDecoder( out, es ); + EsCreateDecoder( out, es ); #else es->p_dec->fmt_in.i_extra = p_fmt->i_extra; es->p_dec->fmt_in.p_extra = @@ -2035,7 +2163,8 @@ static void EsOutAddInfo( es_out_t *out, es_out_id_t *es ) lldiv_t div; /* Add stream info */ - asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 ); + if( asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 ) == -1 ) + return; input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"), "%.4s", (char*)&fmt->i_codec );