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