Commit 2fbc01b9 authored by Christophe Massiot's avatar Christophe Massiot
Browse files

Elementary Stream input plugin (use it with --input es). Only works with

video streams at the moment.
parent f406134a
......@@ -2,7 +2,7 @@
* input.h: structures of the input not exported to other modules
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input.h,v 1.37 2001/05/30 17:03:11 sam Exp $
* $Id: input.h,v 1.38 2001/06/27 09:53:56 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -80,6 +80,8 @@ void input_EscapeAudioDiscontinuity( struct input_thread_s *,
* Prototypes from input_clock.c
*****************************************************************************/
void input_ClockInit( struct pgrm_descriptor_s * );
int input_ClockManageControl( struct input_thread_s *,
struct pgrm_descriptor_s *, mtime_t );
void input_ClockManageRef( struct input_thread_s *,
struct pgrm_descriptor_s *, mtime_t );
mtime_t input_ClockGetTS( struct input_thread_s *,
......
......@@ -4,7 +4,7 @@
* control the pace of reading.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input_ext-intf.h,v 1.39 2001/06/09 17:01:21 stef Exp $
* $Id: input_ext-intf.h,v 1.40 2001/06/27 09:53:56 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -255,6 +255,7 @@ typedef struct i_p_config_s
* This structure includes all the local static variables of an input thread
*****************************************************************************/
struct vout_thread_s;
struct bit_stream_s;
typedef struct input_thread_s
{
......@@ -273,6 +274,11 @@ typedef struct input_thread_s
void (* pf_open)( struct input_thread_s * );
void (* pf_close)( struct input_thread_s * );
void (* pf_end)( struct input_thread_s * );
void (* pf_init_bit_stream)( struct bit_stream_s *,
struct decoder_fifo_s *,
void (* pf_bitstream_callback)( struct bit_stream_s *,
boolean_t ),
void * );
/* Read & Demultiplex */
int (* pf_read)( struct input_thread_s *,
......
......@@ -2,7 +2,7 @@
* modules.h : Module management functions.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: modules.h,v 1.25 2001/05/30 17:03:11 sam Exp $
* $Id: modules.h,v 1.26 2001/06/27 09:53:56 massiot Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
......@@ -78,6 +78,8 @@ struct input_area_s;
struct imdct_s;
struct complex_s;
struct dm_par_s;
struct bit_stream_s;
struct decoder_fifo_s;
/* FIXME: not yet used */
typedef struct probedata_s
......@@ -110,6 +112,11 @@ typedef struct function_list_s
void ( * pf_open ) ( struct input_thread_s * );
void ( * pf_close )( struct input_thread_s * );
void ( * pf_end ) ( struct input_thread_s * );
void ( * pf_init_bit_stream ) ( struct bit_stream_s *,
struct decoder_fifo_s *,
void (* pf_bitstream_callback)( struct bit_stream_s *,
boolean_t ),
void * );
int ( * pf_read ) ( struct input_thread_s *,
struct data_packet_s *
......
......@@ -10,7 +10,7 @@
* -dvd_udf to find files
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: input_dvd.c,v 1.76 2001/06/15 05:12:30 sam Exp $
* $Id: input_dvd.c,v 1.77 2001/06/27 09:53:56 massiot Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
......@@ -133,6 +133,7 @@ void _M( input_getfunctions )( function_list_t * p_function_list )
input.pf_open = DVDOpen;
input.pf_close = DVDClose;
input.pf_end = DVDEnd;
input.pf_init_bit_stream = InitBitstream;
input.pf_read = DVDRead;
input.pf_set_area = DVDSetArea;
input.pf_demux = input_DemuxPS;
......
......@@ -2,9 +2,9 @@
* input_es.c: Elementary Stream demux and packet management
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: input_es.c,v 1.6 2001/06/07 15:27:44 sam Exp $
* $Id: input_es.c,v 1.7 2001/06/27 09:53:56 massiot Exp $
*
* Authors:
* Author: Christophe Massiot <massiot@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
......@@ -44,6 +44,13 @@
#include <fcntl.h>
#if defined( WIN32 )
# include <io.h>
# include "input_iovec.h"
#else
# include <sys/uio.h> /* struct iovec */
#endif
#include "config.h"
#include "common.h"
#include "threads.h"
......@@ -62,6 +69,7 @@
#include "input_es.h"
#include "mpeg_system.h"
#include "input_netlist.h"
#include "debug.h"
......@@ -78,10 +86,12 @@ static void ESInit ( struct input_thread_s * );
static void ESEnd ( struct input_thread_s * );
static void ESSeek ( struct input_thread_s *, off_t );
static void ESDemux ( struct input_thread_s *, struct data_packet_s * );
static struct pes_packet_s * NewPES ( void * );
static struct data_packet_s * NewPacket ( void *, size_t );
static void DeletePacket( void *, struct data_packet_s * );
static void DeletePES ( void *, struct pes_packet_s * );
static void ESNextDataPacket( struct bit_stream_s * );
static void ESInitBitstream( struct bit_stream_s *, struct decoder_fifo_s *,
void (* pf_bitstream_callback)( struct bit_stream_s *,
boolean_t ),
void * );
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
......@@ -95,13 +105,14 @@ void _M( input_getfunctions )( function_list_t * p_function_list )
input.pf_open = NULL; /* Set in ESInit */
input.pf_close = NULL;
input.pf_end = ESEnd;
input.pf_init_bit_stream = ESInitBitstream;
input.pf_set_area = NULL;
input.pf_read = ESRead;
input.pf_demux = ESDemux;
input.pf_new_packet = NewPacket;
input.pf_new_pes = NewPES;
input.pf_delete_packet = DeletePacket;
input.pf_delete_pes = DeletePES;
input.pf_new_packet = input_NetlistNewPacket;
input.pf_new_pes = input_NetlistNewPES;
input.pf_delete_packet = input_NetlistDeletePacket;
input.pf_delete_pes = input_NetlistDeletePES;
input.pf_rewind = NULL;
input.pf_seek = ESSeek;
#undef input
......@@ -142,19 +153,34 @@ static int ESProbe( probedata_t *p_data )
*****************************************************************************/
static void ESInit( input_thread_t * p_input )
{
thread_es_data_t * p_method;
es_descriptor_t * p_es;
if( (p_method =
(thread_es_data_t *)malloc( sizeof(thread_es_data_t) )) == NULL )
p_input->p_method_data = NULL;
/* Initialize netlist */
if( input_NetlistInit( p_input, NB_DATA, NB_PES, ES_PACKET_SIZE,
INPUT_READ_ONCE ) )
{
intf_ErrMsg( "Out of memory" );
p_input->b_error = 1;
intf_ErrMsg( "ES input : Could not initialize netlist" );
return;
}
p_input->p_plugin_data = (void *)p_method;
p_input->pf_open = p_input->pf_file_open;
p_input->pf_close = p_input->pf_file_close;
/* FIXME : detect if InitStream failed */
input_InitStream( p_input, 0 );
input_AddProgram( p_input, 0, 0 );
vlc_mutex_lock( &p_input->stream.stream_lock );
p_es = input_AddES( p_input, p_input->stream.pp_programs[0], 0xE0, 0 );
p_es->i_stream_id = 0xE0;
p_es->i_type = MPEG1_VIDEO_ES;
p_es->i_cat = VIDEO_ES;
input_SelectES( p_input, p_es );
p_input->stream.i_method = INPUT_METHOD_FILE;
p_input->stream.p_selected_area->i_tell = 0;
p_input->stream.pp_programs[0]->b_is_ok = 1;
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
/*****************************************************************************
......@@ -162,39 +188,6 @@ static void ESInit( input_thread_t * p_input )
*****************************************************************************/
static void ESEnd( input_thread_t * p_input )
{
/* XXX */
free( p_input->p_plugin_data );
}
/*****************************************************************************
* SafeRead: reads a chunk of stream and correctly detects errors
*****************************************************************************/
static __inline__ int SafeRead( input_thread_t * p_input, byte_t * p_buffer,
size_t i_len )
{
thread_es_data_t * p_method;
int i_error;
p_method = (thread_es_data_t *)p_input->p_plugin_data;
while( fread( p_buffer, i_len, 1, p_method->stream ) != 1 )
{
if( feof( p_method->stream ) )
{
return( 1 );
}
if( (i_error = ferror( p_method->stream )) )
{
intf_ErrMsg( "Read failed (%s)", strerror(i_error) );
return( -1 );
}
}
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.p_selected_area->i_tell += i_len;
vlc_mutex_unlock( &p_input->stream.stream_lock );
return( 0 );
}
/*****************************************************************************
......@@ -206,7 +199,30 @@ static __inline__ int SafeRead( input_thread_t * p_input, byte_t * p_buffer,
static int ESRead( input_thread_t * p_input,
data_packet_t * pp_packets[INPUT_READ_ONCE] )
{
/* XXX */
int i_read;
struct iovec * p_iovec;
/* Get iovecs */
p_iovec = input_NetlistGetiovec( p_input->p_method_data );
if ( p_iovec == NULL )
{
return( -1 ); /* empty netlist */
}
memset( pp_packets, 0, INPUT_READ_ONCE * sizeof(data_packet_t *) );
i_read = readv( p_input->i_handle, p_iovec, INPUT_READ_ONCE );
if( i_read == -1 )
{
intf_ErrMsg( "input error: ES readv error" );
return( -1 );
}
input_NetlistMviovec( p_input->p_method_data,
(int)(i_read/ES_PACKET_SIZE), pp_packets );
p_input->stream.p_selected_area->i_tell += i_read;
return( 0 );
}
......@@ -216,65 +232,125 @@ static int ESRead( input_thread_t * p_input,
*****************************************************************************/
static void ESSeek( input_thread_t * p_input, off_t i_position )
{
thread_es_data_t * p_method;
p_method = (thread_es_data_t *)p_input->p_plugin_data;
/* A little bourrin but should work for a while --Meuuh */
#ifndef WIN32
fseeko( p_method->stream, i_position, SEEK_SET );
#else
fseek( p_method->stream, (long)i_position, SEEK_SET );
#endif
lseek( p_input->i_handle, i_position, SEEK_SET );
p_input->stream.p_selected_area->i_tell = i_position;
}
void ESDemux( input_thread_t * p_input, data_packet_t * p_data )
{
/* XXX */
}
/*
* Packet management utilities
*/
/*****************************************************************************
* NewPacket: allocates a data packet
* ESDemux: fakes a demultiplexer
*****************************************************************************/
static struct data_packet_s * NewPacket( void * p_packet_cache,
size_t l_size )
{
/* XXX */
static void ESDemux( input_thread_t * p_input, data_packet_t * p_data )
{
pes_packet_t * p_pes = p_input->pf_new_pes( p_input->p_method_data );
decoder_fifo_t * p_fifo =
p_input->stream.pp_programs[0]->pp_es[0]->p_decoder_fifo;
return NULL;
}
if( p_pes == NULL )
{
intf_ErrMsg("Out of memory");
p_input->b_error = 1;
return;
}
p_pes->i_rate = p_input->stream.control.i_rate;
p_pes->p_first = p_data;
/*****************************************************************************
* NewPES: allocates a pes packet
*****************************************************************************/
static pes_packet_t * NewPES( void * p_packet_cache )
{
/* XXX */
if( (p_input->stream.pp_programs[0]->i_synchro_state == SYNCHRO_REINIT)
| (input_ClockManageControl( p_input, p_input->stream.pp_programs[0],
(mtime_t)0 ) == PAUSE_S) )
{
intf_WarnMsg( 2, "synchro reinit" );
p_pes->i_pts = mdate() + DEFAULT_PTS_DELAY;
p_input->stream.pp_programs[0]->i_synchro_state = SYNCHRO_OK;
}
input_DecodePES( p_fifo, p_pes );
return NULL;
vlc_mutex_lock( &p_fifo->data_lock );
if( ( (DECODER_FIFO_END( *p_fifo ) - DECODER_FIFO_START( *p_fifo ))
& FIFO_SIZE ) >= MAX_PACKETS_IN_FIFO )
{
vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
}
vlc_mutex_unlock( &p_fifo->data_lock );
}
/*****************************************************************************
* DeletePacket: deletes a data packet
* ESNextDataPacket: signals the input thread if there isn't enough packets
* available
*****************************************************************************/
static void DeletePacket( void * p_packet_cache,
data_packet_t * p_data )
static void ESNextDataPacket( bit_stream_t * p_bit_stream )
{
/* XXX */
decoder_fifo_t * p_fifo = p_bit_stream->p_decoder_fifo;
boolean_t b_new_pes;
/* We are looking for the next data packet that contains real data,
* and not just a PES header */
do
{
/* We were reading the last data packet of this PES packet... It's
* time to jump to the next PES packet */
if( p_bit_stream->p_data->p_next == NULL )
{
/* We are going to read/write the start and end indexes of the
* decoder fifo and to use the fifo's conditional variable,
* that's why we need to take the lock before. */
vlc_mutex_lock( &p_fifo->data_lock );
/* Free the previous PES packet. */
p_fifo->pf_delete_pes( p_fifo->p_packets_mgt,
DECODER_FIFO_START( *p_fifo ) );
DECODER_FIFO_INCSTART( *p_fifo );
if( DECODER_FIFO_ISEMPTY( *p_fifo ) )
{
/* Signal the input thread we're waiting. */
vlc_cond_signal( &p_fifo->data_wait );
/* Wait for the input to tell us when we receive a packet. */
vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
}
/* The next byte could be found in the next PES packet */
p_bit_stream->p_data = DECODER_FIFO_START( *p_fifo )->p_first;
vlc_mutex_unlock( &p_fifo->data_lock );
b_new_pes = 1;
}
else
{
/* Perhaps the next data packet of the current PES packet contains
* real data (ie its payload's size is greater than 0). */
p_bit_stream->p_data = p_bit_stream->p_data->p_next;
b_new_pes = 0;
}
} while ( p_bit_stream->p_data->p_payload_start
== p_bit_stream->p_data->p_payload_end );
/* We've found a data packet which contains interesting data... */
p_bit_stream->p_byte = p_bit_stream->p_data->p_payload_start;
p_bit_stream->p_end = p_bit_stream->p_data->p_payload_end;
/* Call back the decoder. */
if( p_bit_stream->pf_bitstream_callback != NULL )
{
p_bit_stream->pf_bitstream_callback( p_bit_stream, b_new_pes );
}
}
/*****************************************************************************
* DeletePES: deletes a PES packet and associated data packets
* ESInitBitstream: changes pf_next_data_packet
*****************************************************************************/
static void DeletePES( void * p_packet_cache, pes_packet_t * p_pes )
static void ESInitBitstream( bit_stream_t * p_bit_stream,
decoder_fifo_t * p_decoder_fifo,
void (* pf_bitstream_callback)( struct bit_stream_s *,
boolean_t ),
void * p_callback_arg )
{
/* XXX */
InitBitstream( p_bit_stream, p_decoder_fifo, pf_bitstream_callback,
p_callback_arg );
p_bit_stream->pf_next_data_packet = ESNextDataPacket;
}
......@@ -2,7 +2,7 @@
* input_es.h: thread structure of the ES plugin
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: input_es.h,v 1.1 2001/04/20 15:02:48 sam Exp $
* $Id: input_es.h,v 1.2 2001/06/27 09:53:56 massiot Exp $
*
* Authors:
*
......@@ -21,12 +21,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* thread_es_data_t: extension of input_thread_t
*****************************************************************************/
typedef struct thread_es_data_s
{
/* We're necessarily reading a file. */
FILE * stream;
} thread_es_data_t;
#define NB_DATA 8192
#define NB_PES 4096
#define ES_PACKET_SIZE 2048
#define MAX_PACKETS_IN_FIFO 14
......@@ -2,7 +2,7 @@
* input_ps.c: PS demux and packet management
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: input_ps.c,v 1.28 2001/06/03 12:47:21 sam Exp $
* $Id: input_ps.c,v 1.29 2001/06/27 09:53:56 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Cyril Deguet <asmax@via.ecp.fr>
......@@ -99,6 +99,7 @@ void _M( input_getfunctions )( function_list_t * p_function_list )
input.pf_open = NULL; /* Set in PSInit */
input.pf_close = NULL;
input.pf_end = PSEnd;
input.pf_init_bit_stream = InitBitstream;
input.pf_set_area = NULL;
input.pf_read = PSRead;
input.pf_demux = input_DemuxPS;
......
......@@ -2,7 +2,7 @@
* input_ts.c: TS demux and netlist management
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: input_ts.c,v 1.27 2001/06/21 07:22:03 sam Exp $
* $Id: input_ts.c,v 1.28 2001/06/27 09:53:57 massiot Exp $
*
* Authors: Henri Fallon <henri@videolan.org>
*
......@@ -106,6 +106,7 @@ void _M( input_getfunctions )( function_list_t * p_function_list )
input.pf_open = TSFakeOpen;
input.pf_close = NULL; /* Will be set by pf_open */
input.pf_end = TSEnd;
input.pf_init_bit_stream = InitBitstream;
input.pf_set_area = NULL;
input.pf_read = TSRead;
input.pf_demux = input_DemuxTS;
......@@ -273,7 +274,8 @@ static int TSRead( input_thread_t * p_input,
data_packet_t * pp_packets[INPUT_READ_ONCE] )
{
thread_ts_data_t * p_method;
unsigned int i_read, i_loop;
unsigned int i_loop;
int i_read;
int i_data = 0;
struct iovec * p_iovec;
struct timeval timeout;
......
......@@ -4,7 +4,7 @@
* decoders.
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: input.c,v 1.124 2001/06/21 07:22:03 sam Exp $
* $Id: input.c,v 1.125 2001/06/27 09:53:57 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -407,6 +407,7 @@ static int InitThread( input_thread_t * p_input )
p_input->pf_close = f.pf_close;
}
p_input->pf_end = f.pf_end;
p_input->pf_init_bit_stream= f.pf_init_bit_stream;
p_input->pf_read = f.pf_read;
p_input->pf_set_area = f.pf_set_area;
p_input->pf_demux = f.pf_demux;
......
......@@ -2,7 +2,7 @@
* input_clock.c: Clock/System date convertions, stream management
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input_clock.c,v 1.17 2001/06/09 17:01:22 stef Exp $
* $Id: input_clock.c,v 1.18 2001/06/27 09:53:57 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -140,6 +140,78 @@ void input_ClockInit( pgrm_descriptor_t * p_pgrm )
p_pgrm->c_average_count = 0;
}
/*****************************************************************************
* input_ClockManageControl: handles the messages from the interface
*****************************************************************************
* Returns UNDEF_S if nothing happened, PAUSE_S if the stream was paused
*****************************************************************************/
int input_ClockManageControl( input_thread_t * p_input,
pgrm_descriptor_t * p_pgrm, mtime_t i_clock )
{
int i_return_value = UNDEF_S;
vlc_mutex_lock( &p_input->stream.stream_lock );
if( p_input->stream.i_new_status == PAUSE_S )
{
int i_old_status;
vlc_mutex_lock( &p_input->stream.control.control_lock );
i_old_status = p_input->stream.control.i_status;
p_input->stream.control.i_status = PAUSE_S;
vlc_cond_wait( &p_input->stream.stream_wait,
&p_input->stream.stream_lock );
ClockNewRef( p_input, p_pgrm, i_clock, mdate() );
if( p_input->stream.i_new_status == PAUSE_S )
{
/* PAUSE_S undoes the pause state: Return to old state. */
p_input->stream.control.i_status = i_old_status;
p_input->stream.i_new_status = UNDEF_S;
p_input->stream.i_new_rate = UNDEF_S;
}
/* We handle i_new_status != PAUSE_S below... */
vlc_mutex_unlock( &p_input->stream.control.control_lock );
i_return_value = PAUSE_S;
}
if( p_input->stream.i_new_status != UNDEF_S )
{
vlc_mutex_lock( &p_input->stream.control.control_lock );
p_input->stream.control.i_status = p_input->stream.i_new_status;
ClockNewRef( p_input, p_pgrm, i_clock,
ClockToSysdate( p_input, p_pgrm, i_clock ) );
if( p_input->stream.control.i_status == PLAYING_S )
{
p_input->stream.control.i_rate = DEFAULT_RATE;
p_input->stream.control.b_mute = 0;
}
else
{
p_input->stream.control.i_rate = p_input->stream.i_new_rate;
p_input->stream.control.b_mute = 1;
/* Feed the audio decoders with a NULL packet to avoid
* discontinuities. */
input_EscapeAudioDiscontinuity( p_input, p_pgrm );
}
p_input->stream.i_new_status = UNDEF_S;
p_input->stream.i_new_rate = UNDEF_S;
vlc_mutex_unlock( &p_input->stream.control.control_lock );
}
vlc_mutex_unlock( &p_input->stream.stream_lock );
return( i_return_value );
}
/*****************************************************************************
* input_ClockManageRef: manages a clock reference
*****************************************************************************/
......@@ -193,62 +265,7 @@ void input_ClockManageRef( input_thread_t * p_input,
mwait( p_pgrm->last_syscr );