import { MediaTrack } from '../../../utils/protocols/isom' ; type BufferMutation = ( buffer : Buffer , offset : number ) => void ; const UINT32_RANGE = Math . pow ( 2 , 32 ) ; abstract class BoxElement { public byteLength : number ; public value : any ; abstract copy ( buffer , offset ) ; abstract load ( buffer , offset ) ; constructor ( size ) { this . byteLength = size ; } } class Empty extends BoxElement { constructor ( size = 0 ) { super ( size ) ; } copy : BufferMutation = ( buffer , offset ) => { buffer . fill ( 0 , offset , offset + this . byteLength ) ; } ; load ( ) { } } class CharArray extends BoxElement { public value : string ; constructor ( s ) { super ( s . length ) ; this . value = s ; } copy : BufferMutation = ( buffer , offset ) => { for ( let i = 0 ; i < this . byteLength ; i += 1 ) { buffer [ offset + i ] = this . value . charCodeAt ( i ) ; } } ; load : BufferMutation = ( buffer , offset ) => { this . value = buffer . slice ( offset , offset + this . byteLength ) . toString ( 'ascii' ) ; } ; } class UInt8 extends BoxElement { public value : number ; constructor ( scalar = 0 ) { super ( 1 ) ; this . value = scalar ; } copy : BufferMutation = ( buffer , offset ) => { buffer . writeUInt8 ( this . value , offset ) ; } ; load : BufferMutation = ( buffer , offset ) => { this . value = buffer . readUInt8 ( offset ) ; } ; } class UInt8Array extends BoxElement { public value : number [ ] ; constructor ( array ) { super ( array . length ) ; this . value = array ; } copy : BufferMutation = ( buffer , offset ) => { for ( let i = 0 ; i < this . value . length ; ++ i ) { buffer . writeUInt8 ( this . value [ i ] , offset + i ) ; } } ; load : BufferMutation = ( buffer , offset ) => { for ( let i = 0 ; i < this . value . length ; ++ i ) { this . value [ i ] = buffer . readUInt8 ( offset + i ) ; } } ; } class UInt16BE extends BoxElement { public value : number ; constructor ( scalar = 0 ) { super ( 2 ) ; this . value = scalar ; } copy : BufferMutation = ( buffer , offset ) => { buffer . writeUInt16BE ( this . value , offset ) ; } ; load : BufferMutation = ( buffer , offset ) => { this . value = buffer . readUInt16BE ( offset ) ; } ; } class UInt24BE extends BoxElement { public value : number ; constructor ( scalar = 0 ) { super ( 3 ) ; this . value = scalar ; } copy : BufferMutation = ( buffer , offset ) => { buffer . writeUInt8 ( ( this . value >> 16 ) & 0xff , offset ) ; buffer . writeUInt8 ( ( this . value >> 8 ) & 0xff , offset + 1 ) ; buffer . writeUInt8 ( this . value & 0xff , offset + 2 ) ; } ; load : BufferMutation = ( buffer , offset ) => { this . value = ( buffer . readUInt8 ( offset ) << ( 16 + buffer . readUInt8 ( offset + 1 ) ) ) << ( 8 + buffer . readUInt8 ( offset + 2 ) ) ; } ; } class UInt16BEArray extends BoxElement { public value : number [ ] ; constructor ( array ) { super ( array . length * 2 ) ; this . value = array ; } copy : BufferMutation = ( buffer , offset ) => { for ( let i = 0 ; i < this . value . length ; ++ i ) { buffer . writeUInt16BE ( this . value [ i ] , offset + 2 * i ) ; } } ; load : BufferMutation = ( buffer , offset ) => { for ( let i = 0 ; i < this . value . length ; ++ i ) { this . value [ i ] = buffer . readUInt16BE ( offset + 2 * i ) ; } } ; } class UInt32BE extends BoxElement { public value : number ; constructor ( scalar = 0 ) { super ( 4 ) ; this . value = scalar ; } copy : BufferMutation = ( buffer , offset ) => { buffer . writeUInt32BE ( this . value , offset ) ; } ; load : BufferMutation = ( buffer , offset ) => { this . value = buffer . readUInt32BE ( offset ) ; } ; } class UInt32BEArray extends BoxElement { public value : number [ ] ; constructor ( array ) { super ( array . length * 4 ) ; this . value = array ; } copy : BufferMutation = ( buffer , offset ) => { for ( let i = 0 ; i < this . value . length ; ++ i ) { buffer . writeUInt32BE ( this . value [ i ] , offset + 4 * i ) ; } } ; load : BufferMutation = ( buffer , offset ) => { for ( let i = 0 ; i < this . value . length ; ++ i ) { this . value [ i ] = buffer . readUInt32BE ( offset + 4 * i ) ; } } ; } class UInt64BE extends BoxElement { public value : number ; constructor ( scalar = 0 ) { super ( 8 ) ; this . value = scalar ; } copy : BufferMutation = ( buffer , offset ) => { const high = ( this . value / UINT32_RANGE ) | 0 ; const low = this . value - high * UINT32_RANGE ; buffer . writeUInt32BE ( high , offset ) ; buffer . writeUInt32BE ( low , offset + 4 ) ; } ; load : BufferMutation = ( buffer , offset ) => { const high = buffer . readUInt32BE ( offset ) ; const low = buffer . readUInt32BE ( offset + 4 ) ; this . value = high * UINT32_RANGE + low ; } ; } param sizeMask return const createParameterSetArrayClass = function ( sizeMask = 0x00 ) { return class ParameterSetArray extends BoxElement { public value : any [ ] ; param array constructor ( array ) { super ( 0 ) ; this . value = array . reduce ( ( flatArray , byteArray ) => { return flatArray . concat ( new UInt16BE ( byteArray . length ) , new UInt8Array ( byteArray ) ) ; } , [ new UInt8 ( sizeMask | array . length ) ] ) ; this . byteLength = this . value . reduce ( ( total , element ) => total + element . byteLength , 0 ) ; } copy : BufferMutation = ( buffer , offset ) => { let i = 0 ; for ( const element of this . value ) { element . copy ( buffer , offset + i ) ; i += element . byteLength ; } } ; load : BufferMutation = ( ) => { } ; } ; } ; interface BoxSpec { container ? : string ; mandatory ? : boolean ; quantity ? : string ; box : 'Box' | 'FullBox' | 'None' ; is_container : boolean ; body ? : Array < [ string , any , any ? ] > ; config ? : any ; } /**
 * Specifications for a selection of ISO BMFF box types.
 *
 * Most of these are defined in ISO/IEC 14496-12,
 * For specific boxes like avc1/avcC/mp4a/esds the exact document is specified
 * with the appropriate box/descriptor.
 *
 * To add a new box, follow the same pattern: you need an object with at least
 * the property 'box' (which is 'Box' or 'FullBox') and for non-container boxes
 * you need also a 'body' property specifying the elements that the box contains.
 * The values assigned to each element in the spec are used as default.
 */ const BOXSPEC = { ftyp : { container : 'file' , mandatory : true , quantity : 'one' , box : 'Box' , is_container : true , body : [ [ 'major_brand' , CharArray , 'isom' ] , [ 'minor_version' , UInt32BE , 0 ] , [ 'compatible_brands' , CharArray , 'mp41' ] , ] , } , moov : { container : 'file' , mandatory : true , quantity : 'one' , box : 'Box' , is_container : true , } , mdat : { container : 'file' , mandatory : false , quantity : 'any' , box : 'Box' , is_container : false , body : [ ] , } , mvhd : { container : 'moov' , mandatory : true , quantity : 'one' , box : 'FullBox' , is_container : false , body : [ [ 'creation_time' , UInt32BE , 0 ] , [ 'modification_time' , UInt32BE , 0 ] , [ 'timescale' , UInt32BE , 1000 ] , [ 'duration' , UInt32BE , 0xffffffff ] , [ 'rate' , UInt32BE , 0x00010000 ] , [ 'volume' , UInt16BE , 0x0100 ] , [ 'reserved' , Empty , 10 ] , [ 'matrix' , UInt32BEArray , [ 0x00010000 , 0 , 0 , 0 , 0x00010000 , 0 , 0 , 0 , 0x40000000 ] , ] , [ 'pre_defined' , Empty , 24 ] , [ 'next_track_ID' , UInt32BE , 0xffffffff ] , ] , } , trak : { container : 'moov' , mandatory : true , quantity : 'one+' , box : 'Box' , is_container : true , } , tkhd : { container : 'trak' , mandatory : true , quantity : 'one' , box : 'FullBox' , is_container : false , config : { flags : 0x000003 , } , body : [ [ 'creation_time' , UInt32BE , 0 ] , [ 'modification_time' , UInt32BE , 0 ] , [ 'track_ID' , UInt32BE , 1 ] , [ 'reserved' , Empty , 4 ] , [ 'duration' , UInt32BE , 0 ] , [ 'reserved2' , Empty , 8 ] , [ 'layer' , UInt16BE , 0 ] , [ 'alternate_group' , UInt16BE , 0 ] , [ 'volume' , UInt16BE , 0x0100 ] , [ 'reserved3' , Empty , 2 ] , [ 'matrix' , UInt32BEArray , [ 0x00010000 , 0 , 0 , 0 , 0x00010000 , 0 , 0 , 0 , 0x40000000 ] , ] , [ 'width' , UInt32BE , 0 ] , [ 'height' , UInt32BE , 0 ] , ] , } , tref : { container : 'trak' , mandatory : false , quantity : 'one-' , box : 'Box' , is_container : false , } , mdia : { container : 'trak' , mandatory : false , quantity : 'one' , box : 'Box' , is_container : true , } , mdhd : { container : 'mdia' , mandatory : false , quantity : 'one' , box : 'FullBox' , is_container : false , body : [ [ 'creation_time' , UInt32BE , 0 ] , [ 'modification_time' , UInt32BE , 0 ] , [ 'timescale' , UInt32BE , 1000 ] , [ 'duration' , UInt32BE , 0xffffffff ] , [ 'language' , UInt16BE , 0 ] , [ 'pre_defined' , UInt16BE , 0 ] , ] , } , hdlr : { container : 'mdia' , mandatory : true , quantity : 'one' , box : 'FullBox' , is_container : false , body : [ [ 'predefined' , UInt32BE , 0 ] , [ 'handler_type' , CharArray , 'vide' ] , [ 'reserved' , Empty , 12 ] , [ 'name' , CharArray , 'VideoHandler\0' ] , ] , } , minf : { container : 'mdia' , mandatory : true , quantity : 'one' , box : 'Box' , is_container : true , } , vmhd : { container : 'minf' , mandatory : true , quantity : 'one' , box : 'FullBox' , is_container : false , config : { flags : 0x000001 , } , body : [ [ 'graphicsmode' , UInt16BE , 0 ] , [ 'opcolor' , UInt16BEArray , [ 0 , 0 , 0 ] ] , ] , } , smhd : { container : 'minf' , mandatory : true , quantity : 'one' , box : 'FullBox' , is_container : false , body : [ [ 'balance' , UInt16BE , 0x0000 ] , [ 'reserved' , UInt16BE ] , ] , } , dinf : { container : 'minf' , mandatory : true , quantity : 'one' , box : 'Box' , is_container : true , } , dref : { container : 'dinf' , mandatory : true , quantity : 'one' , box : 'FullBox' , is_container : true , body : [ [ 'entry_count' , UInt32BE , 0 ] , ] , } , 'url ' : { container : 'dref' , mandatory : true , quantity : 'one+' , box : 'FullBox' , is_container : false , config : { flags : 0x000001 , } , body : [ ] , } , stbl : { container : 'minf' , mandatory : true , quantity : 'one' , box : 'Box' , is_container : true , } , stts : { container : 'stbl' , mandatory : true , quantity : 'one' , box : 'FullBox' , is_container : false , body : [ [ 'entry_count' , UInt32BE , 0 ] , ] , } , stsd : { container : 'stbl' , mandatory : true , quantity : 'one' , box : 'FullBox' , is_container : true , body : [ [ 'entry_count' , UInt32BE , 1 ] , ] , } , avc1 : { container : 'stsd' , mandatory : false , quantity : 'one' , box : 'Box' , is_container : true , body : [ [ 'reserved' , Empty , 6 ] , [ 'data_reference_index' , UInt16BE , 1 ] , [ 'pre_defined' , UInt16BE , 0 ] , [ 'reserved2' , Empty , 2 ] , [ 'pre_defined2' , UInt32BEArray , [ 0 , 0 , 0 ] ] , [ 'width' , UInt16BE , 1920 ] , [ 'height' , UInt16BE , 1080 ] , [ 'horizresolution' , UInt32BE , 0x00480000 ] , [ 'vertresolution' , UInt32BE , 0x00480000 ] , [ 'reserved3' , UInt32BE , 0 ] , [ 'frame_count' , UInt16BE , 1 ] , [ 'compressorname' , UInt8Array , Buffer . alloc ( 32 ) ] , [ 'depth' , UInt16BE , 0x0018 ] , [ 'pre_defined3' , UInt16BE , 0xffff ] , ] , } , avcC : { container : 'avc1' , mandatory : false , quantity : 'one' , box : 'Box' , is_container : false , body : [ [ 'configurationVersion' , UInt8 , 1 ] , [ 'AVCProfileIndication' , UInt8 , 0x4d ] , [ 'profile_compatibility' , UInt8 , 0x00 ] , [ 'AVCLevelIndication' , UInt8 , 0x29 ] , [ 'lengthSizeMinusOne' , UInt8 , 0b11111111 ] , [ 'sequenceParameterSets' , createParameterSetArrayClass ( 0xe0 ) , [ ] ] , [ 'pictureParameterSets' , createParameterSetArrayClass ( ) , [ ] ] , ] , } , mp4a : { container : 'stsd' , mandatory : false , quantity : 'one' , box : 'Box' , is_container : true , body : [ [ 'reserved' , Empty , 6 ] , [ 'data_reference_index' , UInt16BE , 1 ] , [ 'reserved2' , UInt32BEArray , [ 0 , 0 ] ] , [ 'channelcount' , UInt16BE , 2 ] , [ 'samplesize' , UInt16BE , 16 ] , [ 'pre_defined' , UInt16BE , 0 ] , [ 'reserved3' , UInt16BE , 0 ] , [ 'samplerate' , UInt32BE , 0 ] , ] , } , esds : { container : 'mp4a' , mandatory : false , quantity : 'one' , box : 'FullBox' , is_container : false , body : [ [ 'ES_DescrTag' , UInt8 , 3 ] , [ 'ES_DescrLength' , UInt8 , 25 ] , [ 'ES_ID' , UInt16BE , 1 ] , [ 'flagsAndStreamPriority' , UInt8 , 0 ] , [ 'DecoderConfigDescrTag' , UInt8 , 4 ] , [ 'DecoderConfigDescrLength' , UInt8 , 17 ] , [ 'objectProfileIndication' , UInt8 , 0x40 ] , [ 'streamTypeUpstreamReserved' , UInt8 , 0x15 ] , [ 'bufferSizeDB' , UInt8Array , [ 0 , 0 , 0 ] ] , [ 'maxBitRate' , UInt32BE , 0 ] , [ 'avgBitRate' , UInt32BE , 0 ] , [ 'DecSpecificInfoShortTag' , UInt8 , 5 ] , [ 'DecSpecificInfoShortLength' , UInt8 , 2 ] , [ 'audioConfigBytes' , UInt16BE , 0 ] , [ 'SLConfigDescrTag' , UInt8 , 6 ] , [ 'SLConfigDescrLength' , UInt8 , 1 ] , [ 'SLConfigDescrPredefined' , UInt8 , 0x02 ] , ] , } , stsz : { container : 'stbl' , mandatory : true , quantity : 'one' , box : 'FullBox' , is_container : false , body : [ [ 'sample_size' , UInt32BE , 0 ] , [ 'sample_count' , UInt32BE , 0 ] , ] , } , stsc : { container : 'stbl' , mandatory : true , quantity : 'one' , box : 'FullBox' , is_container : false , body : [ [ 'entry_count' , UInt32BE , 0 ] , ] , } , stco : { container : 'stbl' , mandatory : true , quantity : 'one' , box : 'FullBox' , is_container : false , body : [ [ 'entry_count' , UInt32BE , 0 ] , ] , } , stss : { container : 'stbl' , mandatory : false , quantity : 'one-' , box : 'FullBox' , is_container : false , body : [ [ 'entry_count' , UInt32BE , 0 ] , ] , } , edts : { container : 'trak' , mandatory : false , quantity : 'one-' , box : 'Box' , is_container : true , } , elst : { container : 'edts' , mandatory : false , quantity : 'one-' , box : 'FullBox' , is_container : false , body : [ [ 'entry_count' , UInt32BE , 1 ] , [ 'segment_duration' , UInt32BE , 0 ] , [ 'media_time' , UInt32BE , 0xffffffff ] , [ 'media_rate_integer' , UInt16BE , 1 ] , [ 'media_rate_fraction' , UInt16BE , 0 ] , ] , } , mvex : { container : 'moov' , mandatory : false , quantity : 'one-' , box : 'Box' , is_container : true , } , mehd : { container : 'mvex' , mandatory : false , quantity : 'one-' , box : 'FullBox' , is_container : false , body : [ [ 'fragment_duration' , UInt32BE , 0 ] , ] , } , trex : { container : 'mvex' , mandatory : true , quantity : 'one+' , box : 'FullBox' , is_container : false , body : [ [ 'track_ID' , UInt32BE , 1 ] , [ 'default_sample_description_index' , UInt32BE , 1 ] , [ 'default_sample_duration' , UInt32BE , 0 ] , [ 'default_sample_size' , UInt32BE , 0 ] , [ 'default_sample_flags' , UInt32BE , 0 ] , ] , } , moof : { container : 'file' , mandatory : false , quantity : 'zero+' , box : 'Box' , is_container : false , } , mfhd : { container : 'moof' , mandatory : true , quantity : 'one' , box : 'FullBox' , is_container : false , body : [ [ 'sequence_number' , UInt32BE , 0 ] , ] , } , traf : { container : 'moof' , mandatory : false , quantity : 'zero+' , box : 'Box' , is_container : true , } , tfhd : { container : 'traf' , mandatory : true , quantity : 'one' , box : 'FullBox' , is_container : false , config : { flags : 0x000020 , } , body : [ [ 'track_ID' , UInt32BE , 1 ] , [ 'default_sample_flags' , UInt32BE , 0 ] , ] , } , tfdt : { container : 'traf' , mandatory : false , quantity : 'one-' , box : 'FullBox' , is_container : false , config : { version : 1 , } , body : [ [ 'baseMediaDecodeTime' , UInt64BE , 0 ] ] , } , trun : { container : 'traf' , mandatory : false , quantity : 'zero+' , box : 'FullBox' , is_container : false , config : { flags : 0x000305 , } , body : [ [ 'sample_count' , UInt32BE , 1 ] , [ 'data_offset' , UInt32BE , 0 ] , [ 'first_sample_flags' , UInt32BE , 0 ] , [ 'sample_duration' , UInt32BE , 0 ] , [ 'sample_size' , UInt32BE , 0 ] , ] , } , '....' : { box : 'Box' , is_container : false , body : [ ] , } , file : { box : 'None' , is_container : true , mandatory : true , quantity : 'one' , } , } ; /**
 * Helper functions to generate some standard elements that are needed by
 * all types of boxes.
 * All boxes have a length and type, where so-called full boxes have an
 * additional 4-bytes (1-byte version and 3-byte flags fields).
 */ class Header { static None ( ) { return [ ] ; } static Box ( type ) { return [ [ 'size' , UInt32BE , 0 ] , [ 'type' , CharArray , type ] , ] ; } static FullBox ( type ) { return ( [ ] as any ) . concat ( this . Box ( type ) , [ [ 'version' , UInt8 , 0x00 ] , [ 'flags' , UInt24BE , 0x000000 ] , ] ) ; } } /**
 * Box class.
 *
 * Defines a box as an entity similar to a C struct, where the struct is
 * represented by a Map of elements.
 * Each element is an object with at least:
 *  - a 'byteLength' property (size of element in bytes)
 *  - a 'copy' method (BufferMutation signature)
 */ export class Box extends BoxElement { public type : string ; public config : { [ key ] : any ; } ; public struct : Map < string , { offset : number ; element : { value ? : any ; byteLength : number ; copy : BufferMutation ; load ? : BufferMutation ; format ? : ( indent ? : number ) => string ; } ; } > ; param type param config constructor ( type , config ? ) { super ( 0 ) ; this . type = type ; const spec = BOXSPEC [ this . type ] ; if ( spec === undefined ) { throw new Error ( `unknown box type: ${ type }` ) ; } this . config = Object . assign ( { } , spec . config , config ) ; const header = Header [ spec . box ] ( this . type ) ; const body = spec . body || [ ] ; this . struct = new Map ( ) ; let offset = 0 ; for ( const [ key , Type , defaultValue ] of ( [ ] as any ) . concat ( header , body ) ) { if ( this . has ( key ) ) { throw new Error ( 'Trying to add existing key' ) ; } let value = defaultValue ; if ( this . config [ key ] ) { value = this . config [ key ] ; } const element = new Type ( value ) ; this . struct . set ( key , { offset , element } ) ; offset += element . byteLength ; } this . byteLength = offset ; } param key return element ( key ) { const value = this . struct . get ( key ) ; if ( value === undefined ) { throw new Error ( 'invalid key' ) ; } return value . element ; } param key param value set ( key , value ) { this . element ( key ) . value = value ; } param key return get ( key ) { return this . element ( key ) . value ; } param key return offset ( key ) { const value = this . struct . get ( key ) ; if ( value === undefined ) { throw new Error ( 'invalid key' ) ; } return value . offset ; } param key return has ( key ) { return this . struct . has ( key ) ; } param key param element return add ( key , element ) { if ( this . has ( key ) ) { throw new Error ( 'Trying to add existing key' ) ; } this . struct . set ( key , { offset : this . byteLength , element } ) ; this . byteLength += element . byteLength ; return this ; } return buffer ( ) { const buffer = Buffer . allocUnsafe ( this . byteLength ) ; this . copy ( buffer ) ; return buffer ; } param buffer param offset copy ( buffer , offset = 0 ) { this . set ( 'size' , this . byteLength ) ; for ( const entry of this . struct . values ( ) ) { entry . element . copy ( buffer , offset + entry . offset ) ; } } param buffer param offset load ( buffer , offset = 0 ) { for ( const entry of this . struct . values ( ) ) { if ( entry . element . load !== undefined ) { entry . element . load ( buffer , offset + entry . offset ) ; } } } param indent format ( indent = 0 ) { const lines = [ ' ' . repeat ( indent ) + `[${ this . type }] (${ this . byteLength })` ] ; for ( const [ key , entry ] of this . struct ) { const element = entry . element ; if ( element . format !== undefined ) { lines . push ( element . format ( indent + 2 ) ) ; } else { lines . push ( ' ' . repeat ( indent + 2 ) + `${ key } = ${ element . value } (${ element . byteLength })` ) ; } } return lines . join ( '\n' ) ; } param indent print ( indent ) { console . warn ( this . format ( indent ) ) ; } } /**
 * Container class
 *
 * special box with an 'add' method which allows appending of other boxes,
 * and a 'parse' method to extract contained boxes.
 */ export class Container extends Box { public boxSize : number ; param type param config param boxes constructor ( type , config ? , ... boxes ) { super ( type , config ) ; this . boxSize = 0 ; this . append ( ... boxes ) ; } param boxes return append ( ... boxes ) { for ( const box of boxes ) { this . add ( `box_${ this . boxSize ++ }` , box ) ; } return this ; } param data parse ( data ) { const tracks = [ ] ; while ( data . byteLength > 0 ) { const type = new CharArray ( '....' ) ; type . load ( data , 4 ) ; const boxType = type . value ; const spec = BOXSPEC [ boxType ] ; let box ; if ( spec !== undefined ) { if ( spec . is_container ) { box = new Container ( boxType ) ; box . load ( data ) ; const boxTracks = box . parse ( data . slice ( box . byteLength , box . get ( 'size' ) ) ) ; tracks . push ( ... boxTracks ) ; } else { box = new Box ( boxType ) ; box . load ( data ) ; if ( boxType === 'avcC' ) { const profile = box . element ( 'AVCProfileIndication' ) . value . toString ( 16 ) . padStart ( 2 , 0 ) ; const compat = box . element ( 'profile_compatibility' ) . value . toString ( 16 ) . padStart ( 2 , 0 ) ; const level = box . element ( 'AVCLevelIndication' ) . value . toString ( 16 ) . padStart ( 2 , 0 ) ; tracks . push ( { type : 'video' , mime : `avc1.${ profile }${ compat }${ level }` , } ) ; } else if ( boxType === 'esds' ) { const audioConfigBytes = box . element ( 'audioConfigBytes' ) . value ; const objectTypeIndication = ( audioConfigBytes >>> 11 ) & 0x001f ; tracks . push ( { type : 'audio' , mime : `mp4a.40.${ objectTypeIndication }` , } ) ; } } } else { box = new Box ( '....' ) ; box . load ( data ) ; box . type = box . get ( 'type' ) ; } this . append ( box ) ; data = data . slice ( box . get ( 'size' ) ) ; } return tracks ; } }