]> git.sesse.net Git - vlc/blobdiff - src/input/input_dec.c
* include/vlc_codec.h: defines decoders/encoders related structures here.
[vlc] / src / input / input_dec.c
index 246369ec875be0f598e9042377010907cee133bc..aa419077cf0a6763fa82da25a79d45bdb029cc0d 100644 (file)
@@ -2,7 +2,7 @@
  * input_dec.c: Functions for the management of decoders
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: input_dec.c,v 1.58 2003/02/18 00:20:01 hartman Exp $
+ * $Id: input_dec.c,v 1.64 2003/10/08 21:01:07 gbazin Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
 #include <string.h>                                    /* memcpy(), memset() */
 
 #include <vlc/vlc.h>
+#include <vlc/decoder.h>
 
-#include "stream_control.h"
-#include "input_ext-dec.h"
 #include "input_ext-intf.h"
 #include "input_ext-plugins.h"
 
-static decoder_fifo_t * CreateDecoderFifo( input_thread_t *,
-                                           es_descriptor_t * );
-static void             DeleteDecoderFifo( decoder_fifo_t * );
+static decoder_t * CreateDecoder( input_thread_t *, es_descriptor_t * );
+static int         DecoderThread( decoder_t * );
+static void        DeleteDecoder( decoder_t * );
 
 /*****************************************************************************
  * input_RunDecoder: spawns a new decoder thread
@@ -44,86 +43,58 @@ static void             DeleteDecoderFifo( decoder_fifo_t * );
 decoder_fifo_t * input_RunDecoder( input_thread_t * p_input,
                                    es_descriptor_t * p_es )
 {
-    char           *psz_sout;
-    decoder_fifo_t *p_fifo;
-    int i_priority;
+    vlc_value_t    val;
+    decoder_t      *p_dec;
+    int            i_priority;
 
     /* Create the decoder configuration structure */
-    p_fifo = CreateDecoderFifo( p_input, p_es );
-
-    if( p_fifo == NULL )
+    p_dec = CreateDecoder( p_input, p_es );
+    if( p_dec == NULL )
     {
-        msg_Err( p_input, "could not create decoder fifo" );
+        msg_Err( p_input, "could not create decoder" );
         return NULL;
     }
 
-    p_fifo->p_module = NULL;
-    /* If we are in sout mode, search first for packetizer module then
-     * codec to do transcoding */
-    psz_sout = config_GetPsz( p_input, "sout" );
-    if( psz_sout != NULL && *psz_sout != 0 )
+    p_dec->p_module = NULL;
+
+    /* If we are in sout mode, search for packetizer module */
+    var_Get( p_input, "sout", &val );
+    if( !p_es->b_force_decoder && val.psz_string && *val.psz_string )
     {
-        vlc_bool_t b_sout = VLC_TRUE;
+        free( val.psz_string );
+        val.b_bool = VLC_TRUE;
 
         if( p_es->i_cat == AUDIO_ES )
         {
-            b_sout = config_GetInt( p_input, "sout-audio" );
+            var_Get( p_input, "sout-audio", &val );
         }
         else if( p_es->i_cat == VIDEO_ES )
         {
-            b_sout = config_GetInt( p_input, "sout-video" );
+            var_Get( p_input, "sout-video", &val );
         }
 
-        if( b_sout )
+        if( val.b_bool )
         {
-            vlc_bool_t b_reencode = VLC_FALSE;
-
-            if( p_es->i_cat == AUDIO_ES )
-            {
-                char *psz_sout_acodec = config_GetPsz( p_input, "sout-acodec" );
-                if( psz_sout_acodec != NULL && *psz_sout_acodec != '\0' )
-                {
-                    msg_Dbg( p_input, "audio reencoding requested -> unsupported" );
-                    b_reencode = VLC_TRUE;
-                }
-            }
-            else if( p_es->i_cat == VIDEO_ES )
-            {
-                char *psz_sout_vcodec = config_GetPsz( p_input, "sout-vcodec" );
-                if( psz_sout_vcodec != NULL && *psz_sout_vcodec != '\0' )
-                {
-                    msg_Dbg( p_input, "video reencoding requested" );
-                    /* force encoder video output */
-                    config_PutPsz( p_input, "vout", "encoder" );
-                    b_reencode = VLC_TRUE;
-                }
-            }
-
-            if( !b_reencode )
-            {
-                /* we don't want to reencode so search for a packetizer */
-                p_fifo->p_module =
-                    module_Need( p_fifo, "packetizer", "$packetizer" );
-            }
-            else
-            {
-                /* get a suitable decoder module to do reencoding*/
-                p_fifo->p_module = module_Need( p_fifo, "decoder", "$codec" );
-            }
+            p_dec->p_module =
+                module_Need( p_dec, "packetizer", "$packetizer" );
         }
     }
     else
     {
         /* default Get a suitable decoder module */
-        p_fifo->p_module = module_Need( p_fifo, "decoder", "$codec" );
+        p_dec->p_module = module_Need( p_dec, "decoder", "$codec" );
+
+        if( val.psz_string ) free( val.psz_string );
     }
 
-    if( p_fifo->p_module == NULL )
+    if( p_dec->p_module == NULL )
     {
-        msg_Err( p_fifo, "no suitable decoder module for fourcc `%4.4s'.\nVLC probably does not support this sound or video format.",
-                       (char*)&p_fifo->i_fourcc );
-        DeleteDecoderFifo( p_fifo );
-        vlc_object_destroy( p_fifo );
+        msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'.\n"
+                 "VLC probably does not support this sound or video format.",
+                 (char*)&p_dec->p_fifo->i_fourcc );
+
+        DeleteDecoder( p_dec );
+        vlc_object_destroy( p_dec );
         return NULL;
     }
 
@@ -137,27 +108,29 @@ decoder_fifo_t * input_RunDecoder( input_thread_t * p_input,
     }
 
     /* Spawn the decoder thread */
-    if( vlc_thread_create( p_fifo, "decoder", p_fifo->pf_run,
+    if( vlc_thread_create( p_dec, "decoder", DecoderThread,
                            i_priority, VLC_FALSE ) )
     {
-        msg_Err( p_fifo, "cannot spawn decoder thread \"%s\"",
-                         p_fifo->p_module->psz_object_name );
-        module_Unneed( p_fifo, p_fifo->p_module );
+        msg_Err( p_dec, "cannot spawn decoder thread \"%s\"",
+                         p_dec->p_module->psz_object_name );
+        module_Unneed( p_dec, p_dec->p_module );
+        DeleteDecoder( p_dec );
+        vlc_object_destroy( p_dec );
         return NULL;
     }
 
     p_input->stream.b_changed = 1;
 
-    return p_fifo;
+    return p_dec->p_fifo;
 }
 
-
 /*****************************************************************************
  * input_EndDecoder: kills a decoder thread and waits until it's finished
  *****************************************************************************/
 void input_EndDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
 {
     int i_dummy;
+    decoder_t *p_dec = p_es->p_decoder_fifo->p_dec;
 
     p_es->p_decoder_fifo->b_die = 1;
 
@@ -177,17 +150,17 @@ void input_EndDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
     /* I thought that unlocking was better since thread join can be long
      * but it actually creates late pictures and freezes --stef */
     /* vlc_mutex_unlock( &p_input->stream.stream_lock ); */
-    vlc_thread_join( p_es->p_decoder_fifo );
+    vlc_thread_join( p_dec );
     /* vlc_mutex_lock( &p_input->stream.stream_lock ); */
 
-    /* Delete decoder configuration */
-    DeleteDecoderFifo( p_es->p_decoder_fifo );
-
     /* Unneed module */
-    module_Unneed( p_es->p_decoder_fifo, p_es->p_decoder_fifo->p_module );
+    module_Unneed( p_dec, p_dec->p_module );
+
+    /* Delete decoder configuration */
+    DeleteDecoder( p_dec );
 
-    /* Delete the fifo */
-    vlc_object_destroy( p_es->p_decoder_fifo );
+    /* Delete the decoder */
+    vlc_object_destroy( p_dec );
 
     /* Tell the input there is no more decoder */
     p_es->p_decoder_fifo = NULL;
@@ -214,77 +187,6 @@ void input_DecodePES( decoder_fifo_t * p_decoder_fifo, pes_packet_t * p_pes )
     vlc_mutex_unlock( &p_decoder_fifo->data_lock );
 }
 
-/****************************************************************************
- * input_ExtractPES
- *****************************************************************************
- * Extract a PES from the fifo. If pp_pes is NULL then the PES is just
- * deleted, otherwise *pp_pes will point to this PES.
- ****************************************************************************/
-void input_ExtractPES( decoder_fifo_t *p_fifo, pes_packet_t **pp_pes )
-{
-    pes_packet_t *p_pes;
-
-    vlc_mutex_lock( &p_fifo->data_lock );
-
-    if( p_fifo->p_first == NULL )
-    {
-        if( p_fifo->b_die )
-        {
-            vlc_mutex_unlock( &p_fifo->data_lock );
-            if( pp_pes ) *pp_pes = NULL;
-            return;
-        }
-
-        /* Signal the input thread we're waiting. This is only
-         * needed in case of slave clock (ES plug-in) but it won't
-         * harm. */
-        vlc_cond_signal( &p_fifo->data_wait );
-
-        /* Wait for the input to tell us when we received a packet. */
-        vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
-    }
-
-    p_pes = p_fifo->p_first;
-    p_fifo->p_first = p_pes->p_next;
-    p_pes->p_next = NULL;
-    p_fifo->i_depth--;
-
-    if( !p_fifo->p_first )
-    {
-        /* No PES in the FIFO. p_last is no longer valid. */
-        p_fifo->pp_last = &p_fifo->p_first;
-    }
-
-    vlc_mutex_unlock( &p_fifo->data_lock );
-
-    if( pp_pes )
-        *pp_pes = p_pes;
-    else
-        input_DeletePES( p_fifo->p_packets_mgt, p_pes );
-}
-
-/****************************************************************************
- * input_FlushPESFifo
- *****************************************************************************
- * Empties the PES fifo of the decoder.
- ****************************************************************************/
-void input_FlushPESFifo( decoder_fifo_t *p_fifo )
-{
-    pes_packet_t * p_pes;
-
-    vlc_mutex_lock( &p_fifo->data_lock );
-    while( p_fifo->p_first )
-    {
-        p_pes = p_fifo->p_first;
-        p_fifo->p_first = p_fifo->p_first->p_next;
-        input_DeletePES( p_fifo->p_packets_mgt, p_pes );
-    }
-    /* No PES in the FIFO. p_last is no longer valid. */
-    p_fifo->pp_last = &p_fifo->p_first;
-    vlc_mutex_unlock( &p_fifo->data_lock );
-}
-
-
 /*****************************************************************************
  * Create a NULL packet for padding in case of a data loss
  *****************************************************************************/
@@ -375,65 +277,164 @@ void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
 /*****************************************************************************
  * CreateDecoderFifo: create a decoder_fifo_t
  *****************************************************************************/
-static decoder_fifo_t * CreateDecoderFifo( input_thread_t * p_input,
-                                           es_descriptor_t * p_es )
+static decoder_t * CreateDecoder( input_thread_t * p_input,
+                                  es_descriptor_t * p_es )
 {
-    decoder_fifo_t * p_fifo;
+    decoder_t * p_dec;
 
-    /* Decoder FIFO */
-    p_fifo = vlc_object_create( p_input, VLC_OBJECT_DECODER );
-    if( p_fifo == NULL )
+    p_dec = vlc_object_create( p_input, VLC_OBJECT_DECODER );
+    if( p_dec == NULL )
     {
         msg_Err( p_input, "out of memory" );
         return NULL;
     }
 
+    p_dec->pf_init = 0;
+    p_dec->pf_decode = 0;
+    p_dec->pf_end = 0;
+    p_dec->pf_run = 0;
+
     /* Select a new ES */
     INSERT_ELEM( p_input->stream.pp_selected_es,
                  p_input->stream.i_selected_es_number,
                  p_input->stream.i_selected_es_number,
                  p_es );
 
+    /* Allocate the memory needed to store the decoder's fifo */
+    //p_dec->p_fifo = (decoder_fifo_t *)malloc(sizeof(decoder_fifo_t));
+    p_dec->p_fifo = vlc_object_create( p_input, VLC_OBJECT_DECODER_FIFO );
+    if( p_dec->p_fifo == NULL )
+    {
+        msg_Err( p_input, "out of memory" );
+        return NULL;
+    }
+
+    /* Initialize the decoder fifo */
+    //memset( p_dec->p_fifo, 0, sizeof(decoder_fifo_t) );
+    p_dec->p_module = NULL;
+
     /* Initialize the p_fifo structure */
-    vlc_mutex_init( p_input, &p_fifo->data_lock );
-    vlc_cond_init( p_input, &p_fifo->data_wait );
-    p_es->p_decoder_fifo = p_fifo;
-
-    p_fifo->i_id = p_es->i_id;
-    p_fifo->i_fourcc = p_es->i_fourcc;
-    p_fifo->p_demux_data   = p_es->p_demux_data;
-    p_fifo->p_waveformatex = p_es->p_waveformatex;
-    p_fifo->p_bitmapinfoheader = p_es->p_bitmapinfoheader;
-    p_fifo->p_stream_ctrl = &p_input->stream.control;
-    p_fifo->p_sout = p_input->stream.p_sout;
-
-    p_fifo->p_first = NULL;
-    p_fifo->pp_last = &p_fifo->p_first;
-    p_fifo->i_depth = 0;
-    p_fifo->b_die = p_fifo->b_error = 0;
-    p_fifo->p_packets_mgt = p_input->p_method_data;
-
-    vlc_object_attach( p_fifo, p_input );
-
-    return p_fifo;
+    vlc_mutex_init( p_input, &p_dec->p_fifo->data_lock );
+    vlc_cond_init( p_input, &p_dec->p_fifo->data_wait );
+    p_es->p_decoder_fifo = p_dec->p_fifo;
+
+    p_dec->p_fifo->i_id = p_es->i_id;
+    p_dec->p_fifo->i_fourcc = p_es->i_fourcc;
+    p_dec->p_fifo->p_demux_data   = p_es->p_demux_data;
+    p_dec->p_fifo->p_waveformatex = p_es->p_waveformatex;
+    p_dec->p_fifo->p_bitmapinfoheader = p_es->p_bitmapinfoheader;
+    p_dec->p_fifo->p_stream_ctrl = &p_input->stream.control;
+    p_dec->p_fifo->p_sout = p_input->stream.p_sout;
+
+    p_dec->p_fifo->p_first = NULL;
+    p_dec->p_fifo->pp_last = &p_dec->p_fifo->p_first;
+    p_dec->p_fifo->i_depth = 0;
+    p_dec->p_fifo->b_die = p_dec->p_fifo->b_error = 0;
+    p_dec->p_fifo->p_packets_mgt = p_input->p_method_data;
+
+    p_dec->p_fifo->p_dec = p_dec;
+
+    vlc_object_attach( p_dec->p_fifo, p_input );
+    vlc_object_attach( p_dec, p_input );
+
+    return p_dec;
+}
+
+/*****************************************************************************
+ * DecoderThread: the decoding main loop
+ *****************************************************************************/
+static int DecoderThread( decoder_t * p_dec )
+{
+    pes_packet_t  *p_pes;
+    data_packet_t *p_data;
+    block_t       *p_block;
+
+    /* Temporary wrapper to keep old decoder api functional */
+    if( p_dec->pf_run )
+    {
+        p_dec->pf_run( p_dec->p_fifo );
+        return 0;
+    }
+
+
+    /* Initialize the decoder */
+    p_dec->p_fifo->b_error = p_dec->pf_init( p_dec );
+
+    /* The decoder's main loop */
+    while( !p_dec->p_fifo->b_die && !p_dec->p_fifo->b_error )
+    {
+        int i_size;
+
+        input_ExtractPES( p_dec->p_fifo, &p_pes );
+        if( !p_pes )
+        {
+            p_dec->p_fifo->b_error = 1;
+            break;
+        }
+
+       for( i_size = 0, p_data = p_pes->p_first;
+            p_data != NULL; p_data = p_data->p_next )
+       {
+           i_size += p_data->p_payload_end - p_data->p_payload_start;
+       }
+       p_block = block_New( p_dec, i_size );
+       for( i_size = 0, p_data = p_pes->p_first;
+            p_data != NULL; p_data = p_data->p_next )
+       {
+            if( p_data->p_payload_end == p_data->p_payload_start )
+                continue;
+            memcpy( p_block->p_buffer + i_size, p_data->p_payload_start,
+                   p_data->p_payload_end - p_data->p_payload_start );
+            i_size += p_data->p_payload_end - p_data->p_payload_start;
+       }
+
+        p_block->i_pts = p_pes->i_pts;
+        p_block->i_dts = p_pes->i_dts;
+        p_block->b_discontinuity = p_pes->b_discontinuity;
+        p_dec->p_fifo->b_error = p_dec->pf_decode( p_dec, p_block );
+
+        input_DeletePES( p_dec->p_fifo->p_packets_mgt, p_pes );
+    }
+
+    /* If b_error is set, the decoder thread enters the error loop */
+    if( p_dec->p_fifo->b_error )
+    {
+        /* Wait until a `die' order is sent */
+        while( !p_dec->p_fifo->b_die )
+        {
+            /* Trash all received PES packets */
+            input_ExtractPES( p_dec->p_fifo, NULL );
+        }
+    }
+
+    /* End of the decoder */
+    p_dec->pf_end( p_dec );
+
+    return 0;
 }
 
 /*****************************************************************************
  * DeleteDecoderFifo: destroy a decoder_fifo_t
  *****************************************************************************/
-static void DeleteDecoderFifo( decoder_fifo_t * p_fifo )
+static void DeleteDecoder( decoder_t * p_dec )
 {
-    vlc_object_detach( p_fifo );
+    vlc_object_detach( p_dec );
+    vlc_object_detach( p_dec->p_fifo );
 
-    msg_Dbg( p_fifo, "killing decoder for 0x%x, fourcc `%4.4s', %d PES in FIFO",
-                     p_fifo->i_id, (char*)&p_fifo->i_fourcc, p_fifo->i_depth );
+    msg_Dbg( p_dec,
+             "killing decoder for 0x%x, fourcc `%4.4s', %d PES in FIFO",
+             p_dec->p_fifo->i_id, (char*)&p_dec->p_fifo->i_fourcc,
+             p_dec->p_fifo->i_depth );
 
     /* Free all packets still in the decoder fifo. */
-    input_DeletePES( p_fifo->p_packets_mgt,
-                     p_fifo->p_first );
+    input_DeletePES( p_dec->p_fifo->p_packets_mgt,
+                     p_dec->p_fifo->p_first );
 
     /* Destroy the lock and cond */
-    vlc_cond_destroy( &p_fifo->data_wait );
-    vlc_mutex_destroy( &p_fifo->data_lock );
-}
+    vlc_cond_destroy( &p_dec->p_fifo->data_wait );
+    vlc_mutex_destroy( &p_dec->p_fifo->data_lock );
 
+    /* Free fifo */
+    vlc_object_destroy( p_dec->p_fifo );
+    //free( p_dec->p_fifo );
+}