]> git.sesse.net Git - vlc/blob - src/video_decoder/video_parser.c
* Closing Debian bug #119369 which was fixed a while ago.
[vlc] / src / video_decoder / 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.8 2001/10/03 13:14:05 sam 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 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include "defs.h"
29
30 #include <stdlib.h>                                      /* malloc(), free() */
31
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>                                              /* getpid() */
34 #endif
35
36 #include <errno.h>
37 #include <string.h>
38
39 #ifdef HAVE_SYS_TIMES_H
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 "modules.h"
48
49 #include "intf_msg.h"
50
51 #include "stream_control.h"
52 #include "input_ext-dec.h"
53
54 #include "video.h"
55 #include "video_output.h"
56
57 #include "vdec_ext-plugins.h"
58 #include "vpar_pool.h"
59 #include "video_parser.h"
60
61 #include "main.h"
62
63 /*
64  * Local prototypes
65  */
66 static int      InitThread          ( vpar_thread_t * );
67 static void     RunThread           ( vpar_thread_t * );
68 static void     ErrorThread         ( vpar_thread_t * );
69 static void     EndThread           ( vpar_thread_t * );
70 static void     BitstreamCallback   ( bit_stream_t *, boolean_t );
71
72 /*****************************************************************************
73  * vpar_CreateThread: create a generic parser thread
74  *****************************************************************************
75  * This function creates a new video parser thread, and returns a pointer
76  * to its description. On error, it returns NULL.
77  *****************************************************************************/
78 vlc_thread_t vpar_CreateThread( vdec_config_t * p_config )
79 {
80     vpar_thread_t *     p_vpar;
81
82     intf_DbgMsg( "vpar debug: creating video parser thread" );
83
84     /* Allocate the memory needed to store the thread's structure */
85     if ( (p_vpar = (vpar_thread_t *)malloc( sizeof(vpar_thread_t) )) == NULL )
86     {
87         intf_ErrMsg( "vpar error: not enough memory "
88                      "for vpar_CreateThread() to create the new thread");
89         return( 0 );
90     }
91
92     /*
93      * Initialize the thread properties
94      */
95     p_vpar->p_fifo = p_config->decoder_config.p_decoder_fifo;
96     p_vpar->p_config = p_config;
97     p_vpar->p_vout = NULL;
98
99     /* Spawn the video parser thread */
100     if ( vlc_thread_create( &p_vpar->thread_id, "video parser",
101                             (vlc_thread_func_t)RunThread, (void *)p_vpar ) )
102     {
103         intf_ErrMsg("vpar error: can't spawn video parser thread");
104         module_Unneed( p_vpar->p_idct_module );
105         module_Unneed( p_vpar->p_motion_module );
106         free( p_vpar );
107         return( 0 );
108     }
109
110     intf_DbgMsg("vpar debug: video parser thread (%p) created", p_vpar);
111     return( p_vpar->thread_id );
112 }
113
114 /* following functions are local */
115
116 /*****************************************************************************
117  * InitThread: initialize vpar output thread
118  *****************************************************************************
119  * This function is called from RunThread and performs the second step of the
120  * initialization. It returns 0 on success. Note that the thread's flag are not
121  * modified inside this function.
122  *****************************************************************************/
123 static int InitThread( vpar_thread_t *p_vpar )
124 {
125     intf_DbgMsg("vpar debug: initializing video parser thread %p", p_vpar);
126
127     /*
128      * Choose the best motion compensation module
129      */
130     p_vpar->p_motion_module = module_Need( MODULE_CAPABILITY_MOTION, NULL );
131
132     if( p_vpar->p_motion_module == NULL )
133     {
134         intf_ErrMsg( "vpar error: no suitable motion compensation module" );
135         free( p_vpar );
136         return( 0 );
137     }
138
139 #define f ( p_vpar->p_motion_module->p_functions->motion.functions.motion )
140     memcpy( p_vpar->pool.ppppf_motion, f.ppppf_motion, sizeof(void *) * 16 );
141 #undef f
142
143     /*
144      * Choose the best IDCT module
145      */
146     p_vpar->p_idct_module = module_Need( MODULE_CAPABILITY_IDCT, NULL );
147
148     if( p_vpar->p_idct_module == NULL )
149     {
150         intf_ErrMsg( "vpar error: no suitable IDCT module" );
151         module_Unneed( p_vpar->p_motion_module );
152         free( p_vpar );
153         return( 0 );
154     }
155
156 #define f p_vpar->p_idct_module->p_functions->idct.functions.idct
157     p_vpar->pool.pf_idct_init   = f.pf_idct_init;
158     p_vpar->pf_sparse_idct_add  = f.pf_sparse_idct_add;
159     p_vpar->pf_idct_add         = f.pf_idct_add;
160     p_vpar->pf_sparse_idct_copy = f.pf_sparse_idct_copy;
161     p_vpar->pf_idct_copy        = f.pf_idct_copy;
162     p_vpar->pf_norm_scan        = f.pf_norm_scan;
163 #undef f
164
165     /* Initialize input bitstream */
166     p_vpar->p_config->decoder_config.pf_init_bit_stream( &p_vpar->bit_stream,
167         p_vpar->p_config->decoder_config.p_decoder_fifo, BitstreamCallback,
168         (void *)p_vpar );
169
170     /* Initialize parsing data */
171     p_vpar->sequence.p_forward = NULL;
172     p_vpar->sequence.p_backward = NULL;
173     p_vpar->sequence.intra_quant.b_allocated = 0;
174     p_vpar->sequence.nonintra_quant.b_allocated = 0;
175     p_vpar->sequence.chroma_intra_quant.b_allocated = 0;
176     p_vpar->sequence.chroma_nonintra_quant.b_allocated = 0;
177     p_vpar->sequence.i_matrix_coefficients = 1;
178     p_vpar->sequence.next_pts = p_vpar->sequence.next_dts = 0;
179     p_vpar->sequence.b_expect_discontinuity = 0;
180
181     /* Initialize copyright information */
182     p_vpar->sequence.b_copyright_flag = 0;
183     p_vpar->sequence.b_original = 0;
184     p_vpar->sequence.i_copyright_id = 0;
185     p_vpar->sequence.i_copyright_nb = 0;
186
187     p_vpar->picture.p_picture = NULL;
188     p_vpar->picture.i_current_structure = 0;
189
190     /* Initialize other properties */
191     p_vpar->c_loops = 0;
192     p_vpar->c_sequences = 0;
193     memset(p_vpar->pc_pictures, 0, sizeof(p_vpar->pc_pictures));
194     memset(p_vpar->pc_decoded_pictures, 0, sizeof(p_vpar->pc_decoded_pictures));
195     memset(p_vpar->pc_malformed_pictures, 0,
196            sizeof(p_vpar->pc_malformed_pictures));
197     vpar_InitScanTable( p_vpar );
198
199     /*
200      * Initialize the synchro properties
201      */
202     vpar_SynchroInit( p_vpar );
203
204     /* Spawn optional video decoder threads */
205     vpar_InitPool( p_vpar );
206
207     /* Mark thread as running and return */
208     intf_DbgMsg("vpar debug: InitThread(%p) succeeded", p_vpar);
209     return( 0 );
210 }
211
212 /*****************************************************************************
213  * RunThread: generic parser thread
214  *****************************************************************************
215  * Video parser thread. This function only returns when the thread is
216  * terminated.
217  *****************************************************************************/
218 static void RunThread( vpar_thread_t *p_vpar )
219 {
220     intf_DbgMsg("vpar debug: running video parser thread (%p) (pid == %i)", p_vpar, getpid());
221
222     /*
223      * Initialize thread
224      */
225     p_vpar->p_fifo->b_error = InitThread( p_vpar );
226
227     /*
228      * Main loop - it is not executed if an error occured during
229      * initialization
230      */
231     while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) )
232     {
233         /* Find the next sequence header in the stream */
234         p_vpar->p_fifo->b_error = vpar_NextSequenceHeader( p_vpar );
235
236         while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) )
237         {
238             p_vpar->c_loops++;
239
240             /* Parse the next sequence, group or picture header */
241             if( vpar_ParseHeader( p_vpar ) )
242             {
243                 /* End of sequence */
244                 break;
245             }
246         }
247     }
248
249     /*
250      * Error loop
251      */
252     if( p_vpar->p_fifo->b_error )
253     {
254         ErrorThread( p_vpar );
255     }
256
257     /* End of thread */
258     EndThread( p_vpar );
259 }
260
261 /*****************************************************************************
262  * ErrorThread: RunThread() error loop
263  *****************************************************************************
264  * This function is called when an error occured during thread main's loop. The
265  * thread can still receive feed, but must be ready to terminate as soon as
266  * possible.
267  *****************************************************************************/
268 static void ErrorThread( vpar_thread_t *p_vpar )
269 {
270     /* We take the lock, because we are going to read/write the start/end
271      * indexes of the decoder fifo */
272     vlc_mutex_lock( &p_vpar->p_fifo->data_lock );
273
274     /* Wait until a `die' order is sent */
275     while( !p_vpar->p_fifo->b_die )
276     {
277         /* Trash all received PES packets */
278         while( !DECODER_FIFO_ISEMPTY(*p_vpar->p_fifo) )
279         {
280             p_vpar->p_fifo->pf_delete_pes( p_vpar->p_fifo->p_packets_mgt,
281                                   DECODER_FIFO_START(*p_vpar->p_fifo) );
282             DECODER_FIFO_INCSTART( *p_vpar->p_fifo );
283         }
284
285         /* Waiting for the input thread to put new PES packets in the fifo */
286         vlc_cond_wait( &p_vpar->p_fifo->data_wait, &p_vpar->p_fifo->data_lock );
287     }
288
289     /* We can release the lock before leaving */
290     vlc_mutex_unlock( &p_vpar->p_fifo->data_lock );
291 }
292
293 /*****************************************************************************
294  * EndThread: thread destruction
295  *****************************************************************************
296  * This function is called when the thread ends after a sucessful
297  * initialization.
298  *****************************************************************************/
299 static void EndThread( vpar_thread_t *p_vpar )
300 {
301     intf_DbgMsg("vpar debug: destroying video parser thread %p", p_vpar);
302
303     /* Release used video buffers. */
304     if( p_vpar->sequence.p_forward != NULL )
305     {
306         vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_forward );
307     }
308     if( p_vpar->sequence.p_backward != NULL )
309     {
310         vout_DatePicture( p_vpar->p_vout, p_vpar->sequence.p_backward,
311                           vpar_SynchroDate( p_vpar ) );
312         vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_backward );
313     }
314     if( p_vpar->picture.p_picture != NULL )
315     {
316         vout_DestroyPicture( p_vpar->p_vout, p_vpar->picture.p_picture );
317     }
318
319     if( p_main->b_stats )
320     {
321 #ifdef HAVE_SYS_TIMES_H
322         struct tms cpu_usage;
323         times( &cpu_usage );
324 #endif
325
326         intf_StatMsg( "vpar stats: %d loops among %d sequence(s)",
327                       p_vpar->c_loops, p_vpar->c_sequences );
328
329 #ifdef HAVE_SYS_TIMES_H
330         intf_StatMsg( "vpar stats: cpu usage (user: %d, system: %d)",
331                       cpu_usage.tms_utime, cpu_usage.tms_stime );
332 #endif
333
334         intf_StatMsg( "vpar stats: Read %d frames/fields (I %d/P %d/B %d)",
335                       p_vpar->pc_pictures[I_CODING_TYPE]
336                       + p_vpar->pc_pictures[P_CODING_TYPE]
337                       + p_vpar->pc_pictures[B_CODING_TYPE],
338                       p_vpar->pc_pictures[I_CODING_TYPE],
339                       p_vpar->pc_pictures[P_CODING_TYPE],
340                       p_vpar->pc_pictures[B_CODING_TYPE] );
341         intf_StatMsg( "vpar stats: Decoded %d frames/fields (I %d/P %d/B %d)",
342                       p_vpar->pc_decoded_pictures[I_CODING_TYPE]
343                       + p_vpar->pc_decoded_pictures[P_CODING_TYPE]
344                       + p_vpar->pc_decoded_pictures[B_CODING_TYPE],
345                       p_vpar->pc_decoded_pictures[I_CODING_TYPE],
346                       p_vpar->pc_decoded_pictures[P_CODING_TYPE],
347                       p_vpar->pc_decoded_pictures[B_CODING_TYPE] );
348         intf_StatMsg( "vpar stats: Read %d malformed frames/fields (I %d/P %d/B %d)",
349                       p_vpar->pc_malformed_pictures[I_CODING_TYPE]
350                       + p_vpar->pc_malformed_pictures[P_CODING_TYPE]
351                       + p_vpar->pc_malformed_pictures[B_CODING_TYPE],
352                       p_vpar->pc_malformed_pictures[I_CODING_TYPE],
353                       p_vpar->pc_malformed_pictures[P_CODING_TYPE],
354                       p_vpar->pc_malformed_pictures[B_CODING_TYPE] );
355 #define S   p_vpar->sequence
356         intf_StatMsg( "vpar info: %s stream (%dx%d), %d.%d pi/s",
357                       S.b_mpeg2 ? "MPEG-2" : "MPEG-1",
358                       S.i_width, S.i_height, S.i_frame_rate/1001,
359                       S.i_frame_rate % 1001 );
360         intf_StatMsg( "vpar info: %s, %s, matrix_coeff: %d",
361                       S.b_progressive ? "Progressive" : "Non-progressive",
362                       S.i_scalable_mode ? "scalable" : "non-scalable",
363                       S.i_matrix_coefficients );
364 #undef S
365     }
366
367     /* Dispose of matrices if they have been allocated. */
368     if( p_vpar->sequence.intra_quant.b_allocated )
369     {
370         free( p_vpar->sequence.intra_quant.pi_matrix );
371     }
372     if( p_vpar->sequence.nonintra_quant.b_allocated )
373     {
374         free( p_vpar->sequence.nonintra_quant.pi_matrix) ;
375     }
376     if( p_vpar->sequence.chroma_intra_quant.b_allocated )
377     {
378         free( p_vpar->sequence.chroma_intra_quant.pi_matrix );
379     }
380     if( p_vpar->sequence.chroma_nonintra_quant.b_allocated )
381     {
382         free( p_vpar->sequence.chroma_nonintra_quant.pi_matrix );
383     }
384
385     vpar_EndPool( p_vpar );
386
387     free( p_vpar->p_config );
388
389     module_Unneed( p_vpar->p_idct_module );
390     module_Unneed( p_vpar->p_motion_module );
391
392     free( p_vpar );
393
394     intf_DbgMsg("vpar debug: EndThread(%p)", p_vpar);
395 }
396
397 /*****************************************************************************
398  * BitstreamCallback: Import parameters from the new data/PES packet
399  *****************************************************************************
400  * This function is called by input's NextDataPacket.
401  *****************************************************************************/
402 static void BitstreamCallback ( bit_stream_t * p_bit_stream,
403                                 boolean_t b_new_pes )
404 {
405     vpar_thread_t * p_vpar = (vpar_thread_t *)p_bit_stream->p_callback_arg;
406
407     if( b_new_pes )
408     {
409         p_vpar->sequence.next_pts =
410             DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_pts;
411         p_vpar->sequence.next_dts =
412             DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_dts;
413         p_vpar->sequence.i_current_rate =
414             DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_rate;
415
416         if( DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->b_discontinuity )
417         {
418 #ifdef TRACE_VPAR
419             intf_DbgMsg( "Discontinuity in BitstreamCallback" );
420 #endif
421             /* Escape the current picture and reset the picture predictors. */
422             p_vpar->sequence.b_expect_discontinuity = 1;
423             p_vpar->picture.b_error = 1;
424         }
425     }
426
427     if( p_bit_stream->p_data->b_discard_payload )
428     {
429 #ifdef TRACE_VPAR
430         intf_DbgMsg( "Discard payload in BitstreamCallback" );
431 #endif
432         /* 1 packet messed up, trash the slice. */
433         p_vpar->picture.b_error = 1;
434     }
435 }