📄 decoder.c
字号:
static void optimize_video_pts( decoder_t *p_dec ){ picture_t * oldest_pict = NULL; picture_t * youngest_pict = NULL; int i; input_thread_t * p_input = p_dec->p_owner->p_input; vout_thread_t * p_vout = p_dec->p_owner->p_vout; input_thread_private_t * p_priv = p_input->p; /* Enable with --auto-adjust-pts-delay */ if( !p_priv->pts_adjust.auto_adjust ) return; for( i = 0; i < I_RENDERPICTURES; i++ ) { picture_t * pic = PP_RENDERPICTURE[i]; if( pic->i_status != READY_PICTURE ) continue; if( !oldest_pict || pic->date < oldest_pict->date ) oldest_pict = pic; if( !youngest_pict || pic->date > youngest_pict->date ) youngest_pict = pic; } if( !youngest_pict || !oldest_pict ) return; /* Try to find if we can reduce the pts * This first draft is way to simple, and we can't say if the * algo will converge. It's also full of constants. * But this simple algo allows to reduce the latency * to the minimum. * The whole point of this, is to bypass the pts_delay set * by the access but also the delay arbitraly set by * the remote server. * Actually the remote server's muxer may set up a * pts<->dts delay in the muxed stream. That is * why we may end up in having a negative pts_delay, * to compensate that artificial delay. */ mtime_t buffer_size = youngest_pict->date - oldest_pict->date; int64_t pts_slide = 0; if( buffer_size < 10000 ) { if( p_priv->pts_adjust.i_num_faulty > 10 ) { pts_slide = __MAX(p_input->i_pts_delay *3 / 2, 10000); p_priv->pts_adjust.i_num_faulty = 0; } if( p_priv->pts_adjust.to_high ) { p_priv->pts_adjust.to_high = !p_priv->pts_adjust.to_high; p_priv->pts_adjust.i_num_faulty = 0; } p_priv->pts_adjust.i_num_faulty++; } else if( buffer_size > 100000 ) { if( p_priv->pts_adjust.i_num_faulty > 25 ) { pts_slide = -buffer_size/2; p_priv->pts_adjust.i_num_faulty = 0; } if( p_priv->pts_adjust.to_high ) { p_priv->pts_adjust.to_high = !p_priv->pts_adjust.to_high; p_priv->pts_adjust.i_num_faulty = 0; } p_priv->pts_adjust.i_num_faulty++; } if( pts_slide ) { mtime_t origi_delay = p_input->i_pts_delay; p_input->i_pts_delay += pts_slide; /* Don't play with the pts delay for more than -2<->3sec */ if( p_input->i_pts_delay < -2000000 ) p_input->i_pts_delay = -2000000; else if( p_input->i_pts_delay > 3000000 ) p_input->i_pts_delay = 3000000; pts_slide = p_input->i_pts_delay - origi_delay; msg_Dbg( p_input, "Sliding the pts by %dms pts delay at %dms picture buffer was %dms", (int)pts_slide/1000, (int)p_input->i_pts_delay/1000, (int)buffer_size/1000); vlc_mutex_lock( &p_vout->picture_lock ); /* Slide all the picture */ for( i = 0; i < I_RENDERPICTURES; i++ ) PP_RENDERPICTURE[i]->date += pts_slide; /* FIXME: slide aout/spu */ vlc_mutex_unlock( &p_vout->picture_lock ); }}static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block ){ input_thread_t *p_input = p_dec->p_owner->p_input; picture_t *p_pic; while( (p_pic = p_dec->pf_decode_video( p_dec, &p_block )) ) { vout_thread_t *p_vout = p_dec->p_owner->p_vout; if( p_dec->b_die ) { /* It prevent freezing VLC in case of broken decoder */ VoutDisplayedPicture( p_vout, p_pic ); 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_video, 1, NULL ); vlc_mutex_unlock( &p_input->p->counters.counters_lock ); if( p_pic->date < p_dec->p_owner->i_preroll_end ) { VoutDisplayedPicture( p_vout, p_pic ); continue; } if( p_dec->p_owner->i_preroll_end > 0 ) { msg_Dbg( p_dec, "End of video preroll" ); if( p_vout ) VoutFlushPicture( p_vout ); /* */ 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_vout, p_pic, p_pic->date ); optimize_video_pts( p_dec ); vout_DisplayPicture( p_vout, p_pic ); }}/** * Decode a block * * \param p_dec the decoder object * \param p_block the block to decode * \return VLC_SUCCESS or an error code */static int DecoderDecode( decoder_t *p_dec, block_t *p_block ){ decoder_owner_sys_t *p_sys = (decoder_owner_sys_t *)p_dec->p_owner; const int i_rate = p_block ? p_block->i_rate : INPUT_RATE_DEFAULT; if( p_block && p_block->i_buffer <= 0 ) { block_Release( p_block ); return VLC_SUCCESS; }#ifdef ENABLE_SOUT if( p_dec->i_object_type == VLC_OBJECT_PACKETIZER ) { block_t *p_sout_block; while( ( p_sout_block = p_dec->pf_packetize( p_dec, p_block ? &p_block : 0 ) ) ) { if( !p_dec->p_owner->p_sout_input ) { es_format_Copy( &p_dec->p_owner->sout, &p_dec->fmt_out ); p_dec->p_owner->sout.i_group = p_dec->fmt_in.i_group; p_dec->p_owner->sout.i_id = p_dec->fmt_in.i_id; if( p_dec->fmt_in.psz_language ) { if( p_dec->p_owner->sout.psz_language ) free( p_dec->p_owner->sout.psz_language ); p_dec->p_owner->sout.psz_language = strdup( p_dec->fmt_in.psz_language ); } p_dec->p_owner->p_sout_input = sout_InputNew( p_dec->p_owner->p_sout, &p_dec->p_owner->sout ); if( p_dec->p_owner->p_sout_input == NULL ) { msg_Err( p_dec, "cannot create packetizer output (%4.4s)", (char *)&p_dec->p_owner->sout.i_codec ); p_dec->b_error = true; while( p_sout_block ) { block_t *p_next = p_sout_block->p_next; block_Release( p_sout_block ); p_sout_block = p_next; } break; } } while( p_sout_block ) { block_t *p_next = p_sout_block->p_next; p_sout_block->p_next = NULL; p_sout_block->i_rate = i_rate; sout_InputSendBuffer( p_dec->p_owner->p_sout_input, p_sout_block ); p_sout_block = p_next; } /* For now it's enough, as only sout impact on this flag */ if( p_dec->p_owner->p_sout->i_out_pace_nocontrol > 0 && p_dec->p_owner->p_input->p->b_out_pace_control ) { msg_Dbg( p_dec, "switching to sync mode" ); p_dec->p_owner->p_input->p->b_out_pace_control = false; } else if( p_dec->p_owner->p_sout->i_out_pace_nocontrol <= 0 && !p_dec->p_owner->p_input->p->b_out_pace_control ) { msg_Dbg( p_dec, "switching to async mode" ); p_dec->p_owner->p_input->p->b_out_pace_control = true; } } } else#endif if( p_dec->fmt_in.i_cat == AUDIO_ES ) { if( p_block ) DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block ); if( p_dec->p_owner->p_packetizer ) { block_t *p_packetized_block; decoder_t *p_packetizer = p_dec->p_owner->p_packetizer; while( (p_packetized_block = p_packetizer->pf_packetize( p_packetizer, p_block ? &p_block : NULL )) ) { if( p_packetizer->fmt_out.i_extra && !p_dec->fmt_in.i_extra ) { es_format_Clean( &p_dec->fmt_in ); es_format_Copy( &p_dec->fmt_in, &p_packetizer->fmt_out ); } while( p_packetized_block ) { block_t *p_next = p_packetized_block->p_next; p_packetized_block->p_next = NULL; p_packetized_block->i_rate = i_rate; DecoderDecodeAudio( p_dec, p_packetized_block ); p_packetized_block = p_next; } } } else if( p_block ) { DecoderDecodeAudio( p_dec, p_block ); } } else if( p_dec->fmt_in.i_cat == VIDEO_ES ) { if( p_block ) DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block ); if( p_dec->p_owner->p_packetizer ) { block_t *p_packetized_block; decoder_t *p_packetizer = p_dec->p_owner->p_packetizer; while( (p_packetized_block = p_packetizer->pf_packetize( p_packetizer, p_block ? &p_block : NULL )) ) { if( p_packetizer->fmt_out.i_extra && !p_dec->fmt_in.i_extra ) { es_format_Clean( &p_dec->fmt_in ); 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 ) { block_t *p_next = p_packetized_block->p_next; p_packetized_block->p_next = NULL; p_packetized_block->i_rate = i_rate; DecoderDecodeVideo( p_dec, p_packetized_block ); p_packetized_block = p_next; } } } else if( p_block ) { DecoderDecodeVideo( p_dec, p_block ); } } else if( p_dec->fmt_in.i_cat == SPU_ES ) { input_thread_t *p_input = p_dec->p_owner->p_input; vout_thread_t *p_vout; subpicture_t *p_spu; if( p_block ) DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block ); while( (p_spu = p_dec->pf_decode_sub( p_dec, p_block ? &p_block : NULL ) ) ) { vlc_mutex_lock( &p_input->p->counters.counters_lock ); stats_UpdateInteger( p_dec, p_input->p->counters.p_decoded_sub, 1, NULL ); vlc_mutex_unlock( &p_input->p->counters.counters_lock ); p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE ); if( p_vout && p_sys->p_spu_vout == p_vout ) { /* Prerool does not work very well with subtitle */ if( p_spu->i_start < p_dec->p_owner->i_preroll_end && ( p_spu->i_stop <= 0 || p_spu->i_stop < p_dec->p_owner->i_preroll_end ) ) spu_DestroySubpicture( p_vout->p_spu, p_spu ); else spu_DisplaySubpicture( p_vout->p_spu, p_spu ); } else { msg_Warn( p_dec, "no vout found, leaking subpicture" ); } if( p_vout ) vlc_object_release( p_vout ); } } else { msg_Err( p_dec, "unknown ES format" ); p_dec->b_error = 1; } return p_dec->b_error ? VLC_EGENERIC : VLC_SUCCESS;}/** * Destroys a decoder object * * \param p_dec the decoder object * \return nothing */static void DeleteDecoder( decoder_t * p_dec ){ msg_Dbg( p_dec, "killing decoder fourcc `%4.4s', %u PES in FIFO", (char*)&p_dec->fmt_in.i_codec, (unsigned)block_FifoCount( p_dec->p_owner->p_fifo ) ); /* Free all packets still in the decoder fifo. */ block_FifoEmpty( p_dec->p_owner->p_fifo ); block_FifoRelease( p_dec->p_owner->p_fifo ); /* Cleanup */ if( p_dec->p_owner->p_aout_input )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -