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