X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Fdecoder.c;h=d0fdd1422945d69276357d49235d100a1dd2fc80;hb=39670df97892b3ef4be6edd28e39826804f51cff;hp=90c019fb7a3addd0c0b96c5530a74bfd62b9541a;hpb=99fab9089e9e1709d9c3a4bc5ced0c137ac59134;p=vlc diff --git a/src/input/decoder.c b/src/input/decoder.c index 90c019fb7a..d0fdd14229 100644 --- a/src/input/decoder.c +++ b/src/input/decoder.c @@ -29,8 +29,9 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif +#include -#include +#include #include #include @@ -66,7 +67,7 @@ static es_format_t null_es_format; struct decoder_owner_sys_t { - vlc_bool_t b_own_thread; + bool b_own_thread; int64_t i_preroll_end; @@ -95,9 +96,9 @@ struct decoder_owner_sys_t block_fifo_t *p_fifo; /* CC */ - vlc_bool_t b_cc_supported; + bool b_cc_supported; vlc_mutex_t lock_cc; - vlc_bool_t pb_cc_present[4]; + bool pb_cc_present[4]; decoder_t *pp_cc[4]; }; @@ -107,7 +108,7 @@ 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"), + intf_UserFatal( p_dec, false, _("No suitable decoder module"), _("VLC does not support the audio or video format \"%4.4s\". " "Unfortunately there is no way for you to fix this."), (char*)&codec ); } @@ -135,6 +136,7 @@ int decoder_GetInputAttachments( decoder_t *p_dec, */ mtime_t decoder_GetDisplayDate( decoder_t *p_dec, mtime_t i_ts ) { + VLC_UNUSED(p_dec); return i_ts; } @@ -146,11 +148,14 @@ mtime_t decoder_GetDisplayDate( decoder_t *p_dec, mtime_t i_ts ) * \return the spawned decoder object */ decoder_t *input_DecoderNew( input_thread_t *p_input, - es_format_t *fmt, vlc_bool_t b_force_decoder ) + es_format_t *fmt, bool b_force_decoder ) { decoder_t *p_dec = NULL; vlc_value_t val; +#ifndef ENABLE_SOUT + (void)b_force_decoder; +#else /* If we are in sout mode, search for packetizer module */ if( p_input->p->p_sout && !b_force_decoder ) { @@ -159,19 +164,20 @@ decoder_t *input_DecoderNew( input_thread_t *p_input, if( p_dec == NULL ) { msg_Err( p_input, "could not create packetizer" ); - intf_UserFatal( p_input, VLC_FALSE, _("Streaming / Transcoding failed"), + intf_UserFatal( p_input, false, _("Streaming / Transcoding failed"), _("VLC could not open the packetizer module.") ); return NULL; } } else +#endif { /* Create the decoder configuration structure */ p_dec = CreateDecoder( p_input, fmt, VLC_OBJECT_DECODER ); if( p_dec == NULL ) { msg_Err( p_input, "could not create decoder" ); - intf_UserFatal( p_input, VLC_FALSE, _("Streaming / Transcoding failed"), + intf_UserFatal( p_input, false, _("Streaming / Transcoding failed"), _("VLC could not open the decoder module.") ); return NULL; } @@ -182,7 +188,7 @@ decoder_t *input_DecoderNew( input_thread_t *p_input, DecoderUnsupportedCodec( p_dec, fmt->i_codec ); DeleteDecoder( p_dec ); - vlc_object_destroy( p_dec ); + vlc_object_release( p_dec ); return NULL; } @@ -190,7 +196,7 @@ decoder_t *input_DecoderNew( input_thread_t *p_input, !b_force_decoder ) { msg_Dbg( p_input, "stream out mode -> no decoder thread" ); - p_dec->p_owner->b_own_thread = VLC_FALSE; + p_dec->p_owner->b_own_thread = false; } else { @@ -208,12 +214,12 @@ decoder_t *input_DecoderNew( input_thread_t *p_input, /* Spawn the decoder thread */ if( vlc_thread_create( p_dec, "decoder", DecoderThread, - i_priority, VLC_FALSE ) ) + i_priority, false ) ) { msg_Err( p_dec, "cannot spawn decoder thread" ); module_Unneed( p_dec, p_dec->p_module ); DeleteDecoder( p_dec ); - vlc_object_destroy( p_dec ); + vlc_object_release( p_dec ); return NULL; } } @@ -257,14 +263,14 @@ void input_DecoderDelete( decoder_t *p_dec ) { int i; for( i = 0; i < 4; i++ ) - input_DecoderSetCcState( p_dec, VLC_FALSE, i ); + input_DecoderSetCcState( p_dec, false, i ); } /* Delete decoder configuration */ DeleteDecoder( p_dec ); /* Delete the decoder */ - vlc_object_destroy( p_dec ); + vlc_object_release( p_dec ); } /** @@ -310,7 +316,7 @@ void input_DecoderDecode( decoder_t * p_dec, block_t *p_block ) } } -void input_DecoderDiscontinuity( decoder_t * p_dec, vlc_bool_t b_flush ) +void input_DecoderDiscontinuity( decoder_t * p_dec, bool b_flush ) { block_t *p_null; @@ -329,17 +335,17 @@ void input_DecoderDiscontinuity( decoder_t * p_dec, vlc_bool_t b_flush ) input_DecoderDecode( p_dec, p_null ); } -vlc_bool_t input_DecoderEmpty( decoder_t * p_dec ) +bool input_DecoderEmpty( decoder_t * p_dec ) { if( p_dec->p_owner->b_own_thread && block_FifoCount( p_dec->p_owner->p_fifo ) > 0 ) { - return VLC_FALSE; + return false; } - return VLC_TRUE; + return true; } -void input_DecoderIsCcPresent( decoder_t *p_dec, vlc_bool_t pb_present[4] ) +void input_DecoderIsCcPresent( decoder_t *p_dec, bool pb_present[4] ) { int i; @@ -348,7 +354,7 @@ void input_DecoderIsCcPresent( decoder_t *p_dec, vlc_bool_t pb_present[4] ) 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 ) +int input_DecoderSetCcState( decoder_t *p_dec, bool b_decode, int i_channel ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; @@ -373,7 +379,7 @@ int input_DecoderSetCcState( decoder_t *p_dec, vlc_bool_t b_decode, int i_channe if( !p_cc ) { msg_Err( p_dec, "could not create decoder" ); - intf_UserFatal( p_dec, VLC_FALSE, _("Streaming / Transcoding failed"), + intf_UserFatal( p_dec, false, _("Streaming / Transcoding failed"), _("VLC could not open the decoder module.") ); return VLC_EGENERIC; } @@ -381,7 +387,7 @@ int input_DecoderSetCcState( decoder_t *p_dec, vlc_bool_t b_decode, int i_channe { DecoderUnsupportedCodec( p_dec, fcc[i_channel] ); DeleteDecoder( p_cc ); - vlc_object_destroy( p_cc ); + vlc_object_release( p_cc ); return VLC_EGENERIC; } @@ -403,16 +409,16 @@ int input_DecoderSetCcState( decoder_t *p_dec, vlc_bool_t b_decode, int i_channe vlc_object_kill( p_cc ); module_Unneed( p_cc, p_cc->p_module ); DeleteDecoder( p_cc ); - vlc_object_destroy( p_cc ); + vlc_object_release( p_cc ); } } return VLC_SUCCESS; } -int input_DecoderGetCcState( decoder_t *p_dec, vlc_bool_t *pb_decode, int i_channel ) +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 = VLC_FALSE; + *pb_decode = false; if( i_channel < 0 || i_channel >= 4 || !p_owner->pb_cc_present[i_channel] ) return VLC_EGENERIC; @@ -439,10 +445,7 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, p_dec = vlc_object_create( p_input, i_object_type ); if( p_dec == NULL ) - { - msg_Err( p_input, "out of memory" ); return NULL; - } p_dec->pf_decode_audio = 0; p_dec->pf_decode_video = 0; @@ -461,10 +464,10 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, p_dec->p_owner = p_owner = malloc( sizeof( decoder_owner_sys_t ) ); if( p_dec->p_owner == NULL ) { - msg_Err( p_dec, "out of memory" ); + vlc_object_release( p_dec ); return NULL; } - p_dec->p_owner->b_own_thread = VLC_TRUE; + 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; @@ -477,9 +480,10 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, p_dec->p_owner->p_packetizer = NULL; /* decoder fifo */ - if( ( p_dec->p_owner->p_fifo = block_FifoNew( p_dec ) ) == NULL ) + if( ( p_dec->p_owner->p_fifo = block_FifoNew() ) == NULL ) { - msg_Err( p_dec, "out of memory" ); + free( p_dec->p_owner ); + vlc_object_release( p_dec ); return NULL; } @@ -525,7 +529,7 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, { es_format_Clean( &p_dec->p_owner->p_packetizer->fmt_in ); vlc_object_detach( p_dec->p_owner->p_packetizer ); - vlc_object_destroy( p_dec->p_owner->p_packetizer ); + vlc_object_release( p_dec->p_owner->p_packetizer ); } } } @@ -548,19 +552,19 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, } } /* */ - p_owner->b_cc_supported = VLC_FALSE; + 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 = VLC_TRUE; + p_owner->b_cc_supported = true; if( p_dec->pf_get_cc ) - p_owner->b_cc_supported = VLC_TRUE; + p_owner->b_cc_supported = true; } - vlc_mutex_init( p_dec, &p_owner->lock_cc ); + vlc_mutex_init( &p_owner->lock_cc ); for( i = 0; i < 4; i++ ) { - p_owner->pb_cc_present[i] = VLC_FALSE; + p_owner->pb_cc_present[i] = false; p_owner->pp_cc[i] = NULL; } return p_dec; @@ -615,20 +619,30 @@ static inline void DecoderUpdatePreroll( int64_t *pi_preroll, const block_t *p ) } 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; + 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_dec->p_owner->p_aout, - p_dec->p_owner->p_aout_input, p_aout_buf ); + aout_DecDeleteBuffer( p_aout, p_aout_input, p_aout_buf ); continue; } @@ -638,15 +652,13 @@ static void DecoderDecodeAudio( decoder_t *p_dec, block_t *p_block ) msg_Dbg( p_dec, "End of audio preroll" ); p_dec->p_owner->i_preroll_end = -1; } - aout_DecPlay( p_dec->p_owner->p_aout, - p_dec->p_owner->p_aout_input, - p_aout_buf, i_rate ); + 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; - vlc_bool_t pb_present[4]; + bool pb_present[4]; int i; int i_cc_decoder; @@ -720,28 +732,136 @@ static void VoutFlushPicture( vout_thread_t *p_vout ) } vlc_mutex_unlock( &p_vout->picture_lock ); } + + +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; + 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_dec->p_owner->p_vout, p_pic ); + 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_dec->p_owner->p_vout ) - VoutFlushPicture( p_dec->p_owner->p_vout ); + if( p_vout ) + VoutFlushPicture( p_vout ); /* */ p_dec->p_owner->i_preroll_end = -1; } @@ -749,9 +869,11 @@ static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block ) 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, - p_pic->date ); - vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic ); + vout_DatePicture( p_vout, p_pic, p_pic->date ); + + optimize_video_pts( p_dec ); + + vout_DisplayPicture( p_vout, p_pic ); } } @@ -773,6 +895,7 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) return VLC_SUCCESS; } +#ifdef ENABLE_SOUT if( p_dec->i_object_type == VLC_OBJECT_PACKETIZER ) { block_t *p_sout_block; @@ -802,7 +925,7 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) { msg_Err( p_dec, "cannot create packetizer output (%4.4s)", (char *)&p_dec->p_owner->sout.i_codec ); - p_dec->b_error = VLC_TRUE; + p_dec->b_error = true; while( p_sout_block ) { @@ -827,22 +950,24 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) p_sout_block = p_next; } - /* For now it's enough, as only sout inpact on this flag */ + /* 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 = VLC_FALSE; + 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 = VLC_TRUE; + p_dec->p_owner->p_input->p->b_out_pace_control = true; } } } - else if( p_dec->fmt_in.i_cat == AUDIO_ES ) + else +#endif + if( p_dec->fmt_in.i_cat == AUDIO_ES ) { if( p_block ) DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block ); @@ -977,7 +1102,11 @@ static void DeleteDecoder( decoder_t * p_dec ) /* Cleanup */ if( p_dec->p_owner->p_aout_input ) aout_DecDelete( p_dec->p_owner->p_aout, p_dec->p_owner->p_aout_input ); - + if( p_dec->p_owner->p_aout ) + { + vlc_object_release( p_dec->p_owner->p_aout ); + p_dec->p_owner->p_aout = NULL; + } if( p_dec->p_owner->p_vout ) { int i_pic; @@ -998,11 +1127,13 @@ static void DeleteDecoder( decoder_t * p_dec ) vout_Request( p_dec, p_dec->p_owner->p_vout, 0 ); } +#ifdef ENABLE_SOUT if( p_dec->p_owner->p_sout_input ) { sout_InputDelete( p_dec->p_owner->p_sout_input ); es_format_Clean( &p_dec->p_owner->sout ); } +#endif if( p_dec->fmt_in.i_cat == SPU_ES ) { @@ -1027,7 +1158,7 @@ static void DeleteDecoder( decoder_t * p_dec ) es_format_Clean( &p_dec->p_owner->p_packetizer->fmt_in ); es_format_Clean( &p_dec->p_owner->p_packetizer->fmt_out ); vlc_object_detach( p_dec->p_owner->p_packetizer ); - vlc_object_destroy( p_dec->p_owner->p_packetizer ); + vlc_object_release( p_dec->p_owner->p_packetizer ); } vlc_mutex_destroy( &p_dec->p_owner->lock_cc ); @@ -1086,15 +1217,14 @@ static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples ) if( p_sys->p_aout_input == NULL ) { msg_Err( p_dec, "failed to create audio output" ); - p_dec->b_error = VLC_TRUE; + p_dec->b_error = true; return NULL; } p_dec->fmt_out.audio.i_bytes_per_frame = p_sys->audio.i_bytes_per_frame; } - p_buffer = aout_DecNewBuffer( p_sys->p_aout, p_sys->p_aout_input, - i_samples ); + p_buffer = aout_DecNewBuffer( p_sys->p_aout_input, i_samples ); return p_buffer; } @@ -1105,6 +1235,9 @@ static void aout_del_buffer( decoder_t *p_dec, aout_buffer_t *p_buffer ) p_dec->p_owner->p_aout_input, p_buffer ); } + +int vout_CountPictureAvailable( vout_thread_t *p_vout ); + static picture_t *vout_new_buffer( decoder_t *p_dec ) { decoder_owner_sys_t *p_sys = (decoder_owner_sys_t *)p_dec->p_owner; @@ -1175,7 +1308,7 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) if( p_sys->p_vout == NULL ) { msg_Err( p_dec, "failed to create video output" ); - p_dec->b_error = VLC_TRUE; + p_dec->b_error = true; return NULL; } @@ -1187,14 +1320,25 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) p_sys->p_vout->render.i_bmask = p_sys->video.i_bmask; } - /* Get a new picture */ - while( !(p_pic = vout_CreatePicture( p_sys->p_vout, 0, 0, 0 ) ) ) + /* Get a new picture + */ + for( p_pic = NULL; ; ) { int i_pic, i_ready_pic = 0; if( p_dec->b_die || p_dec->b_error ) - { return NULL; + + /* The video filter chain required that there is always 1 free buffer + * that it will use as temporary one. It will release the temporary + * buffer once its work is done, so this check is safe even if we don't + * lock around both count() and create(). + */ + if( vout_CountPictureAvailable( p_sys->p_vout ) >= 2 ) + { + p_pic = vout_CreatePicture( p_sys->p_vout, 0, 0, 0 ); + if( p_pic ) + break; } #define p_pic p_dec->p_owner->p_vout->render.pp_picture[i_pic]