]> git.sesse.net Git - vlc/blob - modules/demux/rawdv.c
* demux: fix segfault while trying to opening files without extention...
[vlc] / modules / demux / rawdv.c
1 /*****************************************************************************
2  * rawdv.c : raw dv input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: rawdv.c,v 1.3 2003/01/23 09:00:36 fenrir Exp $
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
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 <stdlib.h>                                      /* malloc(), free() */
28 #include <string.h>                                              /* strdup() */
29 #include <errno.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/input.h>
33
34 #include <sys/types.h>
35
36 #include <codecs.h>                        /* BITMAPINFOHEADER, WAVEFORMATEX */
37
38 /*****************************************************************************
39  A little bit of background information (copied over from libdv glossary).
40
41  - DIF block: A block of 80 bytes. This is the basic data framing unit of the
42        DVC tape format, analogous to sectors of hard disc.
43  
44  - Video Section: Each DIF sequence contains a video section, consisting of
45        135 DIF blocks, which are further subdivided into Video Segments.
46
47  - Video Segment: A video segment consists of 5 DIF blocks, each corresponding
48        to a single compressed macroblock.
49
50 *****************************************************************************/
51
52
53 /*****************************************************************************
54  * Constants
55  *****************************************************************************/
56 #define DV_PAL_FRAME_SIZE  144000
57 #define DV_NTSC_FRAME_SIZE 122000
58
59 /*****************************************************************************
60  * Definitions of structures used by this plugin
61  *****************************************************************************/
62 typedef struct {
63     int8_t sct;      /* Section type (header,subcode,aux,audio,video) */
64     int8_t dsn;      /* DIF sequence number (0-12) */
65     int    fsc;      /* First (0)/Second channel (1) */
66     int8_t dbn;      /* DIF block number (0-134) */
67 } dv_id_t;
68
69 typedef struct {
70     int    dsf;      /* DIF sequence flag: 525/60 (0) or 625,50 (1) */
71     int8_t apt;
72     int    tf1;
73     int8_t ap1;
74     int    tf2;
75     int8_t ap2;
76     int    tf3;
77     int8_t ap3;
78 } dv_header_t;
79
80 struct demux_sys_t
81 {
82     int    frame_size;
83
84     es_descriptor_t  *p_video_es;
85     es_descriptor_t  *p_audio_es;
86
87     /* codec specific stuff */
88     BITMAPINFOHEADER *p_bih;
89
90     double f_rate;
91     int    i_bitrate;
92
93     /* program clock reference (in units of 90kHz) */
94     mtime_t i_pcr;
95 };
96
97 /*****************************************************************************
98  * Local prototypes
99  *****************************************************************************/
100 static int  Activate  ( vlc_object_t * );
101 static void Deactivate( vlc_object_t * );
102 static int  Demux     ( input_thread_t * );
103
104 static uint32_t GetDWBE( uint8_t *p_buff )
105 {
106     return (uint32_t)p_buff[3] | ( ((uint32_t)p_buff[2]) << 8 ) |
107             ( ((uint32_t)p_buff[1]) << 16 ) | ( ((uint32_t)p_buff[0]) << 24 );
108 }
109
110 /*****************************************************************************
111  * Module descriptor
112  *****************************************************************************/
113 vlc_module_begin();
114     set_description( _("raw dv demux") );
115     set_capability( "demux", 2 );
116     set_callbacks( Activate, NULL );
117     add_shortcut( "rawdv" );
118 vlc_module_end();
119
120 /*****************************************************************************
121  * Activate: initializes raw dv demux structures
122  *****************************************************************************/
123 static int Activate( vlc_object_t * p_this )
124 {
125     input_thread_t *p_input = (input_thread_t *)p_this;
126     byte_t         *p_peek;
127     uint32_t       i_dword;
128     demux_sys_t    *p_rawdv;
129     dv_header_t    dv_header;
130     dv_id_t        dv_id;
131     char           *psz_ext;
132
133     /* It isn't easy to recognize a raw dv stream. The chances that we'll
134      * mistake a stream from another type for a raw dv stream are too high, so
135      * we'll rely on the file extension to trigger this demux. Alternatively,
136      * it is possible to force this demux. */
137
138     /* Check for dv file extension */
139     psz_ext = strrchr ( p_input->psz_name, '.' );
140     if( ( !psz_ext || strcasecmp( psz_ext, ".dv") )&&
141         ( !p_input->psz_demux || strcmp(p_input->psz_demux, "rawdv") ) )
142     {
143         return -1;
144     }
145
146     p_input->pf_demux = Demux;
147
148     /* Have a peep at the show. */
149     if( input_Peek(p_input, &p_peek, DV_PAL_FRAME_SIZE) < DV_NTSC_FRAME_SIZE )
150     {
151         /* Stream too short ... */
152         msg_Err( p_input, "cannot peek()" );
153         return -1;
154     }
155
156     /* fill in the dv_id_t structure */
157     i_dword = GetDWBE( p_peek ); p_peek += 4;
158     dv_id.sct = i_dword >> (32 - 3);
159     i_dword <<= 8;
160     dv_id.dsn = i_dword >> (32 - 4);
161     i_dword <<= 4;
162     dv_id.fsc = i_dword >> (32 - 1);
163     i_dword <<= 4;
164     dv_id.dbn = i_dword >> (32 - 8);
165     i_dword <<= 8;
166
167     if( dv_id.sct != 0 )
168     {
169         msg_Warn( p_input, "not a raw dv stream header" );
170         return -1;
171     }
172
173     /* fill in the dv_header_t structure */
174     dv_header.dsf = i_dword >> (32 - 1);
175     i_dword <<= 1;
176     if( i_dword >> (32 - 1) ) /* incorrect bit */
177     {
178         msg_Warn( p_input, "incorrect bit" );
179         return -1;
180     }
181
182     i_dword = GetDWBE( p_peek ); p_peek += 4;
183     i_dword <<= 5;
184     dv_header.apt = i_dword >> (32 - 3);
185     i_dword <<= 3;
186     dv_header.tf1 = i_dword >> (32 - 1);
187     i_dword <<= 5;
188     dv_header.ap1 = i_dword >> (32 - 3);
189     i_dword <<= 3;
190     dv_header.tf2 = i_dword >> (32 - 1);
191     i_dword <<= 5;
192     dv_header.ap2 = i_dword >> (32 - 3);
193     i_dword <<= 3;
194     dv_header.tf3 = i_dword >> (32 - 1);
195     i_dword <<= 5;
196     dv_header.ap3 = i_dword >> (32 - 3);
197
198     p_peek += 72;                                  /* skip rest of DIF block */
199
200
201     /* Setup the structures for our demuxer */
202     if( !( p_rawdv = malloc( sizeof( demux_sys_t ) ) ) )
203     {
204         msg_Err( p_input, "out of memory" );
205         return -1;
206     }
207     memset( p_rawdv, 0, sizeof( demux_sys_t ) );
208     p_rawdv->p_bih = NULL;
209     p_input->p_demux_data = p_rawdv;
210
211     p_rawdv->p_bih = (BITMAPINFOHEADER *) malloc( sizeof(BITMAPINFOHEADER) );
212     if( !p_rawdv->p_bih )
213     {
214         msg_Err( p_input, "out of memory" );
215         goto error;
216     }
217     p_rawdv->p_bih->biSize = sizeof(BITMAPINFOHEADER);
218     p_rawdv->p_bih->biCompression = VLC_FOURCC( 'd','v','s','d' );
219     p_rawdv->p_bih->biSize = 40;
220     p_rawdv->p_bih->biWidth = 720;
221     p_rawdv->p_bih->biHeight = dv_header.dsf ? 576 : 480;
222     p_rawdv->p_bih->biPlanes = 1;
223     p_rawdv->p_bih->biBitCount = 24;
224     p_rawdv->p_bih->biSizeImage =
225         p_rawdv->p_bih->biWidth * p_rawdv->p_bih->biHeight
226           * (p_rawdv->p_bih->biBitCount >> 3);
227
228     /* Properties of our video */
229     if( dv_header.dsf )
230     {
231         p_rawdv->frame_size = 12 * 150 * 80;
232         p_rawdv->f_rate = 25;
233     }
234     else
235     {
236         p_rawdv->frame_size = 10 * 150 * 80;
237         p_rawdv->f_rate = 29.97;
238     }
239
240     /* necessary because input_SplitBuffer() will only get
241      * INPUT_DEFAULT_BUFSIZE bytes at a time. */
242     p_input->i_bufsize = p_rawdv->frame_size;
243
244     /* Create one program */
245     vlc_mutex_lock( &p_input->stream.stream_lock );
246     if( input_InitStream( p_input, 0 ) == -1)
247     {
248         vlc_mutex_unlock( &p_input->stream.stream_lock );
249         msg_Err( p_input, "cannot init stream" );
250         goto error;
251     }
252     if( input_AddProgram( p_input, 0, 0) == NULL )
253     {
254         vlc_mutex_unlock( &p_input->stream.stream_lock );
255         msg_Err( p_input, "cannot add program" );
256         goto error;
257     }
258     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
259     p_input->stream.i_mux_rate = p_rawdv->frame_size * p_rawdv->f_rate;
260     vlc_mutex_unlock( &p_input->stream.stream_lock );
261
262     /* Add video stream */
263     vlc_mutex_lock( &p_input->stream.stream_lock );
264     p_rawdv->p_video_es = input_AddES( p_input,
265                                        p_input->stream.p_selected_program,
266                                        1, 0 );
267     p_rawdv->p_video_es->i_stream_id = 0;
268     p_rawdv->p_video_es->i_fourcc = VLC_FOURCC( 'd','v','s','d' );
269     p_rawdv->p_video_es->i_cat = VIDEO_ES;
270     p_rawdv->p_video_es->p_bitmapinfoheader = (void *)p_rawdv->p_bih;
271     input_SelectES( p_input, p_rawdv->p_video_es );
272     vlc_mutex_unlock( &p_input->stream.stream_lock );
273
274     /* Init pcr */
275     p_rawdv->i_pcr = 0;
276
277     return 0;
278
279  error:
280     if( p_rawdv->p_bih ) free( p_rawdv->p_bih );
281     Deactivate( (vlc_object_t *)p_input );
282     return -1;
283 }
284
285 /*****************************************************************************
286  * Deactivate: frees unused data
287  *****************************************************************************/
288 static void Deactivate( vlc_object_t *p_this )
289 {
290     input_thread_t *p_input = (input_thread_t *)p_this;
291     demux_sys_t *p_rawdv = (demux_sys_t *)p_input->p_demux_data;
292
293     free( p_rawdv );
294 }
295
296 /*****************************************************************************
297  * Demux: reads and demuxes data packets
298  *****************************************************************************
299  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
300  *****************************************************************************/
301 static int Demux( input_thread_t * p_input )
302 {
303     demux_sys_t    *p_rawdv = (demux_sys_t *)p_input->p_demux_data;
304     decoder_fifo_t *p_fifo =
305         p_input->stream.p_selected_program->pp_es[0]->p_decoder_fifo;
306     pes_packet_t   *p_pes;
307     data_packet_t  *p_data;
308     ssize_t        i_read;
309
310     if( p_fifo == NULL )
311     {
312         return -1;
313     }
314
315     if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
316     {
317         off_t i_pos;
318
319         msg_Warn( p_input, "synchro reinit" );
320
321         /* If the user tried to seek in the stream, we need to make sure
322          * the new position is at a DIF block boundary. */
323         vlc_mutex_lock( &p_input->stream.stream_lock );
324         i_pos= p_input->stream.p_selected_area->i_tell;
325         vlc_mutex_unlock( &p_input->stream.stream_lock );
326
327         if( (i_pos % p_rawdv->frame_size) &&
328             p_input->stream.b_seekable &&
329             p_input->stream.i_method == INPUT_METHOD_FILE )
330         {
331             p_input->pf_seek( p_input, (i_pos / p_rawdv->frame_size)
332                               * p_rawdv->frame_size );
333             input_AccessReinit( p_input );
334         }
335     }
336
337     /* Call the pace control */
338     input_ClockManageRef( p_input, p_input->stream.p_selected_program,
339                           p_rawdv->i_pcr );
340
341     i_read = input_SplitBuffer( p_input, &p_data, p_rawdv->frame_size );
342     if( i_read <= 0 )
343     {
344         return i_read;
345     }
346
347     p_pes = input_NewPES( p_input->p_method_data );
348     if( p_pes == NULL )
349     {
350         msg_Err( p_input, "out of memory" );
351         input_DeletePacket( p_input->p_method_data, p_data );
352         return -1;
353     }
354
355     p_pes->i_rate = p_input->stream.control.i_rate;
356     p_pes->p_first = p_pes->p_last = p_data;
357     p_pes->i_pes_size = i_read;
358     p_pes->i_nb_data = 1;
359     p_pes->i_pts =
360         input_ClockGetTS( p_input, p_input->stream.p_selected_program,
361                           p_rawdv->i_pcr );
362
363     input_DecodePES( p_fifo, p_pes );
364
365     p_rawdv->i_pcr += ( 90000 / p_rawdv->f_rate );
366
367     return 1;
368 }