dashjs
Version:
A reference client implementation for the playback of MPEG DASH via Javascript and compliant browsers.
175 lines (174 loc) • 19 kB
JavaScript
;Object.defineProperty(exports,"__esModule",{value:true});var _MssErrors=require('./errors/MssErrors');var _MssErrors2=_interopRequireDefault(_MssErrors);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}/**
* @module MssFragmentMoovProcessor
* @ignore
* @param {Object} config object
*/function MssFragmentMoovProcessor(config){config=config||{};var NALUTYPE_SPS=7;var NALUTYPE_PPS=8;var constants=config.constants;var ISOBoxer=config.ISOBoxer;var protectionController=config.protectionController;var instance=void 0,period=void 0,adaptationSet=void 0,representation=void 0,contentProtection=void 0,timescale=void 0,trackId=void 0;function createFtypBox(isoFile){var ftyp=ISOBoxer.createBox('ftyp',isoFile);ftyp.major_brand='iso6';ftyp.minor_version=1;// is an informative integer for the minor version of the major brand
ftyp.compatible_brands=[];//is a list, to the end of the box, of brands isom, iso6 and msdh
ftyp.compatible_brands[0]='isom';// => decimal ASCII value for isom
ftyp.compatible_brands[1]='iso6';// => decimal ASCII value for iso6
ftyp.compatible_brands[2]='msdh';// => decimal ASCII value for msdh
return ftyp;}function createMoovBox(isoFile){// moov box
var moov=ISOBoxer.createBox('moov',isoFile);// moov/mvhd
createMvhdBox(moov);// moov/trak
var trak=ISOBoxer.createBox('trak',moov);// moov/trak/tkhd
createTkhdBox(trak);// moov/trak/mdia
var mdia=ISOBoxer.createBox('mdia',trak);// moov/trak/mdia/mdhd
createMdhdBox(mdia);// moov/trak/mdia/hdlr
createHdlrBox(mdia);// moov/trak/mdia/minf
var minf=ISOBoxer.createBox('minf',mdia);switch(adaptationSet.type){case constants.VIDEO:// moov/trak/mdia/minf/vmhd
createVmhdBox(minf);break;case constants.AUDIO:// moov/trak/mdia/minf/smhd
createSmhdBox(minf);break;default:break;}// moov/trak/mdia/minf/dinf
var dinf=ISOBoxer.createBox('dinf',minf);// moov/trak/mdia/minf/dinf/dref
createDrefBox(dinf);// moov/trak/mdia/minf/stbl
var stbl=ISOBoxer.createBox('stbl',minf);// Create empty stts, stsc, stco and stsz boxes
// Use data field as for codem-isoboxer unknown boxes for setting fields value
// moov/trak/mdia/minf/stbl/stts
var stts=ISOBoxer.createFullBox('stts',stbl);stts._data=[0,0,0,0,0,0,0,0];// version = 0, flags = 0, entry_count = 0
// moov/trak/mdia/minf/stbl/stsc
var stsc=ISOBoxer.createFullBox('stsc',stbl);stsc._data=[0,0,0,0,0,0,0,0];// version = 0, flags = 0, entry_count = 0
// moov/trak/mdia/minf/stbl/stco
var stco=ISOBoxer.createFullBox('stco',stbl);stco._data=[0,0,0,0,0,0,0,0];// version = 0, flags = 0, entry_count = 0
// moov/trak/mdia/minf/stbl/stsz
var stsz=ISOBoxer.createFullBox('stsz',stbl);stsz._data=[0,0,0,0,0,0,0,0,0,0,0,0];// version = 0, flags = 0, sample_size = 0, sample_count = 0
// moov/trak/mdia/minf/stbl/stsd
createStsdBox(stbl);// moov/mvex
var mvex=ISOBoxer.createBox('mvex',moov);// moov/mvex/trex
createTrexBox(mvex);if(contentProtection&&protectionController){var supportedKS=protectionController.getSupportedKeySystemsFromContentProtection(contentProtection);createProtectionSystemSpecificHeaderBox(moov,supportedKS);}}function createMvhdBox(moov){var mvhd=ISOBoxer.createFullBox('mvhd',moov);mvhd.version=1;// version = 1 in order to have 64bits duration value
mvhd.creation_time=0;// the creation time of the presentation => ignore (set to 0)
mvhd.modification_time=0;// the most recent time the presentation was modified => ignore (set to 0)
mvhd.timescale=timescale;// the time-scale for the entire presentation => 10000000 for MSS
mvhd.duration=Math.round(period.duration*timescale);// the length of the presentation (in the indicated timescale) => take duration of period
mvhd.rate=1.0;// 16.16 number, '1.0' = normal playback
mvhd.volume=1.0;// 8.8 number, '1.0' = full volume
mvhd.reserved1=0;mvhd.reserved2=[0x0,0x0];mvhd.matrix=[1,0,0,// provides a transformation matrix for the video;
0,1,0,// (u,v,w) are restricted here to (0,0,1)
0,0,16384];mvhd.pre_defined=[0,0,0,0,0,0];mvhd.next_track_ID=trackId+1;// indicates a value to use for the track ID of the next track to be added to this presentation
return mvhd;}function createTkhdBox(trak){var tkhd=ISOBoxer.createFullBox('tkhd',trak);tkhd.version=1;// version = 1 in order to have 64bits duration value
tkhd.flags=0x1|// Track_enabled (0x000001): Indicates that the track is enabled
0x2|// Track_in_movie (0x000002): Indicates that the track is used in the presentation
0x4;// Track_in_preview (0x000004): Indicates that the track is used when previewing the presentation
tkhd.creation_time=0;// the creation time of the presentation => ignore (set to 0)
tkhd.modification_time=0;// the most recent time the presentation was modified => ignore (set to 0)
tkhd.track_ID=trackId;// uniquely identifies this track over the entire life-time of this presentation
tkhd.reserved1=0;tkhd.duration=Math.round(period.duration*timescale);// the duration of this track (in the timescale indicated in the Movie Header Box) => take duration of period
tkhd.reserved2=[0x0,0x0];tkhd.layer=0;// specifies the front-to-back ordering of video tracks; tracks with lower numbers are closer to the viewer => 0 since only one video track
tkhd.alternate_group=0;// specifies a group or collection of tracks => ignore
tkhd.volume=1.0;// '1.0' = full volume
tkhd.reserved3=0;tkhd.matrix=[1,0,0,// provides a transformation matrix for the video;
0,1,0,// (u,v,w) are restricted here to (0,0,1)
0,0,16384];tkhd.width=representation.width;// visual presentation width
tkhd.height=representation.height;// visual presentation height
return tkhd;}function createMdhdBox(mdia){var mdhd=ISOBoxer.createFullBox('mdhd',mdia);mdhd.version=1;// version = 1 in order to have 64bits duration value
mdhd.creation_time=0;// the creation time of the presentation => ignore (set to 0)
mdhd.modification_time=0;// the most recent time the presentation was modified => ignore (set to 0)
mdhd.timescale=timescale;// the time-scale for the entire presentation
mdhd.duration=Math.round(period.duration*timescale);// the duration of this media (in the scale of the timescale). If the duration cannot be determined then duration is set to all 1s.
mdhd.language=adaptationSet.lang||'und';// declares the language code for this media (see getLanguageCode())
mdhd.pre_defined=0;return mdhd;}function createHdlrBox(mdia){var hdlr=ISOBoxer.createFullBox('hdlr',mdia);hdlr.pre_defined=0;switch(adaptationSet.type){case constants.VIDEO:hdlr.handler_type='vide';break;case constants.AUDIO:hdlr.handler_type='soun';break;default:hdlr.handler_type='meta';break;}hdlr.name=representation.id;hdlr.reserved=[0,0,0];return hdlr;}function createVmhdBox(minf){var vmhd=ISOBoxer.createFullBox('vmhd',minf);vmhd.flags=1;vmhd.graphicsmode=0;// specifies a composition mode for this video track, from the following enumerated set, which may be extended by derived specifications: copy = 0 copy over the existing image
vmhd.opcolor=[0,0,0];// is a set of 3 colour values (red, green, blue) available for use by graphics modes
return vmhd;}function createSmhdBox(minf){var smhd=ISOBoxer.createFullBox('smhd',minf);smhd.flags=1;smhd.balance=0;// is a fixed-point 8.8 number that places mono audio tracks in a stereo space; 0 is centre (the normal value); full left is -1.0 and full right is 1.0.
smhd.reserved=0;return smhd;}function createDrefBox(dinf){var dref=ISOBoxer.createFullBox('dref',dinf);dref.entry_count=1;dref.entries=[];var url=ISOBoxer.createFullBox('url ',dref,false);url.location='';url.flags=1;dref.entries.push(url);return dref;}function createStsdBox(stbl){var stsd=ISOBoxer.createFullBox('stsd',stbl);stsd.entries=[];switch(adaptationSet.type){case constants.VIDEO:case constants.AUDIO:stsd.entries.push(createSampleEntry(stsd));break;default:break;}stsd.entry_count=stsd.entries.length;// is an integer that counts the actual entries
return stsd;}function createSampleEntry(stsd){var codec=representation.codecs.substring(0,representation.codecs.indexOf('.'));switch(codec){case'avc1':return createAVCVisualSampleEntry(stsd,codec);case'mp4a':return createMP4AudioSampleEntry(stsd,codec);default:throw{code:_MssErrors2.default.MSS_UNSUPPORTED_CODEC_CODE,message:_MssErrors2.default.MSS_UNSUPPORTED_CODEC_MESSAGE,data:{codec:codec}};}}function createAVCVisualSampleEntry(stsd,codec){var avc1=void 0;if(contentProtection){avc1=ISOBoxer.createBox('encv',stsd,false);}else{avc1=ISOBoxer.createBox('avc1',stsd,false);}// SampleEntry fields
avc1.reserved1=[0x0,0x0,0x0,0x0,0x0,0x0];avc1.data_reference_index=1;// VisualSampleEntry fields
avc1.pre_defined1=0;avc1.reserved2=0;avc1.pre_defined2=[0,0,0];avc1.height=representation.height;avc1.width=representation.width;avc1.horizresolution=72;// 72 dpi
avc1.vertresolution=72;// 72 dpi
avc1.reserved3=0;avc1.frame_count=1;// 1 compressed video frame per sample
avc1.compressorname=[0x0A,0x41,0x56,0x43,0x20,0x43,0x6F,0x64,// = 'AVC Coding';
0x69,0x6E,0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00];avc1.depth=0x0018;// 0x0018 – images are in colour with no alpha.
avc1.pre_defined3=65535;avc1.config=createAVC1ConfigurationRecord();if(contentProtection){// Create and add Protection Scheme Info Box
var sinf=ISOBoxer.createBox('sinf',avc1);// Create and add Original Format Box => indicate codec type of the encrypted content
createOriginalFormatBox(sinf,codec);// Create and add Scheme Type box
createSchemeTypeBox(sinf);// Create and add Scheme Information Box
createSchemeInformationBox(sinf);}return avc1;}function createAVC1ConfigurationRecord(){var avcC=null;var avcCLength=15;// length = 15 by default (0 SPS and 0 PPS)
// First get all SPS and PPS from codecPrivateData
var sps=[];var pps=[];var AVCProfileIndication=0;var AVCLevelIndication=0;var profile_compatibility=0;var nalus=representation.codecPrivateData.split('00000001').slice(1);var naluBytes=void 0,naluType=void 0;for(var _i=0;_i<nalus.length;_i++){naluBytes=hexStringtoBuffer(nalus[_i]);naluType=naluBytes[0]&0x1F;switch(naluType){case NALUTYPE_SPS:sps.push(naluBytes);avcCLength+=naluBytes.length+2;// 2 = sequenceParameterSetLength field length
break;case NALUTYPE_PPS:pps.push(naluBytes);avcCLength+=naluBytes.length+2;// 2 = pictureParameterSetLength field length
break;default:break;}}// Get profile and level from SPS
if(sps.length>0){AVCProfileIndication=sps[0][1];profile_compatibility=sps[0][2];AVCLevelIndication=sps[0][3];}// Generate avcC buffer
avcC=new Uint8Array(avcCLength);var i=0;// length
avcC[i++]=(avcCLength&0xFF000000)>>24;avcC[i++]=(avcCLength&0x00FF0000)>>16;avcC[i++]=(avcCLength&0x0000FF00)>>8;avcC[i++]=avcCLength&0x000000FF;avcC.set([0x61,0x76,0x63,0x43],i);// type = 'avcC'
i+=4;avcC[i++]=1;// configurationVersion = 1
avcC[i++]=AVCProfileIndication;avcC[i++]=profile_compatibility;avcC[i++]=AVCLevelIndication;avcC[i++]=0xFF;// '11111' + lengthSizeMinusOne = 3
avcC[i++]=0xE0|sps.length;// '111' + numOfSequenceParameterSets
for(var n=0;n<sps.length;n++){avcC[i++]=(sps[n].length&0xFF00)>>8;avcC[i++]=sps[n].length&0x00FF;avcC.set(sps[n],i);i+=sps[n].length;}avcC[i++]=pps.length;// numOfPictureParameterSets
for(var _n=0;_n<pps.length;_n++){avcC[i++]=(pps[_n].length&0xFF00)>>8;avcC[i++]=pps[_n].length&0x00FF;avcC.set(pps[_n],i);i+=pps[_n].length;}return avcC;}function createMP4AudioSampleEntry(stsd,codec){var mp4a=void 0;if(contentProtection){mp4a=ISOBoxer.createBox('enca',stsd,false);}else{mp4a=ISOBoxer.createBox('mp4a',stsd,false);}// SampleEntry fields
mp4a.reserved1=[0x0,0x0,0x0,0x0,0x0,0x0];mp4a.data_reference_index=1;// AudioSampleEntry fields
mp4a.reserved2=[0x0,0x0];mp4a.channelcount=representation.audioChannels;mp4a.samplesize=16;mp4a.pre_defined=0;mp4a.reserved_3=0;mp4a.samplerate=representation.audioSamplingRate<<16;mp4a.esds=createMPEG4AACESDescriptor();if(contentProtection){// Create and add Protection Scheme Info Box
var sinf=ISOBoxer.createBox('sinf',mp4a);// Create and add Original Format Box => indicate codec type of the encrypted content
createOriginalFormatBox(sinf,codec);// Create and add Scheme Type box
createSchemeTypeBox(sinf);// Create and add Scheme Information Box
createSchemeInformationBox(sinf);}return mp4a;}function createMPEG4AACESDescriptor(){// AudioSpecificConfig (see ISO/IEC 14496-3, subpart 1) => corresponds to hex bytes contained in 'codecPrivateData' field
var audioSpecificConfig=hexStringtoBuffer(representation.codecPrivateData);// ESDS length = esds box header length (= 12) +
// ES_Descriptor header length (= 5) +
// DecoderConfigDescriptor header length (= 15) +
// decoderSpecificInfo header length (= 2) +
// AudioSpecificConfig length (= codecPrivateData length)
var esdsLength=34+audioSpecificConfig.length;var esds=new Uint8Array(esdsLength);var i=0;// esds box
esds[i++]=(esdsLength&0xFF000000)>>24;// esds box length
esds[i++]=(esdsLength&0x00FF0000)>>16;// ''
esds[i++]=(esdsLength&0x0000FF00)>>8;// ''
esds[i++]=esdsLength&0x000000FF;// ''
esds.set([0x65,0x73,0x64,0x73],i);// type = 'esds'
i+=4;esds.set([0,0,0,0],i);// version = 0, flags = 0
i+=4;// ES_Descriptor (see ISO/IEC 14496-1 (Systems))
esds[i++]=0x03;// tag = 0x03 (ES_DescrTag)
esds[i++]=20+audioSpecificConfig.length;// size
esds[i++]=(trackId&0xFF00)>>8;// ES_ID = track_id
esds[i++]=trackId&0x00FF;// ''
esds[i++]=0;// flags and streamPriority
// DecoderConfigDescriptor (see ISO/IEC 14496-1 (Systems))
esds[i++]=0x04;// tag = 0x04 (DecoderConfigDescrTag)
esds[i++]=15+audioSpecificConfig.length;// size
esds[i++]=0x40;// objectTypeIndication = 0x40 (MPEG-4 AAC)
esds[i]=0x05<<2;// streamType = 0x05 (Audiostream)
esds[i]|=0<<1;// upStream = 0
esds[i++]|=1;// reserved = 1
esds[i++]=0xFF;// buffersizeDB = undefined
esds[i++]=0xFF;// ''
esds[i++]=0xFF;// ''
esds[i++]=(representation.bandwidth&0xFF000000)>>24;// maxBitrate
esds[i++]=(representation.bandwidth&0x00FF0000)>>16;// ''
esds[i++]=(representation.bandwidth&0x0000FF00)>>8;// ''
esds[i++]=representation.bandwidth&0x000000FF;// ''
esds[i++]=(representation.bandwidth&0xFF000000)>>24;// avgbitrate
esds[i++]=(representation.bandwidth&0x00FF0000)>>16;// ''
esds[i++]=(representation.bandwidth&0x0000FF00)>>8;// ''
esds[i++]=representation.bandwidth&0x000000FF;// ''
// DecoderSpecificInfo (see ISO/IEC 14496-1 (Systems))
esds[i++]=0x05;// tag = 0x05 (DecSpecificInfoTag)
esds[i++]=audioSpecificConfig.length;// size
esds.set(audioSpecificConfig,i);// AudioSpecificConfig bytes
return esds;}function createOriginalFormatBox(sinf,codec){var frma=ISOBoxer.createBox('frma',sinf);frma.data_format=stringToCharCode(codec);}function createSchemeTypeBox(sinf){var schm=ISOBoxer.createFullBox('schm',sinf);schm.flags=0;schm.version=0;schm.scheme_type=0x63656E63;// 'cenc' => common encryption
schm.scheme_version=0x00010000;// version set to 0x00010000 (Major version 1, Minor version 0)
}function createSchemeInformationBox(sinf){var schi=ISOBoxer.createBox('schi',sinf);// Create and add Track Encryption Box
createTrackEncryptionBox(schi);}function createProtectionSystemSpecificHeaderBox(moov,keySystems){var pssh_bytes=void 0,pssh=void 0,i=void 0,parsedBuffer=void 0;for(i=0;i<keySystems.length;i+=1){pssh_bytes=keySystems[i].initData;if(pssh_bytes){parsedBuffer=ISOBoxer.parseBuffer(pssh_bytes);pssh=parsedBuffer.fetch('pssh');if(pssh){ISOBoxer.Utils.appendBox(moov,pssh);}}}}function createTrackEncryptionBox(schi){var tenc=ISOBoxer.createFullBox('tenc',schi);tenc.flags=0;tenc.version=0;tenc.default_IsEncrypted=0x1;tenc.default_IV_size=8;tenc.default_KID=contentProtection&&contentProtection.length>0&&contentProtection[0]['cenc:default_KID']?contentProtection[0]['cenc:default_KID']:[0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0];}function createTrexBox(moov){var trex=ISOBoxer.createFullBox('trex',moov);trex.track_ID=trackId;trex.default_sample_description_index=1;trex.default_sample_duration=0;trex.default_sample_size=0;trex.default_sample_flags=0;return trex;}function hexStringtoBuffer(str){var buf=new Uint8Array(str.length/2);var i=void 0;for(i=0;i<str.length/2;i+=1){buf[i]=parseInt(''+str[i*2]+str[i*2+1],16);}return buf;}function stringToCharCode(str){var code=0;var i=void 0;for(i=0;i<str.length;i+=1){code|=str.charCodeAt(i)<<(str.length-i-1)*8;}return code;}function generateMoov(rep){if(!rep||!rep.adaptation){return;}var isoFile=void 0,arrayBuffer=void 0;representation=rep;adaptationSet=representation.adaptation;period=adaptationSet.period;trackId=adaptationSet.index+1;contentProtection=period.mpd.manifest.Period_asArray[period.index].AdaptationSet_asArray[adaptationSet.index].ContentProtection;timescale=period.mpd.manifest.Period_asArray[period.index].AdaptationSet_asArray[adaptationSet.index].SegmentTemplate.timescale;isoFile=ISOBoxer.createFile();createFtypBox(isoFile);createMoovBox(isoFile);arrayBuffer=isoFile.write();return arrayBuffer;}instance={generateMoov:generateMoov};return instance;}/**
* The copyright in this software is being made available under the BSD License,
* included below. This software may be subject to other third party and contributor
* rights, including patent rights, and no such rights are granted under this license.
*
* Copyright (c) 2013, Dash Industry Forum.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
* * Neither the name of Dash Industry Forum nor the names of its
* contributors may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/MssFragmentMoovProcessor.__dashjs_factory_name='MssFragmentMoovProcessor';exports.default=dashjs.FactoryMaker.getClassFactory(MssFragmentMoovProcessor);/* jshint ignore:line */
//# sourceMappingURL=MssFragmentMoovProcessor.js.map