1 /*****************************************************************************
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 */
27 #define LSMASH_IMPORTER_INTERNAL
30 /***************************************************************************
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"
40 importer_status status
;
42 uint64_t next_frame_pos
;
43 uint8_t buffer
[DTS_MAX_EXSS_SIZE
];
44 lsmash_multiple_buffers_t
*au_buffers
;
47 uint8_t *incomplete_au
;
48 uint32_t incomplete_au_length
;
52 static void remove_dts_importer( dts_importer_t
*dts_imp
)
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
) );
66 dts_info_t
*dts_info
= &dts_imp
->info
;
67 dts_info
->bits
= lsmash_bits_adhoc_create();
70 lsmash_free( dts_imp
);
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
);
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
);
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
)
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" );
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
;
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" );
132 if( !info
->ddts_param_initialized
)
133 dts_update_specific_param( info
);
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
)
147 dts_parse_frame
= dts_parse_core_substream
;
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" );
157 if( prev_substream_type
== DTS_SUBSTREAM_TYPE_EXTENSION
158 && info
->exss_index
<= prev_exss_index
)
160 dts_parse_frame
= dts_parse_extension_substream
;
164 lsmash_log( importer
, LSMASH_LOG_ERROR
, "unknown substream type is detected.\n" );
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" );
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
)
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
);
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
)
207 if( !importer
->info
|| track_number
!= 1 )
209 lsmash_audio_summary_t
*summary
= (lsmash_audio_summary_t
*)lsmash_get_entry_data( importer
->summaries
, track_number
);
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
)
217 if( current_status
== IMPORTER_EOF
&& dts_imp
->au_length
== 0 )
219 buffered_sample
->length
= 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;
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
);
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
);
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) */
274 case 384000 : /* Invalid? (No reference in the spec) */
275 summary
->frequency
= 48000;
281 case 352800 : /* Invalid? (No reference in the spec) */
282 summary
->frequency
= 44100;
284 case 8000 : /* Invalid? (No reference in the spec) */
289 summary
->frequency
= 32000;
292 summary
->frequency
= 0;
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
);
302 static int dts_importer_probe( importer_t
*importer
)
304 dts_importer_t
*dts_imp
= create_dts_importer();
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 )
317 lsmash_audio_summary_t
*summary
= dts_create_summary( &dts_imp
->info
);
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
);
330 remove_dts_importer( dts_imp
);
331 importer
->info
= NULL
;
335 static uint32_t dts_importer_get_last_delta( importer_t
* importer
, uint32_t track_number
)
337 debug_if( !importer
|| !importer
->info
)
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
)
342 lsmash_audio_summary_t
*summary
= (lsmash_audio_summary_t
*)lsmash_get_entry_data( importer
->summaries
, track_number
);
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
) },
353 dts_importer_get_accessunit
,
354 dts_importer_get_last_delta
,