]> git.sesse.net Git - vlc/blob - modules/demux/dts.c
playlist: Don't allow pl_Release(p_playlist) and pl_Yield(p_playlist).
[vlc] / modules / demux / dts.c
1 /*****************************************************************************
2  * dts.c : raw DTS stream input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001-2007 the VideoLAN team
5  * $Id$
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_demux.h>
34 #include <vlc_codec.h>
35
36 /*****************************************************************************
37  * Module descriptor
38  *****************************************************************************/
39 static int  Open  ( vlc_object_t * );
40 static void Close ( vlc_object_t * );
41
42 vlc_module_begin();
43     set_category( CAT_INPUT );
44     set_subcategory( SUBCAT_INPUT_DEMUX );
45     set_description( N_("Raw DTS demuxer") );
46     set_capability( "demux", 155 );
47     set_callbacks( Open, Close );
48     add_shortcut( "dts" );
49 vlc_module_end();
50
51 /*****************************************************************************
52  * Local prototypes
53  *****************************************************************************/
54 static int Demux  ( demux_t * );
55 static int Control( demux_t *, int, va_list );
56
57 struct demux_sys_t
58 {
59     bool  b_start;
60     es_out_id_t *p_es;
61
62     /* Packetizer */
63     decoder_t *p_packetizer;
64
65     int i_mux_rate;
66 };
67
68 static int CheckSync( const uint8_t *p_peek );
69
70 #define DTS_PACKET_SIZE 16384
71 #define DTS_PROBE_SIZE (DTS_PACKET_SIZE * 4)
72 #define DTS_MAX_HEADER_SIZE 11
73
74 /*****************************************************************************
75  * Open: initializes ES structures
76  *****************************************************************************/
77 static int Open( vlc_object_t * p_this )
78 {
79     demux_t     *p_demux = (demux_t*)p_this;
80     demux_sys_t *p_sys;
81     const uint8_t *p_peek;
82     int          i_peek = 0;
83
84     /* Check if we are dealing with a WAV file */
85     if( stream_Peek( p_demux->s, &p_peek, 20 ) == 20 &&
86         !memcmp( p_peek, "RIFF", 4 ) && !memcmp( &p_peek[8], "WAVE", 4 ) )
87     {
88         /* Find the wave format header */
89         i_peek = 12 + 8;
90         while( memcmp( p_peek + i_peek - 8, "fmt ", 4 ) )
91         {
92             uint32_t i_len = GetDWLE( p_peek + i_peek - 4 );
93             if( i_len > DTS_PROBE_SIZE || i_peek + i_len > DTS_PROBE_SIZE )
94                 return VLC_EGENERIC;
95
96             i_peek += i_len + 8;
97             if( stream_Peek( p_demux->s, &p_peek, i_peek ) != i_peek )
98                 return VLC_EGENERIC;
99         }
100
101         /* Sanity check the wave format header */
102         uint32_t i_len = GetDWLE( p_peek + i_peek - 4 );
103         if( i_len > DTS_PROBE_SIZE )
104             return VLC_EGENERIC;
105
106         i_peek += i_len + 8;
107         if( stream_Peek( p_demux->s, &p_peek, i_peek ) != i_peek )
108             return VLC_EGENERIC;
109         if( GetWLE( p_peek + i_peek - i_len - 8 /* wFormatTag */ ) !=
110             1 /* WAVE_FORMAT_PCM */ )
111             return VLC_EGENERIC;
112         if( GetWLE( p_peek + i_peek - i_len - 6 /* nChannels */ ) != 2 )
113             return VLC_EGENERIC;
114         if( GetDWLE( p_peek + i_peek - i_len - 4 /* nSamplesPerSec */ ) !=
115             44100 )
116             return VLC_EGENERIC;
117
118         /* Skip the wave header */
119         while( memcmp( p_peek + i_peek - 8, "data", 4 ) )
120         {
121             uint32_t i_len = GetDWLE( p_peek + i_peek - 4 );
122             if( i_len > DTS_PROBE_SIZE || i_peek + i_len > DTS_PROBE_SIZE )
123                 return VLC_EGENERIC;
124
125             i_peek += i_len + 8;
126             if( stream_Peek( p_demux->s, &p_peek, i_peek ) != i_peek )
127                 return VLC_EGENERIC;
128         }
129
130         /* Some DTS wav files don't begin with a sync code so we do a more
131          * extensive search */
132         int i_size = stream_Peek( p_demux->s, &p_peek, DTS_PROBE_SIZE );
133         i_size -= DTS_MAX_HEADER_SIZE;
134
135         while( i_peek < i_size )
136         {
137             if( CheckSync( p_peek + i_peek ) != VLC_SUCCESS )
138                 /* The data is stored in 16 bits words */
139                 i_peek += 2;
140             else
141                 break;
142         }
143     }
144
145     /* Have a peep at the show. */
146     CHECK_PEEK( p_peek, i_peek + DTS_MAX_HEADER_SIZE * 2  );
147
148     if( CheckSync( p_peek + i_peek ) != VLC_SUCCESS )
149     {
150         if( !p_demux->b_force )
151             return VLC_EGENERIC;
152
153         /* User forced */
154         msg_Err( p_demux, "this doesn't look like a DTS audio stream, "
155                  "continuing anyway" );
156     }
157
158     DEMUX_INIT_COMMON(); p_sys = p_demux->p_sys;
159  
160     INIT_APACKETIZER( p_sys->p_packetizer, 'd','t','s',' ' );
161     LOAD_PACKETIZER_OR_FAIL( p_sys->p_packetizer, "DTS" );
162
163     p_sys->p_es = es_out_Add( p_demux->out, &p_sys->p_packetizer->fmt_in );
164
165     return VLC_SUCCESS;
166 }
167
168 /*****************************************************************************
169  * Close: frees unused data
170  *****************************************************************************/
171 static void Close( vlc_object_t *p_this )
172 {
173     demux_t     *p_demux = (demux_t*)p_this;
174     demux_sys_t *p_sys = p_demux->p_sys;
175
176     DESTROY_PACKETIZER( p_sys->p_packetizer );
177
178     free( p_sys );
179 }
180
181 /*****************************************************************************
182  * Demux: reads and demuxes data packets
183  *****************************************************************************
184  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
185  *****************************************************************************/
186 static int Demux( demux_t *p_demux )
187 {
188     demux_sys_t *p_sys = p_demux->p_sys;
189     block_t *p_block_in, *p_block_out;
190
191     if( !( p_block_in = stream_Block( p_demux->s, DTS_PACKET_SIZE ) ) )
192     {
193         return 0;
194     }
195
196     if( p_sys->b_start )
197         p_block_in->i_pts = p_block_in->i_dts = 1;
198     else
199         p_block_in->i_pts = p_block_in->i_dts = 0;
200
201     while( (p_block_out = p_sys->p_packetizer->pf_packetize(
202                 p_sys->p_packetizer, &p_block_in )) )
203     {
204         p_sys->b_start = false;
205
206         while( p_block_out )
207         {
208             block_t *p_next = p_block_out->p_next;
209
210             /* We assume a constant bitrate */
211             if( p_block_out->i_length )
212             {
213                 p_sys->i_mux_rate =
214                     p_block_out->i_buffer * INT64_C(1000000) / p_block_out->i_length;
215             }
216
217             /* set PCR */
218             es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block_out->i_dts );
219
220             es_out_Send( p_demux->out, p_sys->p_es, p_block_out );
221
222             p_block_out = p_next;
223         }
224     }
225
226     return 1;
227 }
228
229 /*****************************************************************************
230  * Control:
231  *****************************************************************************/
232 static int Control( demux_t *p_demux, int i_query, va_list args )
233 {
234     demux_sys_t *p_sys  = p_demux->p_sys;
235     if( i_query == DEMUX_SET_TIME )
236         return VLC_EGENERIC;
237     else
238         return demux_vaControlHelper( p_demux->s,
239                                        0, -1,
240                                        8*p_sys->i_mux_rate, 1, i_query, args );
241 }
242
243 /*****************************************************************************
244  * CheckSync: Check if buffer starts with a DTS sync code
245  *****************************************************************************/
246 static int CheckSync( const uint8_t *p_peek )
247 {
248     /* 14 bits, little endian version of the bitstream */
249     if( p_peek[0] == 0xff && p_peek[1] == 0x1f &&
250         p_peek[2] == 0x00 && p_peek[3] == 0xe8 &&
251         (p_peek[4] & 0xf0) == 0xf0 && p_peek[5] == 0x07 )
252     {
253         return VLC_SUCCESS;
254     }
255     /* 14 bits, big endian version of the bitstream */
256     else if( p_peek[0] == 0x1f && p_peek[1] == 0xff &&
257              p_peek[2] == 0xe8 && p_peek[3] == 0x00 &&
258              p_peek[4] == 0x07 && (p_peek[5] & 0xf0) == 0xf0)
259     {
260         return VLC_SUCCESS;
261     }
262     /* 16 bits, big endian version of the bitstream */
263     else if( p_peek[0] == 0x7f && p_peek[1] == 0xfe &&
264              p_peek[2] == 0x80 && p_peek[3] == 0x01 )
265     {
266         return VLC_SUCCESS;
267     }
268     /* 16 bits, little endian version of the bitstream */
269     else if( p_peek[0] == 0xfe && p_peek[1] == 0x7f &&
270              p_peek[2] == 0x01 && p_peek[3] == 0x80 )
271     {
272         return VLC_SUCCESS;
273     }
274
275     return VLC_EGENERIC;
276 }
277