]> git.sesse.net Git - vlc/blob - src/video_decoder/video_parser.c
* Totally rewrote the video decoder (inspired by walken's mpeg2dec), implying :
[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.4 2001/08/22 17:21:45 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      = f.pf_sparse_idct;
157     p_vpar->pf_idct             = f.pf_idct;
158     p_vpar->pf_norm_scan        = f.pf_norm_scan;
159     p_vpar->pool.pf_decode_init = f.pf_decode_init;
160     p_vpar->pool.pf_addblock    = f.pf_addblock;
161     p_vpar->pool.pf_copyblock   = f.pf_copyblock;
162 #undef f
163
164     /* Initialize input bitstream */
165     p_vpar->p_config->decoder_config.pf_init_bit_stream( &p_vpar->bit_stream,
166         p_vpar->p_config->decoder_config.p_decoder_fifo, BitstreamCallback,
167         (void *)p_vpar );
168
169     /* Initialize parsing data */
170     p_vpar->sequence.p_forward = NULL;
171     p_vpar->sequence.p_backward = NULL;
172     p_vpar->sequence.intra_quant.b_allocated = 0;
173     p_vpar->sequence.nonintra_quant.b_allocated = 0;
174     p_vpar->sequence.chroma_intra_quant.b_allocated = 0;
175     p_vpar->sequence.chroma_nonintra_quant.b_allocated = 0;
176     p_vpar->sequence.i_matrix_coefficients = 1;
177     p_vpar->sequence.next_pts = p_vpar->sequence.next_dts = 0;
178     p_vpar->sequence.b_expect_discontinuity = 0;
179
180     /* Initialize copyright information */
181     p_vpar->sequence.b_copyright_flag = 0;
182     p_vpar->sequence.b_original = 0;
183     p_vpar->sequence.i_copyright_id = 0;
184     p_vpar->sequence.i_copyright_nb = 0;
185
186     p_vpar->picture.p_picture = NULL;
187     p_vpar->picture.i_current_structure = 0;
188
189     /* Initialize other properties */
190 #ifdef STATS
191     p_vpar->c_loops = 0;
192     p_vpar->c_sequences = 0;
193     memset(p_vpar->pc_pictures, 0, sizeof(p_vpar->pc_pictures));
194     memset(p_vpar->pc_decoded_pictures, 0, sizeof(p_vpar->pc_decoded_pictures));
195     memset(p_vpar->pc_malformed_pictures, 0,
196            sizeof(p_vpar->pc_malformed_pictures));
197 #endif
198     vpar_InitScanTable( p_vpar );
199
200     /*
201      * Initialize the synchro properties
202      */
203     vpar_SynchroInit( p_vpar );
204
205     /* Spawn optional video decoder threads */
206     vpar_InitPool( p_vpar );
207
208     /* Mark thread as running and return */
209     intf_DbgMsg("vpar debug: InitThread(%p) succeeded", p_vpar);
210     return( 0 );
211 }
212
213 /*****************************************************************************
214  * RunThread: generic parser thread
215  *****************************************************************************
216  * Video parser thread. This function only returns when the thread is
217  * terminated.
218  *****************************************************************************/
219 static void RunThread( vpar_thread_t *p_vpar )
220 {
221     intf_DbgMsg("vpar debug: running video parser thread (%p) (pid == %i)", p_vpar, getpid());
222
223     /*
224      * Initialize thread
225      */
226     p_vpar->p_fifo->b_error = InitThread( p_vpar );
227
228     /*
229      * Main loop - it is not executed if an error occured during
230      * initialization
231      */
232     while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) )
233     {
234         /* Find the next sequence header in the stream */
235         p_vpar->p_fifo->b_error = vpar_NextSequenceHeader( p_vpar );
236
237         while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) )
238         {
239 #ifdef STATS
240             p_vpar->c_loops++;
241 #endif
242             /* Parse the next sequence, group or picture header */
243             if( vpar_ParseHeader( p_vpar ) )
244             {
245                 /* End of sequence */
246                 break;
247             }
248         }
249     }
250
251     /*
252      * Error loop
253      */
254     if( p_vpar->p_fifo->b_error )
255     {
256         ErrorThread( p_vpar );
257     }
258
259     /* End of thread */
260     EndThread( p_vpar );
261 }
262
263 /*****************************************************************************
264  * ErrorThread: RunThread() error loop
265  *****************************************************************************
266  * This function is called when an error occured during thread main's loop. The
267  * thread can still receive feed, but must be ready to terminate as soon as
268  * possible.
269  *****************************************************************************/
270 static void ErrorThread( vpar_thread_t *p_vpar )
271 {
272     /* We take the lock, because we are going to read/write the start/end
273      * indexes of the decoder fifo */
274     vlc_mutex_lock( &p_vpar->p_fifo->data_lock );
275
276     /* Wait until a `die' order is sent */
277     while( !p_vpar->p_fifo->b_die )
278     {
279         /* Trash all received PES packets */
280         while( !DECODER_FIFO_ISEMPTY(*p_vpar->p_fifo) )
281         {
282             p_vpar->p_fifo->pf_delete_pes( p_vpar->p_fifo->p_packets_mgt,
283                                   DECODER_FIFO_START(*p_vpar->p_fifo) );
284             DECODER_FIFO_INCSTART( *p_vpar->p_fifo );
285         }
286
287         /* Waiting for the input thread to put new PES packets in the fifo */
288         vlc_cond_wait( &p_vpar->p_fifo->data_wait, &p_vpar->p_fifo->data_lock );
289     }
290
291     /* We can release the lock before leaving */
292     vlc_mutex_unlock( &p_vpar->p_fifo->data_lock );
293 }
294
295 /*****************************************************************************
296  * EndThread: thread destruction
297  *****************************************************************************
298  * This function is called when the thread ends after a sucessful
299  * initialization.
300  *****************************************************************************/
301 static void EndThread( vpar_thread_t *p_vpar )
302 {
303     intf_DbgMsg("vpar debug: destroying video parser thread %p", p_vpar);
304
305     /* Release used video buffers. */
306     if( p_vpar->sequence.p_forward != NULL )
307     {
308         vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_forward );
309     }
310     if( p_vpar->sequence.p_backward != NULL )
311     {
312         vout_DatePicture( p_vpar->p_vout, p_vpar->sequence.p_backward,
313                           vpar_SynchroDate( p_vpar ) );
314         vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_backward );
315     }
316     if( p_vpar->picture.p_picture != NULL )
317     {
318         vout_DestroyPicture( p_vpar->p_vout, p_vpar->picture.p_picture );
319     }
320
321 #ifdef STATS
322     intf_Msg("vpar stats: %d loops among %d sequence(s)",
323              p_vpar->c_loops, p_vpar->c_sequences);
324
325     {
326         struct tms cpu_usage;
327         times( &cpu_usage );
328
329         intf_Msg("vpar stats: cpu usage (user: %d, system: %d)",
330                  cpu_usage.tms_utime, cpu_usage.tms_stime);
331     }
332
333     intf_Msg("vpar stats: Read %d frames/fields (I %d/P %d/B %d)",
334              p_vpar->pc_pictures[I_CODING_TYPE]
335              + p_vpar->pc_pictures[P_CODING_TYPE]
336              + p_vpar->pc_pictures[B_CODING_TYPE],
337              p_vpar->pc_pictures[I_CODING_TYPE],
338              p_vpar->pc_pictures[P_CODING_TYPE],
339              p_vpar->pc_pictures[B_CODING_TYPE]);
340     intf_Msg("vpar stats: Decoded %d frames/fields (I %d/P %d/B %d)",
341              p_vpar->pc_decoded_pictures[I_CODING_TYPE]
342              + p_vpar->pc_decoded_pictures[P_CODING_TYPE]
343              + p_vpar->pc_decoded_pictures[B_CODING_TYPE],
344              p_vpar->pc_decoded_pictures[I_CODING_TYPE],
345              p_vpar->pc_decoded_pictures[P_CODING_TYPE],
346              p_vpar->pc_decoded_pictures[B_CODING_TYPE]);
347     intf_Msg("vpar stats: Read %d malformed frames/fields (I %d/P %d/B %d)",
348              p_vpar->pc_malformed_pictures[I_CODING_TYPE]
349              + p_vpar->pc_malformed_pictures[P_CODING_TYPE]
350              + p_vpar->pc_malformed_pictures[B_CODING_TYPE],
351              p_vpar->pc_malformed_pictures[I_CODING_TYPE],
352              p_vpar->pc_malformed_pictures[P_CODING_TYPE],
353              p_vpar->pc_malformed_pictures[B_CODING_TYPE]);
354 #define S   p_vpar->sequence
355     intf_Msg("vpar info: %s stream (%dx%d), %d.%d pi/s",
356              S.b_mpeg2 ? "MPEG-2" : "MPEG-1",
357              S.i_width, S.i_height, S.i_frame_rate/1001, S.i_frame_rate % 1001);
358     intf_Msg("vpar info: %s, %s, matrix_coeff: %d",
359              S.b_progressive ? "Progressive" : "Non-progressive",
360              S.i_scalable_mode ? "scalable" : "non-scalable",
361              S.i_matrix_coefficients);
362 #endif
363
364     /* Dispose of matrices if they have been allocated. */
365     if( p_vpar->sequence.intra_quant.b_allocated )
366     {
367         free( p_vpar->sequence.intra_quant.pi_matrix );
368     }
369     if( p_vpar->sequence.nonintra_quant.b_allocated )
370     {
371         free( p_vpar->sequence.nonintra_quant.pi_matrix) ;
372     }
373     if( p_vpar->sequence.chroma_intra_quant.b_allocated )
374     {
375         free( p_vpar->sequence.chroma_intra_quant.pi_matrix );
376     }
377     if( p_vpar->sequence.chroma_nonintra_quant.b_allocated )
378     {
379         free( p_vpar->sequence.chroma_nonintra_quant.pi_matrix );
380     }
381
382     vpar_EndPool( p_vpar );
383
384     free( p_vpar->p_config );
385
386     module_Unneed( p_vpar->p_idct_module );
387     module_Unneed( p_vpar->p_motion_module );
388
389     free( p_vpar );
390
391     intf_DbgMsg("vpar debug: EndThread(%p)", p_vpar);
392 }
393
394 /*****************************************************************************
395  * BitstreamCallback: Import parameters from the new data/PES packet
396  *****************************************************************************
397  * This function is called by input's NextDataPacket.
398  *****************************************************************************/
399 static void BitstreamCallback ( bit_stream_t * p_bit_stream,
400                                 boolean_t b_new_pes )
401 {
402     vpar_thread_t * p_vpar = (vpar_thread_t *)p_bit_stream->p_callback_arg;
403
404     if( b_new_pes )
405     {
406         p_vpar->sequence.next_pts =
407             DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_pts;
408         p_vpar->sequence.next_dts =
409             DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_dts;
410         p_vpar->sequence.i_current_rate =
411             DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_rate;
412
413         if( DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->b_discontinuity )
414         {
415 #ifdef TRACE_VPAR
416             intf_DbgMsg( "Discontinuity in BitstreamCallback" );
417 #endif
418             /* Escape the current picture and reset the picture predictors. */
419             p_vpar->sequence.b_expect_discontinuity = 1;
420             p_vpar->picture.b_error = 1;
421         }
422     }
423
424     if( p_bit_stream->p_data->b_discard_payload )
425     {
426 #ifdef TRACE_VPAR
427         intf_DbgMsg( "Discard payload in BitstreamCallback" );
428 #endif
429         /* 1 packet messed up, trash the slice. */
430         p_vpar->picture.b_error = 1;
431     }
432 }