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