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