list: Decide the entry eliminator of list at its initialization.
[L-SMASH.git] / importer / amr_imp.c
blob7a1dca15268473012dced45283995fa1f661050d
1 /*****************************************************************************
2 * amr_imp.c
3 *****************************************************************************
4 * Copyright (C) 2010-2017 L-SMASH project
6 * Authors: Takashi Hirata <silverfilain@gmail.com>
7 * Contributors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
9 * Permission to use, copy, modify, and/or distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 *****************************************************************************/
22 /* This file is available under an ISC license. */
24 #include "common/internal.h" /* must be placed first */
26 #include <string.h>
28 #define LSMASH_IMPORTER_INTERNAL
29 #include "importer.h"
31 /***************************************************************************
32 AMR-NB/WB storage format importer
33 3GPP TS 26.101 V11.0.0 (2012-9)
34 3GPP TS 26.201 V11.0.0 (2012-9)
35 3GPP TS 26.244 V12.3.0 (2014-03)
36 http://www.ietf.org/rfc/rfc3267.txt (Obsoleted)
37 http://www.ietf.org/rfc/rfc4867.txt
38 ***************************************************************************/
39 typedef struct
41 int wb; /* 0: AMR-NB, 1: AMR-WB */
42 uint32_t samples_in_frame;
43 uint32_t au_number;
44 } amr_importer_t;
46 static void remove_amr_importer
48 amr_importer_t *amr_imp
51 lsmash_free( amr_imp );
54 static amr_importer_t *create_amr_importer
56 importer_t *importer
59 return (amr_importer_t *)lsmash_malloc_zero( sizeof(amr_importer_t) );
62 static void amr_cleanup
64 importer_t *importer
67 debug_if( importer && importer->info )
68 remove_amr_importer( importer->info );
71 static int amr_get_accessunit
73 importer_t *importer,
74 uint32_t track_number,
75 lsmash_sample_t **p_sample
78 if( !importer->info )
79 return LSMASH_ERR_NAMELESS;
80 if( track_number != 1 )
81 return LSMASH_ERR_FUNCTION_PARAM;
82 amr_importer_t *amr_imp = (amr_importer_t *)importer->info;
83 lsmash_bs_t *bs = importer->bs;
84 if( importer->status == IMPORTER_EOF || lsmash_bs_is_end( bs, 0 ) )
86 /* EOF */
87 importer->status = IMPORTER_EOF;
88 return IMPORTER_EOF;
90 /* Each speech frame consists of one speech frame header and one speech data.
91 * At the end of each speech data, octet alignment if needed.
92 * Speech frame header
93 * 0 1 2 3 4 5 6 7
94 * +-+-------+-+-+-+
95 * |P| FT |Q|P|P|
96 * +-+-------+-+-+-+
97 * FT: Frame type index
98 * Q : Frame quality indicator
99 * P : Must be set to 0
100 * FT= 9, 10 and 11 for AMR-NB shall not be used in the file format.
101 * FT=12, 13 and 14 for AMR-NB are not defined yet in the file format.
102 * FT=10, 11, 12 and 13 for AMR-WB are not defined yet in the file format.
103 * FT determines the size of the speech frame starting with it.
105 uint8_t FT = (lsmash_bs_show_byte( bs, 0 ) >> 3) & 0x0F;
106 const int frame_size[2][16] =
108 { 13, 14, 16, 18, 20, 21, 27, 32, 6, -1, -1, -1, 0, 0, 0, 1 },
109 { 18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 0, 0, 0, 0, 1, 1 }
111 int read_size = frame_size[ amr_imp->wb ][FT];
112 if( read_size <= 0 )
114 lsmash_log( importer, LSMASH_LOG_ERROR, "an %s speech frame is detected.\n", read_size < 0 ? "invalid" : "unknown" );
115 importer->status = IMPORTER_ERROR;
116 return read_size < 0 ? LSMASH_ERR_INVALID_DATA : LSMASH_ERR_NAMELESS;
118 lsmash_sample_t *sample = lsmash_create_sample( read_size );
119 if( !sample )
120 return LSMASH_ERR_MEMORY_ALLOC;
121 *p_sample = sample;
122 if( lsmash_bs_get_bytes_ex( bs, read_size, sample->data ) != read_size )
124 lsmash_log( importer, LSMASH_LOG_WARNING, "the stream is truncated at the end.\n" );
125 importer->status = IMPORTER_EOF;
126 return LSMASH_ERR_INVALID_DATA;
128 sample->length = read_size;
129 sample->dts = amr_imp->au_number ++ * amr_imp->samples_in_frame;
130 sample->cts = sample->dts;
131 sample->prop.ra_flags = ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC;
132 return 0;
135 static int amr_check_magic_number
137 lsmash_bs_t *bs
140 #define AMR_STORAGE_MAGIC_LENGTH 6
141 #define AMR_AMRWB_EX_MAGIC_LENGTH 3
142 /* Check the magic number for single-channel AMR-NB/AMR-WB files.
143 * For AMR-NB, "#!AMR\n" (or 0x2321414d520a in hexadecimal).
144 * For AMR-WB, "#!AMR-WB\n" (or 0x2321414d522d57420a in hexadecimal).
145 * Note that AMR-NB and AMR-WB data is stored in the 3GPP/3GPP2 file format according to
146 * the AMR-NB and AMR-WB storage format for single channel header without the AMR magic numbers. */
147 uint8_t buf[AMR_STORAGE_MAGIC_LENGTH];
148 if( lsmash_bs_get_bytes_ex( bs, AMR_STORAGE_MAGIC_LENGTH, buf ) != AMR_STORAGE_MAGIC_LENGTH
149 || memcmp( buf, "#!AMR", AMR_STORAGE_MAGIC_LENGTH - 1 ) )
150 return LSMASH_ERR_INVALID_DATA;
151 if( buf[AMR_STORAGE_MAGIC_LENGTH - 1] == '\n' )
152 /* single-channel AMR-NB file */
153 return 0;
154 if( buf[AMR_STORAGE_MAGIC_LENGTH - 1] != '-'
155 || lsmash_bs_get_bytes_ex( bs, AMR_AMRWB_EX_MAGIC_LENGTH, buf ) != AMR_AMRWB_EX_MAGIC_LENGTH
156 || memcmp( buf, "WB\n", AMR_AMRWB_EX_MAGIC_LENGTH ) )
157 return LSMASH_ERR_INVALID_DATA;
158 /* single-channel AMR-WB file */
159 return 1;
160 #undef AMR_STORAGE_MAGIC_LENGTH
161 #undef AMR_AMRWB_EX_MAGIC_LENGTH
164 static int amr_create_damr
166 lsmash_audio_summary_t *summary,
167 int wb
170 #define AMR_DAMR_LENGTH 17
171 lsmash_bs_t *bs = lsmash_bs_create();
172 if( !bs )
173 return LSMASH_ERR_MEMORY_ALLOC;
174 lsmash_bs_put_be32( bs, AMR_DAMR_LENGTH );
175 lsmash_bs_put_be32( bs, ISOM_BOX_TYPE_DAMR.fourcc );
176 /* NOTE: These are specific to each codec vendor, but we're surely not a vendor.
177 * Using dummy data. */
178 lsmash_bs_put_be32( bs, 0x20202020 ); /* vendor */
179 lsmash_bs_put_byte( bs, 0 ); /* decoder_version */
180 /* NOTE: Using safe value for these settings, maybe sub-optimal. */
181 lsmash_bs_put_be16( bs, wb ? 0xC3FF : 0x81FF ); /* mode_set, represents for all possibly existing and supported frame-types. */
182 lsmash_bs_put_byte( bs, 1 ); /* mode_change_period */
183 lsmash_bs_put_byte( bs, 1 ); /* frames_per_sample */
184 lsmash_codec_specific_t *cs = lsmash_malloc_zero( sizeof(lsmash_codec_specific_t) );
185 if( !cs )
187 lsmash_bs_cleanup( bs );
188 return LSMASH_ERR_MEMORY_ALLOC;
190 cs->type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN;
191 cs->format = LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED;
192 cs->destruct = (lsmash_codec_specific_destructor_t)lsmash_free;
193 cs->data.unstructured = lsmash_bs_export_data( bs, &cs->size );
194 cs->size = AMR_DAMR_LENGTH;
195 lsmash_bs_cleanup( bs );
196 if( !cs->data.unstructured
197 || lsmash_list_add_entry( &summary->opaque->list, cs ) < 0 )
199 lsmash_destroy_codec_specific_data( cs );
200 return LSMASH_ERR_MEMORY_ALLOC;
202 return 0;
203 #undef AMR_DAMR_LENGTH
206 static lsmash_audio_summary_t *amr_create_summary
208 importer_t *importer,
209 int wb
212 /* Establish an audio summary for AMR-NB or AMR-WB stream. */
213 lsmash_audio_summary_t *summary = (lsmash_audio_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_AUDIO );
214 if( !summary )
215 return NULL;
216 summary->sample_type = wb ? ISOM_CODEC_TYPE_SAWB_AUDIO : ISOM_CODEC_TYPE_SAMR_AUDIO;
217 summary->max_au_length = wb ? 61 : 32;
218 summary->aot = MP4A_AUDIO_OBJECT_TYPE_NULL; /* no effect */
219 summary->frequency = (8000 << wb);
220 summary->channels = 1; /* always single channel */
221 summary->sample_size = 16;
222 summary->samples_in_frame = (160 << wb);
223 summary->sbr_mode = MP4A_AAC_SBR_NOT_SPECIFIED; /* no effect */
224 if( amr_create_damr( summary, wb ) < 0
225 || lsmash_list_add_entry( importer->summaries, summary ) < 0 )
227 lsmash_cleanup_summary( (lsmash_summary_t *)summary );
228 return NULL;
230 return summary;
233 static int amr_probe
235 importer_t *importer
239 amr_importer_t *amr_imp = create_amr_importer( importer );
240 if( !amr_imp )
241 return LSMASH_ERR_MEMORY_ALLOC;
242 int err;
243 int wb = amr_check_magic_number( importer->bs );
244 if( wb < 0 )
246 err = wb;
247 goto fail;
249 lsmash_audio_summary_t *summary = amr_create_summary( importer, wb );
250 if( !summary )
252 err = LSMASH_ERR_NAMELESS;
253 goto fail;
255 amr_imp->wb = wb;
256 amr_imp->samples_in_frame = summary->samples_in_frame;
257 amr_imp->au_number = 0;
258 importer->info = amr_imp;
259 importer->status = IMPORTER_OK;
260 return 0;
261 fail:
262 remove_amr_importer( amr_imp );
263 return err;
266 static uint32_t amr_get_last_delta
268 importer_t *importer,
269 uint32_t track_number
272 debug_if( !importer || !importer->info )
273 return 0;
274 amr_importer_t *amr_imp = (amr_importer_t *)importer->info;
275 if( !amr_imp || track_number != 1 )
276 return 0;
277 return amr_imp->samples_in_frame;
280 const importer_functions amr_importer =
282 { "AMR", offsetof( importer_t, log_level ) },
284 amr_probe,
285 amr_get_accessunit,
286 amr_get_last_delta,
287 amr_cleanup