📄 decoder.c
字号:
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, 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_release( 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_release( p_cc ); } } return VLC_SUCCESS;}int input_DecoderGetCcState( decoder_t *p_dec, bool *pb_decode, int i_channel ){ decoder_owner_sys_t *p_owner = p_dec->p_owner; *pb_decode = 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 * * \param p_input the input thread * \param p_es the es descriptor * \param i_object_type Object type as define in include/vlc_objects.h * \return the decoder object */static decoder_t * CreateDecoder( input_thread_t *p_input, es_format_t *fmt, int i_object_type ){ decoder_t *p_dec; decoder_owner_sys_t *p_owner; int i; p_dec = vlc_object_create( p_input, i_object_type ); if( p_dec == NULL ) return NULL; p_dec->pf_decode_audio = 0; p_dec->pf_decode_video = 0; p_dec->pf_decode_sub = 0; p_dec->pf_get_cc = 0; p_dec->pf_packetize = 0; /* Initialize the decoder fifo */ p_dec->p_module = NULL; memset( &null_es_format, 0, sizeof(es_format_t) ); es_format_Copy( &p_dec->fmt_in, fmt ); es_format_Copy( &p_dec->fmt_out, &null_es_format ); /* Allocate our private structure for the decoder */ p_dec->p_owner = p_owner = malloc( sizeof( decoder_owner_sys_t ) ); if( p_dec->p_owner == NULL ) { vlc_object_release( p_dec ); return NULL; } p_dec->p_owner->b_own_thread = true; p_dec->p_owner->i_preroll_end = -1; p_dec->p_owner->p_input = p_input; p_dec->p_owner->p_aout = NULL; p_dec->p_owner->p_aout_input = NULL; p_dec->p_owner->p_vout = NULL; p_dec->p_owner->p_spu_vout = NULL; p_dec->p_owner->i_spu_channel = 0; p_dec->p_owner->p_sout = p_input->p->p_sout; p_dec->p_owner->p_sout_input = NULL; p_dec->p_owner->p_packetizer = NULL; /* decoder fifo */ if( ( p_dec->p_owner->p_fifo = block_FifoNew() ) == NULL ) { free( p_dec->p_owner ); vlc_object_release( p_dec ); return NULL; } /* Set buffers allocation callbacks for the decoders */ p_dec->pf_aout_buffer_new = aout_new_buffer; p_dec->pf_aout_buffer_del = aout_del_buffer; p_dec->pf_vout_buffer_new = vout_new_buffer; p_dec->pf_vout_buffer_del = vout_del_buffer; p_dec->pf_picture_link = vout_link_picture; p_dec->pf_picture_unlink = vout_unlink_picture; p_dec->pf_spu_buffer_new = spu_new_buffer; p_dec->pf_spu_buffer_del = spu_del_buffer; vlc_object_attach( p_dec, p_input ); /* Find a suitable decoder/packetizer module */ if( i_object_type == VLC_OBJECT_DECODER ) p_dec->p_module = module_Need( p_dec, "decoder", "$codec", 0 ); else p_dec->p_module = module_Need( p_dec, "packetizer", "$packetizer", 0 ); /* Check if decoder requires already packetized data */ if( i_object_type == VLC_OBJECT_DECODER && p_dec->b_need_packetized && !p_dec->fmt_in.b_packetized ) { p_dec->p_owner->p_packetizer = vlc_object_create( p_input, VLC_OBJECT_PACKETIZER ); if( p_dec->p_owner->p_packetizer ) { es_format_Copy( &p_dec->p_owner->p_packetizer->fmt_in, &p_dec->fmt_in ); es_format_Copy( &p_dec->p_owner->p_packetizer->fmt_out, &null_es_format ); vlc_object_attach( p_dec->p_owner->p_packetizer, p_input ); p_dec->p_owner->p_packetizer->p_module = module_Need( p_dec->p_owner->p_packetizer, "packetizer", "$packetizer", 0 ); if( !p_dec->p_owner->p_packetizer->p_module ) { es_format_Clean( &p_dec->p_owner->p_packetizer->fmt_in ); vlc_object_detach( p_dec->p_owner->p_packetizer ); vlc_object_release( p_dec->p_owner->p_packetizer ); } } } /* Copy ourself the input replay gain */ if( fmt->i_cat == AUDIO_ES ) { for( i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ ) { if( !p_dec->fmt_out.audio_replay_gain.pb_peak[i] ) { p_dec->fmt_out.audio_replay_gain.pb_peak[i] = fmt->audio_replay_gain.pb_peak[i]; p_dec->fmt_out.audio_replay_gain.pf_peak[i] = fmt->audio_replay_gain.pf_peak[i]; } if( !p_dec->fmt_out.audio_replay_gain.pb_gain[i] ) { p_dec->fmt_out.audio_replay_gain.pb_gain[i] = fmt->audio_replay_gain.pb_gain[i]; p_dec->fmt_out.audio_replay_gain.pf_gain[i] = fmt->audio_replay_gain.pf_gain[i]; } } } /* */ p_owner->b_cc_supported = 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 = true; if( p_dec->pf_get_cc ) p_owner->b_cc_supported = true; } vlc_mutex_init( &p_owner->lock_cc ); for( i = 0; i < 4; i++ ) { p_owner->pb_cc_present[i] = false; p_owner->pp_cc[i] = NULL; } return p_dec;}/** * The decoding main loop * * \param p_dec the decoder * \return 0 */static void* DecoderThread( vlc_object_t *p_this ){ decoder_t * p_dec = (decoder_t *)p_this; block_t *p_block; /* The decoder's main loop */ while( !p_dec->b_die && !p_dec->b_error ) { if( ( p_block = block_FifoGet( p_dec->p_owner->p_fifo ) ) == NULL ) { p_dec->b_error = 1; break; } if( DecoderDecode( p_dec, p_block ) != VLC_SUCCESS ) { break; } } while( !p_dec->b_die ) { /* Trash all received PES packets */ p_block = block_FifoGet( p_dec->p_owner->p_fifo ); if( p_block ) block_Release( p_block ); } /* We do it here because of the dll loader that wants close() in the * same thread than open()/decode() */ module_Unneed( p_dec, p_dec->p_module ); return 0;}static inline void DecoderUpdatePreroll( int64_t *pi_preroll, const block_t *p ){ if( p->i_flags & (BLOCK_FLAG_PREROLL|BLOCK_FLAG_DISCONTINUITY) ) *pi_preroll = INT64_MAX; else if( p->i_pts > 0 ) *pi_preroll = __MIN( *pi_preroll, p->i_pts ); else if( p->i_dts > 0 ) *pi_preroll = __MIN( *pi_preroll, p->i_dts );}static void DecoderDecodeAudio( decoder_t *p_dec, block_t *p_block ){ input_thread_t *p_input = p_dec->p_owner->p_input; const int i_rate = p_block->i_rate; aout_buffer_t *p_aout_buf; while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_block )) ) { aout_instance_t *p_aout = p_dec->p_owner->p_aout; aout_input_t *p_aout_input = p_dec->p_owner->p_aout_input; if( p_dec->b_die ) { /* It prevent freezing VLC in case of broken decoder */ aout_DecDeleteBuffer( p_aout, p_aout_input, p_aout_buf ); if( p_block ) block_Release( p_block ); break; } vlc_mutex_lock( &p_input->p->counters.counters_lock ); stats_UpdateInteger( p_dec, p_input->p->counters.p_decoded_audio, 1, NULL ); vlc_mutex_unlock( &p_input->p->counters.counters_lock ); if( p_aout_buf->start_date < p_dec->p_owner->i_preroll_end ) { aout_DecDeleteBuffer( p_aout, p_aout_input, p_aout_buf ); continue; } if( p_dec->p_owner->i_preroll_end > 0 ) { /* FIXME TODO flush audio output (don't know how to do that) */ msg_Dbg( p_dec, "End of audio preroll" ); p_dec->p_owner->i_preroll_end = -1; } aout_DecPlay( p_aout, p_aout_input, p_aout_buf, i_rate ); }}static void DecoderGetCc( decoder_t *p_dec, decoder_t *p_dec_cc ){ block_t *p_cc; bool 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 ){ vlc_mutex_lock( &p_vout->picture_lock ); if( p_pic->i_status == READY_PICTURE ) { /* Grr cannot destroy ready picture by myself so be sure vout won't like it */ p_pic->date = 1; } else if( p_pic->i_refcount > 0 ) { p_pic->i_status = DISPLAYED_PICTURE; } else { p_pic->i_status = DESTROYED_PICTURE; p_vout->i_heap_size--; } vlc_mutex_unlock( &p_vout->picture_lock );}static void VoutFlushPicture( vout_thread_t *p_vout ){ int i; vlc_mutex_lock( &p_vout->picture_lock ); for( i = 0; i < p_vout->render.i_pictures; i++ ) { picture_t *p_pic = p_vout->render.pp_picture[i]; if( p_pic->i_status == READY_PICTURE || p_pic->i_status == DISPLAYED_PICTURE ) { /* We cannot change picture status if it is in READY_PICTURE state, * Just make sure they won't be displayed */ p_pic->date = 1; } } vlc_mutex_unlock( &p_vout->picture_lock );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -