]> git.sesse.net Git - vlc/blob - modules/codec/mpeg_video/parser.c
* ./src/video_output/video_output.c, modules/*: factorized video output
[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.8 2002/11/28 17:35:00 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 #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 );
85     add_module  ( "mpeg-idct", "idct", NULL, NULL,
86                   VDEC_IDCT_TEXT, VDEC_IDCT_LONGTEXT );
87     add_module  ( "mpeg-motion", "motion compensation", NULL, NULL,
88                   VDEC_MOTION_TEXT, VDEC_MOTION_LONGTEXT );
89     add_integer ( "vdec-smp", 0, NULL, VDEC_SMP_TEXT, VDEC_SMP_LONGTEXT );
90     add_string  ( "vpar-synchro", NULL, NULL, VPAR_SYNCHRO_TEXT,
91                   VPAR_SYNCHRO_LONGTEXT );
92     set_description( _("MPEG I/II video decoder module") );
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             if( vpar_ParseHeader( p_vpar ) )
158             {
159                 /* End of sequence */
160                 break;
161             }
162         }
163     }
164
165     /*
166      * Error loop
167      */
168     if( ( b_error = p_vpar->p_fifo->b_error ) )
169     {
170         DecoderError( p_vpar->p_fifo );
171     }
172
173     /* End of thread */
174     EndThread( p_vpar );
175
176     if( b_error )
177     {
178         return( -1 );
179     }
180    
181     return( 0 );
182     
183
184
185 /*****************************************************************************
186  * InitThread: initialize vpar output thread
187  *****************************************************************************
188  * This function is called from Run and performs the second step 
189  * of the initialization. It returns 0 on success. Note that the thread's 
190  * flag are not modified inside this function.
191  *****************************************************************************/
192 static int InitThread( vpar_thread_t *p_vpar )
193 {
194     /*
195      * Choose the best motion compensation module
196      */
197     p_vpar->p_motion =
198          module_Need( p_vpar->p_fifo, "motion compensation", "$mpeg-motion" );
199
200     if( p_vpar->p_motion == NULL )
201     {
202         msg_Err( p_vpar->p_fifo, "no suitable motion compensation module" );
203         free( p_vpar );
204         return( -1 );
205     }
206
207     memcpy( p_vpar->pool.ppppf_motion,
208             p_vpar->p_fifo->p_private, sizeof(void *) * 16 );
209
210     /*
211      * Choose the best IDCT module
212      */
213     p_vpar->p_idct = module_Need( p_vpar->p_fifo, "idct", "$mpeg-idct" );
214
215     if( p_vpar->p_idct == NULL )
216     {
217         msg_Err( p_vpar->p_fifo, "no suitable IDCT module" );
218         module_Unneed( p_vpar->p_fifo, p_vpar->p_motion );
219         free( p_vpar );
220         return( -1 );
221     }
222
223     p_vpar->pool.pf_idct_init   = ((void**)p_vpar->p_fifo->p_private)[0];
224     p_vpar->pf_norm_scan        = ((void**)p_vpar->p_fifo->p_private)[1];
225     p_vpar->pf_sparse_idct_add  = ((void**)p_vpar->p_fifo->p_private)[2];
226     p_vpar->pf_sparse_idct_copy = ((void**)p_vpar->p_fifo->p_private)[3];
227     p_vpar->pf_idct_add         = ((void**)p_vpar->p_fifo->p_private)[4];
228     p_vpar->pf_idct_copy        = ((void**)p_vpar->p_fifo->p_private)[5];
229
230     /* Initialize input bitstream */
231     if( InitBitstream( &p_vpar->bit_stream, p_vpar->p_fifo,
232                        BitstreamCallback, (void *)p_vpar ) != VLC_SUCCESS )
233     {
234         msg_Err( p_vpar->p_fifo, "cannot initialize bitstream" );
235         module_Unneed( p_vpar->p_fifo, p_vpar->p_motion );
236         free( p_vpar );
237         return( -1 );
238     }
239
240     /* Initialize parsing data */
241     p_vpar->sequence.p_forward = NULL;
242     p_vpar->sequence.p_backward = NULL;
243     p_vpar->sequence.intra_quant.b_allocated = 0;
244     p_vpar->sequence.nonintra_quant.b_allocated = 0;
245     p_vpar->sequence.chroma_intra_quant.b_allocated = 0;
246     p_vpar->sequence.chroma_nonintra_quant.b_allocated = 0;
247     p_vpar->sequence.i_matrix_coefficients = 1;
248     p_vpar->sequence.next_pts = p_vpar->sequence.next_dts = 0;
249     p_vpar->sequence.b_expect_discontinuity = 0;
250
251     p_vpar->sequence.i_width = 0;
252     p_vpar->sequence.i_height = 0;
253     p_vpar->sequence.i_frame_rate = 0;
254     p_vpar->sequence.i_scalable_mode = 0;
255     p_vpar->sequence.i_matrix_coefficients = 0;
256     p_vpar->sequence.b_mpeg2 = 0;
257     p_vpar->sequence.b_progressive = 0;
258
259     /* Initialize copyright information */
260     p_vpar->sequence.b_copyright_flag = 0;
261     p_vpar->sequence.b_original = 0;
262     p_vpar->sequence.i_copyright_id = 0;
263     p_vpar->sequence.i_copyright_nb = 0;
264
265     p_vpar->picture.p_picture = NULL;
266     p_vpar->picture.i_current_structure = 0;
267
268     /* Initialize other properties */
269     p_vpar->c_loops = 0;
270     p_vpar->c_sequences = 0;
271     memset(p_vpar->pc_pictures, 0, sizeof(p_vpar->pc_pictures));
272     memset(p_vpar->pc_decoded_pictures, 0, sizeof(p_vpar->pc_decoded_pictures));
273     memset(p_vpar->pc_malformed_pictures, 0,
274            sizeof(p_vpar->pc_malformed_pictures));
275     vpar_InitScanTable( p_vpar );
276
277     /*
278      * Initialize the synchro properties
279      */
280     vpar_SynchroInit( p_vpar );
281
282     /* Spawn optional video decoder threads */
283     vpar_InitPool( p_vpar );
284
285     /* Mark thread as running and return */
286     return( 0 );
287 }
288
289 /*****************************************************************************
290  * EndThread: thread destruction
291  *****************************************************************************
292  * This function is called when the thread ends after a sucessful
293  * initialization.
294  *****************************************************************************/
295 static void EndThread( vpar_thread_t *p_vpar )
296 {
297 #ifdef HAVE_SYS_TIMES_H
298     struct tms cpu_usage;
299     times( &cpu_usage );
300 #endif
301
302     /* Release used video buffers. */
303     if( p_vpar->sequence.p_forward != NULL )
304     {
305         vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_forward );
306     }
307     if( p_vpar->sequence.p_backward != NULL )
308     {
309         vout_DatePicture( p_vpar->p_vout, p_vpar->sequence.p_backward,
310                           vpar_SynchroDate( p_vpar ) );
311         vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_backward );
312     }
313     if( p_vpar->picture.p_picture != NULL )
314     {
315         vout_DestroyPicture( p_vpar->p_vout, p_vpar->picture.p_picture );
316     }
317
318     vout_Request( p_vpar->p_fifo, p_vpar->p_vout, 0, 0, 0, 0 );
319
320     msg_Dbg( p_vpar->p_fifo, "%d loops among %d sequence(s)",
321              p_vpar->c_loops, p_vpar->c_sequences );
322
323 #ifdef HAVE_SYS_TIMES_H
324     msg_Dbg( p_vpar->p_fifo, "cpu usage (user: %d, system: %d)",
325              cpu_usage.tms_utime, cpu_usage.tms_stime );
326 #endif
327
328     msg_Dbg( p_vpar->p_fifo, "read %d frames/fields (I %d/P %d/B %d)",
329              p_vpar->pc_pictures[I_CODING_TYPE]
330              + p_vpar->pc_pictures[P_CODING_TYPE]
331              + p_vpar->pc_pictures[B_CODING_TYPE],
332              p_vpar->pc_pictures[I_CODING_TYPE],
333              p_vpar->pc_pictures[P_CODING_TYPE],
334              p_vpar->pc_pictures[B_CODING_TYPE] );
335     msg_Dbg( p_vpar->p_fifo, "decoded %d frames/fields (I %d/P %d/B %d)",
336              p_vpar->pc_decoded_pictures[I_CODING_TYPE]
337              + p_vpar->pc_decoded_pictures[P_CODING_TYPE]
338              + p_vpar->pc_decoded_pictures[B_CODING_TYPE],
339              p_vpar->pc_decoded_pictures[I_CODING_TYPE],
340              p_vpar->pc_decoded_pictures[P_CODING_TYPE],
341              p_vpar->pc_decoded_pictures[B_CODING_TYPE] );
342     msg_Dbg( p_vpar->p_fifo,
343              "read %d malformed frames/fields (I %d/P %d/B %d)",
344              p_vpar->pc_malformed_pictures[I_CODING_TYPE]
345              + p_vpar->pc_malformed_pictures[P_CODING_TYPE]
346              + p_vpar->pc_malformed_pictures[B_CODING_TYPE],
347              p_vpar->pc_malformed_pictures[I_CODING_TYPE],
348              p_vpar->pc_malformed_pictures[P_CODING_TYPE],
349              p_vpar->pc_malformed_pictures[B_CODING_TYPE] );
350 #define S   p_vpar->sequence
351     msg_Dbg( p_vpar->p_fifo, "%s stream (%dx%d), %d.%d pi/s",
352              S.b_mpeg2 ? "MPEG-2" : "MPEG-1",
353              S.i_width, S.i_height, S.i_frame_rate/1001,
354              S.i_frame_rate % 1001 );
355     msg_Dbg( p_vpar->p_fifo, "%s, %s, matrix_coeff: %d",
356              S.b_progressive ? "Progressive" : "Non-progressive",
357              S.i_scalable_mode ? "scalable" : "non-scalable",
358              S.i_matrix_coefficients );
359 #undef S
360
361     /* Dispose of matrices if they have been allocated. */
362     if( p_vpar->sequence.intra_quant.b_allocated )
363     {
364         free( p_vpar->sequence.intra_quant.pi_matrix );
365     }
366     if( p_vpar->sequence.nonintra_quant.b_allocated )
367     {
368         free( p_vpar->sequence.nonintra_quant.pi_matrix) ;
369     }
370     if( p_vpar->sequence.chroma_intra_quant.b_allocated )
371     {
372         free( p_vpar->sequence.chroma_intra_quant.pi_matrix );
373     }
374     if( p_vpar->sequence.chroma_nonintra_quant.b_allocated )
375     {
376         free( p_vpar->sequence.chroma_nonintra_quant.pi_matrix );
377     }
378
379     vpar_EndPool( p_vpar );
380
381     module_Unneed( p_vpar->p_fifo, p_vpar->p_idct );
382     module_Unneed( p_vpar->p_fifo, p_vpar->p_motion );
383
384     CloseBitstream( &p_vpar->bit_stream );
385     free( p_vpar );
386 }
387
388 /*****************************************************************************
389  * BitstreamCallback: Import parameters from the new data/PES packet
390  *****************************************************************************
391  * This function is called by input's NextDataPacket.
392  *****************************************************************************/
393 static void BitstreamCallback ( bit_stream_t * p_bit_stream,
394                                 vlc_bool_t b_new_pes )
395 {
396     vpar_thread_t * p_vpar = (vpar_thread_t *)p_bit_stream->p_callback_arg;
397
398     if( b_new_pes )
399     {
400         p_vpar->sequence.i_current_rate =
401             p_bit_stream->p_pes->i_rate;
402
403         if( p_bit_stream->p_pes->b_discontinuity )
404         {
405             /* Escape the current picture and reset the picture predictors. */
406             p_vpar->sequence.b_expect_discontinuity = 1;
407             p_vpar->picture.b_error = 1;
408         }
409     }
410
411     if( p_bit_stream->p_data->b_discard_payload )
412     {
413         /* 1 packet messed up, trash the slice. */
414         p_vpar->picture.b_error = 1;
415     }
416 }