* ./codec/dv/dv.c: moved this single file to its parent directory; removed
[vlc.git] / modules / codec / dv.c
1 /*****************************************************************************
2  * dv.c: a decoder for DV video
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: dv.c,v 1.1 2002/11/05 14:52:28 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/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
44 /*****************************************************************************
45  * Module descriptor
46  *****************************************************************************/
47 vlc_module_begin();
48     set_description( _("DV video decoder") );
49     set_capability( "decoder", 70 );
50     set_callbacks( OpenDecoder, NULL );
51 vlc_module_end();
52
53 /*****************************************************************************
54  * OpenDecoder: probe the decoder and return score
55  *****************************************************************************
56  * The fourcc format for DV is "dvsd"
57  *****************************************************************************/
58 static int OpenDecoder ( vlc_object_t *p_this )
59 {
60     decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
61
62     if( p_fifo->i_fourcc != VLC_FOURCC('d','v','s','d') )
63     {
64         return VLC_EGENERIC;
65     }
66
67     p_fifo->pf_run = RunDecoder;
68     return VLC_SUCCESS;
69 }
70
71 /*****************************************************************************
72  * RunDecoder: this function is called just after the thread is created
73  *****************************************************************************/
74 static int RunDecoder ( decoder_fifo_t *p_fifo )
75 {
76     u8 *p_buffer;
77     pes_packet_t *p_pes = NULL;
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
203             GetChunk( &bit_stream, p_buffer + i_data,
204                                    p_decoder->frame_size - i_data );
205             i_data = p_decoder->frame_size;
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             if( dv_parse_header( p_decoder, p_buffer ) > 0 )
226             {
227                 fprintf(stderr, "size changed\n");
228             }
229
230             if( p_vout && ( !p_decoder->prev_frame_decoded
231                              || dv_frame_changed( p_decoder ) ) )
232             {
233                 picture_t *p_pic;
234                 u8 *pixels[3];
235                 int pitches[3], i;
236
237                 while( !(p_pic = vout_CreatePicture( p_vout, 0, 0, 0 ) ) )
238                 {
239                     if( p_fifo->b_die || p_fifo->b_error )
240                     {
241                         break;
242                     } 
243                     msleep( VOUT_OUTMEM_SLEEP );
244                 }
245
246                 if( !p_pic )
247                 {
248                     break;
249                 }
250
251                 for( i = 0 ; i < p_pic->i_planes ; i++ )
252                 {
253                     pixels[i] = p_pic->p[i].p_pixels;
254                     pitches[i] = p_pic->p[i].i_pitch;
255                 }
256
257                 dv_decode_full_frame( p_decoder, p_buffer,
258                                       e_dv_color_yuv, pixels, pitches );
259                 p_decoder->prev_frame_decoded = 1;
260
261                 vout_DatePicture( p_vout, p_pic, i_pts );
262                 vout_DisplayPicture( p_vout, p_pic );
263             }
264
265             i_data = 0;
266         }
267
268         if( p_vout )
269         {
270             vout_DestroyThread( p_vout );
271         }
272     }
273
274     if( p_pes )
275     {
276         input_DeletePES( p_fifo->p_packets_mgt, p_pes );
277     }
278
279     free( p_buffer );
280     CloseBitstream( &bit_stream );
281
282     if( p_fifo->b_error )
283     {
284         DecoderError( p_fifo );
285         return -1;
286     }
287
288     return 0;
289 }
290
291 static u32 GetFourCC( dv_sample_t x )
292 {
293     switch( x )
294     {
295         case e_dv_sample_411: return VLC_FOURCC('Y','U','Y','2');
296         case e_dv_sample_420: return VLC_FOURCC('Y','U','Y','2');
297         case e_dv_sample_422: return VLC_FOURCC('Y','U','Y','2');
298         default: return 0;
299     }
300 }
301