* 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
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;
}
}
/* 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;
/* 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;
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
*****************************************************************************/
/*****************************************************************************
* 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 );
+}