- /* The fifo is not consumed when waiting and so will
- * deadlock vlc.
- * There is no need to lock as b_waiting is never modified
- * inside decoder thread. */
- if( !p_owner->b_waiting )
- block_FifoPace( p_owner->p_fifo, 10, SIZE_MAX );
- }
-#ifdef __arm__
- else if( block_FifoSize( p_owner->p_fifo ) > 50*1024*1024 /* 50 MiB */ )
-#else
- else if( block_FifoSize( p_owner->p_fifo ) > 400*1024*1024 /* 400 MiB, ie ~ 50mb/s for 60s */ )
-#endif
- {
- /* FIXME: ideally we would check the time amount of data
- * in the FIFO instead of its size. */
- msg_Warn( p_dec, "decoder/packetizer fifo full (data not "
- "consumed quickly enough), resetting fifo!" );
- block_FifoEmpty( p_owner->p_fifo );
- }
-
- block_FifoPut( p_owner->p_fifo, p_block );
-}
-
-bool input_DecoderIsEmpty( decoder_t * p_dec )
-{
- decoder_owner_sys_t *p_owner = p_dec->p_owner;
- assert( !p_owner->b_waiting );
-
- bool b_empty = block_FifoCount( p_dec->p_owner->p_fifo ) <= 0;
-
- if( b_empty )
- {
- vlc_mutex_lock( &p_owner->lock );
- /* TODO subtitles support */
- if( p_dec->fmt_out.i_cat == VIDEO_ES && p_owner->p_vout )
- b_empty = vout_IsEmpty( p_owner->p_vout );
- else if( p_dec->fmt_out.i_cat == AUDIO_ES && p_owner->p_aout )
- b_empty = aout_DecIsEmpty( p_owner->p_aout );
- vlc_mutex_unlock( &p_owner->lock );
- }
- return b_empty;
-}
-
-void input_DecoderIsCcPresent( decoder_t *p_dec, bool pb_present[4] )
-{
- decoder_owner_sys_t *p_owner = p_dec->p_owner;
- int i;
-
- vlc_mutex_lock( &p_owner->lock );
- for( i = 0; i < 4; i++ )
- pb_present[i] = p_owner->cc.pb_present[i];
- vlc_mutex_unlock( &p_owner->lock );
-}
-int input_DecoderSetCcState( decoder_t *p_dec, bool b_decode, int i_channel )
-{
- decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
- //msg_Warn( p_dec, "input_DecoderSetCcState: %d @%d", b_decode, i_channel );
-
- if( i_channel < 0 || i_channel >= 4 || !p_owner->cc.pb_present[i_channel] )
- return VLC_EGENERIC;
-
- if( b_decode )
- {
- static const vlc_fourcc_t fcc[4] = {
- 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 = input_DecoderNew( p_owner->p_input, &fmt,
- p_dec->p_owner->p_clock, p_owner->p_sout );
- if( !p_cc )
- {
- msg_Err( p_dec, "could not create decoder" );
- dialog_Fatal( p_dec, _("Streaming / Transcoding failed"), "%s",
- _("VLC could not open the decoder module.") );
- return VLC_EGENERIC;
- }
- else if( !p_cc->p_module )
- {
- DecoderUnsupportedCodec( p_dec, fcc[i_channel] );
- input_DecoderDelete(p_cc);
- return VLC_EGENERIC;
- }
- p_cc->p_owner->p_clock = p_owner->p_clock;
-
- vlc_mutex_lock( &p_owner->lock );
- p_owner->cc.pp_decoder[i_channel] = p_cc;
- vlc_mutex_unlock( &p_owner->lock );
- }
- else
- {
- decoder_t *p_cc;
-
- vlc_mutex_lock( &p_owner->lock );
- p_cc = p_owner->cc.pp_decoder[i_channel];
- p_owner->cc.pp_decoder[i_channel] = NULL;
- vlc_mutex_unlock( &p_owner->lock );
-
- if( p_cc )
- input_DecoderDelete(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->cc.pb_present[i_channel] )
- return VLC_EGENERIC;
-
- vlc_mutex_lock( &p_owner->lock );
- *pb_decode = p_owner->cc.pp_decoder[i_channel] != NULL;
- vlc_mutex_unlock( &p_owner->lock );
- return VLC_EGENERIC;
-}
-
-void input_DecoderChangePause( decoder_t *p_dec, bool b_paused, mtime_t i_date )
-{
- decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
- vlc_mutex_lock( &p_owner->lock );
- /* Normally, p_owner->b_paused != b_paused here. But if a track is added
- * while the input is paused (e.g. add sub file), then b_paused is
- * (incorrectly) false. */
- if( likely(p_owner->b_paused != b_paused) ) {
- p_owner->b_paused = b_paused;
- p_owner->pause.i_date = i_date;
- p_owner->pause.i_ignore = 0;
- vlc_cond_signal( &p_owner->wait_request );
-
- DecoderOutputChangePause( p_dec, b_paused, i_date );
- }
- vlc_mutex_unlock( &p_owner->lock );
-}
-
-void input_DecoderChangeDelay( decoder_t *p_dec, mtime_t i_delay )
-{
- decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
- vlc_mutex_lock( &p_owner->lock );
- p_owner->i_ts_delay = i_delay;
- vlc_mutex_unlock( &p_owner->lock );
-}
-
-void input_DecoderStartWait( decoder_t *p_dec )
-{
- decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
- vlc_mutex_lock( &p_owner->lock );
-
- DecoderFlush( p_dec );
-
- p_owner->b_first = true;
- p_owner->b_has_data = false;
-
- p_owner->b_waiting = true;
-
- vlc_cond_signal( &p_owner->wait_request );
-
- vlc_mutex_unlock( &p_owner->lock );
-}
-
-void input_DecoderStopWait( decoder_t *p_dec )
-{
- decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
- vlc_mutex_lock( &p_owner->lock );
-
- p_owner->b_waiting = false;
-
- vlc_cond_signal( &p_owner->wait_request );
-
- vlc_mutex_unlock( &p_owner->lock );
-}
-
-void input_DecoderWait( decoder_t *p_dec )
-{
- decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
- vlc_mutex_lock( &p_owner->lock );
-
- while( p_owner->b_waiting && !p_owner->b_has_data )
- {
- block_FifoWake( p_owner->p_fifo );
- vlc_cond_wait( &p_owner->wait_acknowledge, &p_owner->lock );
- }
-
- vlc_mutex_unlock( &p_owner->lock );
-}
-
-void input_DecoderFrameNext( decoder_t *p_dec, mtime_t *pi_duration )
-{
- decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
- *pi_duration = 0;
-
- vlc_mutex_lock( &p_owner->lock );
- if( p_dec->fmt_out.i_cat == VIDEO_ES )
- {
- if( p_owner->b_paused && p_owner->p_vout )
- {
- vout_NextPicture( p_owner->p_vout, pi_duration );
- p_owner->pause.i_ignore++;
- vlc_cond_signal( &p_owner->wait_request );
- }
- }
- else
- {
- /* TODO subtitle should not be flushed */
- DecoderFlush( p_dec );
- }
- vlc_mutex_unlock( &p_owner->lock );
-}
-
-bool input_DecoderHasFormatChanged( decoder_t *p_dec, es_format_t *p_fmt, vlc_meta_t **pp_meta )
-{
- decoder_owner_sys_t *p_owner = p_dec->p_owner;
- bool b_changed;
-
- vlc_mutex_lock( &p_owner->lock );
- b_changed = p_owner->b_fmt_description;
- if( b_changed )
- {
- if( p_fmt )
- es_format_Copy( p_fmt, &p_owner->fmt_description );
-
- if( pp_meta )
- {
- *pp_meta = NULL;
- if( p_owner->p_description )
- {
- *pp_meta = vlc_meta_New();
- if( *pp_meta )
- vlc_meta_Merge( *pp_meta, p_owner->p_description );
- }
- }
- p_owner->b_fmt_description = false;
- }
- vlc_mutex_unlock( &p_owner->lock );
- return b_changed;
-}
-
-size_t input_DecoderGetFifoSize( decoder_t *p_dec )
-{
- decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
- return block_FifoSize( p_owner->p_fifo );
-}
-
-void input_DecoderGetObjects( decoder_t *p_dec,
- vout_thread_t **pp_vout, audio_output_t **pp_aout )
-{
- decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
- vlc_mutex_lock( &p_owner->lock );
- if( pp_vout )
- *pp_vout = p_owner->p_vout ? vlc_object_hold( p_owner->p_vout ) : NULL;
- if( pp_aout )
- *pp_aout = p_owner->p_aout ? vlc_object_hold( p_owner->p_aout ) : NULL;
- vlc_mutex_unlock( &p_owner->lock );
-}
-
-/*****************************************************************************
- * Internal functions
- *****************************************************************************/
-static int DecoderGetInputAttachments( decoder_t *p_dec,
- input_attachment_t ***ppp_attachment,
- int *pi_attachment )
-{
- input_thread_t *p_input = p_dec->p_owner->p_input;
-
- if( unlikely(p_input == NULL) )
- return VLC_ENOOBJ;
- return input_Control( p_input, INPUT_GET_ATTACHMENTS,
- ppp_attachment, pi_attachment );
-}
-static mtime_t DecoderGetDisplayDate( decoder_t *p_dec, mtime_t i_ts )
-{
- decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
- vlc_mutex_lock( &p_owner->lock );
- if( p_owner->b_waiting || p_owner->b_paused )
- i_ts = VLC_TS_INVALID;
- vlc_mutex_unlock( &p_owner->lock );
-
- if( !p_owner->p_clock || i_ts <= VLC_TS_INVALID )
- return i_ts;
-
- if( input_clock_ConvertTS( p_owner->p_clock, NULL, &i_ts, NULL, INT64_MAX ) ) {
- msg_Err(p_dec, "Could not get display date for timestamp %"PRId64"", i_ts);
- return VLC_TS_INVALID;
- }
-
- return i_ts;
-}
-static int DecoderGetDisplayRate( decoder_t *p_dec )
-{
- decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
- if( !p_owner->p_clock )
- return INPUT_RATE_DEFAULT;
- return input_clock_GetRate( p_owner->p_clock );
-}
-
-/* */
-static void DecoderUnsupportedCodec( decoder_t *p_dec, vlc_fourcc_t codec )
-{
- if (codec != VLC_FOURCC('u','n','d','f')) {
- const char *desc = vlc_fourcc_GetDescription(p_dec->fmt_in.i_cat, codec);
- if (!desc || !*desc)
- desc = N_("No description for this codec");
- msg_Err( p_dec, "Codec `%4.4s' (%s) is not supported.", (char*)&codec, desc );
- dialog_Fatal( p_dec, _("Codec not supported"),
- _("VLC could not decode the format \"%4.4s\" (%s)"),
- (char*)&codec, desc );
- } else {
- msg_Err( p_dec, "could not identify codec" );
- dialog_Fatal( p_dec, _("Unidentified codec"),
- _("VLC could not identify the audio or video codec" ) );
- }
-}
-
-
-/**
- * Create a decoder object
- *
- * \param p_input the input thread
- * \param p_es the es descriptor
- * \param b_packetizer instead of a decoder
- * \return the decoder object
- */
-static decoder_t * CreateDecoder( vlc_object_t *p_parent,
- input_thread_t *p_input,
- es_format_t *fmt, bool b_packetizer,
- input_resource_t *p_resource,
- sout_instance_t *p_sout )
-{
- decoder_t *p_dec;
- decoder_owner_sys_t *p_owner;
- es_format_t null_es_format;
-
- p_dec = vlc_custom_create( p_parent, sizeof( *p_dec ), "decoder" );
- if( p_dec == NULL )
- return NULL;
-
- p_dec->pf_decode_audio = NULL;
- p_dec->pf_decode_video = NULL;
- p_dec->pf_decode_sub = NULL;
- p_dec->pf_get_cc = NULL;
- p_dec->pf_packetize = NULL;
-
- /* Initialize the decoder */
- 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 );
-
- p_dec->p_description = NULL;
-
- /* Allocate our private structure for the decoder */
- p_dec->p_owner = p_owner = malloc( sizeof( decoder_owner_sys_t ) );
- if( unlikely(p_owner == NULL) )
- {
- vlc_object_release( p_dec );
- return NULL;
- }
- p_owner->i_preroll_end = VLC_TS_INVALID;
- p_owner->i_last_rate = INPUT_RATE_DEFAULT;
- p_owner->p_input = p_input;
- p_owner->p_resource = p_resource;
- p_owner->p_aout = NULL;
- p_owner->p_vout = NULL;
- p_owner->p_spu_vout = NULL;
- p_owner->i_spu_channel = 0;
- p_owner->i_spu_order = 0;
- p_owner->p_sout = p_sout;
- p_owner->p_sout_input = NULL;
- p_owner->p_packetizer = NULL;
- p_owner->b_packetizer = b_packetizer;
-
- /* decoder fifo */
- p_owner->p_fifo = block_FifoNew();
- if( unlikely(p_owner->p_fifo == NULL) )
- {
- free( p_owner );
- vlc_object_release( p_dec );
- return NULL;
- }
-
- /* Set buffers allocation callbacks for the decoders */
- p_dec->pf_aout_format_update = aout_update_format;
- 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;
- /* */
- p_dec->pf_get_attachments = DecoderGetInputAttachments;
- p_dec->pf_get_display_date = DecoderGetDisplayDate;
- p_dec->pf_get_display_rate = DecoderGetDisplayRate;
-
- /* Find a suitable decoder/packetizer module */
- if( !b_packetizer )
- p_dec->p_module = module_need( p_dec, "decoder", "$codec", false );
- else
- p_dec->p_module = module_need( p_dec, "packetizer", "$packetizer", false );