]> git.sesse.net Git - vlc/blobdiff - src/input/decoder.c
Add LGPL license
[vlc] / src / input / decoder.c
index d0c3db4e135e5d4477178690695573410f3dc2e8..efee19449af1831b6ac9c7271509088a5c8316fa 100644 (file)
@@ -58,7 +58,7 @@ static decoder_t *CreateDecoder( vlc_object_t *, input_thread_t *,
                                  sout_instance_t *p_sout );
 static void       DeleteDecoder( decoder_t * );
 
-static void      *DecoderThread( vlc_object_t * );
+static void      *DecoderThread( void * );
 static void       DecoderProcess( decoder_t *, block_t * );
 static void       DecoderError( decoder_t *p_dec, block_t *p_block );
 static void       DecoderOutputChangePause( decoder_t *, bool b_paused, mtime_t i_date );
@@ -70,7 +70,6 @@ static void       DecoderUnsupportedCodec( decoder_t *, vlc_fourcc_t );
 
 /* Buffers allocation callbacks for the decoders */
 static aout_buffer_t *aout_new_buffer( decoder_t *, int );
-static void aout_del_buffer( decoder_t *, aout_buffer_t * );
 
 static picture_t *vout_new_buffer( decoder_t * );
 static void vout_del_buffer( decoder_t *, picture_t * );
@@ -96,6 +95,8 @@ struct decoder_owner_sys_t
     sout_instance_t         *p_sout;
     sout_packetizer_input_t *p_sout_input;
 
+    vlc_thread_t     thread;
+
     /* Some decoders require already packetized data (ie. not truncated) */
     decoder_t *p_packetizer;
     bool b_packetizer;
@@ -119,13 +120,13 @@ struct decoder_owner_sys_t
     vlc_cond_t  wait_acknowledge;
 
     /* -- These variables need locking on write(only) -- */
-    aout_instance_t *p_aout;
-    aout_input_t    *p_aout_input;
+    audio_output_t *p_aout;
 
     vout_thread_t   *p_vout;
 
     /* -- Theses variables need locking on read *and* write -- */
-    /* */
+    bool b_exit;
+
     /* Pause */
     bool b_paused;
     struct
@@ -211,10 +212,6 @@ aout_buffer_t *decoder_NewAudioBuffer( decoder_t *p_decoder, int i_size )
         return NULL;
     return p_decoder->pf_aout_buffer_new( p_decoder, i_size );
 }
-void decoder_DeleteAudioBuffer( decoder_t *p_decoder, aout_buffer_t *p_buffer )
-{
-    p_decoder->pf_aout_buffer_del( p_decoder, p_buffer );
-}
 
 subpicture_t *decoder_NewSubpicture( decoder_t *p_decoder,
                                      const subpicture_updater_t *p_dyn )
@@ -299,7 +296,7 @@ static decoder_t *decoder_New( vlc_object_t *p_parent, input_thread_t *p_input,
         i_priority = VLC_THREAD_PRIORITY_VIDEO;
 
     /* Spawn the decoder thread */
-    if( vlc_thread_create( p_dec, DecoderThread, i_priority ) )
+    if( vlc_clone( &p_dec->p_owner->thread, DecoderThread, p_dec, i_priority ) )
     {
         msg_Err( p_dec, "cannot spawn decoder thread" );
         module_unneed( p_dec, p_dec->p_module );
@@ -347,18 +344,19 @@ void input_DecoderDelete( decoder_t *p_dec )
 {
     decoder_owner_sys_t *p_owner = p_dec->p_owner;
 
-    vlc_object_kill( p_dec );
+    vlc_cancel( p_owner->thread );
 
-    /* Make sure we aren't paused/buffering/waiting anymore */
+    /* Make sure we aren't paused/buffering/waiting/decoding anymore */
     vlc_mutex_lock( &p_owner->lock );
     const bool b_was_paused = p_owner->b_paused;
     p_owner->b_paused = false;
     p_owner->b_buffering = false;
     p_owner->b_flushing = true;
+    p_owner->b_exit = true;
     vlc_cond_signal( &p_owner->wait_request );
     vlc_mutex_unlock( &p_owner->lock );
 
-    vlc_thread_join( p_dec );
+    vlc_join( p_owner->thread, NULL );
     p_owner->b_paused = b_was_paused;
 
     module_unneed( p_dec, p_dec->p_module );
@@ -424,7 +422,7 @@ bool input_DecoderIsEmpty( decoder_t * p_dec )
         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_InputIsEmpty( p_owner->p_aout, p_owner->p_aout_input );
+            b_empty = aout_DecIsEmpty( p_owner->p_aout );
         vlc_mutex_unlock( &p_owner->lock );
     }
     return b_empty;
@@ -493,7 +491,6 @@ int input_DecoderSetCcState( decoder_t *p_dec, bool b_decode, int i_channel )
 
         if( p_cc )
         {
-            vlc_object_kill( p_cc );
             module_unneed( p_cc, p_cc->p_module );
             DeleteDecoder( p_cc );
         }
@@ -595,7 +592,7 @@ void input_DecoderWaitBuffering( decoder_t *p_dec )
 
     vlc_mutex_lock( &p_owner->lock );
 
-    while( vlc_object_alive( p_dec ) && p_owner->b_buffering && !p_owner->buffer.b_full )
+    while( p_owner->b_buffering && !p_owner->buffer.b_full )
     {
         block_FifoWake( p_owner->p_fifo );
         vlc_cond_wait( &p_owner->wait_acknowledge, &p_owner->lock );
@@ -664,7 +661,7 @@ size_t input_DecoderGetFifoSize( decoder_t *p_dec )
 }
 
 void input_DecoderGetObjects( decoder_t *p_dec,
-                              vout_thread_t **pp_vout, aout_instance_t **pp_aout )
+                              vout_thread_t **pp_vout, audio_output_t **pp_aout )
 {
     decoder_owner_sys_t *p_owner = p_dec->p_owner;
 
@@ -747,8 +744,7 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
     decoder_owner_sys_t *p_owner;
     es_format_t null_es_format;
 
-    p_dec = vlc_custom_create( p_parent, sizeof( *p_dec ), VLC_OBJECT_DECODER,
-                               "decoder" );
+    p_dec = vlc_custom_create( p_parent, sizeof( *p_dec ), "decoder" );
     if( p_dec == NULL )
         return NULL;
 
@@ -779,7 +775,6 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
     p_owner->p_input = p_input;
     p_owner->p_resource = p_resource;
     p_owner->p_aout = NULL;
-    p_owner->p_aout_input = NULL;
     p_owner->p_vout = NULL;
     p_owner->p_spu_vout = NULL;
     p_owner->i_spu_channel = 0;
@@ -800,7 +795,6 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
 
     /* 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;
@@ -812,8 +806,6 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
     p_dec->pf_get_display_date = DecoderGetDisplayDate;
     p_dec->pf_get_display_rate = DecoderGetDisplayRate;
 
-    vlc_object_attach( p_dec, p_parent );
-
     /* Find a suitable decoder/packetizer module */
     if( !b_packetizer )
         p_dec->p_module = module_need( p_dec, "decoder", "$codec", false );
@@ -825,8 +817,7 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
         p_dec->b_need_packetized && !p_dec->fmt_in.b_packetized )
     {
         p_owner->p_packetizer =
-            vlc_custom_create( p_dec, sizeof( decoder_t ),
-                               VLC_OBJECT_DECODER, "packetizer" );
+            vlc_custom_create( p_parent, sizeof( decoder_t ), "packetizer" );
         if( p_owner->p_packetizer )
         {
             es_format_Copy( &p_owner->p_packetizer->fmt_in,
@@ -835,8 +826,6 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
             es_format_Copy( &p_owner->p_packetizer->fmt_out,
                             &null_es_format );
 
-            vlc_object_attach( p_owner->p_packetizer, p_parent );
-
             p_owner->p_packetizer->p_module =
                 module_need( p_owner->p_packetizer,
                              "packetizer", "$packetizer", false );
@@ -876,6 +865,8 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
     es_format_Init( &p_owner->fmt_description, UNKNOWN_ES, 0 );
     p_owner->p_description = NULL;
 
+    p_owner->b_exit = false;
+
     p_owner->b_paused = false;
     p_owner->pause.i_date = VLC_TS_INVALID;
     p_owner->pause.i_ignore = 0;
@@ -915,9 +906,9 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
  *
  * \param p_dec the decoder
  */
-static void *DecoderThread( vlc_object_t *p_this )
+static void *DecoderThread( void *p_data )
 {
-    decoder_t *p_dec = (decoder_t *)p_this;
+    decoder_t *p_dec = (decoder_t *)p_data;
     decoder_owner_sys_t *p_owner = p_dec->p_owner;
 
     /* The decoder's main loop */
@@ -933,6 +924,14 @@ static void *DecoderThread( vlc_object_t *p_this )
         {
             int canc = vlc_savecancel();
 
+            if( p_block->i_flags & BLOCK_FLAG_CORE_EOS )
+            {
+                /* calling DecoderProcess() with NULL block will make
+                 * decoders/packetizers flush their buffers */
+                block_Release( p_block );
+                p_block = NULL;
+            }
+
             if( p_dec->b_error )
                 DecoderError( p_dec, p_block );
             else
@@ -978,7 +977,7 @@ static void DecoderFlush( decoder_t *p_dec )
     input_DecoderDecode( p_dec, p_null, false );
 
     /* */
-    while( vlc_object_alive( p_dec ) && p_owner->b_flushing )
+    while( p_owner->b_flushing )
         vlc_cond_wait( &p_owner->wait_acknowledge, &p_owner->lock );
 }
 
@@ -1055,8 +1054,7 @@ static void DecoderOutputChangePause( decoder_t *p_dec, bool b_paused, mtime_t i
     if( p_dec->fmt_out.i_cat == AUDIO_ES )
     {
         if( p_owner->p_aout )
-            aout_DecChangePause( p_owner->p_aout, p_owner->p_aout_input,
-                                 b_paused, i_date );
+            aout_DecChangePause( p_owner->p_aout, b_paused, i_date );
     }
     else if( p_dec->fmt_out.i_cat == VIDEO_ES )
     {
@@ -1136,6 +1134,17 @@ static void DecoderFixTs( decoder_t *p_dec, mtime_t *pi_ts0, mtime_t *pi_ts1,
     }
 }
 
+static bool DecoderIsExitRequested( decoder_t *p_dec )
+{
+    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+
+    vlc_mutex_lock( &p_owner->lock );
+    bool b_exit = p_owner->b_exit;
+    vlc_mutex_unlock( &p_owner->lock );
+
+    return b_exit;
+}
+
 /**
  * If *pb_reject, it does nothing, otherwise it waits for the given
  * deadline or a flush request (in which case it set *pi_reject to true.
@@ -1151,7 +1160,7 @@ static void DecoderWaitDate( decoder_t *p_dec,
     for( ;; )
     {
         vlc_mutex_lock( &p_owner->lock );
-        if( p_owner->b_flushing || p_dec->b_die )
+        if( p_owner->b_flushing || p_owner->b_exit )
         {
             *pb_reject = true;
             vlc_mutex_unlock( &p_owner->lock );
@@ -1169,8 +1178,7 @@ static void DecoderPlayAudio( decoder_t *p_dec, aout_buffer_t *p_audio,
                               int *pi_played_sum, int *pi_lost_sum )
 {
     decoder_owner_sys_t *p_owner = p_dec->p_owner;
-    aout_instance_t *p_aout = p_owner->p_aout;
-    aout_input_t    *p_aout_input = p_owner->p_aout_input;
+    audio_output_t *p_aout = p_owner->p_aout;
 
     /* */
     if( p_audio->i_pts <= VLC_TS_INVALID ) // FIXME --VLC_TS_INVALID verify audio_output/*
@@ -1234,7 +1242,7 @@ static void DecoderPlayAudio( decoder_t *p_dec, aout_buffer_t *p_audio,
 
         vlc_mutex_unlock( &p_owner->lock );
 
-        if( !p_aout || !p_aout_input ||
+        if( !p_aout ||
             p_audio->i_pts <= VLC_TS_INVALID ||
             i_rate < INPUT_RATE_DEFAULT/AOUT_MAX_INPUT_RATE ||
             i_rate > INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE )
@@ -1245,9 +1253,9 @@ static void DecoderPlayAudio( decoder_t *p_dec, aout_buffer_t *p_audio,
 
         if( !b_reject )
         {
-            if( !aout_DecPlay( p_aout, p_aout_input, p_audio, i_rate ) )
+            if( !aout_DecPlay( p_aout, p_audio, i_rate ) )
                 *pi_played_sum += 1;
-            *pi_lost_sum += aout_DecGetResetLost( p_aout, p_aout_input );
+            *pi_lost_sum += aout_DecGetResetLost( p_aout );
         }
         else
         {
@@ -1282,13 +1290,12 @@ static void DecoderDecodeAudio( decoder_t *p_dec, block_t *p_block )
 
     while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_block )) )
     {
-        aout_instance_t *p_aout = p_owner->p_aout;
-        aout_input_t    *p_aout_input = p_owner->p_aout_input;
+        audio_output_t *p_aout = p_owner->p_aout;
 
-        if( p_dec->b_die )
+        if( DecoderIsExitRequested( p_dec ) )
         {
             /* It prevent freezing VLC in case of broken decoder */
-            aout_DecDeleteBuffer( p_aout, p_aout_input, p_aout_buf );
+            aout_DecDeleteBuffer( p_aout, p_aout_buf );
             if( p_block )
                 block_Release( p_block );
             break;
@@ -1298,15 +1305,15 @@ static void DecoderDecodeAudio( decoder_t *p_dec, block_t *p_block )
         if( p_owner->i_preroll_end > VLC_TS_INVALID &&
             p_aout_buf->i_pts < p_owner->i_preroll_end )
         {
-            aout_DecDeleteBuffer( p_aout, p_aout_input, p_aout_buf );
+            aout_DecDeleteBuffer( p_aout, p_aout_buf );
             continue;
         }
 
         if( p_owner->i_preroll_end > VLC_TS_INVALID )
         {
             msg_Dbg( p_dec, "End of audio preroll" );
-            if( p_owner->p_aout && p_owner->p_aout_input )
-                aout_DecFlush( p_owner->p_aout, p_owner->p_aout_input );
+            if( p_owner->p_aout )
+                aout_DecFlush( p_owner->p_aout );
             /* */
             p_owner->i_preroll_end = VLC_TS_INVALID;
         }
@@ -1510,7 +1517,7 @@ static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block )
     while( (p_pic = p_dec->pf_decode_video( p_dec, &p_block )) )
     {
         vout_thread_t  *p_vout = p_owner->p_vout;
-        if( p_dec->b_die )
+        if( DecoderIsExitRequested( p_dec ) )
         {
             /* It prevent freezing VLC in case of broken decoder */
             vout_ReleasePicture( p_vout, p_pic );
@@ -1699,8 +1706,7 @@ static void DecoderPlaySout( decoder_t *p_dec, block_t *p_sout_block,
         p_sout_block->p_next = NULL;
 
         DecoderFixTs( p_dec, &p_sout_block->i_dts, &p_sout_block->i_pts,
-                      &p_sout_block->i_length,
-                      &p_sout_block->i_rate, INT64_MAX, b_telx );
+                      &p_sout_block->i_length, NULL, INT64_MAX, b_telx );
 
         vlc_mutex_unlock( &p_owner->lock );
 
@@ -1931,7 +1937,7 @@ static void DecoderProcessAudio( decoder_t *p_dec, block_t *p_block, bool b_flus
     }
 
     if( b_flush && p_owner->p_aout )
-        aout_DecFlush( p_owner->p_aout, p_owner->p_aout_input );
+        aout_DecFlush( p_owner->p_aout );
 }
 
 /* This function process a subtitle block
@@ -2111,7 +2117,9 @@ static void DeleteDecoder( decoder_t * p_dec )
     /* Cleanup */
     if( p_owner->p_aout )
     {
-        aout_DecDelete( p_owner->p_aout, p_owner->p_aout_input );
+        /* TODO: REVISIT gap-less audio */
+        aout_DecFlush( p_owner->p_aout );
+        aout_DecDelete( p_owner->p_aout );
         input_resource_RequestAout( p_owner->p_resource, p_owner->p_aout );
         if( p_owner->p_input != NULL )
             input_SendEventAout( p_owner->p_input );
@@ -2219,35 +2227,32 @@ static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples )
     decoder_owner_sys_t *p_owner = p_dec->p_owner;
     aout_buffer_t *p_buffer;
 
-    if( p_owner->p_aout_input != NULL &&
+    if( p_owner->p_aout &&
         ( p_dec->fmt_out.audio.i_rate != p_owner->audio.i_rate ||
           p_dec->fmt_out.audio.i_original_channels !=
               p_owner->audio.i_original_channels ||
           p_dec->fmt_out.audio.i_bytes_per_frame !=
               p_owner->audio.i_bytes_per_frame ) )
     {
-        aout_input_t *p_aout_input = p_owner->p_aout_input;
-        aout_instance_t *p_aout = p_owner->p_aout;
+        audio_output_t *p_aout = p_owner->p_aout;
 
         /* Parameters changed, restart the aout */
         vlc_mutex_lock( &p_owner->lock );
 
         DecoderFlushBuffering( p_dec );
 
+        aout_DecDelete( p_owner->p_aout );
         p_owner->p_aout = NULL;
-        p_owner->p_aout_input = NULL;
-        aout_DecDelete( p_owner->p_aout, p_aout_input );
 
         vlc_mutex_unlock( &p_owner->lock );
         input_resource_RequestAout( p_owner->p_resource, p_aout );
     }
 
-    if( p_owner->p_aout_input == NULL )
+    if( p_owner->p_aout == NULL )
     {
         const int i_force_dolby = var_InheritInteger( p_dec, "force-dolby-surround" );
         audio_sample_format_t format;
-        aout_input_t *p_aout_input;
-        aout_instance_t *p_aout;
+        audio_output_t *p_aout;
         aout_request_vout_t request_vout;
 
         p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec;
@@ -2277,22 +2282,19 @@ static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples )
         p_aout = input_resource_RequestAout( p_owner->p_resource, NULL );
         if( p_aout )
         {
-            p_aout_input = aout_DecNew( p_aout, &format,
-                                        &p_dec->fmt_out.audio_replay_gain,
-                                        &request_vout );
-            if( p_aout_input == NULL )
+            aout_FormatPrepare( &format );
+            if( aout_DecNew( p_aout, &format,
+                             &p_dec->fmt_out.audio_replay_gain,
+                             &request_vout ) )
             {
                 input_resource_RequestAout( p_owner->p_resource, p_aout );
                 p_aout = NULL;
             }
         }
-        else
-            p_aout_input = NULL;
 
         vlc_mutex_lock( &p_owner->lock );
 
         p_owner->p_aout = p_aout;
-        p_owner->p_aout_input = p_aout_input;
         DecoderUpdateFormatLocked( p_dec );
 
         vlc_mutex_unlock( &p_owner->lock );
@@ -2300,7 +2302,7 @@ static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples )
         if( p_owner->p_input != NULL )
             input_SendEventAout( p_owner->p_input );
 
-        if( p_owner->p_aout_input == NULL )
+        if( p_aout == NULL )
         {
             msg_Err( p_dec, "failed to create audio output" );
             p_dec->b_error = true;
@@ -2310,19 +2312,11 @@ static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples )
             p_owner->audio.i_bytes_per_frame;
     }
 
-    p_buffer = aout_DecNewBuffer( p_owner->p_aout_input, i_samples );
+    p_buffer = aout_DecNewBuffer( p_owner->p_aout, i_samples );
 
     return p_buffer;
 }
 
-static void aout_del_buffer( decoder_t *p_dec, aout_buffer_t *p_buffer )
-{
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
-    aout_DecDeleteBuffer( p_owner->p_aout,
-                          p_owner->p_aout_input, p_buffer );
-}
-
 static picture_t *vout_new_buffer( decoder_t *p_dec )
 {
     decoder_owner_sys_t *p_owner = p_dec->p_owner;
@@ -2437,7 +2431,7 @@ static picture_t *vout_new_buffer( decoder_t *p_dec )
      */
     for( ;; )
     {
-        if( p_dec->b_die || p_dec->b_error )
+        if( DecoderIsExitRequested( p_dec ) || p_dec->b_error )
             return NULL;
 
         picture_t *p_picture = vout_GetPicture( p_owner->p_vout );
@@ -2483,7 +2477,7 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec,
 
     while( i_attempts-- )
     {
-        if( p_dec->b_die || p_dec->b_error )
+        if( DecoderIsExitRequested( p_dec ) || p_dec->b_error )
             break;
 
         p_vout = input_resource_HoldVout( p_owner->p_resource );