1 /*****************************************************************************
2  * mp3_imp.c
3  *****************************************************************************
4  * Copyright (C) 2010-2017 L-SMASH project
5  *
6  * Authors: Takashi Hirata <silverfilain@gmail.com>
7  * Contributors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
8  *
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.
12  *
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  *****************************************************************************/
21 
22 /* This file is available under an ISC license. */
23 
24 #include "common/internal.h" /* must be placed first */
25 
26 #include <string.h>
27 
28 #define LSMASH_IMPORTER_INTERNAL
29 #include "importer.h"
30 
31 /***************************************************************************
32     mp3 (Legacy Interface) importer
33 ***************************************************************************/
34 #include "codecs/mp4a.h"
35 
36 #define USE_MP4SYS_LEGACY_INTERFACE 1
37 
38 #define MP4SYS_MP3_MAX_FRAME_LENGTH (1152*(16/8)*2)
39 #define MP4SYS_MP3_HEADER_LENGTH    4
40 #define MP4SYS_MODE_IS_2CH( mode )  ((mode)!=3)
41 #define MP4SYS_LAYER_III            0x1
42 #define MP4SYS_LAYER_II             0x2
43 #define MP4SYS_LAYER_I              0x3
44 
45 typedef struct
46 {
47     uint16_t syncword;           /* <12> */
48     uint8_t  ID;                 /* <1> */
49     uint8_t  layer;              /* <2> */
50     uint8_t  protection_bit;     /* <1> */
51     uint8_t  bitrate_index;      /* <4> */
52     uint8_t  sampling_frequency; /* <2> */
53     uint8_t  padding_bit;        /* <1> */
54 //  uint8_t  private_bit;        /* <1> don't care. */
55     uint8_t  mode;               /* <2> */
56 //  uint8_t  mode_extension;     /* <2> don't care. */
57 //  uint8_t  copyright;          /* <1> don't care. */
58 //  uint8_t  original_copy;      /* <1> don't care. */
59     uint8_t  emphasis;           /* <2> for error check only. */
60 } mp4sys_mp3_header_t;
61 
62 typedef struct
63 {
64     mp4sys_mp3_header_t header;
65     uint8_t             raw_header[MP4SYS_MP3_HEADER_LENGTH];
66     uint32_t            samples_in_frame;
67     uint32_t            au_number;
68     uint16_t            main_data_size[32]; /* size of main_data of the last 32 frames, FIFO */
69     uint16_t            prev_preroll_count; /* number of dependent frames of *previous* frame */
70     uint16_t            enc_delay;
71     uint16_t            padding;
72     uint64_t            valid_samples;
73 } mp4sys_mp3_importer_t;
74 
remove_mp4sys_mp3_importer(mp4sys_mp3_importer_t * mp3_imp)75 static void remove_mp4sys_mp3_importer
76 (
77     mp4sys_mp3_importer_t *mp3_imp
78 )
79 {
80     lsmash_free( mp3_imp );
81 }
82 
create_mp4sys_mp3_importer(importer_t * importer)83 static mp4sys_mp3_importer_t *create_mp4sys_mp3_importer
84 (
85     importer_t *importer
86 )
87 {
88     return (mp4sys_mp3_importer_t *)lsmash_malloc_zero( sizeof(mp4sys_mp3_importer_t) );
89 }
90 
mp4sys_mp3_cleanup(importer_t * importer)91 static void mp4sys_mp3_cleanup( importer_t *importer )
92 {
93     debug_if( importer && importer->info )
94         remove_mp4sys_mp3_importer( importer->info );
95 }
96 
mp4sys_mp3_parse_header(uint8_t * buf,mp4sys_mp3_header_t * header)97 static int mp4sys_mp3_parse_header( uint8_t *buf, mp4sys_mp3_header_t *header )
98 {
99     /* FIXME: should we rewrite these code using bitstream reader? */
100     uint32_t data = LSMASH_GET_BE32( buf );
101     header->syncword           = (data >> 20) & 0xFFF; /* NOTE: don't consider what is called MPEG2.5, which last bit is 0. */
102     header->ID                 = (data >> 19) & 0x1;
103     header->layer              = (data >> 17) & 0x3;
104     header->protection_bit     = (data >> 16) & 0x1;
105     header->bitrate_index      = (data >> 12) & 0xF;
106     header->sampling_frequency = (data >> 10) & 0x3;
107     header->padding_bit        = (data >>  9) & 0x1;
108 //  header->private_bit        = (data >>  8) & 0x1; /* don't care. */
109     header->mode               = (data >>  6) & 0x3;
110 //  header->mode_extension     = (data >>  4) & 0x3;
111 //  header->copyright          = (data >>  3) & 0x1; /* don't care. */
112 //  header->original_copy      = (data >>  2) & 0x1; /* don't care. */
113     header->emphasis           = data         & 0x3; /* for error check only. */
114     if( header->syncword != 0xFFF )         return LSMASH_ERR_INVALID_DATA;
115     if( header->layer == 0x0 )              return LSMASH_ERR_NAMELESS;         /* 0b00: reserved */
116     if( header->bitrate_index == 0x0 )      return LSMASH_ERR_PATCH_WELCOME;    /* FIXME: "free" bitrate is unsupported currently. */
117     if( header->bitrate_index == 0xF )      return LSMASH_ERR_INVALID_DATA;     /* Forbidden */
118     if( header->sampling_frequency == 0x3 ) return LSMASH_ERR_NAMELESS;         /* 0b11: reserved */
119     if( header->emphasis == 0x2 )           return LSMASH_ERR_NAMELESS;         /* 0b10: reserved */
120     return 0;
121 }
122 
123 static const uint32_t mp4sys_mp3_frequency_tbl[2][3] =
124 {
125     { 22050, 24000, 16000 }, /* MPEG-2 BC audio */
126     { 44100, 48000, 32000 }  /* MPEG-1 audio */
127 };
128 
mp4sys_mp3_samples_in_frame(mp4sys_mp3_header_t * header)129 static int mp4sys_mp3_samples_in_frame( mp4sys_mp3_header_t *header )
130 {
131     if( header->layer == MP4SYS_LAYER_I )
132         return 384;
133     else if( header->ID == 1 || header->layer == MP4SYS_LAYER_II )
134         return 1152;
135     else
136         return 576;
137 }
138 
mp4sys_mp3_create_summary(mp4sys_mp3_header_t * header,int legacy_mode)139 static lsmash_audio_summary_t *mp4sys_mp3_create_summary( mp4sys_mp3_header_t *header, int legacy_mode )
140 {
141     lsmash_audio_summary_t *summary = (lsmash_audio_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_AUDIO );
142     if( !summary )
143         return NULL;
144     summary->sample_type            = ISOM_CODEC_TYPE_MP4A_AUDIO;
145     summary->max_au_length          = MP4SYS_MP3_MAX_FRAME_LENGTH;
146     summary->frequency              = mp4sys_mp3_frequency_tbl[header->ID][header->sampling_frequency];
147     summary->channels               = MP4SYS_MODE_IS_2CH( header->mode ) + 1;
148     summary->sample_size            = 16;
149     summary->samples_in_frame       = mp4sys_mp3_samples_in_frame( header );
150     summary->aot                    = MP4A_AUDIO_OBJECT_TYPE_Layer_1 + (MP4SYS_LAYER_I - header->layer); /* no effect with Legacy Interface. */
151     summary->sbr_mode               = MP4A_AAC_SBR_NOT_SPECIFIED; /* no effect */
152 #if !USE_MP4SYS_LEGACY_INTERFACE /* FIXME: This is very unstable. Many players crash with this. */
153     if( !legacy_mode )
154     {
155         summary->object_type_indication = MP4SYS_OBJECT_TYPE_Audio_ISO_14496_3;
156         if( lsmash_setup_AudioSpecificConfig( summary ) < 0 )
157         {
158             lsmash_cleanup_summary( summary );
159             return NULL;
160         }
161     }
162     uint32_t data_length;
163     uint8_t *data = mp4a_export_AudioSpecificConfig( MP4A_AUDIO_OBJECT_TYPE_Layer_1 + (MP4SYS_LAYER_I - header->layer),
164                                                      summary->frequency, summary->channels, summary->sbr_mode,
165                                                      NULL, 0, &data_length );
166     if( !data )
167     {
168         lsmash_cleanup_summary( (lsmash_summary_t *)summary );
169         return NULL;
170     }
171 #endif
172     lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG,
173                                                                            LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
174     if( !specific )
175     {
176         lsmash_cleanup_summary( (lsmash_summary_t *)summary );
177 #if !USE_MP4SYS_LEGACY_INTERFACE
178         lsmash_free( data );
179 #endif
180         return NULL;
181     }
182     lsmash_mp4sys_decoder_parameters_t *param = (lsmash_mp4sys_decoder_parameters_t *)specific->data.structured;
183     param->objectTypeIndication = header->ID ? MP4SYS_OBJECT_TYPE_Audio_ISO_11172_3 : MP4SYS_OBJECT_TYPE_Audio_ISO_13818_3;
184     param->streamType           = MP4SYS_STREAM_TYPE_AudioStream;
185 #if !USE_MP4SYS_LEGACY_INTERFACE
186     if( lsmash_set_mp4sys_decoder_specific_info( param, data, data_length ) < 0 )
187     {
188         lsmash_cleanup_summary( (lsmash_summary_t *)summary );
189         lsmash_destroy_codec_specific_data( specific );
190         lsmash_free( data );
191         return NULL;
192     }
193     lsmash_free( data );
194 #endif
195     if( lsmash_list_add_entry( &summary->opaque->list, specific ) < 0 )
196     {
197         lsmash_cleanup_summary( (lsmash_summary_t *)summary );
198         lsmash_destroy_codec_specific_data( specific );
199         return NULL;
200     }
201     return summary;
202 }
203 
parse_xing_info_header(mp4sys_mp3_importer_t * mp3_imp,mp4sys_mp3_header_t * header,uint8_t * frame)204 static int parse_xing_info_header( mp4sys_mp3_importer_t *mp3_imp, mp4sys_mp3_header_t *header, uint8_t *frame )
205 {
206     unsigned int sip = header->protection_bit ? 4 : 6;
207     unsigned int side_info_size;
208     if( header->ID == 1 )
209         side_info_size = MP4SYS_MODE_IS_2CH( header->mode ) ? 32 : 17;
210     else
211         side_info_size = MP4SYS_MODE_IS_2CH( header->mode ) ? 17 : 9;
212 
213     uint8_t *mdp = frame + sip + side_info_size;
214     if( memcmp( mdp, "Info", 4 )
215      && memcmp( mdp, "Xing", 4 ) )
216         return 0;
217     uint32_t flags = LSMASH_GET_BE32( &mdp[4] );
218     uint32_t off = 8;
219     uint32_t frame_count = 0;
220     if( flags & 1 )
221     {
222         frame_count = LSMASH_GET_BE32( &mdp[8] );
223         mp3_imp->valid_samples = (uint64_t)frame_count * mp4sys_mp3_samples_in_frame( header );
224         off += 4;
225     }
226     if( flags & 2 ) off +=   4; /* file size    */
227     if( flags & 4 ) off += 100; /* TOC          */
228     if( flags & 8 ) off +=   4; /* VBR quality  */
229 
230     if( mdp[off] == 'L' )
231     {   /* LAME header present */
232         unsigned int v = LSMASH_GET_BE24( &mdp[off + 21] );
233         mp3_imp->enc_delay     = v >> 12;
234         mp3_imp->padding       = v & 0xfff;
235         if( frame_count )
236             mp3_imp->valid_samples -= mp3_imp->enc_delay + mp3_imp->padding;
237     }
238     return 1;
239 }
240 
parse_vbri_header(mp4sys_mp3_importer_t * mp3_imp,mp4sys_mp3_header_t * header,uint8_t * frame)241 static int parse_vbri_header( mp4sys_mp3_importer_t *mp3_imp, mp4sys_mp3_header_t *header, uint8_t *frame )
242 {
243     return memcmp( frame + 36, "VBRI", 4 ) == 0;
244 }
245 
mp4sys_mp3_get_accessunit(importer_t * importer,uint32_t track_number,lsmash_sample_t ** p_sample)246 static int mp4sys_mp3_get_accessunit( importer_t *importer, uint32_t track_number, lsmash_sample_t **p_sample )
247 {
248     if( !importer->info )
249         return LSMASH_ERR_NAMELESS;
250     if( track_number != 1 )
251         return LSMASH_ERR_FUNCTION_PARAM;
252     mp4sys_mp3_importer_t *mp3_imp        = (mp4sys_mp3_importer_t *)importer->info;
253     mp4sys_mp3_header_t   *header         = (mp4sys_mp3_header_t *)&mp3_imp->header;
254     importer_status        current_status = importer->status;
255     /* bitrate */
256     const uint32_t bitrate_tbl[2][3][16] =
257     {
258         {   /* MPEG-2 BC audio */
259             { 1,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, 0 }, /* Layer III */
260             { 1,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, 0 }, /* Layer II  */
261             { 1, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }  /* Layer I   */
262         },
263         {   /* MPEG-1 audio */
264             { 1, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 0 }, /* Layer III */
265             { 1, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384, 0 }, /* Layer II  */
266             { 1, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }  /* Layer I   */
267         }
268     };
269     uint32_t bitrate = bitrate_tbl[ header->ID ][ header->layer - 1 ][ header->bitrate_index ];
270     if( bitrate == 0 )
271         return LSMASH_ERR_INVALID_DATA;
272     else if( bitrate == 1 )
273         return LSMASH_ERR_PATCH_WELCOME;    /* free format */
274     /* sampling frequency */
275     uint32_t frequency = mp4sys_mp3_frequency_tbl[header->ID][header->sampling_frequency];
276     if( frequency == 0 )
277         return LSMASH_ERR_NAMELESS;         /* reserved */
278     /* frame size */
279     uint32_t frame_size;
280     if( header->layer == MP4SYS_LAYER_I )
281         /* mp1's 'slot' is 4 bytes unit. see 11172-3, Audio Sequence General. */
282         frame_size = (12 * 1000 * bitrate / frequency + header->padding_bit) * 4;
283     else
284     {
285         /* mp2/3's 'slot' is 1 bytes unit. */
286         uint32_t div = frequency;
287         if( header->layer == MP4SYS_LAYER_III && header->ID == 0 )
288             div <<= 1;
289         frame_size = 144 * 1000 * bitrate / div + header->padding_bit;
290     }
291     if( frame_size <= 4 )
292         return LSMASH_ERR_INVALID_DATA;
293     if( current_status == IMPORTER_ERROR )
294         return LSMASH_ERR_NAMELESS;
295     if( current_status == IMPORTER_EOF )
296         return IMPORTER_EOF;
297     if( current_status == IMPORTER_CHANGE )
298     {
299         lsmash_entry_t *entry = lsmash_list_get_entry( importer->summaries, track_number );
300         if( !entry || !entry->data )
301             return LSMASH_ERR_NAMELESS;
302         lsmash_audio_summary_t *summary = mp4sys_mp3_create_summary( header, 1 ); /* FIXME: use legacy mode. */
303         if( !summary )
304             return LSMASH_ERR_NAMELESS;
305         lsmash_cleanup_summary( entry->data );
306         entry->data = summary;
307         mp3_imp->samples_in_frame = summary->samples_in_frame;
308     }
309     /* read a frame's data. */
310     lsmash_sample_t *sample = *p_sample;
311     if( !sample )
312     {
313         sample = lsmash_create_sample( MP4SYS_MP3_MAX_FRAME_LENGTH );
314         if( !sample )
315             return LSMASH_ERR_MEMORY_ALLOC;
316         *p_sample = sample;
317     }
318     uint8_t *frame_data = sample->data;
319     memcpy( frame_data, mp3_imp->raw_header, MP4SYS_MP3_HEADER_LENGTH );
320     frame_size -= MP4SYS_MP3_HEADER_LENGTH;
321     if( lsmash_bs_get_bytes_ex( importer->bs, frame_size, frame_data + MP4SYS_MP3_HEADER_LENGTH ) != frame_size )
322     {
323         importer->status = IMPORTER_ERROR;
324         return LSMASH_ERR_INVALID_DATA;
325     }
326     sample->length                 = MP4SYS_MP3_HEADER_LENGTH + frame_size;
327     sample->dts                    = mp3_imp->au_number ++ * mp3_imp->samples_in_frame;
328     sample->cts                    = sample->dts;
329     sample->prop.ra_flags          = ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC;
330     sample->prop.pre_roll.distance = header->layer == MP4SYS_LAYER_III ? 1 : 0; /* Layer III uses MDCT */
331 
332     int vbr_header_present = 0;
333     if( mp3_imp->au_number == 1
334      && (parse_xing_info_header( mp3_imp, header, frame_data )
335       || parse_vbri_header( mp3_imp, header, frame_data )) )
336     {
337         vbr_header_present = 1;
338         mp3_imp->au_number--;
339     }
340 
341     /* handle additional inter-frame dependency due to bit reservoir */
342     if( !vbr_header_present && header->layer == MP4SYS_LAYER_III )
343     {
344         /* position of side_info */
345         unsigned int sip = header->protection_bit ? 4 : 6;
346         unsigned int main_data_begin = frame_data[sip];
347         if( header->ID == 1 )
348         {
349             main_data_begin <<= 1;
350             main_data_begin |= (frame_data[sip + 1] >> 7);
351         }
352         if( main_data_begin > 0 )
353         {
354             /* main_data_begin is a backpointer to the start of
355              * bit reservoir data for this frame.
356              * it contains total amount of bytes required from
357              * preceding frames.
358              * we just add up main_data size from history until it reaches
359              * the required amount.
360              */
361             unsigned int reservoir_data = 0;
362             unsigned int i;
363             for( i = 0; i < 32 && reservoir_data < main_data_begin; ++i )
364             {
365                 reservoir_data += mp3_imp->main_data_size[i];
366                 if( mp3_imp->main_data_size[i] == 0 )
367                     break;
368             }
369             sample->prop.pre_roll.distance += mp3_imp->prev_preroll_count;
370             mp3_imp->prev_preroll_count = i;
371         }
372         uint16_t side_info_size;
373         if( header->ID == 1 )
374             side_info_size = MP4SYS_MODE_IS_2CH( header->mode ) ? 32 : 17;
375         else
376             side_info_size = MP4SYS_MODE_IS_2CH( header->mode ) ? 17 : 9;
377 
378         /* pop back main_data_size[] and push main_data size of this frame
379          * to the front */
380         memmove( mp3_imp->main_data_size + 1, mp3_imp->main_data_size, sizeof(mp3_imp->main_data_size) - sizeof( mp3_imp->main_data_size[0] ) );
381         mp3_imp->main_data_size[0] = frame_size - sip - side_info_size;
382     }
383     /* now we succeeded to read current frame, so "return" takes 0 always below. */
384     /* preparation for next frame */
385 
386     uint8_t buf[MP4SYS_MP3_HEADER_LENGTH];
387     int64_t ret = lsmash_bs_get_bytes_ex( importer->bs, MP4SYS_MP3_HEADER_LENGTH, buf );
388     if( ret == 0 )
389     {
390         importer->status = IMPORTER_EOF;
391         return 0;
392     }
393     if( ret >= 2 && (!memcmp( buf, "TA", 2 ) || !memcmp( buf, "AP", 2 )) )
394     {
395         /* ID3v1 or APE tag */
396         importer->status = IMPORTER_EOF;
397         return 0;
398     }
399     if( ret == 1 && *buf == 0x00 )
400     {
401         /* NOTE: ugly hack for mp1 stream created with SCMPX. */
402         importer->status = IMPORTER_EOF;
403         return 0;
404     }
405     if( ret != MP4SYS_MP3_HEADER_LENGTH )
406     {
407         importer->status = IMPORTER_ERROR;
408         return 0;
409     }
410 
411     mp4sys_mp3_header_t new_header = { 0 };
412     if( mp4sys_mp3_parse_header( buf, &new_header ) < 0 )
413     {
414         importer->status = IMPORTER_ERROR;
415         return 0;
416     }
417     memcpy( mp3_imp->raw_header, buf, MP4SYS_MP3_HEADER_LENGTH );
418 
419     /* currently UNsupported "change(s)". */
420     if( header->layer != new_header.layer /* This means change of object_type_indication with Legacy Interface. */
421      || header->sampling_frequency != new_header.sampling_frequency ) /* This may change timescale. */
422     {
423         importer->status = IMPORTER_ERROR;
424         return 0;
425     }
426 
427     /* currently supported "change(s)". */
428     if( MP4SYS_MODE_IS_2CH( header->mode ) != MP4SYS_MODE_IS_2CH( new_header.mode ) )
429         importer->status = IMPORTER_CHANGE;
430     else
431         importer->status = IMPORTER_OK; /* no change which matters to mp4 muxing was found */
432     mp3_imp->header = new_header;
433 
434     if( vbr_header_present )
435         return mp4sys_mp3_get_accessunit( importer, track_number, &sample );
436     return 0;
437 }
438 
mp4sys_mp3_probe(importer_t * importer)439 static int mp4sys_mp3_probe( importer_t *importer )
440 {
441     mp4sys_mp3_importer_t *mp3_imp = create_mp4sys_mp3_importer( importer );
442     if( !mp3_imp )
443         return LSMASH_ERR_MEMORY_ALLOC;
444     lsmash_bs_t *bs = importer->bs;
445     /* Multiple ID3 tags could be present, loop to skip them first. */
446     while( lsmash_bs_show_byte( bs, 0 ) == 'I'
447         && lsmash_bs_show_byte( bs, 1 ) == 'D'
448         && lsmash_bs_show_byte( bs, 2 ) == '3' )
449     {
450         lsmash_bs_read_seek( bs, 6, SEEK_CUR );
451         uint32_t size = 0;
452         for( int i = 0 ; i < 4; i++ )
453         {
454             size <<= 7;
455             size |= lsmash_bs_get_byte( bs );
456         }
457         lsmash_bs_read_seek( bs, size, SEEK_CUR );
458     }
459     /* Parse the header. */
460     int err;
461     uint8_t buf[MP4SYS_MP3_HEADER_LENGTH];
462     if( lsmash_bs_get_bytes_ex( bs, MP4SYS_MP3_HEADER_LENGTH, buf ) != MP4SYS_MP3_HEADER_LENGTH )
463     {
464         err = LSMASH_ERR_INVALID_DATA;
465         goto fail;
466     }
467     mp4sys_mp3_header_t header = { 0 };
468     if( (err = mp4sys_mp3_parse_header( buf, &header )) < 0 )
469         goto fail;
470     /* Now, the stream seems valid mp3. */
471     lsmash_audio_summary_t *summary = mp4sys_mp3_create_summary( &header, 1 );
472     if( !summary )
473     {
474         err = LSMASH_ERR_NAMELESS;
475         goto fail;
476     }
477     /* importer status */
478     if( lsmash_list_add_entry( importer->summaries, summary ) < 0 )
479     {
480         lsmash_cleanup_summary( (lsmash_summary_t *)summary );
481         err = LSMASH_ERR_MEMORY_ALLOC;
482         goto fail;
483     }
484     mp3_imp->header           = header;
485     mp3_imp->samples_in_frame = summary->samples_in_frame;
486     memcpy( mp3_imp->raw_header, buf, MP4SYS_MP3_HEADER_LENGTH );
487     importer->info   = mp3_imp;
488     importer->status = IMPORTER_OK;
489     return 0;
490 fail:
491     remove_mp4sys_mp3_importer( mp3_imp );
492     return err;
493 }
494 
mp4sys_mp3_get_last_delta(importer_t * importer,uint32_t track_number)495 static uint32_t mp4sys_mp3_get_last_delta( importer_t *importer, uint32_t track_number )
496 {
497     debug_if( !importer || !importer->info )
498         return 0;
499     mp4sys_mp3_importer_t *mp3_imp = (mp4sys_mp3_importer_t *)importer->info;
500     if( !mp3_imp || track_number != 1 || importer->status != IMPORTER_EOF )
501         return 0;
502     return mp3_imp->samples_in_frame;
503 }
504 
505 const importer_functions mp4sys_mp3_importer =
506 {
507     { "MPEG-1/2BC Audio Legacy" },
508     1,
509     mp4sys_mp3_probe,
510     mp4sys_mp3_get_accessunit,
511     mp4sys_mp3_get_last_delta,
512     mp4sys_mp3_cleanup
513 };
514