]> git.sesse.net Git - vlc/blob - modules/codec/xvid.c
Add RV16 rendering. With transparancy, but still only Y plane is done.
[vlc] / modules / codec / xvid.c
1 /*****************************************************************************
2  * xvid.c: a decoder for libxvidcore, the Xvid video codec
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: xvid.c,v 1.8 2003/11/22 23:39:14 fenrir Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <vlc/vlc.h>
28 #include <vlc/vout.h>
29 #include <vlc/decoder.h>
30
31 #include "codecs.h"
32
33 #include <xvid.h>
34
35 /*****************************************************************************
36  * Local prototypes
37  *****************************************************************************/
38 static int RunDecoder  ( decoder_fifo_t * );
39 static int OpenDecoder ( vlc_object_t * );
40
41 /*****************************************************************************
42  * Module descriptor
43  *****************************************************************************/
44 vlc_module_begin();
45     set_description( _("Xvid video decoder") );
46     set_capability( "decoder", 50 );
47     set_callbacks( OpenDecoder, NULL );
48     add_bool( "xvid-direct-render", 0, NULL, "direct rendering",
49               "Use libxvidcore's direct rendering feature.", VLC_TRUE );
50 vlc_module_end();
51
52 /*****************************************************************************
53  * OpenDecoder: probe the decoder and return score
54  *****************************************************************************
55  * FIXME: find fourcc formats supported by xvid
56  *****************************************************************************/
57 static int OpenDecoder ( vlc_object_t *p_this )
58 {
59     decoder_t *p_dec = (decoder_t*)p_this;
60
61     if( p_dec->fmt_in.i_codec != VLC_FOURCC('x','v','i','d')
62          && p_dec->fmt_in.i_codec != VLC_FOURCC('X','V','I','D')
63          && p_dec->fmt_in.i_codec != VLC_FOURCC('D','I','V','X') )
64     {
65         return VLC_EGENERIC;
66     }
67
68     p_dec->pf_run = RunDecoder;
69     return VLC_SUCCESS;
70 }
71
72 /*****************************************************************************
73  * RunDecoder: this function is called just after the thread is created
74  *****************************************************************************/
75 static int RunDecoder ( decoder_fifo_t *p_fifo )
76 {
77     XVID_INIT_PARAM    xinit;
78     XVID_DEC_PARAM     xparam;
79     BITMAPINFOHEADER * p_format;
80     void *             p_xvid;
81
82     pes_packet_t *     p_pes = NULL;
83     bit_stream_t       bit_stream;
84     vout_thread_t *    p_vout;
85
86     uint8_t *  p_buffer, * p_image;
87     int        i_ret;
88     int        i_width, i_height, i_chroma, i_aspect;
89     int        i_size, i_offset, i_image_size;
90
91     vlc_bool_t b_direct = config_GetInt( p_fifo, "xvid-direct-render" );
92
93     if( InitBitstream( &bit_stream, p_fifo, NULL, NULL ) != VLC_SUCCESS )
94     {
95         msg_Err( p_fifo, "cannot initialise bitstream" );
96         p_fifo->b_error = VLC_TRUE;
97         DecoderError( p_fifo );
98         return VLC_EGENERIC;
99     }
100     if( ( p_format = (BITMAPINFOHEADER *)p_fifo->p_bitmapinfoheader ) == NULL )
101     {
102         i_width  = 1;
103         i_height = 1;   // avoid segfault anyway it's wrong
104     }
105     else
106     {
107         /* Guess picture properties from the BIH */
108         i_width = p_format->biWidth;
109         i_height = p_format->biHeight;
110     }
111
112     i_chroma = VLC_FOURCC('Y','V','1','2');
113     i_aspect = VOUT_ASPECT_FACTOR * i_width / i_height;
114
115     /* XXX: Completely arbitrary buffer size */
116     i_size = i_width * i_height / 4;
117     i_image_size = b_direct ? 0 : i_width * i_height * 4;
118     i_offset = 0;
119
120     p_buffer = malloc( i_size + i_image_size );
121     p_image = p_buffer + i_size;
122
123     if( !p_buffer )
124     {
125         msg_Err( p_fifo, "out of memory" );
126         p_fifo->b_error = VLC_TRUE;
127         CloseBitstream( &bit_stream );
128         DecoderError( p_fifo );
129         return VLC_EGENERIC;
130     }
131
132     xinit.cpu_flags = 0;
133     xvid_init( NULL, 0, &xinit, NULL );
134
135     xparam.width = i_width;
136     xparam.height = i_height;
137     i_ret = xvid_decore( NULL, XVID_DEC_CREATE, &xparam, NULL );
138
139     if( i_ret )
140     {
141         msg_Err( p_fifo, "cannot create xvid decoder" );
142         p_fifo->b_error = VLC_TRUE;
143         free( p_buffer );
144         CloseBitstream( &bit_stream );
145         DecoderError( p_fifo );
146         return VLC_EGENERIC;
147     }
148
149     p_xvid = xparam.handle;
150
151     /* Spawn a video output if there is none. First we look amongst our
152      * children, then we look for any other vout that might be available */
153     p_vout = vout_Request( p_fifo, NULL,
154                            i_width, i_height, i_chroma, i_aspect );
155
156     if( !p_vout )
157     {
158         msg_Err( p_fifo, "could not spawn vout" );
159         p_fifo->b_error = VLC_TRUE;
160         xvid_decore( p_xvid, XVID_DEC_DESTROY, NULL, NULL );
161         free( p_buffer );
162         CloseBitstream( &bit_stream );
163         DecoderError( p_fifo );
164         return VLC_EGENERIC;
165     }
166
167     /* Main loop */
168     while( !p_fifo->b_die && !p_fifo->b_error )
169     {
170         XVID_DEC_FRAME xframe;
171         XVID_DEC_PICTURE xpic;
172         mtime_t i_pts = 0;
173         picture_t *p_pic;
174
175         GetChunk( &bit_stream, p_buffer + i_offset, i_size - i_offset );
176
177         if( p_pes )
178         {
179             input_DeletePES( p_fifo->p_packets_mgt, p_pes );
180         }
181
182         input_ExtractPES( p_fifo, &p_pes );
183         if( p_pes )
184         {
185             /* Don't trust the sucker */
186             //i_pts = p_pes->i_pts + DEFAULT_PTS_DELAY;
187             i_pts = mdate() + DEFAULT_PTS_DELAY;
188         }
189
190         if( p_fifo->b_die || p_fifo->b_error )
191         {
192             break;
193         }
194
195         while( !(p_pic = vout_CreatePicture( p_vout, 0, 0, 0 ) ) )
196         {
197             if( p_fifo->b_die || p_fifo->b_error )
198             {
199                 break;
200             } 
201             msleep( VOUT_OUTMEM_SLEEP );
202         }
203
204         if( !p_pic )
205         {
206             break;
207         }
208
209         if( b_direct )
210         {
211             xpic.y = p_pic->p[0].p_pixels;
212             xpic.u = p_pic->p[1].p_pixels;
213             xpic.v = p_pic->p[2].p_pixels;
214             xpic.stride_y = p_pic->p[0].i_pitch;
215             xpic.stride_u = p_pic->p[1].i_pitch;
216             xpic.stride_v = p_pic->p[2].i_pitch;
217         }
218
219         /* Decode the stuff */
220         xframe.bitstream = p_buffer;
221         xframe.length = i_size;
222         xframe.image = b_direct ? (void*)&xpic : p_image;
223         xframe.stride = i_width;
224         xframe.colorspace = b_direct ? XVID_CSP_EXTERN : XVID_CSP_YV12;
225         i_ret = xvid_decore( p_xvid, XVID_DEC_DECODE, &xframe, NULL );
226         /* FIXME: check i_ret */
227
228         if( !b_direct )
229         {
230             /* TODO: use pf_memcpy when this is stable. */
231             memcpy( p_pic->p[0].p_pixels,
232                     p_image,
233                     i_width * i_height );
234             memcpy( p_pic->p[2].p_pixels,
235                     p_image + i_width * i_height,
236                     i_width * i_height / 4 );
237             memcpy( p_pic->p[1].p_pixels,
238                     p_image + i_width * i_height + i_width * i_height / 4,
239                     i_width * i_height / 4 );
240         }
241
242         vout_DatePicture( p_vout, p_pic, i_pts );
243         vout_DisplayPicture( p_vout, p_pic );
244
245         /* Move the remaining data. TODO: only do this when necessary. */
246         memmove( p_buffer, p_buffer + xframe.length, i_size - xframe.length );
247         i_offset = i_size - xframe.length;
248     }
249
250     /* Clean up everything */
251     vout_Request( p_fifo, p_vout, 0, 0, 0, 0 );
252
253     xvid_decore( p_xvid, XVID_DEC_DESTROY, NULL, NULL );
254
255     if( p_pes )
256     {
257         input_DeletePES( p_fifo->p_packets_mgt, p_pes );
258     }
259
260     free( p_buffer );
261     CloseBitstream( &bit_stream );
262
263     if( p_fifo->b_error )
264     {
265         DecoderError( p_fifo );
266         return VLC_EGENERIC;
267     }
268
269     return VLC_SUCCESS;
270 }