1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2014 L-SMASH project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *****************************************************************************/
21 /* This file is available under an ISC license. */
23 #include "common/internal.h" /* must be placed first */
27 #define LSMASH_IMPORTER_INTERNAL
30 /*********************************************************************************
31 Waveform Audio File Format (WAVE) importer
34 Multimedia Programming Interface and Data Specifications 1.0
35 New Multimedia Data Types and Data Techniques April 15, 1994 Revision: 3.0
36 Multiple channel audio data and WAVE files March 7, 2007
37 Microsoft Windows SDK MMReg.h
38 **********************************************************************************/
39 #define WAVE_MIN_FILESIZE 45
41 #define WAVE_FORMAT_TYPE_ID_PCM 0x0001 /* WAVE_FORMAT_PCM */
42 #define WAVE_FORMAT_TYPE_ID_EXTENSIBLE 0xFFFE /* WAVE_FORMAT_EXTENSIBLE */
44 #define PASS_GUID( _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15 ) \
45 { _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15 }
46 #define DEFINE_WAVEFORMAT_EXTENSIBLE_SUBTYPE_GUID( name, value ) \
47 static const uint8_t name[16] = value
49 /* KSDATAFORMAT_SUBTYPE_PCM := 00000001-0000-0010-8000-00aa00389b71 */
50 DEFINE_WAVEFORMAT_EXTENSIBLE_SUBTYPE_GUID
52 WAVEFORMAT_EXTENSIBLE_SUBTYPE_GUID_PCM
,
53 PASS_GUID( 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
54 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 )
61 uint32_t nSamplesPerSec
;
62 uint32_t nAvgBytesPerSec
;
64 uint16_t wBitsPerSample
;
66 } waveformat_extended_t
;
70 waveformat_extended_t wfx
;
73 uint16_t wValidBitsPerSample
;
74 uint16_t wSamplesPerBlock
;
77 uint32_t dwChannelMask
;
79 } waveformat_extensible_t
;
83 uint32_t number_of_samples
;
86 waveformat_extensible_t fmt
;
89 static void remove_wave_importer( wave_importer_t
*wave_imp
)
93 lsmash_free( wave_imp
);
96 static wave_importer_t
*create_wave_importer( importer_t
*importer
)
98 return (wave_importer_t
*)lsmash_malloc_zero( sizeof(wave_importer_t
) );
101 static void wave_importer_cleanup( importer_t
*importer
)
103 debug_if( importer
&& importer
->info
)
104 remove_wave_importer( importer
->info
);
107 static int wave_importer_get_accessunit( importer_t
*importer
, uint32_t track_number
, lsmash_sample_t
**p_sample
)
109 if( !importer
->info
)
110 return LSMASH_ERR_NAMELESS
;
111 if( track_number
!= 1 )
112 return LSMASH_ERR_FUNCTION_PARAM
;
113 lsmash_audio_summary_t
*summary
= (lsmash_audio_summary_t
*)lsmash_get_entry_data( importer
->summaries
, track_number
);
115 return LSMASH_ERR_NAMELESS
;
116 wave_importer_t
*wave_imp
= (wave_importer_t
*)importer
->info
;
117 importer_status current_status
= importer
->status
;
118 if( current_status
== IMPORTER_ERROR
)
119 return LSMASH_ERR_NAMELESS
;
120 if( current_status
== IMPORTER_EOF
)
122 if( wave_imp
->number_of_samples
/ summary
->samples_in_frame
> wave_imp
->au_number
)
123 wave_imp
->au_length
= summary
->bytes_per_frame
;
126 wave_imp
->au_length
= wave_imp
->fmt
.wfx
.nBlockAlign
* (wave_imp
->number_of_samples
% summary
->samples_in_frame
);
127 importer
->status
= IMPORTER_EOF
;
128 if( wave_imp
->au_length
== 0 )
131 lsmash_sample_t
*sample
= lsmash_create_sample( wave_imp
->au_length
);
133 return LSMASH_ERR_MEMORY_ALLOC
;
135 if( lsmash_bs_get_bytes_ex( importer
->bs
, wave_imp
->au_length
, sample
->data
) != wave_imp
->au_length
)
137 importer
->status
= IMPORTER_ERROR
;
138 return LSMASH_ERR_INVALID_DATA
;
140 sample
->length
= wave_imp
->au_length
;
141 sample
->dts
= wave_imp
->au_number
++ * summary
->samples_in_frame
;
142 sample
->cts
= sample
->dts
;
143 sample
->prop
.ra_flags
= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
144 return current_status
;
147 static inline int wave_fmt_subtype_cmp( const waveformat_extensible_t
*fmt
, const uint8_t guid
[16] )
149 return memcmp( fmt
->guid
, guid
, 16 );
152 static int wave_parse_fmt_chunk( wave_importer_t
*wave_imp
, lsmash_bs_t
*bs
)
154 waveformat_extensible_t
*fmt
= &wave_imp
->fmt
;
155 waveformat_extended_t
*wfx
= &fmt
->wfx
;
156 wfx
->wFormatTag
= lsmash_bs_get_le16( bs
);
157 wfx
->nChannels
= lsmash_bs_get_le16( bs
);
158 wfx
->nSamplesPerSec
= lsmash_bs_get_le32( bs
);
159 wfx
->nAvgBytesPerSec
= lsmash_bs_get_le32( bs
);
160 wfx
->nBlockAlign
= lsmash_bs_get_le16( bs
);
161 wfx
->wBitsPerSample
= lsmash_bs_get_le16( bs
);
162 switch( wfx
->wFormatTag
)
164 case WAVE_FORMAT_TYPE_ID_PCM
:
166 case WAVE_FORMAT_TYPE_ID_EXTENSIBLE
:
167 wfx
->cbSize
= lsmash_bs_get_le16( bs
);
168 if( wfx
->cbSize
< 22 )
169 return LSMASH_ERR_INVALID_DATA
;
170 fmt
->Samples
.wValidBitsPerSample
= lsmash_bs_get_le16( bs
);
171 fmt
->dwChannelMask
= lsmash_bs_get_le32( bs
);
172 if( lsmash_bs_get_bytes_ex( bs
, 16, fmt
->guid
) != 16 )
173 return LSMASH_ERR_NAMELESS
;
174 /* We support only PCM audio currently. */
175 if( wave_fmt_subtype_cmp( fmt
, WAVEFORMAT_EXTENSIBLE_SUBTYPE_GUID_PCM
) )
176 return LSMASH_ERR_INVALID_DATA
;
179 return LSMASH_ERR_NAMELESS
;
183 static lsmash_audio_summary_t
*wave_create_summary( waveformat_extensible_t
*fmt
)
185 lsmash_audio_summary_t
*summary
= (lsmash_audio_summary_t
*)lsmash_create_summary( LSMASH_SUMMARY_TYPE_AUDIO
);
188 waveformat_extended_t
*wfx
= &fmt
->wfx
;
189 summary
->sample_type
= QT_CODEC_TYPE_LPCM_AUDIO
;
190 summary
->aot
= MP4A_AUDIO_OBJECT_TYPE_NULL
;
191 summary
->frequency
= wfx
->nSamplesPerSec
;
192 summary
->channels
= wfx
->nChannels
;
193 summary
->sample_size
= wfx
->wFormatTag
== WAVE_FORMAT_TYPE_ID_EXTENSIBLE
194 ? fmt
->Samples
.wValidBitsPerSample
195 : wfx
->wBitsPerSample
;
196 summary
->samples_in_frame
= 1000; /* arbitrary */
197 summary
->sbr_mode
= MP4A_AAC_SBR_NOT_SPECIFIED
;
198 summary
->bytes_per_frame
= wfx
->nBlockAlign
* summary
->samples_in_frame
;
199 summary
->max_au_length
= summary
->bytes_per_frame
;
200 lsmash_codec_specific_t
*cs
= lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS
,
201 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED
);
204 lsmash_qt_audio_format_specific_flags_t
*lpcm
= (lsmash_qt_audio_format_specific_flags_t
*)cs
->data
.structured
;
205 if( (summary
->sample_size
& 7) == 0 )
206 lpcm
->format_flags
|= QT_AUDIO_FORMAT_FLAG_PACKED
;
208 lpcm
->format_flags
|= QT_AUDIO_FORMAT_FLAG_ALIGNED_HIGH
;
209 if( summary
->sample_size
> 8 )
210 lpcm
->format_flags
|= QT_AUDIO_FORMAT_FLAG_SIGNED_INTEGER
;
211 if( lsmash_add_entry( &summary
->opaque
->list
, cs
) < 0 )
213 lsmash_destroy_codec_specific_data( cs
);
216 if( wfx
->wFormatTag
== WAVE_FORMAT_TYPE_ID_EXTENSIBLE
|| wfx
->nChannels
> 2 )
218 cs
= lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT
,
219 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED
);
222 lsmash_qt_audio_channel_layout_t
*layout
= (lsmash_qt_audio_channel_layout_t
*)cs
->data
.structured
;
223 if( wfx
->wFormatTag
== WAVE_FORMAT_TYPE_ID_EXTENSIBLE
)
225 layout
->channelLayoutTag
= QT_CHANNEL_LAYOUT_USE_CHANNEL_BITMAP
;
226 layout
->channelBitmap
= fmt
->dwChannelMask
;
230 layout
->channelLayoutTag
= QT_CHANNEL_LAYOUT_UNKNOWN
| wfx
->nChannels
;
231 layout
->channelBitmap
= 0;
233 if( lsmash_add_entry( &summary
->opaque
->list
, cs
) < 0 )
235 lsmash_destroy_codec_specific_data( cs
);
241 lsmash_cleanup_summary( (lsmash_summary_t
*)summary
);
245 static int wave_importer_probe( importer_t
*importer
)
247 wave_importer_t
*wave_imp
= create_wave_importer( importer
);
249 return LSMASH_ERR_MEMORY_ALLOC
;
252 lsmash_bs_t
*bs
= importer
->bs
;
253 if( lsmash_bs_get_be32( bs
) != LSMASH_4CC( 'R', 'I', 'F', 'F' )
254 || ((filesize
= lsmash_bs_get_le32( bs
) + 8) < WAVE_MIN_FILESIZE
&& filesize
> 8)
255 || lsmash_bs_get_be32( bs
) != LSMASH_4CC( 'W', 'A', 'V', 'E' ) )
257 err
= LSMASH_ERR_INVALID_DATA
;
260 int fmt_chunk_present
= 0;
261 int data_chunk_present
= 0;
262 while( !bs
->eob
&& !(fmt_chunk_present
&& data_chunk_present
) )
264 uint32_t ckID
= lsmash_bs_get_be32( bs
);
265 uint32_t ckSize
= lsmash_bs_get_le32( bs
);
266 lsmash_bs_reset_counter( bs
);
269 case LSMASH_4CC( 'f', 'm', 't', ' ' ) :
272 err
= LSMASH_ERR_INVALID_DATA
;
275 if( (err
= wave_parse_fmt_chunk( wave_imp
, bs
)) < 0 )
277 fmt_chunk_present
= 1;
279 case LSMASH_4CC( 'd', 'a', 't', 'a' ) :
280 if( !fmt_chunk_present
)
282 /* The 'fmt ' chunk must be present before the 'data' chunk. */
283 err
= LSMASH_ERR_INVALID_DATA
;
286 wave_imp
->number_of_samples
= ckSize
/ wave_imp
->fmt
.wfx
.nBlockAlign
;
287 data_chunk_present
= 1;
292 if( !data_chunk_present
)
294 /* Skip the rest of this chunk.
295 * Note that ckData is word-aligned even if ckSize is an odd number. */
296 uint32_t skip_size
= ckSize
;
299 if( skip_size
> lsmash_bs_count( bs
) )
301 skip_size
-= lsmash_bs_count( bs
);
302 lsmash_bs_read_seek( bs
, skip_size
, SEEK_CUR
);
306 if( !(fmt_chunk_present
&& data_chunk_present
) )
308 err
= LSMASH_ERR_INVALID_DATA
;
311 lsmash_audio_summary_t
*summary
= wave_create_summary( &wave_imp
->fmt
);
314 err
= LSMASH_ERR_NAMELESS
;
317 if( (err
= lsmash_add_entry( importer
->summaries
, summary
)) < 0 )
319 lsmash_cleanup_summary( (lsmash_summary_t
*)summary
);
322 importer
->info
= wave_imp
;
323 importer
->status
= IMPORTER_OK
;
326 remove_wave_importer( wave_imp
);
327 importer
->info
= NULL
;
331 static uint32_t wave_importer_get_last_delta( importer_t
*importer
, uint32_t track_number
)
333 debug_if( !importer
|| !importer
->info
)
335 wave_importer_t
*wave_imp
= (wave_importer_t
*)importer
->info
;
336 if( !wave_imp
|| track_number
!= 1 || importer
->status
!= IMPORTER_EOF
)
338 lsmash_audio_summary_t
*summary
= (lsmash_audio_summary_t
*)lsmash_get_entry_data( importer
->summaries
, track_number
);
341 return wave_imp
->number_of_samples
/ summary
->samples_in_frame
>= wave_imp
->au_number
342 ? summary
->samples_in_frame
343 : (wave_imp
->number_of_samples
% summary
->samples_in_frame
);
346 const importer_functions wave_importer
=
348 { "WAVE", offsetof( importer_t
, log_level
) },
351 wave_importer_get_accessunit
,
352 wave_importer_get_last_delta
,
353 wave_importer_cleanup