]> git.sesse.net Git - vlc/blob - modules/codec/xvid.c
2a8d1cfe29a79f7f501c0cbd7e3c9f4de12248f3
[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.2 2002/11/06 09:26:25 sam 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/input.h>
30 #include <vlc/decoder.h>
31
32 #include <stdlib.h>
33
34 #include "codecs.h"
35
36 #include <xvid.h>
37
38 /*****************************************************************************
39  * Local prototypes
40  *****************************************************************************/
41 static int RunDecoder  ( decoder_fifo_t * );
42 static int OpenDecoder ( vlc_object_t * );
43
44 /*****************************************************************************
45  * Module descriptor
46  *****************************************************************************/
47 vlc_module_begin();
48     set_description( _("Xvid video decoder") );
49     set_capability( "decoder", 50 );
50     set_callbacks( OpenDecoder, NULL );
51     add_bool( "xvid-direct-render", 0, NULL, "direct rendering", 
52               "Use libxvidcore's direct rendering feature." );
53 vlc_module_end();
54
55 /*****************************************************************************
56  * OpenDecoder: probe the decoder and return score
57  *****************************************************************************
58  * FIXME: find fourcc formats supported by xvid
59  *****************************************************************************/
60 static int OpenDecoder ( vlc_object_t *p_this )
61 {
62     decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
63
64     if( p_fifo->i_fourcc != VLC_FOURCC('x','v','i','d')
65          && p_fifo->i_fourcc != VLC_FOURCC('X','V','I','D')
66          && p_fifo->i_fourcc != VLC_FOURCC('D','I','V','X') )
67     {
68         return VLC_EGENERIC;
69     }
70
71     p_fifo->pf_run = RunDecoder;
72     return VLC_SUCCESS;
73 }
74
75 /*****************************************************************************
76  * RunDecoder: this function is called just after the thread is created
77  *****************************************************************************/
78 static int RunDecoder ( decoder_fifo_t *p_fifo )
79 {
80     XVID_INIT_PARAM    xinit;
81     XVID_DEC_PARAM     xparam;
82     BITMAPINFOHEADER * p_format;
83     void *             p_xvid;
84
85     pes_packet_t *     p_pes = NULL;
86     bit_stream_t       bit_stream;
87     vout_thread_t *    p_vout;
88
89     uint8_t *  p_buffer, * p_image;
90     int        i_ret;
91     int        i_width, i_height, i_chroma, i_aspect;
92     int        i_size, i_offset, i_image_size;
93
94     vlc_bool_t b_direct = config_GetInt( p_fifo, "xvid-direct-render" );
95
96     if( InitBitstream( &bit_stream, p_fifo, NULL, NULL ) != VLC_SUCCESS )
97     {
98         msg_Err( p_fifo, "cannot initialise bitstream" );
99         p_fifo->b_error = VLC_TRUE;
100         DecoderError( p_fifo );
101         return VLC_EGENERIC;
102     }
103
104     p_format = (BITMAPINFOHEADER *)p_fifo->p_demux_data;
105
106     /* Guess picture properties from the BIH */
107     i_width = p_format->biWidth;
108     i_height = p_format->biHeight;
109     i_chroma = VLC_FOURCC('Y','V','1','2');
110     i_aspect = VOUT_ASPECT_FACTOR * i_width / i_height;
111
112     /* XXX: Completely arbitrary buffer size */
113     i_size = i_width * i_height / 4;
114     i_image_size = b_direct ? 0 : i_width * i_height * 4;
115     i_offset = 0;
116
117     p_buffer = malloc( i_size + i_image_size );
118     p_image = p_buffer + i_size;
119
120     if( !p_buffer )
121     {
122         msg_Err( p_fifo, "out of memory" );
123         p_fifo->b_error = VLC_TRUE;
124         CloseBitstream( &bit_stream );
125         DecoderError( p_fifo );
126         return VLC_EGENERIC;
127     }
128
129     xinit.cpu_flags = 0;
130     xvid_init( NULL, 0, &xinit, NULL );
131
132     xparam.width = i_width;
133     xparam.height = i_height;
134     i_ret = xvid_decore( NULL, XVID_DEC_CREATE, &xparam, NULL );
135
136     if( i_ret )
137     {
138         msg_Err( p_fifo, "cannot create xvid decoder" );
139         p_fifo->b_error = VLC_TRUE;
140         free( p_buffer );
141         CloseBitstream( &bit_stream );
142         DecoderError( p_fifo );
143         return VLC_EGENERIC;
144     }
145
146     p_xvid = xparam.handle;
147
148     /* Spawn a video output if there is none. First we look amongst our
149      * children, then we look for any other vout that might be available */
150     p_vout = vlc_object_find( p_fifo, VLC_OBJECT_VOUT, FIND_CHILD );
151     if( !p_vout ) 
152     {
153         p_vout = vlc_object_find( p_fifo, VLC_OBJECT_VOUT, FIND_ANYWHERE );
154     }
155
156     if( p_vout )
157     {
158         if( p_vout->render.i_width != i_width
159          || p_vout->render.i_height != i_height
160          || p_vout->render.i_chroma != i_chroma
161          || p_vout->render.i_aspect != i_aspect )
162         {
163             /* We are not interested in this format, close this vout */
164             vlc_object_detach( p_vout );
165             vlc_object_release( p_vout );
166             vout_DestroyThread( p_vout );
167             p_vout = NULL;
168         }
169         else
170         {
171             /* This video output is cool! Hijack it. */
172             vlc_object_detach( p_vout );
173             vlc_object_attach( p_vout, p_fifo );
174             vlc_object_release( p_vout );
175         }
176     }
177
178     if( !p_vout )
179     {
180         msg_Dbg( p_fifo, "no vout present, spawning one" );
181
182         p_vout = vout_CreateThread( p_fifo,
183                                     i_width, i_height,
184                                     i_chroma, i_aspect );
185         if( !p_vout )
186         {
187             msg_Err( p_fifo, "could not spawn vout" );
188             p_fifo->b_error = VLC_TRUE;
189             xvid_decore( p_xvid, XVID_DEC_DESTROY, NULL, NULL );
190             free( p_buffer );
191             CloseBitstream( &bit_stream );
192             DecoderError( p_fifo );
193             return VLC_EGENERIC;
194         }
195     }
196
197     /* Main loop */
198     while( !p_fifo->b_die && !p_fifo->b_error )
199     {
200         XVID_DEC_FRAME xframe;
201         XVID_DEC_PICTURE xpic;
202         mtime_t i_pts = 0;
203         picture_t *p_pic;
204
205         GetChunk( &bit_stream, p_buffer + i_offset, i_size - i_offset );
206
207         if( p_pes )
208         {
209             input_DeletePES( p_fifo->p_packets_mgt, p_pes );
210         }
211
212         input_ExtractPES( p_fifo, &p_pes );
213         if( p_pes )
214         {
215             /* Don't trust the sucker */
216             //i_pts = p_pes->i_pts + DEFAULT_PTS_DELAY;
217             i_pts = mdate() + DEFAULT_PTS_DELAY;
218         }
219
220         if( p_fifo->b_die || p_fifo->b_error )
221         {
222             break;
223         }
224
225         while( !(p_pic = vout_CreatePicture( p_vout, 0, 0, 0 ) ) )
226         {
227             if( p_fifo->b_die || p_fifo->b_error )
228             {
229                 break;
230             } 
231             msleep( VOUT_OUTMEM_SLEEP );
232         }
233
234         if( !p_pic )
235         {
236             break;
237         }
238
239         if( b_direct )
240         {
241             xpic.y = p_pic->p[0].p_pixels;
242             xpic.u = p_pic->p[1].p_pixels;
243             xpic.v = p_pic->p[2].p_pixels;
244             xpic.stride_y = p_pic->p[0].i_pitch;
245             xpic.stride_u = p_pic->p[1].i_pitch;
246             xpic.stride_v = p_pic->p[2].i_pitch;
247         }
248
249         /* Decode the stuff */
250         xframe.bitstream = p_buffer;
251         xframe.length = i_size;
252         xframe.image = b_direct ? (void*)&xpic : p_image;
253         xframe.stride = i_width;
254         xframe.colorspace = b_direct ? XVID_CSP_EXTERN : XVID_CSP_YV12;
255         i_ret = xvid_decore( p_xvid, XVID_DEC_DECODE, &xframe, NULL );
256         /* FIXME: check i_ret */
257
258         if( !b_direct )
259         {
260             /* TODO: use pf_memcpy when this is stable. */
261             memcpy( p_pic->p[0].p_pixels,
262                     p_image,
263                     i_width * i_height );
264             memcpy( p_pic->p[2].p_pixels,
265                     p_image + i_width * i_height,
266                     i_width * i_height / 4 );
267             memcpy( p_pic->p[1].p_pixels,
268                     p_image + i_width * i_height + i_width * i_height / 4,
269                     i_width * i_height / 4 );
270         }
271
272         vout_DatePicture( p_vout, p_pic, i_pts );
273         vout_DisplayPicture( p_vout, p_pic );
274
275         /* Move the remaining data. TODO: only do this when necessary. */
276         memmove( p_buffer, p_buffer + xframe.length, i_size - xframe.length );
277         i_offset = i_size - xframe.length;
278     }
279
280     /* Clean up everything */
281     vlc_object_detach( p_vout );
282     vout_DestroyThread( p_vout );
283
284     xvid_decore( p_xvid, XVID_DEC_DESTROY, NULL, NULL );
285
286     if( p_pes )
287     {
288         input_DeletePES( p_fifo->p_packets_mgt, p_pes );
289     }
290
291     free( p_buffer );
292     CloseBitstream( &bit_stream );
293
294     if( p_fifo->b_error )
295     {
296         DecoderError( p_fifo );
297         return VLC_EGENERIC;
298     }
299
300     return VLC_SUCCESS;
301 }
302