]> git.sesse.net Git - vlc/blob - plugins/mpeg_vdec/video_parser.c
* Removed unused code (intf_channels.c, keystrokes.h).
[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.7 2001/12/10 04:53:11 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 #define MODULE_NAME mpeg_vdec
26 #include "modules_inner.h"
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include "defs.h"
32
33 #include <stdlib.h>                                      /* malloc(), free() */
34
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>                                              /* getpid() */
37 #endif
38
39 #include <errno.h>
40 #include <string.h>
41
42 #ifdef HAVE_SYS_TIMES_H
43 #   include <sys/times.h>
44 #endif
45
46 #include "common.h"
47 #include "intf_msg.h"
48 #include "threads.h"
49 #include "mtime.h"
50
51 #include "video.h"
52 #include "video_output.h"
53
54 #include "stream_control.h"
55 #include "input_ext-dec.h"
56
57 #include "vdec_ext-plugins.h"
58 #include "vpar_pool.h"
59 #include "video_parser.h"
60
61 #include "modules.h"
62 #include "modules_export.h"
63
64 /*
65  * Local prototypes
66  */
67 static int      mpeg_vdec_Probe         ( probedata_t * );
68 static int      mpeg_vdec_Run           ( decoder_config_t * );
69 static int      mpeg_vdec_Init          ( vpar_thread_t * );
70 static void     mpeg_vdec_ErrorThread   ( vpar_thread_t * );
71 static void     mpeg_vdec_EndThread     ( vpar_thread_t * );
72 static void     BitstreamCallback       ( bit_stream_t *, boolean_t );
73
74 /*****************************************************************************
75  * Capabilities
76  *****************************************************************************/
77 void _M( vdec_getfunctions )( function_list_t * p_function_list )
78 {
79     p_function_list->pf_probe = mpeg_vdec_Probe;
80     p_function_list->functions.dec.pf_run = mpeg_vdec_Run;
81 }
82
83 /*****************************************************************************
84  * Build configuration tree.
85  *****************************************************************************/
86 MODULE_CONFIG_START
87 ADD_WINDOW( "Configuration for MPEG video decoder module" )
88     ADD_COMMENT( "Nothing to configure" )
89 MODULE_CONFIG_STOP
90
91 MODULE_INIT_START
92     p_module->i_capabilities = MODULE_CAPABILITY_DEC;
93     p_module->psz_longname = "MPEG I/II video decoder module";
94 MODULE_INIT_STOP
95
96 MODULE_ACTIVATE_START
97     _M( vdec_getfunctions )( &p_module->p_functions->dec );
98 MODULE_ACTIVATE_STOP
99
100 MODULE_DEACTIVATE_START
101 MODULE_DEACTIVATE_STOP
102
103
104 /*****************************************************************************
105  * mpeg_vdec_Probe: probe the decoder and return score
106  *****************************************************************************
107  * Tries to launch a decoder and return score so that the interface is able 
108  * to chose.
109  *****************************************************************************/
110 static int mpeg_vdec_Probe( probedata_t *p_data )
111 {
112     if( p_data->i_type == MPEG1_VIDEO_ES || p_data->i_type == MPEG2_VIDEO_ES )
113         return( 50 );
114     else
115         return( 0 );
116 }
117
118 /*****************************************************************************
119  * mpeg_vdec_Run: this function is called just after the thread is created
120  *****************************************************************************/
121 static int mpeg_vdec_Run ( decoder_config_t * p_config )
122 {
123     vpar_thread_t *     p_vpar;
124     boolean_t           b_error;
125
126     intf_DbgMsg( "vpar debug: video parser thread created. Initializing..." );
127
128     /* Allocate the memory needed to store the thread's structure */
129     if ( (p_vpar = (vpar_thread_t *)malloc( sizeof(vpar_thread_t) )) == NULL )
130     {
131         intf_ErrMsg( "vpar error: not enough memory "
132                      "for vpar_CreateThread() to create the new thread");
133         return( -1 );
134     }
135
136     /*
137      * Initialize the thread properties
138      */
139     p_vpar->p_fifo = p_config->p_decoder_fifo;
140     p_vpar->p_config = p_config;
141     p_vpar->p_vout = NULL;
142
143     /*
144      * Initialize thread
145      */
146     p_vpar->p_fifo->b_error = mpeg_vdec_Init( p_vpar );
147      
148     /*
149      * Main loop - it is not executed if an error occured during
150      * initialization
151      */
152     while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) )
153     {
154         /* Find the next sequence header in the stream */
155         p_vpar->p_fifo->b_error = vpar_NextSequenceHeader( p_vpar );
156
157         while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) )
158         {
159             p_vpar->c_loops++;
160
161             /* Parse the next sequence, group or picture header */
162             if( vpar_ParseHeader( p_vpar ) )
163             {
164                 /* End of sequence */
165                 break;
166             }
167         }
168     }
169
170     /*
171      * Error loop
172      */
173     if( ( b_error = p_vpar->p_fifo->b_error ) )
174     {
175         mpeg_vdec_ErrorThread( p_vpar );
176     }
177
178     /* End of thread */
179     mpeg_vdec_EndThread( p_vpar );
180
181     if( b_error )
182     {
183         return( -1 );
184     }
185    
186     return( 0 );
187     
188
189
190 /*****************************************************************************
191  * mpeg_vdec_Init: initialize vpar output thread
192  *****************************************************************************
193  * This function is called from mpeg_vdec_Run and performs the second step 
194  * of the initialization. It returns 0 on success. Note that the thread's 
195  * flag are not modified inside this function.
196  *****************************************************************************/
197 static int mpeg_vdec_Init( vpar_thread_t *p_vpar )
198 {
199     /*
200      * Choose the best motion compensation module
201      */
202     p_vpar->p_motion_module = module_Need( MODULE_CAPABILITY_MOTION, NULL );
203
204     if( p_vpar->p_motion_module == NULL )
205     {
206         intf_ErrMsg( "vpar error: no suitable motion compensation module" );
207         free( p_vpar );
208         return( -1 );
209     }
210
211 #define f ( p_vpar->p_motion_module->p_functions->motion.functions.motion )
212     memcpy( p_vpar->pool.ppppf_motion, f.ppppf_motion, sizeof(void *) * 16 );
213 #undef f
214
215     /*
216      * Choose the best IDCT module
217      */
218     p_vpar->p_idct_module = module_Need( MODULE_CAPABILITY_IDCT, NULL );
219
220     if( p_vpar->p_idct_module == NULL )
221     {
222         intf_ErrMsg( "vpar error: no suitable IDCT module" );
223         module_Unneed( p_vpar->p_motion_module );
224         free( p_vpar );
225         return( -1 );
226     }
227
228 #define f p_vpar->p_idct_module->p_functions->idct.functions.idct
229     p_vpar->pool.pf_idct_init   = f.pf_idct_init;
230     p_vpar->pf_sparse_idct_add  = f.pf_sparse_idct_add;
231     p_vpar->pf_idct_add         = f.pf_idct_add;
232     p_vpar->pf_sparse_idct_copy = f.pf_sparse_idct_copy;
233     p_vpar->pf_idct_copy        = f.pf_idct_copy;
234     p_vpar->pf_norm_scan        = f.pf_norm_scan;
235 #undef f
236
237     /* Initialize input bitstream */
238     p_vpar->p_config->pf_init_bit_stream( &p_vpar->bit_stream,
239         p_vpar->p_config->p_decoder_fifo, BitstreamCallback,
240         (void *)p_vpar );
241
242     /* Initialize parsing data */
243     p_vpar->sequence.p_forward = NULL;
244     p_vpar->sequence.p_backward = NULL;
245     p_vpar->sequence.intra_quant.b_allocated = 0;
246     p_vpar->sequence.nonintra_quant.b_allocated = 0;
247     p_vpar->sequence.chroma_intra_quant.b_allocated = 0;
248     p_vpar->sequence.chroma_nonintra_quant.b_allocated = 0;
249     p_vpar->sequence.i_matrix_coefficients = 1;
250     p_vpar->sequence.next_pts = p_vpar->sequence.next_dts = 0;
251     p_vpar->sequence.b_expect_discontinuity = 0;
252
253     /* Initialize copyright information */
254     p_vpar->sequence.b_copyright_flag = 0;
255     p_vpar->sequence.b_original = 0;
256     p_vpar->sequence.i_copyright_id = 0;
257     p_vpar->sequence.i_copyright_nb = 0;
258
259     p_vpar->picture.p_picture = NULL;
260     p_vpar->picture.i_current_structure = 0;
261
262     /* Initialize other properties */
263     p_vpar->c_loops = 0;
264     p_vpar->c_sequences = 0;
265     memset(p_vpar->pc_pictures, 0, sizeof(p_vpar->pc_pictures));
266     memset(p_vpar->pc_decoded_pictures, 0, sizeof(p_vpar->pc_decoded_pictures));
267     memset(p_vpar->pc_malformed_pictures, 0,
268            sizeof(p_vpar->pc_malformed_pictures));
269     vpar_InitScanTable( p_vpar );
270
271     /*
272      * Initialize the synchro properties
273      */
274     vpar_SynchroInit( p_vpar );
275
276     /* Spawn optional video decoder threads */
277     vpar_InitPool( p_vpar );
278
279     /* Mark thread as running and return */
280     intf_DbgMsg("vpar debug: mpeg_vdec_Init(%p) succeeded", p_vpar);
281     return( 0 );
282 }
283
284 /*****************************************************************************
285  * mpeg_vdec_ErrorThread: RunThread() error loop
286  *****************************************************************************
287  * This function is called when an error occured during thread main's loop. The
288  * thread can still receive feed, but must be ready to terminate as soon as
289  * possible.
290  *****************************************************************************/
291 static void mpeg_vdec_ErrorThread( vpar_thread_t *p_vpar )
292 {
293     /* We take the lock, because we are going to read/write the start/end
294      * indexes of the decoder fifo */
295     vlc_mutex_lock( &p_vpar->p_fifo->data_lock );
296
297     /* Wait until a `die' order is sent */
298     while( !p_vpar->p_fifo->b_die )
299     {
300         /* Trash all received PES packets */
301         while( !DECODER_FIFO_ISEMPTY(*p_vpar->p_fifo) )
302         {
303             p_vpar->p_fifo->pf_delete_pes( p_vpar->p_fifo->p_packets_mgt,
304                                   DECODER_FIFO_START(*p_vpar->p_fifo) );
305             DECODER_FIFO_INCSTART( *p_vpar->p_fifo );
306         }
307
308         /* Waiting for the input thread to put new PES packets in the fifo */
309         vlc_cond_wait( &p_vpar->p_fifo->data_wait, &p_vpar->p_fifo->data_lock );
310     }
311
312     /* We can release the lock before leaving */
313     vlc_mutex_unlock( &p_vpar->p_fifo->data_lock );
314 }
315
316 /*****************************************************************************
317  * mpeg_vdec_EndThread: thread destruction
318  *****************************************************************************
319  * This function is called when the thread ends after a sucessful
320  * initialization.
321  *****************************************************************************/
322 static void mpeg_vdec_EndThread( vpar_thread_t *p_vpar )
323 {
324     intf_DbgMsg("vpar debug: destroying video parser thread %p", p_vpar);
325
326     /* Release used video buffers. */
327     if( p_vpar->sequence.p_forward != NULL )
328     {
329         vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_forward );
330     }
331     if( p_vpar->sequence.p_backward != NULL )
332     {
333         vout_DatePicture( p_vpar->p_vout, p_vpar->sequence.p_backward,
334                           vpar_SynchroDate( p_vpar ) );
335         vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_backward );
336     }
337     if( p_vpar->picture.p_picture != NULL )
338     {
339         vout_DestroyPicture( p_vpar->p_vout, p_vpar->picture.p_picture );
340     }
341
342     if( p_main->b_stats )
343     {
344 #ifdef HAVE_SYS_TIMES_H
345         struct tms cpu_usage;
346         times( &cpu_usage );
347 #endif
348
349         intf_StatMsg( "vpar stats: %d loops among %d sequence(s)",
350                       p_vpar->c_loops, p_vpar->c_sequences );
351
352 #ifdef HAVE_SYS_TIMES_H
353         intf_StatMsg( "vpar stats: cpu usage (user: %d, system: %d)",
354                       cpu_usage.tms_utime, cpu_usage.tms_stime );
355 #endif
356
357         intf_StatMsg( "vpar stats: Read %d frames/fields (I %d/P %d/B %d)",
358                       p_vpar->pc_pictures[I_CODING_TYPE]
359                       + p_vpar->pc_pictures[P_CODING_TYPE]
360                       + p_vpar->pc_pictures[B_CODING_TYPE],
361                       p_vpar->pc_pictures[I_CODING_TYPE],
362                       p_vpar->pc_pictures[P_CODING_TYPE],
363                       p_vpar->pc_pictures[B_CODING_TYPE] );
364         intf_StatMsg( "vpar stats: Decoded %d frames/fields (I %d/P %d/B %d)",
365                       p_vpar->pc_decoded_pictures[I_CODING_TYPE]
366                       + p_vpar->pc_decoded_pictures[P_CODING_TYPE]
367                       + p_vpar->pc_decoded_pictures[B_CODING_TYPE],
368                       p_vpar->pc_decoded_pictures[I_CODING_TYPE],
369                       p_vpar->pc_decoded_pictures[P_CODING_TYPE],
370                       p_vpar->pc_decoded_pictures[B_CODING_TYPE] );
371         intf_StatMsg( "vpar stats: Read %d malformed frames/fields (I %d/P %d/B %d)",
372                       p_vpar->pc_malformed_pictures[I_CODING_TYPE]
373                       + p_vpar->pc_malformed_pictures[P_CODING_TYPE]
374                       + p_vpar->pc_malformed_pictures[B_CODING_TYPE],
375                       p_vpar->pc_malformed_pictures[I_CODING_TYPE],
376                       p_vpar->pc_malformed_pictures[P_CODING_TYPE],
377                       p_vpar->pc_malformed_pictures[B_CODING_TYPE] );
378 #define S   p_vpar->sequence
379         intf_StatMsg( "vpar info: %s stream (%dx%d), %d.%d pi/s",
380                       S.b_mpeg2 ? "MPEG-2" : "MPEG-1",
381                       S.i_width, S.i_height, S.i_frame_rate/1001,
382                       S.i_frame_rate % 1001 );
383         intf_StatMsg( "vpar info: %s, %s, matrix_coeff: %d",
384                       S.b_progressive ? "Progressive" : "Non-progressive",
385                       S.i_scalable_mode ? "scalable" : "non-scalable",
386                       S.i_matrix_coefficients );
387 #undef S
388     }
389
390     /* Dispose of matrices if they have been allocated. */
391     if( p_vpar->sequence.intra_quant.b_allocated )
392     {
393         free( p_vpar->sequence.intra_quant.pi_matrix );
394     }
395     if( p_vpar->sequence.nonintra_quant.b_allocated )
396     {
397         free( p_vpar->sequence.nonintra_quant.pi_matrix) ;
398     }
399     if( p_vpar->sequence.chroma_intra_quant.b_allocated )
400     {
401         free( p_vpar->sequence.chroma_intra_quant.pi_matrix );
402     }
403     if( p_vpar->sequence.chroma_nonintra_quant.b_allocated )
404     {
405         free( p_vpar->sequence.chroma_nonintra_quant.pi_matrix );
406     }
407
408     vpar_EndPool( p_vpar );
409
410     module_Unneed( p_vpar->p_idct_module );
411     module_Unneed( p_vpar->p_motion_module );
412
413     free( p_vpar );
414
415     intf_DbgMsg("vpar debug: EndThread(%p)", p_vpar);
416 }
417
418 /*****************************************************************************
419  * BitstreamCallback: Import parameters from the new data/PES packet
420  *****************************************************************************
421  * This function is called by input's NextDataPacket.
422  *****************************************************************************/
423 static void BitstreamCallback ( bit_stream_t * p_bit_stream,
424                                 boolean_t b_new_pes )
425 {
426     vpar_thread_t * p_vpar = (vpar_thread_t *)p_bit_stream->p_callback_arg;
427
428     if( b_new_pes )
429     {
430         p_vpar->sequence.next_pts =
431             DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_pts;
432         p_vpar->sequence.next_dts =
433             DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_dts;
434         p_vpar->sequence.i_current_rate =
435             DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_rate;
436
437         if( DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->b_discontinuity )
438         {
439 #ifdef TRACE_VPAR
440             intf_DbgMsg( "Discontinuity in BitstreamCallback" );
441 #endif
442             /* Escape the current picture and reset the picture predictors. */
443             p_vpar->sequence.b_expect_discontinuity = 1;
444             p_vpar->picture.b_error = 1;
445         }
446     }
447
448     if( p_bit_stream->p_data->b_discard_payload )
449     {
450 #ifdef TRACE_VPAR
451         intf_DbgMsg( "Discard payload in BitstreamCallback" );
452 #endif
453         /* 1 packet messed up, trash the slice. */
454         p_vpar->picture.b_error = 1;
455     }
456 }