fragment: Utilize meaningful error values.
[L-SMASH.git] / cli / dts_imp.c
blob923cb33cf6f4f205e191d21d17c8c7ccb80e8a3d
1 /*****************************************************************************
2 * dts_imp.c
3 *****************************************************************************
4 * Copyright (C) 2012-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 DTS importer
32 ETSI TS 102 114 V1.2.1 (2002-12)
33 ETSI TS 102 114 V1.3.1 (2011-08)
34 ETSI TS 102 114 V1.4.1 (2012-09)
35 ***************************************************************************/
36 #include "codecs/dts.h"
38 typedef struct
40 importer_status status;
41 dts_info_t info;
42 uint64_t next_frame_pos;
43 uint8_t buffer[DTS_MAX_EXSS_SIZE];
44 lsmash_multiple_buffers_t *au_buffers;
45 uint8_t *au;
46 uint32_t au_length;
47 uint8_t *incomplete_au;
48 uint32_t incomplete_au_length;
49 uint32_t au_number;
50 } dts_importer_t;
52 static void remove_dts_importer( dts_importer_t *dts_imp )
54 if( !dts_imp )
55 return;
56 lsmash_destroy_multiple_buffers( dts_imp->au_buffers );
57 lsmash_bits_adhoc_cleanup( dts_imp->info.bits );
58 lsmash_free( dts_imp );
61 static dts_importer_t *create_dts_importer( void )
63 dts_importer_t *dts_imp = (dts_importer_t *)lsmash_malloc_zero( sizeof(dts_importer_t) );
64 if( !dts_imp )
65 return NULL;
66 dts_info_t *dts_info = &dts_imp->info;
67 dts_info->bits = lsmash_bits_adhoc_create();
68 if( !dts_info->bits )
70 lsmash_free( dts_imp );
71 return NULL;
73 dts_imp->au_buffers = lsmash_create_multiple_buffers( 2, DTS_MAX_EXSS_SIZE );
74 if( !dts_imp->au_buffers )
76 lsmash_bits_adhoc_cleanup( dts_info->bits );
77 lsmash_free( dts_imp );
78 return NULL;
80 dts_imp->au = lsmash_withdraw_buffer( dts_imp->au_buffers, 1 );
81 dts_imp->incomplete_au = lsmash_withdraw_buffer( dts_imp->au_buffers, 2 );
82 dts_setup_parser( dts_info );
83 return dts_imp;
86 static void dts_importer_cleanup( importer_t *importer )
88 debug_if( importer && importer->info )
89 remove_dts_importer( importer->info );
92 static int dts_importer_get_next_accessunit_internal( importer_t *importer )
94 int au_completed = 0;
95 dts_importer_t *dts_imp = (dts_importer_t *)importer->info;
96 dts_info_t *info = &dts_imp->info;
97 lsmash_bs_t *bs = info->bits->bs;
98 while( !au_completed )
100 /* Read data from the stream if needed. */
101 dts_imp->next_frame_pos += info->frame_size;
102 lsmash_bs_read_seek( bs, dts_imp->next_frame_pos, SEEK_SET );
103 uint64_t remain_size = lsmash_bs_get_remaining_buffer_size( bs );
104 if( remain_size < DTS_MAX_EXSS_SIZE )
106 if( lsmash_bs_read( bs, bs->buffer.max_size ) < 0 )
108 lsmash_log( importer, LSMASH_LOG_ERROR, "failed to read data from the stream.\n" );
109 return -1;
111 remain_size = lsmash_bs_get_remaining_buffer_size( bs );
113 memcpy( dts_imp->buffer, lsmash_bs_get_buffer_data( bs ), LSMASH_MIN( remain_size, DTS_MAX_EXSS_SIZE ) );
114 /* Check the remainder length of the buffer.
115 * If there is enough length, then parse the frame in it.
116 * The length 10 is the required byte length to get frame size. */
117 if( bs->eob || (bs->eof && remain_size < 10) )
119 /* Reached the end of stream. */
120 dts_imp->status = IMPORTER_EOF;
121 au_completed = !!dts_imp->incomplete_au_length;
122 if( !au_completed )
124 /* No more access units in the stream. */
125 if( lsmash_bs_get_remaining_buffer_size( bs ) )
127 lsmash_log( importer, LSMASH_LOG_WARNING, "the stream is truncated at the end.\n" );
128 return -1;
130 return 0;
132 if( !info->ddts_param_initialized )
133 dts_update_specific_param( info );
135 else
137 /* Parse substream frame. */
138 dts_substream_type prev_substream_type = info->substream_type;
139 info->substream_type = dts_get_substream_type( info );
140 int (*dts_parse_frame)( dts_info_t * ) = NULL;
141 switch( info->substream_type )
143 /* Decide substream frame parser and check if this frame and the previous frame belong to the same AU. */
144 case DTS_SUBSTREAM_TYPE_CORE :
145 if( prev_substream_type != DTS_SUBSTREAM_TYPE_NONE )
146 au_completed = 1;
147 dts_parse_frame = dts_parse_core_substream;
148 break;
149 case DTS_SUBSTREAM_TYPE_EXTENSION :
151 uint8_t prev_exss_index = info->exss_index;
152 if( dts_get_exss_index( info, &info->exss_index ) < 0 )
154 lsmash_log( importer, LSMASH_LOG_ERROR, "failed to get the index of an extension substream.\n" );
155 return -1;
157 if( prev_substream_type == DTS_SUBSTREAM_TYPE_EXTENSION
158 && info->exss_index <= prev_exss_index )
159 au_completed = 1;
160 dts_parse_frame = dts_parse_extension_substream;
161 break;
163 default :
164 lsmash_log( importer, LSMASH_LOG_ERROR, "unknown substream type is detected.\n" );
165 return -1;
167 if( !info->ddts_param_initialized && au_completed )
168 dts_update_specific_param( info );
169 info->frame_size = 0;
170 if( dts_parse_frame( info ) < 0 )
172 lsmash_log( importer, LSMASH_LOG_ERROR, "failed to parse a frame.\n" );
173 return -1;
176 if( au_completed )
178 memcpy( dts_imp->au, dts_imp->incomplete_au, dts_imp->incomplete_au_length );
179 dts_imp->au_length = dts_imp->incomplete_au_length;
180 dts_imp->incomplete_au_length = 0;
181 info->exss_count = (info->substream_type == DTS_SUBSTREAM_TYPE_EXTENSION);
182 if( dts_imp->status == IMPORTER_EOF )
183 break;
185 /* Increase buffer size to store AU if short. */
186 if( dts_imp->incomplete_au_length + info->frame_size > dts_imp->au_buffers->buffer_size )
188 lsmash_multiple_buffers_t *temp = lsmash_resize_multiple_buffers( dts_imp->au_buffers,
189 dts_imp->au_buffers->buffer_size + DTS_MAX_EXSS_SIZE );
190 if( !temp )
191 return -1;
192 dts_imp->au_buffers = temp;
193 dts_imp->au = lsmash_withdraw_buffer( dts_imp->au_buffers, 1 );
194 dts_imp->incomplete_au = lsmash_withdraw_buffer( dts_imp->au_buffers, 2 );
196 /* Append frame data. */
197 memcpy( dts_imp->incomplete_au + dts_imp->incomplete_au_length, dts_imp->buffer, info->frame_size );
198 dts_imp->incomplete_au_length += info->frame_size;
200 return info->bits->bs->error ? -1 : 0;
203 static int dts_importer_get_accessunit( importer_t *importer, uint32_t track_number, lsmash_sample_t *buffered_sample )
205 debug_if( !importer || !importer->info || !buffered_sample->data || !buffered_sample->length )
206 return -1;
207 if( !importer->info || track_number != 1 )
208 return -1;
209 lsmash_audio_summary_t *summary = (lsmash_audio_summary_t *)lsmash_get_entry_data( importer->summaries, track_number );
210 if( !summary )
211 return -1;
212 dts_importer_t *dts_imp = (dts_importer_t *)importer->info;
213 dts_info_t *info = &dts_imp->info;
214 importer_status current_status = dts_imp->status;
215 if( current_status == IMPORTER_ERROR || buffered_sample->length < dts_imp->au_length )
216 return -1;
217 if( current_status == IMPORTER_EOF && dts_imp->au_length == 0 )
219 buffered_sample->length = 0;
220 return 0;
222 if( current_status == IMPORTER_CHANGE )
223 summary->max_au_length = 0;
224 memcpy( buffered_sample->data, dts_imp->au, dts_imp->au_length );
225 buffered_sample->length = dts_imp->au_length;
226 buffered_sample->dts = dts_imp->au_number++ * summary->samples_in_frame;
227 buffered_sample->cts = buffered_sample->dts;
228 buffered_sample->prop.ra_flags = ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC;
229 buffered_sample->prop.pre_roll.distance = !!(info->flags & DTS_EXT_SUBSTREAM_LBR_FLAG); /* MDCT */
230 if( dts_imp->status == IMPORTER_EOF )
232 dts_imp->au_length = 0;
233 return 0;
235 if( dts_importer_get_next_accessunit_internal( importer ) < 0 )
236 dts_imp->status = IMPORTER_ERROR;
237 return current_status;
240 static lsmash_audio_summary_t *dts_create_summary( dts_info_t *info )
242 lsmash_audio_summary_t *summary = (lsmash_audio_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_AUDIO );
243 if( !summary )
244 return NULL;
245 lsmash_dts_specific_parameters_t *param = &info->ddts_param;
246 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS,
247 LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
248 specific->data.unstructured = lsmash_create_dts_specific_info( param, &specific->size );
249 if( !specific->data.unstructured
250 || lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
252 lsmash_cleanup_summary( (lsmash_summary_t *)summary );
253 lsmash_destroy_codec_specific_data( specific );
254 return NULL;
256 /* The CODEC identifiers probably should not be the combination of 'mp4a' and
257 * the objectTypeIndications for DTS audio since there is no public specification
258 * which defines the encapsulation of the stream as the MPEG-4 Audio context yet.
259 * In the world, there are muxers which is using such doubtful implementation.
260 * The objectTypeIndications are registered at MP4RA, but this does not always
261 * mean we can mux by using those objectTypeIndications.
262 * If available, there shall be the specification which defines the existence of
263 * DecoderSpecificInfo and its semantics, and what access unit consists of. */
264 summary->sample_type = lsmash_dts_get_codingname( param );
265 summary->aot = MP4A_AUDIO_OBJECT_TYPE_NULL; /* make no sense */
266 summary->sbr_mode = MP4A_AAC_SBR_NOT_SPECIFIED; /* make no sense */
267 switch( param->DTSSamplingFrequency )
269 case 12000 : /* Invalid? (No reference in the spec) */
270 case 24000 :
271 case 48000 :
272 case 96000 :
273 case 192000 :
274 case 384000 : /* Invalid? (No reference in the spec) */
275 summary->frequency = 48000;
276 break;
277 case 22050 :
278 case 44100 :
279 case 88200 :
280 case 176400 :
281 case 352800 : /* Invalid? (No reference in the spec) */
282 summary->frequency = 44100;
283 break;
284 case 8000 : /* Invalid? (No reference in the spec) */
285 case 16000 :
286 case 32000 :
287 case 64000 :
288 case 128000 :
289 summary->frequency = 32000;
290 break;
291 default :
292 summary->frequency = 0;
293 break;
295 summary->samples_in_frame = (summary->frequency * info->frame_duration) / param->DTSSamplingFrequency;
296 summary->max_au_length = DTS_MAX_CORE_SIZE + DTS_MAX_NUM_EXSS * DTS_MAX_EXSS_SIZE;
297 summary->sample_size = param->pcmSampleDepth;
298 summary->channels = dts_get_max_channel_count( info );
299 return summary;
302 static int dts_importer_probe( importer_t *importer )
304 dts_importer_t *dts_imp = create_dts_importer();
305 if( !dts_imp )
306 return -1;
307 lsmash_bits_t *bits = dts_imp->info.bits;
308 lsmash_bs_t *bs = bits->bs;
309 bs->stream = importer->stream;
310 bs->read = lsmash_fread_wrapper;
311 bs->seek = lsmash_fseek_wrapper;
312 bs->unseekable = importer->is_stdin;
313 bs->buffer.max_size = DTS_MAX_EXSS_SIZE;
314 importer->info = dts_imp;
315 if( dts_importer_get_next_accessunit_internal( importer ) < 0 )
316 goto fail;
317 lsmash_audio_summary_t *summary = dts_create_summary( &dts_imp->info );
318 if( !summary )
319 goto fail;
320 if( dts_imp->status != IMPORTER_EOF )
321 dts_imp->status = IMPORTER_OK;
322 dts_imp->au_number = 0;
323 if( lsmash_add_entry( importer->summaries, summary ) < 0 )
325 lsmash_cleanup_summary( (lsmash_summary_t *)summary );
326 goto fail;
328 return 0;
329 fail:
330 remove_dts_importer( dts_imp );
331 importer->info = NULL;
332 return -1;
335 static uint32_t dts_importer_get_last_delta( importer_t* importer, uint32_t track_number )
337 debug_if( !importer || !importer->info )
338 return 0;
339 dts_importer_t *dts_imp = (dts_importer_t *)importer->info;
340 if( !dts_imp || track_number != 1 || dts_imp->status != IMPORTER_EOF || dts_imp->au_length )
341 return 0;
342 lsmash_audio_summary_t *summary = (lsmash_audio_summary_t *)lsmash_get_entry_data( importer->summaries, track_number );
343 if( !summary )
344 return 0;
345 return (summary->frequency * dts_imp->info.frame_duration) / dts_imp->info.ddts_param.DTSSamplingFrequency;
348 const importer_functions dts_importer =
350 { "DTS Coherent Acoustics", offsetof( importer_t, log_level ) },
352 dts_importer_probe,
353 dts_importer_get_accessunit,
354 dts_importer_get_last_delta,
355 dts_importer_cleanup