dashjs
Version:
A reference client implementation for the playback of MPEG DASH via Javascript and compliant browsers.
79 lines (78 loc) • 11.2 kB
JavaScript
;Object.defineProperty(exports,"__esModule",{value:true});var _DashJSError=require('../streaming/vo/DashJSError');var _DashJSError2=_interopRequireDefault(_DashJSError);var _MssErrors=require('./errors/MssErrors');var _MssErrors2=_interopRequireDefault(_MssErrors);var _MediaPlayerEvents=require('../streaming/MediaPlayerEvents');var _MediaPlayerEvents2=_interopRequireDefault(_MediaPlayerEvents);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}/**
* @module MssFragmentMoofProcessor
* @ignore
* @param {Object} config object
*/function MssFragmentMoofProcessor(config){config=config||{};var instance=void 0,type=void 0,logger=void 0;var dashMetrics=config.dashMetrics;var playbackController=config.playbackController;var errorHandler=config.errHandler;var eventBus=config.eventBus;var ISOBoxer=config.ISOBoxer;var debug=config.debug;function setup(){logger=debug.getLogger(instance);type='';}function processTfrf(request,tfrf,tfdt,streamProcessor){var representationController=streamProcessor.getRepresentationController();var representation=representationController.getCurrentRepresentation();var indexHandler=streamProcessor.getIndexHandler();var manifest=representation.adaptation.period.mpd.manifest;var adaptation=manifest.Period_asArray[representation.adaptation.period.index].AdaptationSet_asArray[representation.adaptation.index];var timescale=adaptation.SegmentTemplate.timescale;type=streamProcessor.getType();if(manifest.type!=='dynamic'&&!manifest.timeShiftBufferDepth){return;}if(!tfrf){errorHandler.error(new _DashJSError2.default(_MssErrors2.default.MSS_NO_TFRF_CODE,_MssErrors2.default.MSS_NO_TFRF_MESSAGE));return;}// Get adaptation's segment timeline (always a SegmentTimeline in Smooth Streaming use case)
var segments=adaptation.SegmentTemplate.SegmentTimeline.S;var entries=tfrf.entry;var entry=void 0,segmentTime=void 0,range=void 0;var segment=null;var t=0;var availabilityStartTime=null;if(entries.length===0){return;}// Consider only first tfrf entry (to avoid pre-condition failure on fragment info requests)
entry=entries[0];// In case of start-over streams, check if we have reached end of original manifest duration (set in timeShiftBufferDepth)
// => then do not update anymore timeline
if(manifest.type==='static'){// Get first segment time
segmentTime=segments[0].tManifest?parseFloat(segments[0].tManifest):segments[0].t;if(entry.fragment_absolute_time>segmentTime+manifest.timeShiftBufferDepth*timescale){return;}}logger.debug('entry - t = ',entry.fragment_absolute_time/timescale);// Get last segment time
segmentTime=segments[segments.length-1].tManifest?parseFloat(segments[segments.length-1].tManifest):segments[segments.length-1].t;logger.debug('Last segment - t = ',segmentTime/timescale);// Check if we have to append new segment to timeline
if(entry.fragment_absolute_time<=segmentTime){// Update DVR window range
// => set range end to end time of current segment
range={start:segments[0].t/timescale,end:tfdt.baseMediaDecodeTime/timescale+request.duration};updateDVR(request.mediaType,range,streamProcessor.getStreamInfo().manifestInfo);return;}logger.debug('Add new segment - t = ',entry.fragment_absolute_time/timescale);segment={};segment.t=entry.fragment_absolute_time;segment.d=entry.fragment_duration;// If timestamps starts at 0 relative to 1st segment (dynamic to static) then update segment time
if(segments[0].tManifest){segment.t-=parseFloat(segments[0].tManifest)-segments[0].t;segment.tManifest=entry.fragment_absolute_time;}segments.push(segment);// In case of static start-over streams, update content duration
if(manifest.type==='static'){if(type==='video'){segment=segments[segments.length-1];var end=(segment.t+segment.d)/timescale;if(end>representation.adaptation.period.duration){eventBus.trigger(_MediaPlayerEvents2.default.MANIFEST_VALIDITY_CHANGED,{sender:this,newDuration:end});}}return;}// In case of live streams, update segment timeline according to DVR window
else if(manifest.timeShiftBufferDepth&&manifest.timeShiftBufferDepth>0){// Get timestamp of the last segment
segment=segments[segments.length-1];t=segment.t;// Determine the segments' availability start time
availabilityStartTime=Math.round((t-manifest.timeShiftBufferDepth*timescale)/timescale);// Remove segments prior to availability start time
segment=segments[0];while(Math.round(segment.t/timescale)<availabilityStartTime){logger.debug('Remove segment - t = '+segment.t/timescale);segments.splice(0,1);segment=segments[0];}// Update DVR window range => set range end to end time of current segment
range={start:segments[0].t/timescale,end:tfdt.baseMediaDecodeTime/timescale+request.duration};updateDVR(type,range,streamProcessor.getStreamInfo().manifestInfo);}indexHandler.updateRepresentation(representation,true);}function updateDVR(type,range,manifestInfo){var dvrInfos=dashMetrics.getCurrentDVRInfo(type);if(!dvrInfos||range.end>dvrInfos.range.end){logger.debug('Update DVR Infos ['+range.start+' - '+range.end+']');dashMetrics.addDVRInfo(type,playbackController.getTime(),manifestInfo,range);}}// This function returns the offset of the 1st byte of a child box within a container box
function getBoxOffset(parent,type){var offset=8;var i=0;for(i=0;i<parent.boxes.length;i++){if(parent.boxes[i].type===type){return offset;}offset+=parent.boxes[i].size;}return offset;}function convertFragment(e,sp){var i=void 0;// e.request contains request description object
// e.response contains fragment bytes
var isoFile=ISOBoxer.parseBuffer(e.response);// Update track_Id in tfhd box
var tfhd=isoFile.fetch('tfhd');tfhd.track_ID=e.request.mediaInfo.index+1;// Add tfdt box
var tfdt=isoFile.fetch('tfdt');var traf=isoFile.fetch('traf');if(tfdt===null){tfdt=ISOBoxer.createFullBox('tfdt',traf,tfhd);tfdt.version=1;tfdt.flags=0;tfdt.baseMediaDecodeTime=Math.floor(e.request.startTime*e.request.timescale);}var trun=isoFile.fetch('trun');// Process tfxd boxes
// This box provide absolute timestamp but we take the segment start time for tfdt
var tfxd=isoFile.fetch('tfxd');if(tfxd){tfxd._parent.boxes.splice(tfxd._parent.boxes.indexOf(tfxd),1);tfxd=null;}var tfrf=isoFile.fetch('tfrf');processTfrf(e.request,tfrf,tfdt,sp);if(tfrf){tfrf._parent.boxes.splice(tfrf._parent.boxes.indexOf(tfrf),1);tfrf=null;}// If protected content in PIFF1.1 format (sepiff box = Sample Encryption PIFF)
// => convert sepiff box it into a senc box
// => create saio and saiz boxes (if not already present)
var sepiff=isoFile.fetch('sepiff');if(sepiff!==null){sepiff.type='senc';sepiff.usertype=undefined;var _saio=isoFile.fetch('saio');if(_saio===null){// Create Sample Auxiliary Information Offsets Box box (saio)
_saio=ISOBoxer.createFullBox('saio',traf);_saio.version=0;_saio.flags=0;_saio.entry_count=1;_saio.offset=[0];var saiz=ISOBoxer.createFullBox('saiz',traf);saiz.version=0;saiz.flags=0;saiz.sample_count=sepiff.sample_count;saiz.default_sample_info_size=0;saiz.sample_info_size=[];if(sepiff.flags&0x02){// Sub-sample encryption => set sample_info_size for each sample
for(i=0;i<sepiff.sample_count;i+=1){// 10 = 8 (InitializationVector field size) + 2 (subsample_count field size)
// 6 = 2 (BytesOfClearData field size) + 4 (BytesOfEncryptedData field size)
saiz.sample_info_size[i]=10+6*sepiff.entry[i].NumberOfEntries;}}else{// No sub-sample encryption => set default sample_info_size = InitializationVector field size (8)
saiz.default_sample_info_size=8;}}}tfhd.flags&=0xFFFFFE;// set tfhd.base-data-offset-present to false
tfhd.flags|=0x020000;// set tfhd.default-base-is-moof to true
trun.flags|=0x000001;// set trun.data-offset-present to true
// Update trun.data_offset field that corresponds to first data byte (inside mdat box)
var moof=isoFile.fetch('moof');var length=moof.getLength();trun.data_offset=length+8;// Update saio box offset field according to new senc box offset
var saio=isoFile.fetch('saio');if(saio!==null){var trafPosInMoof=getBoxOffset(moof,'traf');var sencPosInTraf=getBoxOffset(traf,'senc');// Set offset from begin fragment to the first IV field in senc box
saio.offset[0]=trafPosInMoof+sencPosInTraf+16;// 16 = box header (12) + sample_count field size (4)
}// Write transformed/processed fragment into request reponse data
e.response=isoFile.write();}function updateSegmentList(e,sp){// e.request contains request description object
// e.response contains fragment bytes
if(!e.response){throw new Error('e.response parameter is missing');}var isoFile=ISOBoxer.parseBuffer(e.response);// Update track_Id in tfhd box
var tfhd=isoFile.fetch('tfhd');tfhd.track_ID=e.request.mediaInfo.index+1;// Add tfdt box
var tfdt=isoFile.fetch('tfdt');var traf=isoFile.fetch('traf');if(tfdt===null){tfdt=ISOBoxer.createFullBox('tfdt',traf,tfhd);tfdt.version=1;tfdt.flags=0;tfdt.baseMediaDecodeTime=Math.floor(e.request.startTime*e.request.timescale);}var tfrf=isoFile.fetch('tfrf');processTfrf(e.request,tfrf,tfdt,sp);if(tfrf){tfrf._parent.boxes.splice(tfrf._parent.boxes.indexOf(tfrf),1);tfrf=null;}}function getType(){return type;}instance={convertFragment:convertFragment,updateSegmentList:updateSegmentList,getType:getType};setup();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.
*/MssFragmentMoofProcessor.__dashjs_factory_name='MssFragmentMoofProcessor';exports.default=dashjs.FactoryMaker.getClassFactory(MssFragmentMoofProcessor);/* jshint ignore:line */
//# sourceMappingURL=MssFragmentMoofProcessor.js.map