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