]> git.sesse.net Git - vlc/blob - modules/codec/mpeg_video/decoder.c
* ./modules/*: moved plugins to the new tree. Yet untested builds include
[vlc] / modules / codec / mpeg_video / decoder.c
1 /*****************************************************************************
2  * video_decoder.c : video decoder thread
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: decoder.c,v 1.1 2002/08/04 17:23:42 sam Exp $
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *          Michel Lespinasse <walken@zoy.org>
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>                                                /* free() */
29 #include <string.h>                                    /* memcpy(), memset() */
30 #include <errno.h>                                                  /* errno */
31
32 #include <vlc/vlc.h>
33 #include <vlc/vout.h>
34 #include <vlc/decoder.h>
35
36 #ifdef HAVE_UNISTD_H
37 #   include <unistd.h>                                           /* getpid() */
38 #endif
39
40 #include "vdec_ext-plugins.h"
41
42 #include "decoder.h"
43 #include "pool.h"
44 #include "parser.h"
45
46 /*
47  * Local prototypes
48  */
49 static void     RunThread           ( vdec_thread_t *p_vdec );
50
51 /*****************************************************************************
52  * vdec_CreateThread: create a video decoder thread
53  *****************************************************************************
54  * This function creates a new video decoder thread, and returns a pointer
55  * to its description. On error, it returns NULL.
56  *****************************************************************************/
57 vdec_thread_t * vdec_CreateThread( vdec_pool_t * p_pool )
58 {
59     vdec_thread_t *     p_vdec;
60
61     /* Allocate the memory needed to store the thread's structure */
62     p_vdec = vlc_object_create( p_pool->p_vpar->p_fifo, sizeof(vdec_thread_t) );
63     if( p_vdec == NULL )
64     {
65         msg_Err( p_pool->p_vpar->p_fifo, "out of memory" );
66         return NULL;
67     }
68
69     /*
70      * Initialize the parser properties
71      */
72     p_vdec->p_pool = p_pool;
73
74     /* Spawn the video decoder thread */
75     if( vlc_thread_create( p_vdec, "video decoder", RunThread, 0 ) )
76     {
77         msg_Err( p_vdec, "cannot spawn video decoder thread" );
78         vlc_object_destroy( p_vdec );
79         return( NULL );
80     }
81
82     return p_vdec;
83 }
84
85 /*****************************************************************************
86  * vdec_DestroyThread: destroy a video decoder thread
87  *****************************************************************************/
88 void vdec_DestroyThread( vdec_thread_t *p_vdec )
89 {
90     /* Ask thread to kill itself */
91     p_vdec->b_die = 1;
92
93     /* Make sure the decoder thread leaves the vpar_GetMacroblock() function */
94     vlc_mutex_lock( &p_vdec->p_pool->lock );
95     vlc_cond_broadcast( &p_vdec->p_pool->wait_undecoded );
96     vlc_mutex_unlock( &p_vdec->p_pool->lock );
97
98     /* Waiting for the decoder thread to exit */
99     vlc_thread_join( p_vdec );
100
101     /* Free the object */
102     vlc_object_destroy( p_vdec );
103 }
104
105 /* following functions are local */
106
107 /*****************************************************************************
108  * vdec_InitThread: initialize video decoder thread
109  *****************************************************************************
110  * This function is called from RunThread and performs the second step of the
111  * initialization.
112  *****************************************************************************/
113 void vdec_InitThread( vdec_thread_t * p_vdec )
114 {
115     /* Re-nice ourself - otherwise we would steal CPU time from the video
116      * output, which would make a poor display. */
117 #if defined( HAVE_NICE )
118     if( nice(VDEC_NICE) == -1 )
119 #elif defined( WIN32 )
120     if( !SetThreadPriority( GetCurrentThread(),
121                             THREAD_PRIORITY_BELOW_NORMAL ) )
122 #else
123     if( 0 )
124 #endif
125     {
126         msg_Warn( p_vdec, "couldn't nice() (%s)", strerror(errno) );
127     }
128
129     p_vdec->p_idct_data = NULL;
130
131     p_vdec->p_pool->pf_idct_init( &p_vdec->p_idct_data );
132
133     /* Mark thread as running and return */
134 }
135
136 /*****************************************************************************
137  * vdec_EndThread: thread destruction
138  *****************************************************************************
139  * This function is called when the thread ends after a sucessful
140  * initialization.
141  *****************************************************************************/
142 void vdec_EndThread( vdec_thread_t * p_vdec )
143 {
144     if( p_vdec->p_idct_data != NULL )
145     {
146         free( p_vdec->p_idct_data );
147     }
148 }
149
150 /*****************************************************************************
151  * MotionBlock: does one component of the motion compensation
152  *****************************************************************************/
153 static inline void MotionBlock( vdec_pool_t * p_pool, vlc_bool_t b_average,
154                                 int i_x_pred, int i_y_pred,
155                                 yuv_data_t * pp_dest[3], int i_dest_offset,
156                                 yuv_data_t * pp_src[3], int i_src_offset,
157                                 int i_stride, int i_height,
158                                 vlc_bool_t b_second_half, int i_chroma_format )
159 {
160     int             i_xy_half;
161     yuv_data_t *    p_src1;
162     yuv_data_t *    p_src2;
163
164     i_xy_half = ((i_y_pred & 1) << 1) | (i_x_pred & 1);
165
166     p_src1 = pp_src[0] + i_src_offset
167                 + (i_x_pred >> 1) + (i_y_pred >> 1) * i_stride
168                 + b_second_half * (i_stride << 3);
169
170     p_pool->ppppf_motion[b_average][0][i_xy_half]
171             ( pp_dest[0] + i_dest_offset + b_second_half * (i_stride << 3),
172               p_src1, i_stride, i_height );
173
174     if( i_chroma_format != CHROMA_NONE )
175     {
176         /* Expanded at compile-time. */
177         if( i_chroma_format != CHROMA_444 )
178         {
179             i_x_pred /= 2;
180             i_stride >>= 1;
181             i_src_offset >>= 1;
182             i_dest_offset >>= 1;
183         }
184         if( i_chroma_format == CHROMA_420 )
185         {
186             i_y_pred /= 2;
187             i_height >>= 1;
188         }
189
190         i_xy_half = ((i_y_pred & 1) << 1) | (i_x_pred & 1);
191
192         i_src_offset += b_second_half * (i_stride << 3);
193         i_dest_offset += b_second_half * (i_stride << 3);
194
195         p_src1 = pp_src[1] + i_src_offset
196                     + (i_x_pred >> 1) + (i_y_pred >> 1) * i_stride;
197         p_src2 = pp_src[2] + i_src_offset
198                     + (i_x_pred >> 1) + (i_y_pred >> 1) * i_stride;
199
200         p_pool->ppppf_motion[b_average][(i_chroma_format != CHROMA_444)]
201                             [i_xy_half]
202                 ( pp_dest[1] + i_dest_offset, p_src1, i_stride, i_height );
203         p_pool->ppppf_motion[b_average][(i_chroma_format != CHROMA_444)]
204                             [i_xy_half]
205                 ( pp_dest[2] + i_dest_offset, p_src2, i_stride, i_height );
206     }
207 }
208
209
210 /*****************************************************************************
211  * DecodeMacroblock: decode a macroblock
212  *****************************************************************************/
213 #define DECODE_INTRA_BLOCK( i_b, p_dest )                                   \
214     p_idct = &p_mb->p_idcts[i_b];                                           \
215     p_idct->pf_idct( p_idct->pi_block, p_dest,                              \
216                      i_b < 4 ? i_lum_dct_stride : i_chrom_dct_stride,       \
217                      p_vdec->p_idct_data, p_idct->i_sparse_pos );
218
219 #define DECODE_NONINTRA_BLOCK( i_b, p_dest )                                \
220     if( p_mb->i_coded_block_pattern & (1 << (11 - (i_b))) )                 \
221     {                                                                       \
222         DECODE_INTRA_BLOCK( i_b, p_dest );                                  \
223     }
224
225 #define DECLARE_DECODEMB( PSZ_NAME, I_CHROMA )                              \
226 void PSZ_NAME ( vdec_thread_t *p_vdec, macroblock_t * p_mb )                \
227 {                                                                           \
228     int             i, i_lum_dct_offset, i_lum_dct_stride;                  \
229     int             i_chrom_dct_offset, i_chrom_dct_stride;                 \
230     idct_inner_t *  p_idct;                                                 \
231     vdec_pool_t *   p_pool = p_vdec->p_pool;                                \
232     vpar_thread_t * p_vpar = p_pool->p_vpar;                                \
233                                                                             \
234     if( p_mb->i_mb_modes & DCT_TYPE_INTERLACED )                            \
235     {                                                                       \
236         i_lum_dct_offset = p_vpar->picture.i_lum_stride;                    \
237         i_lum_dct_stride = p_vpar->picture.i_lum_stride * 2;                \
238     }                                                                       \
239     else                                                                    \
240     {                                                                       \
241         i_lum_dct_offset = p_vpar->picture.i_lum_stride * 8;                \
242         i_lum_dct_stride = p_vpar->picture.i_lum_stride;                    \
243     }                                                                       \
244                                                                             \
245     i_chrom_dct_offset = p_vpar->picture.i_chrom_stride * 8;                \
246     i_chrom_dct_stride = p_vpar->picture.i_chrom_stride;                    \
247                                                                             \
248     if( !(p_mb->i_mb_modes & MB_INTRA) )                                    \
249     {                                                                       \
250         /*                                                                  \
251          * Motion Compensation (ISO/IEC 13818-2 section 7.6)                \
252          */                                                                 \
253         for( i = 0; i < p_mb->i_nb_motions; i++ )                           \
254         {                                                                   \
255             motion_inner_t *    p_motion = &p_mb->p_motions[i];             \
256             MotionBlock( p_pool, p_motion->b_average,                       \
257                          p_motion->i_x_pred, p_motion->i_y_pred,            \
258                          p_mb->pp_dest, p_motion->i_dest_offset,            \
259                          p_motion->pp_source, p_motion->i_src_offset,       \
260                          p_motion->i_stride, p_motion->i_height,            \
261                          p_motion->b_second_half, I_CHROMA );               \
262         }                                                                   \
263                                                                             \
264         /*                                                                  \
265          * Inverse DCT (ISO/IEC 13818-2 section Annex A) and                \
266          * adding prediction and coefficient data (ISO/IEC                  \
267          * 13818-2 section 7.6.8)                                           \
268          */                                                                 \
269         DECODE_NONINTRA_BLOCK( 0, p_mb->p_y_data );                         \
270         DECODE_NONINTRA_BLOCK( 1, p_mb->p_y_data + 8 );                     \
271         DECODE_NONINTRA_BLOCK( 2, p_mb->p_y_data + i_lum_dct_offset );      \
272         DECODE_NONINTRA_BLOCK( 3, p_mb->p_y_data + i_lum_dct_offset + 8 );  \
273         if( I_CHROMA != CHROMA_NONE )                                       \
274         {                                                                   \
275             DECODE_NONINTRA_BLOCK( 4, p_mb->p_u_data );                     \
276             DECODE_NONINTRA_BLOCK( 5, p_mb->p_v_data );                     \
277             if( I_CHROMA != CHROMA_420 )                                    \
278             {                                                               \
279                 DECODE_NONINTRA_BLOCK( 6, p_mb->p_u_data                    \
280                                            + i_chrom_dct_offset );          \
281                 DECODE_NONINTRA_BLOCK( 7, p_mb->p_v_data                    \
282                                            + i_chrom_dct_offset );          \
283                 if( I_CHROMA == CHROMA_444 )                                \
284                 {                                                           \
285                     DECODE_NONINTRA_BLOCK( 8, p_mb->p_u_data + 8 );         \
286                     DECODE_NONINTRA_BLOCK( 9, p_mb->p_v_data + 8 );         \
287                     DECODE_NONINTRA_BLOCK( 10, p_mb->p_u_data + 8           \
288                                            + i_chrom_dct_offset );          \
289                     DECODE_NONINTRA_BLOCK( 11, p_mb->p_v_data + 8           \
290                                            + i_chrom_dct_offset );          \
291                 }                                                           \
292             }                                                               \
293         }                                                                   \
294     }                                                                       \
295     else                                                                    \
296     {                                                                       \
297         /* Intra macroblock */                                              \
298         DECODE_INTRA_BLOCK( 0, p_mb->p_y_data );                            \
299         DECODE_INTRA_BLOCK( 1, p_mb->p_y_data + 8 );                        \
300         DECODE_INTRA_BLOCK( 2, p_mb->p_y_data + i_lum_dct_offset );         \
301         DECODE_INTRA_BLOCK( 3, p_mb->p_y_data + i_lum_dct_offset + 8 );     \
302         if( I_CHROMA != CHROMA_NONE )                                       \
303         {                                                                   \
304             DECODE_INTRA_BLOCK( 4, p_mb->p_u_data );                        \
305             DECODE_INTRA_BLOCK( 5, p_mb->p_v_data );                        \
306             if( I_CHROMA != CHROMA_420 )                                    \
307             {                                                               \
308                 DECODE_INTRA_BLOCK( 6, p_mb->p_u_data                       \
309                                         + i_chrom_dct_offset );             \
310                 DECODE_INTRA_BLOCK( 7, p_mb->p_v_data                       \
311                                         + i_chrom_dct_offset );             \
312                 if( I_CHROMA == CHROMA_444 )                                \
313                 {                                                           \
314                     DECODE_INTRA_BLOCK( 8, p_mb->p_u_data + 8 );            \
315                     DECODE_INTRA_BLOCK( 9, p_mb->p_v_data + 8 );            \
316                     DECODE_INTRA_BLOCK( 10, p_mb->p_u_data + 8              \
317                                            + i_chrom_dct_offset );          \
318                     DECODE_INTRA_BLOCK( 11, p_mb->p_v_data + 8              \
319                                            + i_chrom_dct_offset );          \
320                 }                                                           \
321             }                                                               \
322         }                                                                   \
323     }                                                                       \
324 }
325
326 DECLARE_DECODEMB( vdec_DecodeMacroblockBW, CHROMA_NONE );
327 DECLARE_DECODEMB( vdec_DecodeMacroblock420, CHROMA_420 );
328 DECLARE_DECODEMB( vdec_DecodeMacroblock422, CHROMA_422 );
329 DECLARE_DECODEMB( vdec_DecodeMacroblock444, CHROMA_444 );
330
331 #undef DECLARE_DECODEMB
332
333 /*****************************************************************************
334  * RunThread: video decoder thread
335  *****************************************************************************
336  * Video decoder thread. This function does only return when the thread is
337  * terminated.
338  *****************************************************************************/
339 static void RunThread( vdec_thread_t *p_vdec )
340 {
341     vdec_InitThread( p_vdec );
342
343     /*
344      * Main loop
345      */
346     while( !p_vdec->b_die )
347     {
348         macroblock_t *          p_mb;
349
350         if( (p_mb = vpar_GetMacroblock( p_vdec->p_pool, &p_vdec->b_die )) != NULL )
351         {
352             p_vdec->p_pool->pf_vdec_decode( p_vdec, p_mb );
353
354             /* Decoding is finished, release the macroblock and free
355              * unneeded memory. */
356             p_vdec->p_pool->pf_free_mb( p_vdec->p_pool, p_mb );
357         }
358     }
359
360     /* End of thread */
361     vdec_EndThread( p_vdec );
362 }
363