]> git.sesse.net Git - vlc/blob - modules/codec/xvid.c
* ALL: final improvements to the decoders/packetizers api.
[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.7 2003/11/16 21:07:30 gbazin 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.", VLC_TRUE );
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_t *p_dec = (decoder_t*)p_this;
63
64     if( p_dec->fmt_in.i_codec != VLC_FOURCC('x','v','i','d')
65          && p_dec->fmt_in.i_codec != VLC_FOURCC('X','V','I','D')
66          && p_dec->fmt_in.i_codec != VLC_FOURCC('D','I','V','X') )
67     {
68         return VLC_EGENERIC;
69     }
70
71     p_dec->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     if( ( p_format = (BITMAPINFOHEADER *)p_fifo->p_bitmapinfoheader ) == NULL )
104     {
105         i_width  = 1;
106         i_height = 1;   // avoid segfault anyway it's wrong
107     }
108     else
109     {
110         /* Guess picture properties from the BIH */
111         i_width = p_format->biWidth;
112         i_height = p_format->biHeight;
113     }
114
115     i_chroma = VLC_FOURCC('Y','V','1','2');
116     i_aspect = VOUT_ASPECT_FACTOR * i_width / i_height;
117
118     /* XXX: Completely arbitrary buffer size */
119     i_size = i_width * i_height / 4;
120     i_image_size = b_direct ? 0 : i_width * i_height * 4;
121     i_offset = 0;
122
123     p_buffer = malloc( i_size + i_image_size );
124     p_image = p_buffer + i_size;
125
126     if( !p_buffer )
127     {
128         msg_Err( p_fifo, "out of memory" );
129         p_fifo->b_error = VLC_TRUE;
130         CloseBitstream( &bit_stream );
131         DecoderError( p_fifo );
132         return VLC_EGENERIC;
133     }
134
135     xinit.cpu_flags = 0;
136     xvid_init( NULL, 0, &xinit, NULL );
137
138     xparam.width = i_width;
139     xparam.height = i_height;
140     i_ret = xvid_decore( NULL, XVID_DEC_CREATE, &xparam, NULL );
141
142     if( i_ret )
143     {
144         msg_Err( p_fifo, "cannot create xvid decoder" );
145         p_fifo->b_error = VLC_TRUE;
146         free( p_buffer );
147         CloseBitstream( &bit_stream );
148         DecoderError( p_fifo );
149         return VLC_EGENERIC;
150     }
151
152     p_xvid = xparam.handle;
153
154     /* Spawn a video output if there is none. First we look amongst our
155      * children, then we look for any other vout that might be available */
156     p_vout = vout_Request( p_fifo, NULL,
157                            i_width, i_height, i_chroma, i_aspect );
158
159     if( !p_vout )
160     {
161         msg_Err( p_fifo, "could not spawn vout" );
162         p_fifo->b_error = VLC_TRUE;
163         xvid_decore( p_xvid, XVID_DEC_DESTROY, NULL, NULL );
164         free( p_buffer );
165         CloseBitstream( &bit_stream );
166         DecoderError( p_fifo );
167         return VLC_EGENERIC;
168     }
169
170     /* Main loop */
171     while( !p_fifo->b_die && !p_fifo->b_error )
172     {
173         XVID_DEC_FRAME xframe;
174         XVID_DEC_PICTURE xpic;
175         mtime_t i_pts = 0;
176         picture_t *p_pic;
177
178         GetChunk( &bit_stream, p_buffer + i_offset, i_size - i_offset );
179
180         if( p_pes )
181         {
182             input_DeletePES( p_fifo->p_packets_mgt, p_pes );
183         }
184
185         input_ExtractPES( p_fifo, &p_pes );
186         if( p_pes )
187         {
188             /* Don't trust the sucker */
189             //i_pts = p_pes->i_pts + DEFAULT_PTS_DELAY;
190             i_pts = mdate() + DEFAULT_PTS_DELAY;
191         }
192
193         if( p_fifo->b_die || p_fifo->b_error )
194         {
195             break;
196         }
197
198         while( !(p_pic = vout_CreatePicture( p_vout, 0, 0, 0 ) ) )
199         {
200             if( p_fifo->b_die || p_fifo->b_error )
201             {
202                 break;
203             } 
204             msleep( VOUT_OUTMEM_SLEEP );
205         }
206
207         if( !p_pic )
208         {
209             break;
210         }
211
212         if( b_direct )
213         {
214             xpic.y = p_pic->p[0].p_pixels;
215             xpic.u = p_pic->p[1].p_pixels;
216             xpic.v = p_pic->p[2].p_pixels;
217             xpic.stride_y = p_pic->p[0].i_pitch;
218             xpic.stride_u = p_pic->p[1].i_pitch;
219             xpic.stride_v = p_pic->p[2].i_pitch;
220         }
221
222         /* Decode the stuff */
223         xframe.bitstream = p_buffer;
224         xframe.length = i_size;
225         xframe.image = b_direct ? (void*)&xpic : p_image;
226         xframe.stride = i_width;
227         xframe.colorspace = b_direct ? XVID_CSP_EXTERN : XVID_CSP_YV12;
228         i_ret = xvid_decore( p_xvid, XVID_DEC_DECODE, &xframe, NULL );
229         /* FIXME: check i_ret */
230
231         if( !b_direct )
232         {
233             /* TODO: use pf_memcpy when this is stable. */
234             memcpy( p_pic->p[0].p_pixels,
235                     p_image,
236                     i_width * i_height );
237             memcpy( p_pic->p[2].p_pixels,
238                     p_image + i_width * i_height,
239                     i_width * i_height / 4 );
240             memcpy( p_pic->p[1].p_pixels,
241                     p_image + i_width * i_height + i_width * i_height / 4,
242                     i_width * i_height / 4 );
243         }
244
245         vout_DatePicture( p_vout, p_pic, i_pts );
246         vout_DisplayPicture( p_vout, p_pic );
247
248         /* Move the remaining data. TODO: only do this when necessary. */
249         memmove( p_buffer, p_buffer + xframe.length, i_size - xframe.length );
250         i_offset = i_size - xframe.length;
251     }
252
253     /* Clean up everything */
254     vout_Request( p_fifo, p_vout, 0, 0, 0, 0 );
255
256     xvid_decore( p_xvid, XVID_DEC_DESTROY, NULL, NULL );
257
258     if( p_pes )
259     {
260         input_DeletePES( p_fifo->p_packets_mgt, p_pes );
261     }
262
263     free( p_buffer );
264     CloseBitstream( &bit_stream );
265
266     if( p_fifo->b_error )
267     {
268         DecoderError( p_fifo );
269         return VLC_EGENERIC;
270     }
271
272     return VLC_SUCCESS;
273 }