📄 ts.c
字号:
default: return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED ); }}/***************************************************************************** * AddStream: called for each stream addition *****************************************************************************/static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ){ sout_mux_sys_t *p_sys = p_mux->p_sys; ts_stream_t *p_stream; msg_Dbg( p_mux, "adding input codec=%4.4s", (char*)&p_input->p_fmt->i_fourcc ); p_input->p_sys = (void*)p_stream = malloc( sizeof( ts_stream_t ) ); /* Init this new stream */ p_stream->i_pid = AllocatePID( p_sys ); p_stream->i_continuity_counter = 0; p_stream->i_decoder_specific_info = 0; p_stream->p_decoder_specific_info = NULL; /* All others fields depand on codec */ switch( p_input->p_fmt->i_cat ) { case VIDEO_ES: switch( p_input->p_fmt->i_fourcc ) { case VLC_FOURCC( 'm', 'p','g', 'v' ): /* TODO: do we need to check MPEG-I/II ? */ p_stream->i_stream_type = 0x02; p_stream->i_stream_id = p_sys->i_stream_id_mpgv; p_sys->i_stream_id_mpgv++; break; case VLC_FOURCC( 'm', 'p','4', 'v' ): p_stream->i_stream_type = 0x10; p_stream->i_stream_id = 0xfa; p_sys->i_mpeg4_streams++; p_stream->i_es_id = p_stream->i_pid; break; /* XXX dirty dirty but somebody want that : using crapy MS-codec XXX */ /* I didn't want to do that :P */ case VLC_FOURCC( 'H', '2', '6', '3' ): case VLC_FOURCC( 'I', '2', '6', '3' ): case VLC_FOURCC( 'W', 'M', 'V', '2' ): case VLC_FOURCC( 'W', 'M', 'V', '1' ): case VLC_FOURCC( 'D', 'I', 'V', '3' ): case VLC_FOURCC( 'D', 'I', 'V', '2' ): case VLC_FOURCC( 'D', 'I', 'V', '1' ): case VLC_FOURCC( 'M', 'J', 'P', 'G' ): p_stream->i_stream_type = 0xa0; // private p_stream->i_stream_id = 0xa0; // beurk p_stream->i_bih_codec = p_input->p_fmt->i_fourcc; p_stream->i_bih_width = p_input->p_fmt->i_width; p_stream->i_bih_height = p_input->p_fmt->i_height; break; default: free( p_stream ); return VLC_EGENERIC; } p_sys->i_video_bound++; break; case AUDIO_ES: switch( p_input->p_fmt->i_fourcc ) { case VLC_FOURCC( 'm', 'p','g', 'a' ): p_stream->i_stream_type = p_input->p_fmt->i_sample_rate >= 32000 ? 0x03 : 0x04; p_stream->i_stream_id = p_sys->i_stream_id_mpga; p_sys->i_stream_id_mpga++; break; case VLC_FOURCC( 'a', '5','2', ' ' ): p_stream->i_stream_type = 0x81; p_stream->i_stream_id = p_sys->i_stream_id_a52; p_sys->i_stream_id_a52++; break; case VLC_FOURCC( 'm', 'p','4', 'a' ): p_stream->i_stream_type = 0x11; p_stream->i_stream_id = 0xfa; p_sys->i_mpeg4_streams++; p_stream->i_es_id = p_stream->i_pid; break; default: free( p_stream ); return VLC_EGENERIC; } p_sys->i_audio_bound++; break; case SPU_ES: switch( p_input->p_fmt->i_fourcc ) { case VLC_FOURCC( 's', 'p','u', ' ' ): p_stream->i_stream_type = 0x82; p_stream->i_stream_id = 0x82; break; default: free( p_stream ); return VLC_EGENERIC; } break; default: free( p_stream ); return VLC_EGENERIC; } /* Copy extra data (VOL for MPEG-4 and extra BitMapInfoHeader for VFW */ p_stream->i_decoder_specific_info = p_input->p_fmt->i_extra_data; if( p_stream->i_decoder_specific_info > 0 ) { p_stream->p_decoder_specific_info = malloc( p_stream->i_decoder_specific_info ); memcpy( p_stream->p_decoder_specific_info, p_input->p_fmt->p_extra_data, p_input->p_fmt->i_extra_data ); } /* Init chain for TS building */ BufferChainInit( &p_stream->chain_ts ); /* We only change PMT version (PAT isn't changed) */ p_sys->i_pmt_version_number = ( p_sys->i_pmt_version_number + 1 )%32; /* Update pcr_pid */ if( p_input->p_fmt->i_cat != SPU_ES && ( p_sys->i_pcr_pid == 0x1fff || p_input->p_fmt->i_cat == VIDEO_ES ) ) { sout_buffer_t *p_data; if( p_sys->p_pcr_input ) { /* There was already a PCR stream, so clean context */ ts_stream_t *p_pcr_stream = (ts_stream_t*)p_sys->p_pcr_input->p_sys; while( ( p_data = BufferChainGet( &p_pcr_stream->chain_ts ) ) ) { sout_BufferDelete( p_mux->p_sout, p_data ); } } p_sys->i_pcr_pid = p_stream->i_pid; p_sys->p_pcr_input = p_input; /* Empty TS buffer (avoid broken data/problems with pcr stream changement ) */ while( ( p_data = BufferChainGet( &p_sys->chain_ts ) ) ) { sout_BufferDelete( p_mux->p_sout, p_data ); } } return VLC_SUCCESS;}/***************************************************************************** * DelStream: called before a stream deletion *****************************************************************************/static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input ){ sout_mux_sys_t *p_sys = p_mux->p_sys; ts_stream_t *p_stream; sout_buffer_t *p_data; msg_Dbg( p_mux, "removing input" ); p_stream = (ts_stream_t*)p_input->p_sys; if( p_sys->i_pcr_pid == p_stream->i_pid ) { int i; /* Find a new pcr stream (Prefer Video Stream) */ p_sys->i_pcr_pid = 0x1fff; p_sys->p_pcr_input = NULL; for( i = 0; i < p_mux->i_nb_inputs; i++ ) { if( p_mux->pp_inputs[i] == p_input ) { continue; } if( p_mux->pp_inputs[i]->p_fmt->i_cat == VIDEO_ES ) { p_sys->i_pcr_pid = ((ts_stream_t*)p_mux->pp_inputs[i]->p_sys)->i_pid; p_sys->p_pcr_input= p_mux->pp_inputs[i]; break; } else if( p_mux->pp_inputs[i]->p_fmt->i_cat != SPU_ES && p_sys->i_pcr_pid == 0x1fff ) { p_sys->i_pcr_pid = ((ts_stream_t*)p_mux->pp_inputs[i]->p_sys)->i_pid; p_sys->p_pcr_input= p_mux->pp_inputs[i]; } } if( p_sys->p_pcr_input ) { /* Empty TS buffer */ while( ( p_data = BufferChainGet( &((ts_stream_t*)p_sys->p_pcr_input->p_sys)->chain_ts ) ) ) { sout_BufferDelete( p_mux->p_sout, p_data ); } } } /* Empty all data in chain_ts */ while( ( p_data = BufferChainGet( &p_stream->chain_ts ) ) ) { sout_BufferDelete( p_mux->p_sout, p_data ); } if( p_stream->p_decoder_specific_info ) { free( p_stream->p_decoder_specific_info ); } if( p_stream->i_stream_id == 0xfa || p_stream->i_stream_id == 0xfb ) { p_sys->i_mpeg4_streams--; } free( p_stream ); /* We only change PMT version (PAT isn't changed) */ p_sys->i_pmt_version_number++; p_sys->i_pmt_version_number %= 32; /*Empty TS buffer (avoid broken data/problems with pcr stream changement) */ while( ( p_data = BufferChainGet( &p_sys->chain_ts ) ) ) { sout_BufferDelete( p_mux->p_sout, p_data ); } return VLC_SUCCESS;}/***************************************************************************** * Mux: Call each time there is new data for at least one stream ***************************************************************************** * *****************************************************************************/static int Mux( sout_mux_t *p_mux ){ sout_mux_sys_t *p_sys = p_mux->p_sys; sout_input_t *p_pcr_input = p_sys->p_pcr_input; ts_stream_t *p_pcr_stream = (ts_stream_t*)p_sys->p_pcr_input->p_sys; if( p_sys->i_pcr_pid == 0x1fff ) { msg_Dbg( p_mux, "waiting PCR streams" ); msleep( 1000 ); return VLC_SUCCESS; } for( ;; ) { ts_stream_t *p_stream = NULL; sout_buffer_t *p_data; int i_stream, i; mtime_t i_dts; /* fill ts packets for pcr XXX before GetPAT/GetPMT */ if( p_pcr_stream->chain_ts.p_first == NULL && TSFill( p_mux, p_pcr_input ) ) { /* We need more data */ return VLC_SUCCESS; } if( p_sys->chain_ts.p_first == NULL ) { /* Every pcr packet send PAT/PMT */ GetPAT( p_mux, &p_sys->chain_ts); GetPMT( p_mux, &p_sys->chain_ts ); } /* search stream with lowest dts */ for( i = 0, i_stream = -1, i_dts = 0; i < p_mux->i_nb_inputs; i++ ) { p_stream = (ts_stream_t*)p_mux->pp_inputs[i]->p_sys; if( p_stream->chain_ts.p_first == NULL ) { if( TSFill( p_mux, p_mux->pp_inputs[i] ) ) { /* We need more data */ return VLC_SUCCESS; } if( p_stream->chain_ts.p_first == NULL ) { continue; /* SPU_ES */ } } if( i_stream == -1 || p_stream->chain_ts.p_first->i_dts < i_dts ) { i_stream = i; i_dts = p_stream->chain_ts.p_first->i_dts; } } p_stream = (ts_stream_t*)p_mux->pp_inputs[i_stream]->p_sys; p_data = BufferChainGet( &p_stream->chain_ts ); BufferChainAppend( &p_sys->chain_ts, p_data ); if( p_stream->i_pid == p_pcr_stream->i_pid && p_stream->chain_ts.p_first == NULL ) { sout_buffer_t *p_ts = p_sys->chain_ts.p_first; /* We have consume all TS packets from the PCR stream */ if( p_sys->i_length > p_sys->i_pcr_delay ) { /* Send TS data if last PCR was i_pcr_delay ago */ if( p_sys->i_bitrate_min > 0 || p_sys->i_bitrate_max > 0 ) { TSSetConstraints( p_mux, &p_sys->chain_ts, p_sys->i_length, p_sys->i_bitrate_min, p_sys->i_bitrate_max ); } /* Send all data */ TSSetDate( &p_sys->chain_ts, p_sys->i_dts + 3 * p_sys->i_pcr_delay / 2, /* latency is equal to i_pcr_delay, 3/2 is for security */ p_sys->i_length ); sout_AccessOutWrite( p_mux->p_access, p_ts ); /* Reset the ts chain */ BufferChainInit( &p_sys->chain_ts ); p_sys->i_length = 0; } } } return VLC_SUCCESS;}/***************************************************************************** * * *****************************************************************************/static int TSFill( sout_mux_t *p_mux, sout_input_t *p_input ){ sout_mux_sys_t *p_sys = p_mux->p_sys; ts_stream_t *p_pcr_stream = (ts_stream_t*)p_sys->p_pcr_input->p_sys; ts_stream_t *p_stream = (ts_stream_t*)p_input->p_sys; mtime_t i_dts, i_length; sout_buffer_t *p_data; vlc_bool_t b_pcr = VLC_FALSE; vlc_bool_t b_pcr_soft = VLC_FALSE; for( ;; ) { if( p_input->p_fifo->i_depth <= 0 ) { if( p_input->p_fmt->i_cat == AUDIO_ES || p_input->p_fmt->i_cat == VIDEO_ES ) { /* We need more data */ return VLC_EGENERIC; } else { return VLC_SUCCESS; } } p_data = sout_FifoGet( p_input->p_fifo ); i_dts = p_data->i_dts; i_length = p_data->i_length;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -