* modules/codec/ffmpeg/*: modified the ffmpeg video codec to use direct
[vlc.git] / modules / codec / dv / dv.c
1 /*****************************************************************************
2  * dv.c: a decoder for DV video
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: dv.c,v 1.4 2002/11/02 17:31:37 sigmunau 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 #undef vlc_error /*vlc_error is defined in the libdv headers, but not
32                   * used in thes file */
33 #include <libdv/dv_types.h>
34 #include <libdv/dv.h>
35
36 /*****************************************************************************
37  * Local prototypes
38  *****************************************************************************/
39 static int RunDecoder  ( decoder_fifo_t * );
40 static int OpenDecoder ( vlc_object_t * );
41
42 static u32 GetFourCC   ( dv_sample_t );
43 static pes_packet_t *GetFirstPES( decoder_fifo_t * );
44
45 /*****************************************************************************
46  * Module descriptor
47  *****************************************************************************/
48 vlc_module_begin();
49     set_description( _("DV video decoder") );
50     set_capability( "decoder", 70 );
51     set_callbacks( OpenDecoder, NULL );
52 vlc_module_end();
53
54 /*****************************************************************************
55  * OpenDecoder: probe the decoder and return score
56  *****************************************************************************
57  * The fourcc format for DV is "dvsd"
58  *****************************************************************************/
59 static int OpenDecoder ( vlc_object_t *p_this )
60 {
61     decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
62
63     if( p_fifo->i_fourcc != VLC_FOURCC('d','v','s','d') )
64     {
65         return VLC_EGENERIC;
66     }
67
68     p_fifo->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     u8 *p_buffer;
78     int i_data = 120000;
79     int i_aspect;
80
81     bit_stream_t    bit_stream;
82     dv_decoder_t *  p_decoder;
83     vout_thread_t * p_vout;
84     
85     p_buffer = malloc( i_data );
86     if( !p_buffer )
87     {
88         msg_Err( p_fifo, "out of memory" );
89         p_fifo->b_error = 1;
90         DecoderError( p_fifo );
91         return -1;
92     }
93
94     p_decoder = dv_decoder_new( TRUE, FALSE, FALSE );
95     if( !p_decoder )
96     {
97         msg_Err( p_fifo, "cannot create DV decoder" );
98         free( p_buffer );
99         p_fifo->b_error = 1;
100         DecoderError( p_fifo );
101         return -1;
102     }
103
104     if( InitBitstream( &bit_stream, p_fifo, NULL, NULL ) != VLC_SUCCESS )
105     {
106         msg_Err( p_fifo, "cannot initialise bitstream" );
107         free( p_buffer );
108         p_fifo->b_error = 1;
109         DecoderError( p_fifo );
110         return -1;
111     }
112
113     /* Fill the buffer */
114     GetChunk( &bit_stream, p_buffer, i_data );
115
116     while( !p_fifo->b_die && !p_fifo->b_error )
117     {
118         /* Parsing the beginning of the stream */
119         if( dv_parse_header( p_decoder, p_buffer ) < 0 )
120         {
121             fprintf(stderr, "parse error\n");
122             p_fifo->b_error = 1;
123             break;
124         }
125
126         if( dv_format_wide( p_decoder ) )
127         {
128             msg_Dbg( p_fifo, "aspect is 4:3" );
129             i_aspect = VOUT_ASPECT_FACTOR * 4 / 3;
130         }
131         else if( dv_format_normal( p_decoder ) )
132         {
133             msg_Dbg( p_fifo, "aspect is 16:9" );
134             i_aspect = VOUT_ASPECT_FACTOR * 4/3;//16 / 9;
135         }
136         else
137         {
138             msg_Dbg( p_fifo, "aspect is square pixels" );
139             i_aspect = VOUT_ASPECT_FACTOR
140                         * p_decoder->width / p_decoder->height;
141         }
142
143         if( p_decoder->frame_size <= i_data )
144         {
145             /* XXX: what to do? */
146             i_data = p_decoder->frame_size;
147         }
148         else
149         {
150             p_buffer = realloc( p_buffer, p_decoder->frame_size );
151         }
152     
153         /* Don't trust the sucker */
154         //p_decoder->quality = p_decoder->video->quality;
155         p_decoder->quality = DV_QUALITY_BEST;
156         p_decoder->prev_frame_decoded = 0;
157
158         /* Spawn a video output if there is none. First we look amongst our
159          * children, then we look for any other vout that might be available */
160         p_vout = vlc_object_find( p_fifo, VLC_OBJECT_VOUT, FIND_CHILD );
161         if( !p_vout ) 
162         {
163             p_vout = vlc_object_find( p_fifo, VLC_OBJECT_VOUT, FIND_ANYWHERE );
164         }
165
166         if( p_vout )
167         {
168             if( p_vout->render.i_width != p_decoder->width
169              || p_vout->render.i_height != p_decoder->height
170              || p_vout->render.i_chroma != GetFourCC( p_decoder->sampling )
171              || p_vout->render.i_aspect != i_aspect )
172             {
173                 /* We are not interested in this format, close this vout */
174                 vlc_object_detach( p_vout );
175                 vlc_object_release( p_vout );
176                 vout_DestroyThread( p_vout );
177                 p_vout = NULL;
178             }
179             else
180             {
181                 /* This video output is cool! Hijack it. */
182                 vlc_object_detach( p_vout );
183                 vlc_object_attach( p_vout, p_fifo );
184                 vlc_object_release( p_vout );
185             }
186         }
187
188         if( !p_vout )
189         {
190             msg_Dbg( p_fifo, "no vout present, spawning one" );
191
192             p_vout = vout_CreateThread( p_fifo,
193                                         p_decoder->width, p_decoder->height,
194                                         GetFourCC( p_decoder->sampling ),
195                                         i_aspect );
196         }
197
198         /* Main loop */
199         while( !p_fifo->b_die && !p_fifo->b_error )
200         {
201             mtime_t i_pts = 0;
202             pes_packet_t *p_pes;
203
204             GetChunk( &bit_stream, p_buffer + i_data,
205                                    p_decoder->frame_size - i_data );
206             i_data = p_decoder->frame_size;
207
208             p_pes = GetFirstPES( p_fifo );
209
210             if( p_pes )
211             {
212                 /* Don't trust the sucker */
213                 //i_pts = p_pes->i_pts + DEFAULT_PTS_DELAY;
214                 i_pts = mdate() + DEFAULT_PTS_DELAY;
215             }
216
217             if( p_fifo->b_die || p_fifo->b_error )
218             {
219                 break;
220             }
221
222             if( dv_parse_header( p_decoder, p_buffer ) > 0 )
223             {
224                 fprintf(stderr, "size changed\n");
225             }
226
227             if( p_vout && ( !p_decoder->prev_frame_decoded
228                              || dv_frame_changed( p_decoder ) ) )
229             {
230                 picture_t *p_pic;
231                 u8 *pixels[3];
232                 int pitches[3], i;
233
234                 while( !(p_pic = vout_CreatePicture( p_vout, 0, 0, 0 ) ) )
235                 {
236                     if( p_fifo->b_die || p_fifo->b_error )
237                     {
238                         break;
239                     } 
240                     msleep( VOUT_OUTMEM_SLEEP );
241                 }
242
243                 if( !p_pic )
244                 {
245                     break;
246                 }
247
248                 for( i = 0 ; i < p_pic->i_planes ; i++ )
249                 {
250                     pixels[i] = p_pic->p[i].p_pixels;
251                     pitches[i] = p_pic->p[i].i_pitch;
252                 }
253
254                 dv_decode_full_frame( p_decoder, p_buffer,
255                                       e_dv_color_yuv, pixels, pitches );
256                 p_decoder->prev_frame_decoded = 1;
257
258                 vout_DatePicture( p_vout, p_pic, i_pts );
259                 vout_DisplayPicture( p_vout, p_pic );
260             }
261
262             i_data = 0;
263         }
264
265         if( p_vout )
266         {
267             vout_DestroyThread( p_vout );
268         }
269     }
270
271     free( p_buffer );
272     CloseBitstream( &bit_stream );
273
274     if( p_fifo->b_error )
275     {
276         DecoderError( p_fifo );
277         return -1;
278     }
279
280     return 0;
281 }
282
283 static u32 GetFourCC( dv_sample_t x )
284 {
285     switch( x )
286     {
287         case e_dv_sample_411: return VLC_FOURCC('Y','U','Y','2');
288         case e_dv_sample_420: return VLC_FOURCC('Y','U','Y','2');
289         case e_dv_sample_422: return VLC_FOURCC('Y','U','Y','2');
290         default: return 0;
291     }
292 }
293
294 static pes_packet_t *GetFirstPES( decoder_fifo_t *p_fifo )
295 {
296     pes_packet_t *p_pes;
297
298     vlc_mutex_lock( &p_fifo->data_lock );
299
300     /* if fifo is empty wait */
301     while( !p_fifo->p_first )
302     {
303         if( p_fifo->b_die )
304         {
305             vlc_mutex_unlock( &p_fifo->data_lock );
306             return NULL;
307         } 
308         vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
309     }
310     p_pes = p_fifo->p_first;
311
312     vlc_mutex_unlock( &p_fifo->data_lock );
313     
314     return p_pes;
315 }