UNPKG

dashjs

Version:

A reference client implementation for the playback of MPEG DASH via Javascript and compliant browsers.

175 lines (174 loc) 19 kB
'use strict';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