* modules/codec/rawvideo.c: added support for YUY2 and I422 and fixed a bug in FillPi...
[vlc.git] / modules / codec / rawvideo.c
1 /*****************************************************************************
2  * rawvideo.c: Pseudo audio decoder; for raw video data
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: rawvideo.c,v 1.2 2003/04/26 12:26:46 gbazin Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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 #include <vlc/input.h>
31
32 #include <stdlib.h>                                      /* malloc(), free() */
33 #include <string.h>                                              /* strdup() */
34 #include "codecs.h"
35 /*****************************************************************************
36  * Local prototypes
37  *****************************************************************************/
38
39 typedef struct
40 {
41     /* Input properties */
42     decoder_fifo_t *p_fifo;
43     int            i_raw_size;
44
45     /* Output properties */
46
47     mtime_t             pts;
48
49     vout_thread_t       *p_vout;
50
51 } vdec_thread_t;
52
53 static int  OpenDecoder    ( vlc_object_t * );
54
55 static int  RunDecoder     ( decoder_fifo_t * );
56 static int  InitThread     ( vdec_thread_t * );
57 static void DecodeThread   ( vdec_thread_t * );
58 static void EndThread      ( vdec_thread_t * );
59
60 /*****************************************************************************
61  * Module descriptor
62  *****************************************************************************/
63
64 vlc_module_begin();
65     set_description( _("Pseudo Raw Video decoder") );
66     set_capability( "decoder", 50 );
67     set_callbacks( OpenDecoder, NULL );
68 vlc_module_end();
69
70
71 /*****************************************************************************
72  * OpenDecoder: probe the decoder and return score
73  *****************************************************************************
74  * Tries to launch a decoder and return score so that the interface is able
75  * to choose.
76  *****************************************************************************/
77 static int OpenDecoder( vlc_object_t *p_this )
78 {
79     decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
80
81     switch( p_fifo->i_fourcc )
82     {
83         case VLC_FOURCC('I','4','2','0'):
84         case VLC_FOURCC('I','4','2','2'):
85         case VLC_FOURCC('Y','U','Y','2'):
86             p_fifo->pf_run = RunDecoder;
87             return VLC_SUCCESS;
88
89         default:
90             return VLC_EGENERIC;
91     }
92
93 }
94
95 /*****************************************************************************
96  * RunDecoder: this function is called just after the thread is created
97  *****************************************************************************/
98 static int RunDecoder( decoder_fifo_t *p_fifo )
99 {
100     vdec_thread_t *p_vdec;
101     int b_error;
102
103     if( !( p_vdec = malloc( sizeof( vdec_thread_t ) ) ) )
104     {
105         msg_Err( p_fifo, "out of memory" );
106         DecoderError( p_fifo );
107         return( -1 );
108     }
109     memset( p_vdec, 0, sizeof( vdec_thread_t ) );
110
111     p_vdec->p_fifo = p_fifo;
112
113     if( InitThread( p_vdec ) != 0 )
114     {
115         DecoderError( p_fifo );
116         return( -1 );
117     }
118
119     while( ( !p_vdec->p_fifo->b_die )&&( !p_vdec->p_fifo->b_error ) )
120     {
121         DecodeThread( p_vdec );
122     }
123
124
125     if( ( b_error = p_vdec->p_fifo->b_error ) )
126     {
127         DecoderError( p_vdec->p_fifo );
128     }
129
130     EndThread( p_vdec );
131     if( b_error )
132     {
133         return( -1 );
134     }
135
136     return( 0 );
137 }
138
139
140 #define FREE( p ) if( p ) { free( p ); p = NULL; }
141
142
143 /*****************************************************************************
144  * InitThread: initialize data before entering main loop
145  *****************************************************************************/
146 static int InitThread( vdec_thread_t * p_vdec )
147 {
148     vlc_fourcc_t i_chroma;
149
150 #define bih ((BITMAPINFOHEADER*)p_vdec->p_fifo->p_bitmapinfoheader)
151     if( bih == NULL )
152     {
153         msg_Err( p_vdec->p_fifo,
154                  "info missing, fatal" );
155         return( VLC_EGENERIC );
156     }
157     if( bih->biWidth <= 0 || bih->biHeight <= 0 )
158     {
159         msg_Err( p_vdec->p_fifo,
160                  "invalid display size %dx%d",
161                  bih->biWidth, bih->biHeight );
162         return( VLC_EGENERIC );
163     }
164
165     switch( p_vdec->p_fifo->i_fourcc )
166     {
167         case VLC_FOURCC( 'I', '4', '2', '0' ):
168             i_chroma = VLC_FOURCC( 'I', '4', '2', '0' );
169             p_vdec->i_raw_size = bih->biWidth * bih->biHeight * 3 / 2;
170             break;
171         case VLC_FOURCC( 'I', '4', '2', '2' ):
172             i_chroma = VLC_FOURCC( 'I', '4', '2', '2' );
173             p_vdec->i_raw_size = bih->biWidth * bih->biHeight * 2;
174             break;
175         case VLC_FOURCC( 'Y', 'U', 'Y', '2' ):
176             i_chroma = VLC_FOURCC( 'Y', 'U', 'Y', '2' );
177             p_vdec->i_raw_size = bih->biWidth * bih->biHeight * 2;
178             break;
179         default:
180             msg_Err( p_vdec->p_fifo, "invalid codec=%4.4s", (char*)&p_vdec->p_fifo->i_fourcc );
181             return( VLC_EGENERIC );
182     }
183
184     p_vdec->p_vout = vout_Request( p_vdec->p_fifo, NULL,
185                                    bih->biWidth, bih->biHeight,
186                                    i_chroma,
187                                    VOUT_ASPECT_FACTOR * bih->biWidth / bih->biHeight );
188
189     if( p_vdec->p_vout == NULL )
190     {
191         msg_Err( p_vdec->p_fifo, "failled created vout" );
192         return( VLC_EGENERIC );
193     }
194
195     return( VLC_SUCCESS );
196 #undef bih
197 }
198
199
200 static void FillPicture( pes_packet_t *p_pes, picture_t *p_pic )
201 {
202     int i_plane;
203
204     data_packet_t   *p_data;
205     uint8_t *p_src;
206     int     i_src;
207
208     p_data = p_pes->p_first;
209     p_src  = p_data->p_payload_start;
210     i_src = p_data->p_payload_end - p_data->p_payload_start;
211
212     for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
213     {
214
215         uint8_t *p_dst;
216         int     i_dst;
217
218         p_dst = p_pic->p[i_plane].p_pixels;
219         i_dst = p_pic->p[i_plane].i_pitch * p_pic->p[i_plane].i_lines;
220
221         while( i_dst > 0 )
222         {
223             int i_copy;
224
225             i_copy = __MIN( i_src, i_dst );
226             if( i_copy > 0 )
227             {
228                 memcpy( p_dst, p_src, i_copy );
229             }
230             i_dst -= i_copy;
231             p_dst += i_copy;
232
233             i_src -= i_copy;
234             if( i_src <= 0 )
235             {
236                 do
237                 {
238                     p_data = p_data->p_next;
239                     if( p_data == NULL )
240                     {
241                         return;
242                     }
243                     p_src  = p_data->p_payload_start;
244                     i_src = p_data->p_payload_end - p_data->p_payload_start;
245                 } while( i_src <= 0 );
246             }
247         }
248     }
249 }
250
251 /*****************************************************************************
252  * DecodeThread: decodes a frame
253  *****************************************************************************/
254 static void DecodeThread( vdec_thread_t *p_vdec )
255 {
256     int             i_size;
257     pes_packet_t    *p_pes;
258     picture_t       *p_pic;
259
260     /* **** get frame **** */
261     input_ExtractPES( p_vdec->p_fifo, &p_pes );
262     if( !p_pes )
263     {
264         p_vdec->p_fifo->b_error = 1;
265         return;
266     }
267     i_size = p_pes->i_pes_size;
268
269     if( i_size < p_vdec->i_raw_size )
270     {
271         msg_Warn( p_vdec->p_fifo, "invalid frame size (%d < %d)", i_size, p_vdec->i_raw_size );
272         input_DeletePES( p_vdec->p_fifo->p_packets_mgt, p_pes );
273         return;
274     }
275
276     /* **** get video picture **** */
277     while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
278     {
279         if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
280         {
281             return;
282         }
283         msleep( VOUT_OUTMEM_SLEEP );
284     }
285
286
287     /* **** fill p_pic **** */
288     FillPicture( p_pes, p_pic );
289
290     /* **** display p_pic **** */
291     vout_DatePicture( p_vdec->p_vout, p_pic, p_pes->i_pts);
292     vout_DisplayPicture( p_vdec->p_vout, p_pic );
293
294
295     input_DeletePES( p_vdec->p_fifo->p_packets_mgt, p_pes );
296 }
297
298
299 /*****************************************************************************
300  * EndThread : faad decoder thread destruction
301  *****************************************************************************/
302 static void EndThread (vdec_thread_t *p_vdec)
303 {
304     if( p_vdec->p_vout )
305     {
306         vout_Request( p_vdec->p_fifo, p_vdec->p_vout, 0, 0, 0, 0 );
307     }
308
309     msg_Dbg( p_vdec->p_fifo, "raw video decoder closed" );
310
311     free( p_vdec );
312 }