importer: Add fake movie maker.
[L-SMASH.git] / importer / wave_imp.c
blob0a776f62e8dc06b6f000f3f5542f8aa822413fda
1 /*****************************************************************************
2 * wave_imp.c
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 */
25 #include <string.h>
27 #define LSMASH_IMPORTER_INTERNAL
28 #include "importer.h"
30 /*********************************************************************************
31 Waveform Audio File Format (WAVE) importer
33 References
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 )
57 typedef struct
59 uint16_t wFormatTag;
60 uint16_t nChannels;
61 uint32_t nSamplesPerSec;
62 uint32_t nAvgBytesPerSec;
63 uint16_t nBlockAlign;
64 uint16_t wBitsPerSample;
65 uint16_t cbSize;
66 } waveformat_extended_t;
68 typedef struct
70 waveformat_extended_t wfx;
71 union
73 uint16_t wValidBitsPerSample;
74 uint16_t wSamplesPerBlock;
75 uint16_t wReserved;
76 } Samples;
77 uint32_t dwChannelMask;
78 uint8_t guid[16];
79 } waveformat_extensible_t;
81 typedef struct
83 uint32_t number_of_samples;
84 uint32_t au_length;
85 uint32_t au_number;
86 waveformat_extensible_t fmt;
87 } wave_importer_t;
89 static void remove_wave_importer( wave_importer_t *wave_imp )
91 if( !wave_imp )
92 return;
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 );
114 if( !summary )
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 )
121 return 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;
124 else
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 )
129 return IMPORTER_EOF;
131 lsmash_sample_t *sample = lsmash_create_sample( wave_imp->au_length );
132 if( !sample )
133 return LSMASH_ERR_MEMORY_ALLOC;
134 *p_sample = sample;
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 :
165 return 0;
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;
177 return 0;
178 default :
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 );
186 if( !summary )
187 return NULL;
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 );
202 if( !cs )
203 goto fail;
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;
207 else
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 );
214 goto fail;
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 );
220 if( !cs )
221 goto fail;
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;
228 else
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 );
236 goto fail;
239 return summary;
240 fail:
241 lsmash_cleanup_summary( (lsmash_summary_t *)summary );
242 return NULL;
245 static int wave_importer_probe( importer_t *importer )
247 wave_importer_t *wave_imp = create_wave_importer( importer );
248 if( !wave_imp )
249 return LSMASH_ERR_MEMORY_ALLOC;
250 int err = 0;
251 uint32_t filesize;
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;
258 goto fail;
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 );
267 switch( ckID )
269 case LSMASH_4CC( 'f', 'm', 't', ' ' ) :
270 if( ckSize < 16 )
272 err = LSMASH_ERR_INVALID_DATA;
273 goto fail;
275 if( (err = wave_parse_fmt_chunk( wave_imp, bs )) < 0 )
276 goto fail;
277 fmt_chunk_present = 1;
278 break;
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;
284 goto fail;
286 wave_imp->number_of_samples = ckSize / wave_imp->fmt.wfx.nBlockAlign;
287 data_chunk_present = 1;
288 break;
289 default :
290 break;
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;
297 if( skip_size & 1 )
298 skip_size++;
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;
309 goto fail;
311 lsmash_audio_summary_t *summary = wave_create_summary( &wave_imp->fmt );
312 if( !summary )
314 err = LSMASH_ERR_NAMELESS;
315 goto fail;
317 if( (err = lsmash_add_entry( importer->summaries, summary )) < 0 )
319 lsmash_cleanup_summary( (lsmash_summary_t *)summary );
320 goto fail;
322 importer->info = wave_imp;
323 importer->status = IMPORTER_OK;
324 return 0;
325 fail:
326 remove_wave_importer( wave_imp );
327 importer->info = NULL;
328 return err;
331 static uint32_t wave_importer_get_last_delta( importer_t *importer, uint32_t track_number )
333 debug_if( !importer || !importer->info )
334 return 0;
335 wave_importer_t *wave_imp = (wave_importer_t *)importer->info;
336 if( !wave_imp || track_number != 1 || importer->status != IMPORTER_EOF )
337 return 0;
338 lsmash_audio_summary_t *summary = (lsmash_audio_summary_t *)lsmash_get_entry_data( importer->summaries, track_number );
339 if( !summary )
340 return 0;
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 ) },
350 wave_importer_probe,
351 wave_importer_get_accessunit,
352 wave_importer_get_last_delta,
353 wave_importer_cleanup