]> git.sesse.net Git - vlc/blob - plugins/mpeg_vdec/video_parser.c
1677cd10ba99df0c6198b6a5fffbd8e371bf8717
[vlc] / plugins / mpeg_vdec / video_parser.c
1 /*****************************************************************************
2  * video_parser.c : video parser thread
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: video_parser.c,v 1.19 2002/05/19 09:37:02 gbazin 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 <stdlib.h>                                      /* malloc(), free() */
29
30 #include <videolan/vlc.h>
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 "video.h"
44 #include "video_output.h"
45
46 #include "stream_control.h"
47 #include "input_ext-dec.h"
48
49 #include "vdec_ext-plugins.h"
50 #include "vpar_pool.h"
51 #include "video_parser.h"
52
53 /*
54  * Local prototypes
55  */
56 static int      decoder_Probe     ( u8 * );
57 static int      decoder_Run       ( decoder_config_t * );
58 static int      InitThread        ( vpar_thread_t * );
59 static void     EndThread         ( vpar_thread_t * );
60 static void     BitstreamCallback ( bit_stream_t *, boolean_t );
61
62 /*****************************************************************************
63  * Capabilities
64  *****************************************************************************/
65 void _M( vdec_getfunctions )( function_list_t * p_function_list )
66 {
67     p_function_list->functions.dec.pf_probe = decoder_Probe;
68     p_function_list->functions.dec.pf_run   = decoder_Run;
69 }
70
71 /*****************************************************************************
72  * Build configuration tree.
73  *****************************************************************************/
74 #define VDEC_IDCT_TEXT N_("IDCT module")
75 #define VDEC_IDCT_LONGTEXT N_( \
76     "This option allows you to select the IDCT module used by this video " \
77     "decoder.\n" \
78     "Note that the default behavior is to automatically select the best " \
79     "module available.")
80
81 #define VDEC_MOTION_TEXT N_("motion compensation module")
82 #define VDEC_MOTION_LONGTEXT N_( \
83     "This option allows you to select the motion compensation module used by "\
84     "this video decoder.\n" \
85     "Note that the default behavior is to automatically select the best " \
86     "module available.")
87
88 #define VDEC_SMP_TEXT N_("use additional processors")
89 #define VDEC_SMP_LONGTEXT N_( \
90     "This video decoder can benefit from a multiprocessor computer. If you " \
91     "have one, you can specify the number of processors here.")
92
93 #define VPAR_SYNCHRO_TEXT N_("force synchro algorithm {I|I+|IP|IP+|IPB}")
94 #define VPAR_SYNCHRO_LONGTEXT N_( \
95     "If you don't want this video decoder to decode all frames of the video, "\
96     "you can specify which synchro algorithm you want to use.")
97
98 MODULE_CONFIG_START
99 ADD_CATEGORY_HINT( N_("Miscellaneous"), NULL)
100 ADD_MODULE  ( "mpeg-idct", MODULE_CAPABILITY_IDCT, NULL, NULL,
101               VDEC_IDCT_TEXT, VDEC_IDCT_LONGTEXT )
102 ADD_MODULE  ( "mpeg-motion", MODULE_CAPABILITY_MOTION, NULL, NULL,
103               VDEC_MOTION_TEXT, VDEC_IDCT_LONGTEXT )
104 ADD_INTEGER ( "vdec-smp", 0, NULL, VDEC_SMP_TEXT, VDEC_SMP_LONGTEXT )
105 ADD_STRING  ( "vpar-synchro", NULL, NULL, VPAR_SYNCHRO_TEXT,
106               VPAR_SYNCHRO_LONGTEXT )
107 MODULE_CONFIG_STOP
108
109 MODULE_INIT_START
110     SET_DESCRIPTION( _("MPEG I/II video decoder module") )
111     ADD_CAPABILITY( DECODER, 50 )
112 MODULE_INIT_STOP
113
114 MODULE_ACTIVATE_START
115     _M( vdec_getfunctions )( &p_module->p_functions->dec );
116 MODULE_ACTIVATE_STOP
117
118 MODULE_DEACTIVATE_START
119 MODULE_DEACTIVATE_STOP
120
121
122 /*****************************************************************************
123  * decoder_Probe: probe the decoder and return score
124  *****************************************************************************
125  * Tries to launch a decoder and return score so that the interface is able 
126  * to chose.
127  *****************************************************************************/
128 static int decoder_Probe( u8 *pi_type )
129 {
130     return( ( *pi_type == MPEG1_VIDEO_ES
131                || *pi_type == MPEG2_VIDEO_ES ) ? 0 : -1 );
132 }
133
134 /*****************************************************************************
135  * decoder_Run: this function is called just after the thread is created
136  *****************************************************************************/
137 static int decoder_Run ( decoder_config_t * p_config )
138 {
139     vpar_thread_t *     p_vpar;
140     boolean_t           b_error;
141
142     /* Allocate the memory needed to store the thread's structure */
143     if ( (p_vpar = (vpar_thread_t *)malloc( sizeof(vpar_thread_t) )) == NULL )
144     {
145         intf_ErrMsg( "vpar error: not enough memory "
146                      "for vpar_CreateThread() to create the new thread");
147         DecoderError( p_config->p_decoder_fifo );
148         return( -1 );
149     }
150
151     /*
152      * Initialize the thread properties
153      */
154     p_vpar->p_fifo = p_config->p_decoder_fifo;
155     p_vpar->p_config = p_config;
156     p_vpar->p_vout = NULL;
157
158     /*
159      * Initialize thread
160      */
161     p_vpar->p_fifo->b_error = InitThread( p_vpar );
162      
163     /*
164      * Main loop - it is not executed if an error occured during
165      * initialization
166      */
167     while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) )
168     {
169         /* Find the next sequence header in the stream */
170         p_vpar->p_fifo->b_error = vpar_NextSequenceHeader( p_vpar );
171
172         while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) )
173         {
174             p_vpar->c_loops++;
175
176             /* Parse the next sequence, group or picture header */
177             if( vpar_ParseHeader( p_vpar ) )
178             {
179                 /* End of sequence */
180                 break;
181             }
182         }
183     }
184
185     /*
186      * Error loop
187      */
188     if( ( b_error = p_vpar->p_fifo->b_error ) )
189     {
190         DecoderError( p_vpar->p_fifo );
191     }
192
193     /* End of thread */
194     EndThread( p_vpar );
195
196     if( b_error )
197     {
198         return( -1 );
199     }
200    
201     return( 0 );
202     
203
204
205 /*****************************************************************************
206  * InitThread: initialize vpar output thread
207  *****************************************************************************
208  * This function is called from decoder_Run and performs the second step 
209  * of the initialization. It returns 0 on success. Note that the thread's 
210  * flag are not modified inside this function.
211  *****************************************************************************/
212 static int InitThread( vpar_thread_t *p_vpar )
213 {
214     char *psz_name;
215
216     /*
217      * Choose the best motion compensation module
218      */
219     psz_name = config_GetPszVariable( "mpeg-motion" );
220     p_vpar->p_motion_module = module_Need( MODULE_CAPABILITY_MOTION, psz_name,
221                                            NULL );
222     if( psz_name ) free( psz_name );
223
224     if( p_vpar->p_motion_module == NULL )
225     {
226         intf_ErrMsg( "vpar error: no suitable motion compensation module" );
227         free( p_vpar );
228         return( -1 );
229     }
230
231 #define f ( p_vpar->p_motion_module->p_functions->motion.functions.motion )
232     memcpy( p_vpar->pool.ppppf_motion, f.ppppf_motion, sizeof(void *) * 16 );
233 #undef f
234
235     /*
236      * Choose the best IDCT module
237      */
238     psz_name = config_GetPszVariable( "mpeg-idct" );
239     p_vpar->p_idct_module = module_Need( MODULE_CAPABILITY_IDCT, psz_name,
240                                          NULL );
241     if( psz_name ) free( psz_name );
242
243     if( p_vpar->p_idct_module == NULL )
244     {
245         intf_ErrMsg( "vpar error: no suitable IDCT module" );
246         module_Unneed( p_vpar->p_motion_module );
247         free( p_vpar );
248         return( -1 );
249     }
250
251 #define f p_vpar->p_idct_module->p_functions->idct.functions.idct
252     p_vpar->pool.pf_idct_init   = f.pf_idct_init;
253     p_vpar->pf_sparse_idct_add  = f.pf_sparse_idct_add;
254     p_vpar->pf_idct_add         = f.pf_idct_add;
255     p_vpar->pf_sparse_idct_copy = f.pf_sparse_idct_copy;
256     p_vpar->pf_idct_copy        = f.pf_idct_copy;
257     p_vpar->pf_norm_scan        = f.pf_norm_scan;
258 #undef f
259
260     /* Initialize input bitstream */
261     InitBitstream( &p_vpar->bit_stream, p_vpar->p_config->p_decoder_fifo,
262                    BitstreamCallback, (void *)p_vpar );
263
264     /* Initialize parsing data */
265     p_vpar->sequence.p_forward = NULL;
266     p_vpar->sequence.p_backward = NULL;
267     p_vpar->sequence.intra_quant.b_allocated = 0;
268     p_vpar->sequence.nonintra_quant.b_allocated = 0;
269     p_vpar->sequence.chroma_intra_quant.b_allocated = 0;
270     p_vpar->sequence.chroma_nonintra_quant.b_allocated = 0;
271     p_vpar->sequence.i_matrix_coefficients = 1;
272     p_vpar->sequence.next_pts = p_vpar->sequence.next_dts = 0;
273     p_vpar->sequence.b_expect_discontinuity = 0;
274
275     /* Initialize copyright information */
276     p_vpar->sequence.b_copyright_flag = 0;
277     p_vpar->sequence.b_original = 0;
278     p_vpar->sequence.i_copyright_id = 0;
279     p_vpar->sequence.i_copyright_nb = 0;
280
281     p_vpar->picture.p_picture = NULL;
282     p_vpar->picture.i_current_structure = 0;
283
284     /* Initialize other properties */
285     p_vpar->c_loops = 0;
286     p_vpar->c_sequences = 0;
287     memset(p_vpar->pc_pictures, 0, sizeof(p_vpar->pc_pictures));
288     memset(p_vpar->pc_decoded_pictures, 0, sizeof(p_vpar->pc_decoded_pictures));
289     memset(p_vpar->pc_malformed_pictures, 0,
290            sizeof(p_vpar->pc_malformed_pictures));
291     vpar_InitScanTable( p_vpar );
292
293     /*
294      * Initialize the synchro properties
295      */
296     vpar_SynchroInit( p_vpar );
297
298     /* Spawn optional video decoder threads */
299     vpar_InitPool( p_vpar );
300
301     /* Mark thread as running and return */
302     return( 0 );
303 }
304
305 /*****************************************************************************
306  * EndThread: thread destruction
307  *****************************************************************************
308  * This function is called when the thread ends after a sucessful
309  * initialization.
310  *****************************************************************************/
311 static void EndThread( vpar_thread_t *p_vpar )
312 {
313     /* Release used video buffers. */
314     if( p_vpar->sequence.p_forward != NULL )
315     {
316         vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_forward );
317     }
318     if( p_vpar->sequence.p_backward != NULL )
319     {
320         vout_DatePicture( p_vpar->p_vout, p_vpar->sequence.p_backward,
321                           vpar_SynchroDate( p_vpar ) );
322         vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_backward );
323     }
324     if( p_vpar->picture.p_picture != NULL )
325     {
326         vout_DestroyPicture( p_vpar->p_vout, p_vpar->picture.p_picture );
327     }
328
329     if( p_main->b_stats )
330     {
331 #ifdef HAVE_SYS_TIMES_H
332         struct tms cpu_usage;
333         times( &cpu_usage );
334 #endif
335
336         intf_StatMsg( "vpar stats: %d loops among %d sequence(s)",
337                       p_vpar->c_loops, p_vpar->c_sequences );
338
339 #ifdef HAVE_SYS_TIMES_H
340         intf_StatMsg( "vpar stats: cpu usage (user: %d, system: %d)",
341                       cpu_usage.tms_utime, cpu_usage.tms_stime );
342 #endif
343
344         intf_StatMsg( "vpar stats: Read %d frames/fields (I %d/P %d/B %d)",
345                       p_vpar->pc_pictures[I_CODING_TYPE]
346                       + p_vpar->pc_pictures[P_CODING_TYPE]
347                       + p_vpar->pc_pictures[B_CODING_TYPE],
348                       p_vpar->pc_pictures[I_CODING_TYPE],
349                       p_vpar->pc_pictures[P_CODING_TYPE],
350                       p_vpar->pc_pictures[B_CODING_TYPE] );
351         intf_StatMsg( "vpar stats: Decoded %d frames/fields (I %d/P %d/B %d)",
352                       p_vpar->pc_decoded_pictures[I_CODING_TYPE]
353                       + p_vpar->pc_decoded_pictures[P_CODING_TYPE]
354                       + p_vpar->pc_decoded_pictures[B_CODING_TYPE],
355                       p_vpar->pc_decoded_pictures[I_CODING_TYPE],
356                       p_vpar->pc_decoded_pictures[P_CODING_TYPE],
357                       p_vpar->pc_decoded_pictures[B_CODING_TYPE] );
358         intf_StatMsg( "vpar stats: Read %d malformed frames/fields (I %d/P %d/B %d)",
359                       p_vpar->pc_malformed_pictures[I_CODING_TYPE]
360                       + p_vpar->pc_malformed_pictures[P_CODING_TYPE]
361                       + p_vpar->pc_malformed_pictures[B_CODING_TYPE],
362                       p_vpar->pc_malformed_pictures[I_CODING_TYPE],
363                       p_vpar->pc_malformed_pictures[P_CODING_TYPE],
364                       p_vpar->pc_malformed_pictures[B_CODING_TYPE] );
365 #define S   p_vpar->sequence
366         intf_StatMsg( "vpar info: %s stream (%dx%d), %d.%d pi/s",
367                       S.b_mpeg2 ? "MPEG-2" : "MPEG-1",
368                       S.i_width, S.i_height, S.i_frame_rate/1001,
369                       S.i_frame_rate % 1001 );
370         intf_StatMsg( "vpar info: %s, %s, matrix_coeff: %d",
371                       S.b_progressive ? "Progressive" : "Non-progressive",
372                       S.i_scalable_mode ? "scalable" : "non-scalable",
373                       S.i_matrix_coefficients );
374 #undef S
375     }
376
377     /* Dispose of matrices if they have been allocated. */
378     if( p_vpar->sequence.intra_quant.b_allocated )
379     {
380         free( p_vpar->sequence.intra_quant.pi_matrix );
381     }
382     if( p_vpar->sequence.nonintra_quant.b_allocated )
383     {
384         free( p_vpar->sequence.nonintra_quant.pi_matrix) ;
385     }
386     if( p_vpar->sequence.chroma_intra_quant.b_allocated )
387     {
388         free( p_vpar->sequence.chroma_intra_quant.pi_matrix );
389     }
390     if( p_vpar->sequence.chroma_nonintra_quant.b_allocated )
391     {
392         free( p_vpar->sequence.chroma_nonintra_quant.pi_matrix );
393     }
394
395     vpar_EndPool( p_vpar );
396
397     module_Unneed( p_vpar->p_idct_module );
398     module_Unneed( p_vpar->p_motion_module );
399
400     free( p_vpar );
401 }
402
403 /*****************************************************************************
404  * BitstreamCallback: Import parameters from the new data/PES packet
405  *****************************************************************************
406  * This function is called by input's NextDataPacket.
407  *****************************************************************************/
408 static void BitstreamCallback ( bit_stream_t * p_bit_stream,
409                                 boolean_t b_new_pes )
410 {
411     vpar_thread_t * p_vpar = (vpar_thread_t *)p_bit_stream->p_callback_arg;
412
413     if( b_new_pes )
414     {
415         p_vpar->sequence.i_current_rate =
416             p_bit_stream->p_decoder_fifo->p_first->i_rate;
417
418         if( p_bit_stream->p_decoder_fifo->p_first->b_discontinuity )
419         {
420             /* Escape the current picture and reset the picture predictors. */
421             p_vpar->sequence.b_expect_discontinuity = 1;
422             p_vpar->picture.b_error = 1;
423         }
424     }
425
426     if( p_bit_stream->p_data->b_discard_payload )
427     {
428         /* 1 packet messed up, trash the slice. */
429         p_vpar->picture.b_error = 1;
430     }
431 }