]> git.sesse.net Git - vlc/blob - src/video_parser/video_parser.c
Fixed various memory leaks.
[vlc] / src / video_parser / video_parser.c
1 /*****************************************************************************
2  * video_parser.c : video parser thread
3  *****************************************************************************
4  * Copyright (C) 1999, 2000 VideoLAN
5  * $Id: video_parser.c,v 1.56 2000/12/21 14:18:15 massiot Exp $
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *          Samuel Hocevar <sam@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /* FIXME: passer en terminate/destroy avec les signaux supplĂ©mentaires ?? */
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #include "defs.h"
31
32 #include <stdlib.h>                                      /* malloc(), free() */
33 #include <unistd.h>                                              /* getpid() */
34 #include <sys/types.h>                        /* on BSD, uio.h needs types.h */
35 #include <sys/uio.h>                                            /* "input.h" */
36 #include <errno.h>
37 #include <string.h>
38
39 #ifdef STATS
40 #  include <sys/times.h>
41 #endif
42
43 #include "config.h"
44 #include "common.h"
45 #include "threads.h"
46 #include "mtime.h"
47 #include "plugins.h"
48
49 #include "intf_msg.h"
50 #include "debug.h"                 /* XXX?? temporaire, requis par netlist.h */
51
52 #include "stream_control.h"
53 #include "input_ext-dec.h"
54
55 #include "video.h"
56 #include "video_output.h"
57
58 #include "vdec_idct.h"
59 #include "video_decoder.h"
60 #include "vdec_motion.h"
61
62 #include "vpar_blocks.h"
63 #include "vpar_headers.h"
64 #include "vpar_synchro.h"
65 #include "video_parser.h"
66 #include "video_fifo.h"
67
68 /*
69  * Local prototypes
70  */
71 static int      InitThread          ( vpar_thread_t *p_vpar );
72 static void     RunThread           ( vpar_thread_t *p_vpar );
73 static void     ErrorThread         ( vpar_thread_t *p_vpar );
74 static void     EndThread           ( vpar_thread_t *p_vpar );
75
76 /*****************************************************************************
77  * vpar_CreateThread: create a generic parser thread
78  *****************************************************************************
79  * This function creates a new video parser thread, and returns a pointer
80  * to its description. On error, it returns NULL.
81  * Following configuration properties are used:
82  * XXX??
83  *****************************************************************************/
84 vlc_thread_t vpar_CreateThread( vdec_config_t * p_config )
85 {
86     vpar_thread_t *     p_vpar;
87
88     intf_DbgMsg( "vpar debug: creating video parser thread\n" );
89
90     /* Allocate the memory needed to store the thread's structure */
91     if ( (p_vpar = (vpar_thread_t *)malloc( sizeof(vpar_thread_t) )) == NULL )
92     {
93         intf_ErrMsg( "vpar error: not enough memory "
94                      "for vpar_CreateThread() to create the new thread\n");
95         return( 0 );
96     }
97
98     /*
99      * Initialize the thread properties
100      */
101     p_vpar->p_fifo = p_config->decoder_config.p_decoder_fifo;
102     p_vpar->p_config = p_config;
103
104     p_vpar->p_vout = p_config->p_vout;
105
106     /* Spawn the video parser thread */
107     if ( vlc_thread_create( &p_vpar->thread_id, "video parser",
108                             (vlc_thread_func_t)RunThread, (void *)p_vpar ) )
109     {
110         intf_ErrMsg("vpar error: can't spawn video parser thread\n");
111         free( p_vpar );
112         return( 0 );
113     }
114
115     intf_DbgMsg("vpar debug: video parser thread (%p) created\n", p_vpar);
116     return( p_vpar->thread_id );
117 }
118
119 /* following functions are local */
120
121 /*****************************************************************************
122  * InitThread: initialize vpar output thread
123  *****************************************************************************
124  * This function is called from RunThread and performs the second step of the
125  * initialization. It returns 0 on success. Note that the thread's flag are not
126  * modified inside this function.
127  *****************************************************************************/
128 static int InitThread( vpar_thread_t *p_vpar )
129 {
130 #ifdef VDEC_SMP
131     int i_dummy;
132 #endif
133
134     intf_DbgMsg("vpar debug: initializing video parser thread %p\n", p_vpar);
135
136     p_vpar->p_config->decoder_config.pf_init_bit_stream( &p_vpar->bit_stream,
137         p_vpar->p_config->decoder_config.p_decoder_fifo );
138
139     /* Initialize parsing data */
140     p_vpar->sequence.p_forward = NULL;
141     p_vpar->sequence.p_backward = NULL;
142     p_vpar->sequence.intra_quant.b_allocated = 0;
143     p_vpar->sequence.nonintra_quant.b_allocated = 0;
144     p_vpar->sequence.chroma_intra_quant.b_allocated = 0;
145     p_vpar->sequence.chroma_nonintra_quant.b_allocated = 0;
146
147     /* Initialize copyright information */
148     p_vpar->sequence.b_copyright_flag = 0;
149     p_vpar->sequence.b_original = 0;
150     p_vpar->sequence.i_copyright_id = 0;
151     p_vpar->sequence.i_copyright_nb = 0;
152
153     p_vpar->picture.p_picture = NULL;
154     p_vpar->picture.i_current_structure = 0;
155
156     /* Initialize other properties */
157 #ifdef STATS
158     p_vpar->c_loops = 0;
159     p_vpar->c_sequences = 0;
160     memset(p_vpar->pc_pictures, 0, sizeof(p_vpar->pc_pictures));
161     memset(p_vpar->pc_decoded_pictures, 0, sizeof(p_vpar->pc_decoded_pictures));
162     memset(p_vpar->pc_malformed_pictures, 0,
163            sizeof(p_vpar->pc_malformed_pictures));
164 #endif
165
166     /* Initialize video FIFO */
167     vpar_InitFIFO( p_vpar );
168
169     memset( p_vpar->pp_vdec, 0, NB_VDEC*sizeof(vdec_thread_t *) );
170
171 #ifdef VDEC_SMP
172     /* Spawn video_decoder threads */
173     /* FIXME: modify the number of vdecs at runtime ?? */
174     for( i_dummy = 0; i_dummy < NB_VDEC; i_dummy++ )
175     {
176         if( (p_vpar->pp_vdec[i_dummy] = vdec_CreateThread( p_vpar )) == NULL )
177         {
178             return( 1 );
179         }
180     }
181 #else
182     /* Fake a video_decoder thread */
183     if( (p_vpar->pp_vdec[0] = (vdec_thread_t *)malloc(sizeof( vdec_thread_t )))
184          == NULL || vdec_InitThread( p_vpar->pp_vdec[0] ) )
185     {
186         return( 1 );
187     }
188     p_vpar->pp_vdec[0]->b_die = 0;
189     p_vpar->pp_vdec[0]->b_error = 0;
190     p_vpar->pp_vdec[0]->p_vpar = p_vpar;
191
192     /* Re-nice ourself */
193     if( nice(VDEC_NICE) == -1 )
194     {
195         intf_WarnMsg( 2, "vpar warning : couldn't nice() (%s)\n",
196                       strerror(errno) );
197     }
198 #endif
199
200     /* Initialize lookup tables */
201 #if defined(MPEG2_COMPLIANT) && !defined(VDEC_DFT)
202     vpar_InitCrop( p_vpar );
203 #endif
204     vpar_InitMbAddrInc( p_vpar );
205     vpar_InitDCTTables( p_vpar );
206     vpar_InitPMBType( p_vpar );
207     vpar_InitBMBType( p_vpar );
208     vpar_InitDCTTables( p_vpar );
209
210     /*
211      * Initialize the synchro properties
212      */
213     vpar_SynchroInit( p_vpar );
214
215     /* Mark thread as running and return */
216     intf_DbgMsg("vpar debug: InitThread(%p) succeeded\n", p_vpar);
217     return( 0 );
218 }
219
220 /*****************************************************************************
221  * RunThread: generic parser thread
222  *****************************************************************************
223  * Video parser thread. This function only returns when the thread is
224  * terminated.
225  *****************************************************************************/
226 static void RunThread( vpar_thread_t *p_vpar )
227 {
228     intf_DbgMsg("vpar debug: running video parser thread (%p) (pid == %i)\n", p_vpar, getpid());
229
230     /*
231      * Initialize thread
232      */
233     p_vpar->p_fifo->b_error = InitThread( p_vpar );
234
235     /*
236      * Main loop - it is not executed if an error occured during
237      * initialization
238      */
239     while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) )
240     {
241         /* Find the next sequence header in the stream */
242         p_vpar->p_fifo->b_error = vpar_NextSequenceHeader( p_vpar );
243
244         while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) )
245         {
246 #ifdef STATS
247             p_vpar->c_loops++;
248 #endif
249             /* Parse the next sequence, group or picture header */
250             if( vpar_ParseHeader( p_vpar ) )
251             {
252                 /* End of sequence */
253                 break;
254             };
255         }
256     }
257
258     /*
259      * Error loop
260      */
261     if( p_vpar->p_fifo->b_error )
262     {
263         ErrorThread( p_vpar );
264     }
265
266     /* End of thread */
267     EndThread( p_vpar );
268 }
269
270 /*****************************************************************************
271  * ErrorThread: RunThread() error loop
272  *****************************************************************************
273  * This function is called when an error occured during thread main's loop. The
274  * thread can still receive feed, but must be ready to terminate as soon as
275  * possible.
276  *****************************************************************************/
277 static void ErrorThread( vpar_thread_t *p_vpar )
278 {
279     /* We take the lock, because we are going to read/write the start/end
280      * indexes of the decoder fifo */
281     vlc_mutex_lock( &p_vpar->p_fifo->data_lock );
282
283     /* Wait until a `die' order is sent */
284     while( !p_vpar->p_fifo->b_die )
285     {
286         /* Trash all received PES packets */
287         while( !DECODER_FIFO_ISEMPTY(*p_vpar->p_fifo) )
288         {
289             p_vpar->p_fifo->pf_delete_pes( p_vpar->p_fifo->p_packets_mgt,
290                                   DECODER_FIFO_START(*p_vpar->p_fifo) );
291             DECODER_FIFO_INCSTART( *p_vpar->p_fifo );
292         }
293
294         /* Waiting for the input thread to put new PES packets in the fifo */
295         vlc_cond_wait( &p_vpar->p_fifo->data_wait, &p_vpar->p_fifo->data_lock );
296     }
297
298     /* We can release the lock before leaving */
299     vlc_mutex_unlock( &p_vpar->p_fifo->data_lock );
300 }
301
302 /*****************************************************************************
303  * EndThread: thread destruction
304  *****************************************************************************
305  * This function is called when the thread ends after a sucessful
306  * initialization.
307  *****************************************************************************/
308 static void EndThread( vpar_thread_t *p_vpar )
309 {
310 #ifdef VDEC_SMP
311     int i_dummy;
312 #endif
313
314     intf_DbgMsg("vpar debug: destroying video parser thread %p\n", p_vpar);
315
316 #ifdef STATS
317     intf_Msg("vpar stats: %d loops among %d sequence(s)\n",
318              p_vpar->c_loops, p_vpar->c_sequences);
319
320     {
321         struct tms cpu_usage;
322         times( &cpu_usage );
323
324         intf_Msg("vpar stats: cpu usage (user: %d, system: %d)\n",
325                  cpu_usage.tms_utime, cpu_usage.tms_stime);
326     }
327
328     intf_Msg("vpar stats: Read %d frames/fields (I %d/P %d/B %d)\n",
329              p_vpar->pc_pictures[I_CODING_TYPE]
330              + p_vpar->pc_pictures[P_CODING_TYPE]
331              + p_vpar->pc_pictures[B_CODING_TYPE],
332              p_vpar->pc_pictures[I_CODING_TYPE],
333              p_vpar->pc_pictures[P_CODING_TYPE],
334              p_vpar->pc_pictures[B_CODING_TYPE]);
335     intf_Msg("vpar stats: Decoded %d frames/fields (I %d/P %d/B %d)\n",
336              p_vpar->pc_decoded_pictures[I_CODING_TYPE]
337              + p_vpar->pc_decoded_pictures[P_CODING_TYPE]
338              + p_vpar->pc_decoded_pictures[B_CODING_TYPE],
339              p_vpar->pc_decoded_pictures[I_CODING_TYPE],
340              p_vpar->pc_decoded_pictures[P_CODING_TYPE],
341              p_vpar->pc_decoded_pictures[B_CODING_TYPE]);
342     intf_Msg("vpar stats: Read %d malformed frames/fields (I %d/P %d/B %d)\n",
343              p_vpar->pc_malformed_pictures[I_CODING_TYPE]
344              + p_vpar->pc_malformed_pictures[P_CODING_TYPE]
345              + p_vpar->pc_malformed_pictures[B_CODING_TYPE],
346              p_vpar->pc_malformed_pictures[I_CODING_TYPE],
347              p_vpar->pc_malformed_pictures[P_CODING_TYPE],
348              p_vpar->pc_malformed_pictures[B_CODING_TYPE]);
349 #define S   p_vpar->sequence
350     intf_Msg("vpar info: %s stream (%dx%d), %d pi/s\n",
351              S.b_mpeg2 ? "MPEG-2" : "MPEG-1",
352              S.i_width, S.i_height, S.i_frame_rate/1001);
353     intf_Msg("vpar info: %s, %s, matrix_coeff: %d\n",
354              S.b_progressive ? "Progressive" : "Non-progressive",
355              S.i_scalable_mode ? "scalable" : "non-scalable",
356              S.i_matrix_coefficients);
357 #endif
358
359     /* Dispose of matrices if they have been allocated. */
360     if( p_vpar->sequence.intra_quant.b_allocated )
361     {
362         free( p_vpar->sequence.intra_quant.pi_matrix );
363     }
364     if( p_vpar->sequence.nonintra_quant.b_allocated )
365     {
366         free( p_vpar->sequence.nonintra_quant.pi_matrix) ;
367     }
368     if( p_vpar->sequence.chroma_intra_quant.b_allocated )
369     {
370         free( p_vpar->sequence.chroma_intra_quant.pi_matrix );
371     }
372     if( p_vpar->sequence.chroma_nonintra_quant.b_allocated )
373     {
374         free( p_vpar->sequence.chroma_nonintra_quant.pi_matrix );
375     }
376
377 #ifdef VDEC_SMP
378     /* Destroy vdec threads */
379     for( i_dummy = 0; i_dummy < NB_VDEC; i_dummy++ )
380     {
381         if( p_vpar->pp_vdec[i_dummy] != NULL )
382             vdec_DestroyThread( p_vpar->pp_vdec[i_dummy] );
383         else
384             break;
385     }
386 #else
387     free( p_vpar->pp_vdec[0] );
388 #endif
389
390     free( p_vpar->p_config );
391     free( p_vpar );
392
393     intf_DbgMsg("vpar debug: EndThread(%p)\n", p_vpar);
394 }