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