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