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