]> git.sesse.net Git - vlc/blob - src/video_parser/video_parser.c
d478efaf2cd275cbf088815f19b5f18b16d0256c
[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.84 2001/05/01 15:12:22 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 #include <unistd.h>                                              /* getpid() */
32 #include <errno.h>
33 #include <string.h>
34
35 #ifdef STATS
36 #  include <sys/times.h>
37 #endif
38
39 #include "config.h"
40 #include "common.h"
41 #include "threads.h"
42 #include "mtime.h"
43 #include "modules.h"
44
45 #include "intf_msg.h"
46
47 #include "stream_control.h"
48 #include "input_ext-dec.h"
49
50 #include "video.h"
51 #include "video_output.h"
52
53 #include "video_decoder.h"
54 #include "vdec_motion.h"
55 #include "../video_decoder/vdec_idct.h"
56
57 #include "vpar_blocks.h"
58 #include "../video_decoder/vpar_headers.h"
59 #include "../video_decoder/vpar_synchro.h"
60 #include "../video_decoder/video_parser.h"
61 #include "../video_decoder/video_fifo.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     /*
100      * Choose the best motion compensation module
101      */
102     p_vpar->p_motion_module = module_Need( MODULE_CAPABILITY_MOTION, NULL );
103
104     if( p_vpar->p_motion_module == NULL )
105     {
106         intf_ErrMsg( "vpar error: no suitable motion compensation module" );
107         free( p_vpar );
108         return( 0 );
109     }
110
111 #define M ( p_vpar->pppf_motion )
112 #define S ( p_vpar->ppf_motion_skipped )
113 #define F ( p_vpar->p_motion_module->p_functions->motion.functions.motion )
114     M[0][0][0] = M[0][0][1] = M[0][0][2] = M[0][0][3] = NULL;
115     M[0][1][0] = M[0][1][1] = M[0][1][2] = M[0][1][3] = NULL;
116     M[1][0][0] = NULL;
117     M[1][1][0] = NULL;
118     M[2][0][0] = NULL;
119     M[2][1][0] = NULL;
120     M[3][0][0] = NULL;
121     M[3][1][0] = NULL;
122
123     M[1][0][1] = F.pf_field_field_420;
124     M[1][1][1] = F.pf_frame_field_420;
125     M[2][0][1] = F.pf_field_field_422;
126     M[2][1][1] = F.pf_frame_field_422;
127     M[3][0][1] = F.pf_field_field_444;
128     M[3][1][1] = F.pf_frame_field_444;
129
130     M[1][0][2] = F.pf_field_16x8_420;
131     M[1][1][2] = F.pf_frame_frame_420;
132     M[2][0][2] = F.pf_field_16x8_422;
133     M[2][1][2] = F.pf_frame_frame_422;
134     M[3][0][2] = F.pf_field_16x8_444;
135     M[3][1][2] = F.pf_frame_frame_444;
136
137     M[1][0][3] = F.pf_field_dmv_420;
138     M[1][1][3] = F.pf_frame_dmv_420;
139     M[2][0][3] = F.pf_field_dmv_422;
140     M[2][1][3] = F.pf_frame_dmv_422;
141     M[3][0][3] = F.pf_field_dmv_444;
142     M[3][1][3] = F.pf_frame_dmv_444;
143
144     S[0][0] = S[0][1] = S[0][2] = S[0][3] = NULL;
145     S[1][0] = NULL;
146     S[2][0] = NULL;
147     S[3][0] = NULL;
148
149     S[1][1] = F.pf_field_field_420;
150     S[2][1] = F.pf_field_field_422;
151     S[3][1] = F.pf_field_field_444;
152
153     S[1][2] = F.pf_field_field_420;
154     S[2][2] = F.pf_field_field_422;
155     S[3][2] = F.pf_field_field_444;
156
157     S[1][3] = F.pf_frame_frame_420;
158     S[2][3] = F.pf_frame_frame_422;
159     S[3][3] = F.pf_frame_frame_444;
160 #undef F
161 #undef S
162 #undef M
163
164      /*
165       * Choose the best IDCT module
166       */
167     p_vpar->p_idct_module = module_Need( MODULE_CAPABILITY_IDCT, NULL );
168
169     if( p_vpar->p_idct_module == NULL )
170     {
171         intf_ErrMsg( "vpar error: no suitable IDCT module" );
172         module_Unneed( p_vpar->p_motion_module );
173         free( p_vpar );
174         return( 0 );
175     }
176
177 #define f p_vpar->p_idct_module->p_functions->idct.functions.idct
178     p_vpar->pf_init         = f.pf_init;
179     p_vpar->pf_sparse_idct  = f.pf_sparse_idct;
180     p_vpar->pf_idct         = f.pf_idct;
181     p_vpar->pf_norm_scan    = f.pf_norm_scan;
182 #undef f
183
184     /* Spawn the video parser thread */
185     if ( vlc_thread_create( &p_vpar->thread_id, "video parser",
186                             (vlc_thread_func_t)RunThread, (void *)p_vpar ) )
187     {
188         intf_ErrMsg("vpar error: can't spawn video parser thread");
189         module_Unneed( p_vpar->p_idct_module );
190         module_Unneed( p_vpar->p_motion_module );
191         free( p_vpar );
192         return( 0 );
193     }
194
195     intf_DbgMsg("vpar debug: video parser thread (%p) created", p_vpar);
196     return( p_vpar->thread_id );
197 }
198
199 /* following functions are local */
200
201 /*****************************************************************************
202  * InitThread: initialize vpar output thread
203  *****************************************************************************
204  * This function is called from RunThread and performs the second step of the
205  * initialization. It returns 0 on success. Note that the thread's flag are not
206  * modified inside this function.
207  *****************************************************************************/
208 static int InitThread( vpar_thread_t *p_vpar )
209 {
210 #ifdef VDEC_SMP
211     int i_dummy;
212 #endif
213
214     intf_DbgMsg("vpar debug: initializing video parser thread %p", p_vpar);
215
216     p_vpar->p_config->decoder_config.pf_init_bit_stream( &p_vpar->bit_stream,
217         p_vpar->p_config->decoder_config.p_decoder_fifo, BitstreamCallback,
218         (void *)p_vpar );
219
220     /* Initialize parsing data */
221     p_vpar->sequence.p_forward = NULL;
222     p_vpar->sequence.p_backward = NULL;
223     p_vpar->sequence.intra_quant.b_allocated = 0;
224     p_vpar->sequence.nonintra_quant.b_allocated = 0;
225     p_vpar->sequence.chroma_intra_quant.b_allocated = 0;
226     p_vpar->sequence.chroma_nonintra_quant.b_allocated = 0;
227     p_vpar->sequence.i_matrix_coefficients = 1;
228     p_vpar->sequence.next_pts = p_vpar->sequence.next_dts = 0;
229     p_vpar->sequence.b_expect_discontinuity = 0;
230
231     /* Initialize copyright information */
232     p_vpar->sequence.b_copyright_flag = 0;
233     p_vpar->sequence.b_original = 0;
234     p_vpar->sequence.i_copyright_id = 0;
235     p_vpar->sequence.i_copyright_nb = 0;
236
237     p_vpar->picture.p_picture = NULL;
238     p_vpar->picture.i_current_structure = 0;
239
240     /* Initialize other properties */
241 #ifdef STATS
242     p_vpar->c_loops = 0;
243     p_vpar->c_sequences = 0;
244     memset(p_vpar->pc_pictures, 0, sizeof(p_vpar->pc_pictures));
245     memset(p_vpar->pc_decoded_pictures, 0, sizeof(p_vpar->pc_decoded_pictures));
246     memset(p_vpar->pc_malformed_pictures, 0,
247            sizeof(p_vpar->pc_malformed_pictures));
248 #endif
249
250     /* Initialize video FIFO */
251     vpar_InitFIFO( p_vpar );
252
253     memset( p_vpar->pp_vdec, 0, NB_VDEC*sizeof(vdec_thread_t *) );
254
255 #ifdef VDEC_SMP
256     /* Spawn video_decoder threads */
257     /* FIXME: modify the number of vdecs at runtime ?? */
258     for( i_dummy = 0; i_dummy < NB_VDEC; i_dummy++ )
259     {
260         if( (p_vpar->pp_vdec[i_dummy] = vdec_CreateThread( p_vpar )) == NULL )
261         {
262             return( 1 );
263         }
264     }
265 #else
266     /* Fake a video_decoder thread */
267     if( (p_vpar->pp_vdec[0] = (vdec_thread_t *)malloc(sizeof( vdec_thread_t )))
268          == NULL || vdec_InitThread( p_vpar->pp_vdec[0] ) )
269     {
270         return( 1 );
271     }
272     p_vpar->pp_vdec[0]->b_die = 0;
273     p_vpar->pp_vdec[0]->b_error = 0;
274     p_vpar->pp_vdec[0]->p_vpar = p_vpar;
275
276 #   if !defined(SYS_BEOS) && !defined(WIN32)
277 #       if VDEC_NICE
278     /* Re-nice ourself */
279     if( nice(VDEC_NICE) == -1 )
280     {
281         intf_WarnMsg( 2, "vpar warning : couldn't nice() (%s)",
282                       strerror(errno) );
283     }
284 #       endif
285 #   endif
286 #endif
287
288     /* Initialize lookup tables */
289     vpar_InitMbAddrInc( p_vpar );
290     vpar_InitDCTTables( p_vpar );
291     vpar_InitPMBType( p_vpar );
292     vpar_InitBMBType( p_vpar );
293     vpar_InitDCTTables( p_vpar );
294     vpar_InitScanTable( p_vpar );
295
296     /*
297      * Initialize the synchro properties
298      */
299     vpar_SynchroInit( p_vpar );
300
301     /* Mark thread as running and return */
302     intf_DbgMsg("vpar debug: InitThread(%p) succeeded", p_vpar);
303     return( 0 );
304 }
305
306 /*****************************************************************************
307  * RunThread: generic parser thread
308  *****************************************************************************
309  * Video parser thread. This function only returns when the thread is
310  * terminated.
311  *****************************************************************************/
312 static void RunThread( vpar_thread_t *p_vpar )
313 {
314     intf_DbgMsg("vpar debug: running video parser thread (%p) (pid == %i)", p_vpar, getpid());
315
316     /*
317      * Initialize thread
318      */
319     p_vpar->p_fifo->b_error = InitThread( p_vpar );
320
321     /*
322      * Main loop - it is not executed if an error occured during
323      * initialization
324      */
325     while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) )
326     {
327         /* Find the next sequence header in the stream */
328         p_vpar->p_fifo->b_error = vpar_NextSequenceHeader( p_vpar );
329
330         while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) )
331         {
332 #ifdef STATS
333             p_vpar->c_loops++;
334 #endif
335             /* Parse the next sequence, group or picture header */
336             if( vpar_ParseHeader( p_vpar ) )
337             {
338                 /* End of sequence */
339                 break;
340             };
341         }
342     }
343
344     /*
345      * Error loop
346      */
347     if( p_vpar->p_fifo->b_error )
348     {
349         ErrorThread( p_vpar );
350     }
351
352     /* End of thread */
353     EndThread( p_vpar );
354 }
355
356 /*****************************************************************************
357  * ErrorThread: RunThread() error loop
358  *****************************************************************************
359  * This function is called when an error occured during thread main's loop. The
360  * thread can still receive feed, but must be ready to terminate as soon as
361  * possible.
362  *****************************************************************************/
363 static void ErrorThread( vpar_thread_t *p_vpar )
364 {
365     /* We take the lock, because we are going to read/write the start/end
366      * indexes of the decoder fifo */
367     vlc_mutex_lock( &p_vpar->p_fifo->data_lock );
368
369     /* Wait until a `die' order is sent */
370     while( !p_vpar->p_fifo->b_die )
371     {
372         /* Trash all received PES packets */
373         while( !DECODER_FIFO_ISEMPTY(*p_vpar->p_fifo) )
374         {
375             p_vpar->p_fifo->pf_delete_pes( p_vpar->p_fifo->p_packets_mgt,
376                                   DECODER_FIFO_START(*p_vpar->p_fifo) );
377             DECODER_FIFO_INCSTART( *p_vpar->p_fifo );
378         }
379
380         /* Waiting for the input thread to put new PES packets in the fifo */
381         vlc_cond_wait( &p_vpar->p_fifo->data_wait, &p_vpar->p_fifo->data_lock );
382     }
383
384     /* We can release the lock before leaving */
385     vlc_mutex_unlock( &p_vpar->p_fifo->data_lock );
386 }
387
388 /*****************************************************************************
389  * EndThread: thread destruction
390  *****************************************************************************
391  * This function is called when the thread ends after a sucessful
392  * initialization.
393  *****************************************************************************/
394 static void EndThread( vpar_thread_t *p_vpar )
395 {
396 #ifdef VDEC_SMP
397     int i_dummy;
398 #endif
399
400     intf_DbgMsg("vpar debug: destroying video parser thread %p", p_vpar);
401
402     /* Release used video buffers. */
403     if( p_vpar->sequence.p_forward != NULL )
404     {
405         vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_forward );
406     }
407     if( p_vpar->sequence.p_backward != NULL )
408     {
409         vout_DatePicture( p_vpar->p_vout, p_vpar->sequence.p_backward,
410                           vpar_SynchroDate( p_vpar ) );
411         vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_backward );
412     }
413     if( p_vpar->picture.p_picture != NULL )
414     {
415         vout_DestroyPicture( p_vpar->p_vout, p_vpar->picture.p_picture );
416     }
417
418 #ifdef STATS
419     intf_Msg("vpar stats: %d loops among %d sequence(s)",
420              p_vpar->c_loops, p_vpar->c_sequences);
421
422     {
423         struct tms cpu_usage;
424         times( &cpu_usage );
425
426         intf_Msg("vpar stats: cpu usage (user: %d, system: %d)",
427                  cpu_usage.tms_utime, cpu_usage.tms_stime);
428     }
429
430     intf_Msg("vpar stats: Read %d frames/fields (I %d/P %d/B %d)",
431              p_vpar->pc_pictures[I_CODING_TYPE]
432              + p_vpar->pc_pictures[P_CODING_TYPE]
433              + p_vpar->pc_pictures[B_CODING_TYPE],
434              p_vpar->pc_pictures[I_CODING_TYPE],
435              p_vpar->pc_pictures[P_CODING_TYPE],
436              p_vpar->pc_pictures[B_CODING_TYPE]);
437     intf_Msg("vpar stats: Decoded %d frames/fields (I %d/P %d/B %d)",
438              p_vpar->pc_decoded_pictures[I_CODING_TYPE]
439              + p_vpar->pc_decoded_pictures[P_CODING_TYPE]
440              + p_vpar->pc_decoded_pictures[B_CODING_TYPE],
441              p_vpar->pc_decoded_pictures[I_CODING_TYPE],
442              p_vpar->pc_decoded_pictures[P_CODING_TYPE],
443              p_vpar->pc_decoded_pictures[B_CODING_TYPE]);
444     intf_Msg("vpar stats: Read %d malformed frames/fields (I %d/P %d/B %d)",
445              p_vpar->pc_malformed_pictures[I_CODING_TYPE]
446              + p_vpar->pc_malformed_pictures[P_CODING_TYPE]
447              + p_vpar->pc_malformed_pictures[B_CODING_TYPE],
448              p_vpar->pc_malformed_pictures[I_CODING_TYPE],
449              p_vpar->pc_malformed_pictures[P_CODING_TYPE],
450              p_vpar->pc_malformed_pictures[B_CODING_TYPE]);
451 #define S   p_vpar->sequence
452     intf_Msg("vpar info: %s stream (%dx%d), %d.%d pi/s",
453              S.b_mpeg2 ? "MPEG-2" : "MPEG-1",
454              S.i_width, S.i_height, S.i_frame_rate/1001, S.i_frame_rate % 1001);
455     intf_Msg("vpar info: %s, %s, matrix_coeff: %d",
456              S.b_progressive ? "Progressive" : "Non-progressive",
457              S.i_scalable_mode ? "scalable" : "non-scalable",
458              S.i_matrix_coefficients);
459 #endif
460
461     /* Dispose of matrices if they have been allocated. */
462     if( p_vpar->sequence.intra_quant.b_allocated )
463     {
464         free( p_vpar->sequence.intra_quant.pi_matrix );
465     }
466     if( p_vpar->sequence.nonintra_quant.b_allocated )
467     {
468         free( p_vpar->sequence.nonintra_quant.pi_matrix) ;
469     }
470     if( p_vpar->sequence.chroma_intra_quant.b_allocated )
471     {
472         free( p_vpar->sequence.chroma_intra_quant.pi_matrix );
473     }
474     if( p_vpar->sequence.chroma_nonintra_quant.b_allocated )
475     {
476         free( p_vpar->sequence.chroma_nonintra_quant.pi_matrix );
477     }
478
479 #ifdef VDEC_SMP
480     /* Destroy vdec threads */
481     for( i_dummy = 0; i_dummy < NB_VDEC; i_dummy++ )
482     {
483         if( p_vpar->pp_vdec[i_dummy] != NULL )
484             vdec_DestroyThread( p_vpar->pp_vdec[i_dummy] );
485         else
486             break;
487     }
488 #else
489     free( p_vpar->pp_vdec[0] );
490 #endif
491
492     free( p_vpar->p_config );
493
494 #ifdef VDEC_SMP
495     /* Destroy lock and cond */
496     vlc_mutex_destroy( &(p_vpar->vbuffer.lock) );
497     vlc_cond_destroy( &(p_vpar->vfifo.wait) );
498     vlc_mutex_destroy( &(p_vpar->vfifo.lock) );
499 #endif
500     
501     vlc_mutex_destroy( &(p_vpar->synchro.fifo_lock) );
502     
503     module_Unneed( p_vpar->p_idct_module );
504     module_Unneed( p_vpar->p_motion_module );
505
506     free( p_vpar );
507
508     intf_DbgMsg("vpar debug: EndThread(%p)", p_vpar);
509 }
510
511 /*****************************************************************************
512  * BitstreamCallback: Import parameters from the new data/PES packet
513  *****************************************************************************
514  * This function is called by input's NextDataPacket.
515  *****************************************************************************/
516 static void BitstreamCallback ( bit_stream_t * p_bit_stream,
517                                 boolean_t b_new_pes )
518 {
519     vpar_thread_t * p_vpar = (vpar_thread_t *)p_bit_stream->p_callback_arg;
520
521     if( b_new_pes )
522     {
523         p_vpar->sequence.next_pts =
524             DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_pts;
525         p_vpar->sequence.next_dts =
526             DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_dts;
527         p_vpar->sequence.i_current_rate =
528             DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_rate;
529
530         if( DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->b_discontinuity )
531         {
532 #ifdef TRACE_VPAR
533             intf_DbgMsg( "Discontinuity in BitstreamCallback" );
534 #endif
535             /* Escape the current picture and reset the picture predictors. */
536             p_vpar->sequence.b_expect_discontinuity = 1;
537             p_vpar->picture.b_error = 1;
538         }
539     }
540
541     if( p_bit_stream->p_data->b_discard_payload )
542     {
543 #ifdef TRACE_VPAR
544         intf_DbgMsg( "Discard payload in BitstreamCallback" );
545 #endif
546         /* 1 packet messed up, trash the slice. */
547         p_vpar->picture.b_error = 1;
548     }
549 }