]> git.sesse.net Git - vlc/blob - plugins/mpeg_system/input_es.c
* Decoders do not necessarily use bit stream (see mad plug-in)
[vlc] / plugins / mpeg_system / input_es.c
1 /*****************************************************************************
2  * input_es.c: Elementary Stream demux and packet management
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: input_es.c,v 1.12 2002/01/21 23:57:46 massiot Exp $
6  *
7  * Author: Christophe Massiot <massiot@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30
31 #include <videolan/vlc.h>
32
33 #include <sys/types.h>
34 #include <sys/stat.h>
35
36 #ifdef HAVE_UNISTD_H
37 #   include <unistd.h>
38 #endif
39
40 #include <fcntl.h>
41
42 #if defined( WIN32 )
43 #   include <io.h>                                                 /* read() */
44 #else
45 #   include <sys/uio.h>                                      /* struct iovec */
46 #endif
47
48 #if defined( WIN32 )
49 #   include "input_iovec.h"
50 #endif
51
52 #include "stream_control.h"
53 #include "input_ext-intf.h"
54 #include "input_ext-dec.h"
55 #include "input_ext-plugins.h"
56
57 #include "input_es.h"
58
59 #include "debug.h"
60
61 /*****************************************************************************
62  * Local prototypes
63  *****************************************************************************/
64 static int  ESProbe     ( probedata_t * );
65 static int  ESRead      ( struct input_thread_s *, data_packet_t ** );
66 static void ESInit          ( struct input_thread_s * );
67 static void ESEnd           ( struct input_thread_s * );
68 static void ESSeek          ( struct input_thread_s *, off_t );
69 static int  ESSetProgram    ( struct input_thread_s *, pgrm_descriptor_t * );
70 static void ESDemux         ( struct input_thread_s *, 
71                               struct data_packet_s * );
72
73 /*****************************************************************************
74  * Declare a buffer manager
75  *****************************************************************************/
76 #define FLAGS           BUFFERS_UNIQUE_SIZE
77 #define NB_LIFO         1
78 DECLARE_BUFFERS_EMBEDDED( FLAGS, NB_LIFO );
79 DECLARE_BUFFERS_INIT( FLAGS, NB_LIFO );
80 DECLARE_BUFFERS_END( FLAGS, NB_LIFO );
81 DECLARE_BUFFERS_NEWPACKET( FLAGS, NB_LIFO );
82 DECLARE_BUFFERS_DELETEPACKET( FLAGS, NB_LIFO, 150 );
83 DECLARE_BUFFERS_NEWPES( FLAGS, NB_LIFO );
84 DECLARE_BUFFERS_DELETEPES( FLAGS, NB_LIFO, 150 );
85 DECLARE_BUFFERS_TOIO( FLAGS, ES_PACKET_SIZE );
86
87 /*****************************************************************************
88  * Functions exported as capabilities. They are declared as static so that
89  * we don't pollute the namespace too much.
90  *****************************************************************************/
91 void _M( input_getfunctions )( function_list_t * p_function_list )
92 {
93 #define input p_function_list->functions.input
94     p_function_list->pf_probe = ESProbe;
95     input.pf_init             = ESInit;
96     input.pf_open             = NULL;
97     input.pf_close            = NULL;
98     input.pf_end              = ESEnd;
99     input.pf_set_area         = NULL;
100     input.pf_set_program      = ESSetProgram;
101     input.pf_read             = ESRead;
102     input.pf_demux            = ESDemux;
103     input.pf_new_packet       = input_NewPacket;
104     input.pf_new_pes          = input_NewPES;
105     input.pf_delete_packet    = input_DeletePacket;
106     input.pf_delete_pes       = input_DeletePES;
107     input.pf_rewind           = NULL;
108     input.pf_seek             = ESSeek;
109 #undef input
110 }
111
112 /*
113  * Data reading functions
114  */
115
116 /*****************************************************************************
117  * ESProbe: verifies that the stream is a ES stream
118  *****************************************************************************/
119 static int ESProbe( probedata_t *p_data )
120 {
121     int i_score = 5;
122
123     return( i_score );
124 }
125
126 /*****************************************************************************
127  * ESInit: initializes ES structures
128  *****************************************************************************/
129 static void ESInit( input_thread_t * p_input )
130 {
131     es_descriptor_t *   p_es;
132
133     p_input->p_method_data = NULL;
134
135     if( (p_input->p_method_data = input_BuffersInit()) == NULL )
136     {
137         p_input->b_error = 1;
138         return;
139     }
140
141     /* FIXME : detect if InitStream failed */
142     input_InitStream( p_input, 0 );
143     input_AddProgram( p_input, 0, 0 );
144     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
145     vlc_mutex_lock( &p_input->stream.stream_lock );
146     p_es = input_AddES( p_input, p_input->stream.p_selected_program, 0xE0, 0 );
147     p_es->i_stream_id = 0xE0;
148     p_es->i_type = MPEG1_VIDEO_ES;
149     p_es->i_cat = VIDEO_ES;
150     input_SelectES( p_input, p_es );
151     p_input->stream.p_selected_area->i_tell = 0;
152     p_input->stream.p_selected_program->b_is_ok = 1;
153     vlc_mutex_unlock( &p_input->stream.stream_lock );
154 }
155
156 /*****************************************************************************
157  * ESEnd: frees unused data
158  *****************************************************************************/
159 static void ESEnd( input_thread_t * p_input )
160 {
161     input_BuffersEnd( p_input->p_method_data );
162 }
163
164 /*****************************************************************************
165  * ESRead: reads data packets
166  *****************************************************************************
167  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
168  * packets.
169  *****************************************************************************/
170 static int ESRead( input_thread_t * p_input,
171                    data_packet_t ** pp_data )
172 {
173     int             i_read;
174     struct iovec    p_iovec[ES_READ_ONCE];
175     data_packet_t * p_data;
176
177     /* Get iovecs */
178     *pp_data = p_data = input_BuffersToIO( p_input->p_method_data, p_iovec,
179                                            ES_READ_ONCE );
180
181     if ( p_data == NULL )
182     {
183         return( -1 );
184     }
185
186     i_read = readv( p_input->i_handle, p_iovec, ES_READ_ONCE );
187     if( i_read == -1 )
188     {
189         intf_ErrMsg( "input error: ES readv error" );
190         p_input->pf_delete_packet( p_input->p_method_data, p_data );
191         return( -1 );
192     }
193     p_input->stream.p_selected_area->i_tell += i_read;
194     i_read /= ES_PACKET_SIZE;
195
196     if( i_read != ES_READ_ONCE )
197     {
198         /* We got fewer packets than wanted. Give remaining packets
199          * back to the buffer allocator. */
200         int i_loop;
201
202         for( i_loop = 0; i_loop < i_read; i_loop++ )
203         {
204             pp_data = &(*pp_data)->p_next;
205         }
206
207         p_input->pf_delete_packet( p_input->p_method_data, *pp_data );
208         *pp_data = NULL;
209     }
210
211     return( i_read );
212 }
213
214 /*****************************************************************************
215  * ESSeek: changes the stream position indicator
216  *****************************************************************************/
217 static void ESSeek( input_thread_t * p_input, off_t i_position )
218 {
219     lseek( p_input->i_handle, i_position, SEEK_SET );
220
221     p_input->stream.p_selected_area->i_tell = i_position;
222 }
223
224
225 /*****************************************************************************
226  * ESSetProgram: Does nothing
227  *****************************************************************************/
228 static int ESSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm )
229 {
230     return( 0 );
231 }
232
233 /*****************************************************************************
234  * ESDemux: fakes a demultiplexer
235  *****************************************************************************/
236 static void ESDemux( input_thread_t * p_input, data_packet_t * p_data )
237 {
238     pes_packet_t *  p_pes = p_input->pf_new_pes( p_input->p_method_data );
239     decoder_fifo_t * p_fifo =
240         p_input->stream.p_selected_program->pp_es[0]->p_decoder_fifo;
241
242     if( p_pes == NULL )
243     {
244         intf_ErrMsg("Out of memory");
245         p_input->b_error = 1;
246         return;
247     }
248
249     p_pes->i_rate = p_input->stream.control.i_rate;
250     p_pes->p_first = p_pes->p_last = p_data;
251     p_pes->i_nb_data = 1;
252
253     vlc_mutex_lock( &p_input->stream.stream_lock );
254     if( p_fifo->i_depth >= MAX_PACKETS_IN_FIFO )
255     {
256         /* Wait for the decoder. */
257         vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
258     }
259     vlc_mutex_unlock( &p_input->stream.stream_lock );
260
261     if( (p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT)
262          | (input_ClockManageControl( p_input, 
263                           p_input->stream.p_selected_program,
264                          (mtime_t)0 ) == PAUSE_S) )
265     {
266         intf_WarnMsg( 2, "synchro reinit" );
267         p_pes->i_pts = mdate() + DEFAULT_PTS_DELAY;
268         p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_OK;
269     }
270
271     input_DecodePES( p_fifo, p_pes );
272 }
273