Commit 915759dc authored by Christophe Massiot's avatar Christophe Massiot

* Exploded the outdated generic decoder ;

* Updated ChangeLog and TODO.
parent 1a03af9a
......@@ -50,6 +50,13 @@ HEAD
* Put most builtins in plugins again due to performances issues.
* Fixed the painfully slow build process (at last!).
* Added new dummy input plugin.
* Wrote an ES input plug-in for .mpg files which didn't work.
* Fixed a bug in GetChunk() for very small chunks of data (hence a bug
in the SPU decoder).
* Reactivated SDL parachute in non-debug mode (because of a memory
leakage).
* Added IDEALX developer documentation in doc/.
* Removed the outdated generic decoder.
0.2.80
Tue, 5 Jun 2001 04:41:06 +0200
......
......@@ -30,7 +30,6 @@ AC3_SPDIF := ac3_spdif ac3_iec958
LPCM_DECODER := lpcm_decoder_thread
AUDIO_DECODER := audio_decoder adec_generic adec_layer1 adec_layer2 adec_math
SPU_DECODER := spu_decoder
#GEN_DECODER := generic_decoder
VIDEO_PARSER := video_parser vpar_headers vpar_blocks vpar_synchro video_fifo
VIDEO_DECODER := video_decoder
MISC := mtime tests modules netutils
......@@ -44,7 +43,6 @@ C_OBJ := $(INTERFACE:%=src/interface/%.o) \
$(LPCM_DECODER:%=src/lpcm_decoder/%.o) \
$(AUDIO_DECODER:%=src/audio_decoder/%.o) \
$(SPU_DECODER:%=src/spu_decoder/%.o) \
$(GEN_DECODER:%=src/generic_decoder/%.o) \
$(VIDEO_PARSER:%=src/video_parser/%.o) \
$(VIDEO_DECODER:%=src/video_decoder/%.o) \
$(MISC:%=src/misc/%.o)
......
......@@ -144,7 +144,7 @@ Difficulty: Hard
Urgency: Important
Description: Write stream zones support
For random access we need to know where stream descriptors are valid
and reside (essentially DVD plugin). -> Meuuh
and reside (essentially DVD plugin).
Status: Done (stef)
Task: 0x4d
......@@ -161,7 +161,7 @@ Description: Update documentation
The input structures have undergone a major restructuration with
input-II. It might be a good idea to reflect thoses changes in the
documentation.
Status: Todo
Status: Done 16 Jul 2001 (Meuuh)
Task: 0x4b
Difficulty: Guru
......@@ -176,8 +176,7 @@ Difficulty: Medium
Urgency: Normal
Description: Write ES input plugin
We need to be able to read .mpg video streams, or .mp* audio streams.
More information -> Meuuh
Status: Todo
Status: Done 27 Jun 2001 (Meuuh)
Task: 0x49
Difficulty: Easy
......
/*****************************************************************************
* generic_decoder.c : generic decoder thread
* This decoder provides a way to parse packets which do not belong to any
* known stream type, or to redirect packets to files. It can extract PES files
* from a multiplexed stream, identify automatically ES in a stream missing
* stream informations (i.e. a TS stream without PSI) and update ES tables in
* its input thread, or just print informations about what it receives in DEBUG
* mode.
* A single generic decoder is able to handle several ES, therefore it can be
* used as a 'default' decoder by the input thread.
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: generic_decoder.c,v 1.18 2001/03/21 13:42:34 sam Exp $
*
* Authors: Vincent Seguin <seguin@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include "defs.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "config.h"
#include "common.h"
#include "mtime.h"
#include "threads.h"
#include "threads.h"
#include "intf_msg.h"
#include "debug.h"
#include "input.h"
#include "input_netlist.h"
#include "decoder_fifo.h"
#include "generic_decoder.h"
/*
* Local prototypes
*/
static int CheckConfiguration ( gdec_cfg_t *p_cfg );
static int InitThread ( gdec_thread_t *p_gdec );
static void RunThread ( gdec_thread_t *p_gdec );
static void ErrorThread ( gdec_thread_t *p_gdec );
static void EndThread ( gdec_thread_t *p_gdec );
static void IdentifyPES ( gdec_thread_t *p_gdec, pes_packet_t *p_pes,
int i_stream_id );
static void PrintPES ( pes_packet_t *p_pes, int i_stream_id );
/*****************************************************************************
* gdec_CreateThread: create a generic decoder thread
*****************************************************************************
* This function creates a new generic decoder thread, and returns a pointer
* to its description. On error, it returns NULL.
* Following configuration properties are used:
* GDEC_CFG_ACTIONS (required)
* XXX??
*****************************************************************************/
gdec_thread_t * gdec_CreateThread( gdec_cfg_t *p_cfg, input_thread_t *p_input,
int *pi_status )
{
gdec_thread_t * p_gdec; /* thread descriptor */
int i_status; /* thread status */
/*
* Check configuration
*/
if( CheckConfiguration( p_cfg ) )
{
return( NULL );
}
/* Allocate descriptor and initialize flags */
p_gdec = (gdec_thread_t *) malloc( sizeof(gdec_thread_t) );
if( p_gdec == NULL ) /* error */
{
return( NULL );
}
/* Copy configuration */
p_gdec->i_actions = p_cfg->i_actions;
/* XXX?? */
/* Set status */
p_gdec->pi_status = (pi_status != NULL) ? pi_status : &i_status;
*p_gdec->pi_status = THREAD_CREATE;
/* Initialize flags */
p_gdec->b_die = 0;
p_gdec->b_error = 0;
p_gdec->b_active = 1;
/* Create thread */
if( vlc_thread_create( &p_gdec->thread_id, "generic decoder", (vlc_thread_func)RunThread, (void *) p_gdec) )
{
intf_ErrMsg("gdec error: %s", strerror(ENOMEM));
intf_DbgMsg("failed");
free( p_gdec );
return( NULL );
}
/* If status is NULL, wait until the thread is created */
if( pi_status == NULL )
{
do
{
msleep( THREAD_SLEEP );
}while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
&& (i_status != THREAD_FATAL) );
if( i_status != THREAD_READY )
{
intf_DbgMsg("failed");
return( NULL );
}
}
intf_DbgMsg("succeeded -> %p", p_gdec);
return( p_gdec );
}
/*****************************************************************************
* gdec_DestroyThread: destroy a generic decoder thread
*****************************************************************************
* Destroy a terminated thread. This function will return 0 if the thread could
* be destroyed, and non 0 else. The last case probably means that the thread
* was still active, and another try may succeed.
*****************************************************************************/
void gdec_DestroyThread( gdec_thread_t *p_gdec, int *pi_status )
{
int i_status; /* thread status */
/* Set status */
p_gdec->pi_status = (pi_status != NULL) ? pi_status : &i_status;
*p_gdec->pi_status = THREAD_DESTROY;
/* Request thread destruction */
p_gdec->b_die = 1;
/* Make sure the decoder thread leaves the GetByte() function */
vlc_mutex_lock( &(p_gdec->fifo.data_lock) );
vlc_cond_signal( &(p_gdec->fifo.data_wait) );
vlc_mutex_unlock( &(p_gdec->fifo.data_lock) );
/* If status is NULL, wait until thread has been destroyed */
if( pi_status )
{
do
{
msleep( THREAD_SLEEP );
}while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
&& (i_status != THREAD_FATAL) );
}
intf_DbgMsg("%p -> succeeded", p_gdec);
}
/* following functions are local */
/*****************************************************************************
* CheckConfiguration: check gdec_CreateThread() configuration
*****************************************************************************
* Set default parameters where required. In DEBUG mode, check if configuration
* is valid.
*****************************************************************************/
static int CheckConfiguration( gdec_cfg_t *p_cfg )
{
#ifdef DEBUG
/* Actions (required) */
if( !(p_cfg->i_properties & GDEC_CFG_ACTIONS) )
{
return( 1 );
}
#endif
return( 0 );
}
/*****************************************************************************
* InitThread: initialize gdec thread
*****************************************************************************
* This function is called from RunThread and performs the second step of the
* initialization. It returns 0 on success. Note that the thread's flag are not
* modified inside this function.
*****************************************************************************/
static int InitThread( gdec_thread_t *p_gdec )
{
/* XXX?? */
/* Update status */
*p_gdec->pi_status = THREAD_START;
/* Initialize other properties */
#ifdef STATS
p_gdec->c_loops = 0;
p_gdec->c_idle_loops = 0;
p_gdec->c_pes = 0;
#endif
/* Mark thread as running and return */
*p_gdec->pi_status = THREAD_READY;
intf_DbgMsg("%p -> succeeded", p_gdec);
return(0);
}
/*****************************************************************************
* RunThread: generic decoder thread
*****************************************************************************
* Generic decoder thread. This function does only returns when the thread is
* terminated.
*****************************************************************************/
static void RunThread( gdec_thread_t *p_gdec )
{
pes_packet_t * p_pes; /* current packet */
int i_stream_id; /* PES stream id */
/*
* Initialize thread and free configuration
*/
p_gdec->b_error = InitThread( p_gdec );
if( p_gdec->b_error )
{
free( p_gdec ); /* destroy descriptor */
return;
}
/*
* Main loop - it is not executed if an error occured during
* initialization
*/
while( (!p_gdec->b_die) && (!p_gdec->b_error) )
{
/* FIXME: locks rajouter ?? - vrifier les macros (transformer en inline ?) */
/* on idle loop, increment c_idle_loops */
while( !DECODER_FIFO_ISEMPTY( p_gdec->fifo ) )
{
p_pes = DECODER_FIFO_START( p_gdec->fifo );
DECODER_FIFO_INCSTART( p_gdec->fifo );
/* Extract stream id from packet if required - stream id is used
* by GDEC_IDENTIFY, GDEC_SAVE_DEMUX and GDEC_PRINT */
if( p_gdec->i_actions & (GDEC_IDENTIFY | GDEC_SAVE_DEMUX | GDEC_PRINT) )
{
i_stream_id = p_pes->p_pes_header[3];
}
/* PES identification */
if( p_gdec->i_actions & GDEC_IDENTIFY )
{
IdentifyPES( p_gdec, p_pes, i_stream_id );
}
/* PES multiplexed stream saving */
if( p_gdec->i_actions & GDEC_SAVE )
{
/* XXX?? */
}
/* PES demultiplexed stream saving */
if( p_gdec->i_actions & GDEC_SAVE_DEMUX )
{
/* XXX?? */
}
/* PES information printing */
if( p_gdec->i_actions & GDEC_PRINT )
{
PrintPES( p_pes, i_stream_id );
}
/* Trash PES packet (give it back to fifo) */
input_NetlistFreePES( p_gdec->p_input, p_pes );
#ifdef STATS
p_gdec->c_pes++;
#endif
}
#ifdef STATS
p_gdec->c_loops++;
#endif
}
/*
* Error loop
*/
if( p_gdec->b_error )
{
ErrorThread( p_gdec );
}
/* End of thread */
EndThread( p_gdec );
}
/*****************************************************************************
* ErrorThread: RunThread() error loop
*****************************************************************************
* This function is called when an error occured during thread main's loop. The
* thread can still receive feed, but must be ready to terminate as soon as
* possible.
*****************************************************************************/
static void ErrorThread( gdec_thread_t *p_gdec )
{
pes_packet_t * p_pes; /* pes packet */
/* Wait until a `die' order */
while( !p_gdec->b_die )
{
/* Trash all received PES packets */
while( !DECODER_FIFO_ISEMPTY( p_gdec->fifo ) )
{
p_pes = DECODER_FIFO_START( p_gdec->fifo );
DECODER_FIFO_INCSTART( p_gdec->fifo );
input_NetlistFreePES( p_gdec->p_input, p_pes );
}
/* Sleep a while */
msleep( GDEC_IDLE_SLEEP );
}
}
/*****************************************************************************
* EndThread: thread destruction
*****************************************************************************
* This function is called when the thread ends after a sucessful
* initialization.
*****************************************************************************/
static void EndThread( gdec_thread_t *p_gdec )
{
int * pi_status; /* thread status */
/* Store status */
pi_status = p_gdec->pi_status;
*pi_status = THREAD_END;
#ifdef DEBUG
/* Check for remaining PES packets */
/* XXX?? */
#endif
/* Destroy thread structures allocated by InitThread */
free( p_gdec ); /* destroy descriptor */
*pi_status = THREAD_OVER;
intf_DbgMsg("%p", p_gdec);
}
/*****************************************************************************
* IdentifyPES: identify a PES packet
*****************************************************************************
* Update ES tables in the input thread according to the stream_id value. See
* ISO 13818-1, table 2-18.
*****************************************************************************/
static void IdentifyPES( gdec_thread_t *p_gdec, pes_packet_t *p_pes, int i_stream_id )
{
int i_id; /* stream id in es table */
int i_type; /* stream type according ISO/IEC 13818-1 table 2-29 */
/* Search where the elementary stream id does come from */
switch( p_gdec->p_input->i_method )
{
case INPUT_METHOD_TS_FILE: /* TS methods: id is TS PID */
case INPUT_METHOD_TS_UCAST:
case INPUT_METHOD_TS_BCAST:
case INPUT_METHOD_TS_VLAN_BCAST:
/* XXX?? since PID is extracted by demux, it could be useful to store it
* in a readable place, i.e. the TS packet descriptor, rather than to
* re-extract it now */
i_id = U16_AT(&p_pes->p_first_ts->buffer[1]) & 0x1fff;
break;
#ifdef DEBUG
default: /* unknown id origin */
intf_DbgMsg("unable to identify PES using input method %d",
p_gdec->p_input->i_method );
break;
#endif
}
/* Try to identify PES stream_id - see ISO 13818-1 table 2-18 */
if( i_stream_id == 0xbd )
{
/* Dolby AC-3 stream - might be specific to DVD PS streams */
i_type = MPEG2_AUDIO_ES;
intf_DbgMsg("PES %p identified as AUDIO AC3", p_pes);
}
else if( (i_stream_id & 0xe0) == 0xc0 )
{
/* ISO/IEC 13818-3 or ISO/IEC 11172-3 audio stream - since there is no
* way to make the difference between the two possibilities, and since
* an ISO/IEC 13818-3 is capable of decoding an ISO/IEC 11172-3 stream,
* the first one is used */
i_type = MPEG2_AUDIO_ES;
intf_DbgMsg("PES %p identified as AUDIO MPEG", p_pes);
}
else if( (i_stream_id & 0xf0) == 0xe0 )
{
/* ISO/IEC 13818-2 or ISO/IEC 11172-2 video stream - since there is no
* way to make the difference between the two possibilities, and since
* an ISO/IEC 13818-2 is capable of decoding an ISO/IEC 11172-2 stream,
* the first one is used */
i_type = MPEG2_VIDEO_ES;
intf_DbgMsg("PES %p identified as VIDEO", p_pes);
}
else
{
/* The stream could not be identified - just return */
intf_DbgMsg("PES %p could not be identified", p_pes);
return;
}
/* Update ES table */
/* XXX?? */
}
/*****************************************************************************
* PrintPES: print informations about a PES packet
*****************************************************************************
* This function will print information about a received PES packet. It is
* probably useful only for debugging purposes, or before demultiplexing a
* stream. It has two different formats, depending of the presence of the DEBUG
* symbol.
*****************************************************************************/
static void PrintPES( pes_packet_t *p_pes, int i_stream_id )
{
char psz_pes[128]; /* descriptor buffer */
#ifdef DEBUG
/* PES informations, long (DEBUG) format - this string is maximum 70 bytes
* long */
sprintf(psz_pes, "id 0x%x, %d bytes (%d TS): %p %c%c%c%c",
i_stream_id, p_pes->i_pes_size, p_pes->i_ts_packets,
p_pes,
p_pes->b_data_loss ? 'l' : '-', p_pes->b_data_alignment ? 'a' : '-',
p_pes->b_random_access ? 'r' : '-', p_pes->b_discard_payload ? 'd' : '-' );
#else
/* PES informations, short format */
sprintf(psz_pes, "id 0x%x, %d bytes",
i_stream_id, p_pes->i_pes_size );
#endif
intf_Msg("gdec: PES %s", psz_pes );
}
/*****************************************************************************
* generic_decoder.h : generic decoder thread
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: generic_decoder.h,v 1.6 2001/03/21 13:42:34 sam Exp $
*
* Authors: Vincent Seguin <seguin@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************
/*****************************************************************************
* Requires:
* "config.h"
* "common.h"
* "mtime.h"
* "threads.h"
* "input.h"
* "decoder_fifo.h"
* XXX??
*****************************************************************************/
/*****************************************************************************
* gdec_cfg_t: generic decoder configuration structure
*****************************************************************************
* This structure is passed as an initializer when a generic decoder thread is
* created.
*****************************************************************************/
typedef struct gdec_cfg_s
{
u64 i_properties;
int i_actions; /* decoder actions */
char * psz_base_filename; /* base demux file name */
} gdec_cfg_t;
/* Properties flags */
#define GDEC_CFG_ACTIONS (1 << 0)
#define GDEC_CFG_FILENAME (1 << 1)
/*****************************************************************************
* gdec_thread_t: generic decoder thread descriptor
*****************************************************************************
* This type describes a generic decoder thread.
*****************************************************************************/
typedef struct gdec_thread_s
{
/* Thread properties and locks */
boolean_t b_die; /* `die' flag */
boolean_t b_error; /* `error' flag */
boolean_t b_active; /* `active' flag */
vlc_thread_t thread_id; /* id for thread functions */
/* Thread configuration */
int i_actions; /* decoder actions */
/* Input properties */
input_thread_t * p_input; /* input thread */
decoder_fifo_t fifo; /* PES input fifo */
/* XXX?? status info */
int * pi_status;
/* Files array - these files are used to extract ES streams from a
* demultiplexed stream */
/* XXX?? */
#ifdef STATS
/* Statistics */
count_t c_loops; /* number of loops */
count_t c_idle_loops; /* number of idle loops */
count_t c_pes; /* number of PES packets read */
#endif
} gdec_thread_t;
/* Decoder actions - this flags select which actions the decoder will perform
* when it receives a PES packet */
#define GDEC_IDENTIFY (1 << 0) /* update input's ES tables */
#define GDEC_SAVE (1 << 1) /* save all PES to a same file */
#define GDEC_SAVE_DEMUX (1 << 2) /* save PES to files by stream id */
#define GDEC_PRINT (1 << 3) /* print PES informations */
/*****************************************************************************
* Prototypes
*****************************************************************************/
/* Thread management functions */
gdec_thread_t * gdec_CreateThread ( gdec_cfg_t *p_cfg,
input_thread_t *p_input, int *pi_status );
void gdec_DestroyThread ( gdec_thread_t *p_gdec, int *pi_status );