123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959 |
- import document from 'global/document';
- import window from 'global/window';
- import QUnit from 'qunit';
- import sinon from 'sinon';
- import videojs from 'video.js';
- import HtmlMediaSource from '../src/html-media-source';
- import {
- gopsSafeToAlignWith,
- updateGopBuffer,
- removeGopBuffer
- } from '../src/virtual-source-buffer';
- // we disable this because browserify needs to include these files
- // but the exports are not important
- /* eslint-disable no-unused-vars */
- import {MediaSource, URL} from '../src/videojs-contrib-media-sources.js';
- /* eslint-disable no-unused-vars */
- QUnit.module('videojs-contrib-media-sources - HTML', {
- beforeEach() {
- this.fixture = document.getElementById('qunit-fixture');
- this.video = document.createElement('video');
- this.fixture.appendChild(this.video);
- this.source = document.createElement('source');
- this.player = videojs(this.video);
- // add a fake source so that we can get this.player_ on sourceopen
- this.url = 'fake.ts';
- this.source.src = this.url;
- this.video.appendChild(this.source);
- // Mock the environment's timers because certain things - particularly
- // player readiness - are asynchronous in video.js 5.
- this.clock = sinon.useFakeTimers();
- this.oldMediaSource = window.MediaSource || window.WebKitMediaSource;
- window.MediaSource = videojs.extend(videojs.EventTarget, {
- constructor() {
- this.isNative = true;
- this.sourceBuffers = [];
- this.duration = NaN;
- },
- addSourceBuffer(type) {
- let buffer = new (videojs.extend(videojs.EventTarget, {
- type,
- appendBuffer() {}
- }))();
- this.sourceBuffers.push(buffer);
- return buffer;
- }
- });
- window.MediaSource.isTypeSupported = function(mime) {
- return true;
- };
- window.WebKitMediaSource = window.MediaSource;
- },
- afterEach() {
- this.clock.restore();
- this.player.dispose();
- window.MediaSource = this.oldMediaSource;
- window.WebKitMediaSource = window.MediaSource;
- }
- });
- QUnit.test('constructs a native MediaSource', function() {
- QUnit.ok(
- new videojs.MediaSource().nativeMediaSource_.isNative,
- 'constructed a MediaSource'
- );
- });
- const createDataMessage = function(type, typedArray, extraObject) {
- let message = {
- data: {
- action: 'data',
- segment: {
- type,
- data: typedArray.buffer,
- initSegment: {
- data: typedArray.buffer,
- byteOffset: typedArray.byteOffset,
- byteLength: typedArray.byteLength
- }
- },
- byteOffset: typedArray.byteOffset,
- byteLength: typedArray.byteLength
- }
- };
- return Object.keys(extraObject || {}).reduce(function(obj, key) {
- obj.data.segment[key] = extraObject[key];
- return obj;
- }, message);
- };
- // Create a WebWorker-style message that signals the transmuxer is done
- const doneMessage = {
- data: {
- action: 'done'
- }
- };
- // send fake data to the transmuxer to trigger the creation of the
- // native source buffers
- const initializeNativeSourceBuffers = function(sourceBuffer) {
- // initialize an audio source buffer
- sourceBuffer.transmuxer_.onmessage(createDataMessage('audio', new Uint8Array(1)));
- // initialize a video source buffer
- sourceBuffer.transmuxer_.onmessage(createDataMessage('video', new Uint8Array(1)));
- // instruct the transmuxer to flush the "data" it has buffered so
- // far
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- };
- QUnit.test('creates mp4 source buffers for mp2t segments', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- initializeNativeSourceBuffers(sourceBuffer);
- QUnit.ok(mediaSource.videoBuffer_, 'created a video buffer');
- QUnit.equal(
- mediaSource.videoBuffer_.type,
- 'video/mp4;codecs="avc1.4d400d"',
- 'video buffer has the default codec'
- );
- QUnit.ok(mediaSource.audioBuffer_, 'created an audio buffer');
- QUnit.equal(
- mediaSource.audioBuffer_.type,
- 'audio/mp4;codecs="mp4a.40.2"',
- 'audio buffer has the default codec'
- );
- QUnit.equal(mediaSource.sourceBuffers.length, 1, 'created one virtual buffer');
- QUnit.equal(
- mediaSource.sourceBuffers[0],
- sourceBuffer,
- 'returned the virtual buffer'
- );
- QUnit.ok(sourceBuffer.transmuxer_, 'created a transmuxer');
- });
- QUnit.test(
- 'the terminate is called on the transmuxer when the media source is killed',
- function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- let terminates = 0;
- sourceBuffer.transmuxer_ = {
- terminate() {
- terminates++;
- }
- };
- mediaSource.trigger('sourceclose');
- QUnit.equal(terminates, 1, 'called terminate on transmux web worker');
- });
- QUnit.test('duration is faked when playing a live stream', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- mediaSource.duration = Infinity;
- mediaSource.nativeMediaSource_.duration = 100;
- QUnit.equal(mediaSource.nativeMediaSource_.duration, 100,
- 'native duration was not set to infinity');
- QUnit.equal(mediaSource.duration, Infinity,
- 'the MediaSource wrapper pretends it has an infinite duration');
- });
- QUnit.test(
- 'duration uses the underlying MediaSource\'s duration when not live', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- mediaSource.duration = 100;
- mediaSource.nativeMediaSource_.duration = 120;
- QUnit.equal(mediaSource.duration, 120,
- 'the MediaSource wrapper returns the native duration');
- });
- QUnit.test('abort on the fake source buffer calls abort on the real ones', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- let messages = [];
- let aborts = 0;
- initializeNativeSourceBuffers(sourceBuffer);
- sourceBuffer.transmuxer_.postMessage = function(message) {
- messages.push(message);
- };
- sourceBuffer.bufferUpdating_ = true;
- sourceBuffer.videoBuffer_.abort = function() {
- aborts++;
- };
- sourceBuffer.audioBuffer_.abort = function() {
- aborts++;
- };
- sourceBuffer.abort();
- QUnit.equal(aborts, 2, 'called abort on both');
- QUnit.equal(
- sourceBuffer.bufferUpdating_,
- false,
- 'set updating to false'
- );
- QUnit.equal(messages.length, 1, 'has one message');
- QUnit.equal(messages[0].action, 'reset', 'reset called on transmuxer');
- });
- QUnit.test(
- 'calling remove deletes cues and invokes remove on any extant source buffers',
- function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- let removedCue = [];
- let removes = 0;
- initializeNativeSourceBuffers(sourceBuffer);
- sourceBuffer.inbandTextTracks_ = {
- CC1: {
- removeCue(cue) {
- removedCue.push(cue);
- this.cues.splice(this.cues.indexOf(cue), 1);
- },
- cues: [
- {startTime: 10, endTime: 20, text: 'delete me'},
- {startTime: 0, endTime: 2, text: 'save me'}
- ]
- }
- };
- mediaSource.videoBuffer_.remove = function(start, end) {
- if (start === 3 && end === 10) {
- removes++;
- }
- };
- mediaSource.audioBuffer_.remove = function(start, end) {
- if (start === 3 && end === 10) {
- removes++;
- }
- };
- sourceBuffer.remove(3, 10);
- QUnit.equal(removes, 2, 'called remove on both sourceBuffers');
- QUnit.equal(
- sourceBuffer.inbandTextTracks_.CC1.cues.length,
- 1,
- 'one cue remains after remove'
- );
- QUnit.equal(
- removedCue[0].text,
- 'delete me',
- 'the cue that overlapped the remove region was removed'
- );
- });
- QUnit.test(
- 'calling remove property handles absence of cues (null)',
- function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- initializeNativeSourceBuffers(sourceBuffer);
- sourceBuffer.inbandTextTracks_ = {
- CC1: {
- cues: null
- }
- };
- mediaSource.videoBuffer_.remove = function(start, end) {
- // pass
- };
- mediaSource.audioBuffer_.remove = function(start, end) {
- // pass
- };
- // this call should not raise an exception
- sourceBuffer.remove(3, 10);
- QUnit.equal(
- sourceBuffer.inbandTextTracks_.CC1.cues,
- null,
- 'cues are still null'
- );
- });
- QUnit.test('removing doesn\'t happen with audio disabled', function() {
- let mediaSource = new videojs.MediaSource();
- let muxedBuffer = mediaSource.addSourceBuffer('video/mp2t');
- // creating this audio buffer disables audio in the muxed one
- let audioBuffer = mediaSource.addSourceBuffer('audio/mp2t; codecs="mp4a.40.2"');
- let removedCue = [];
- let removes = 0;
- initializeNativeSourceBuffers(muxedBuffer);
- muxedBuffer.inbandTextTracks_ = {
- CC1: {
- removeCue(cue) {
- removedCue.push(cue);
- this.cues.splice(this.cues.indexOf(cue), 1);
- },
- cues: [
- {startTime: 10, endTime: 20, text: 'delete me'},
- {startTime: 0, endTime: 2, text: 'save me'}
- ]
- }
- };
- mediaSource.videoBuffer_.remove = function(start, end) {
- if (start === 3 && end === 10) {
- removes++;
- }
- };
- mediaSource.audioBuffer_.remove = function(start, end) {
- if (start === 3 && end === 10) {
- removes++;
- }
- };
- muxedBuffer.remove(3, 10);
- QUnit.equal(removes, 1, 'called remove on only one source buffer');
- QUnit.equal(muxedBuffer.inbandTextTracks_.CC1.cues.length,
- 1,
- 'one cue remains after remove');
- QUnit.equal(removedCue[0].text,
- 'delete me',
- 'the cue that overlapped the remove region was removed');
- });
- QUnit.test('readyState delegates to the native implementation', function() {
- let mediaSource = new HtmlMediaSource();
- QUnit.equal(
- mediaSource.readyState,
- mediaSource.nativeMediaSource_.readyState,
- 'readyStates are equal'
- );
- mediaSource.nativeMediaSource_.readyState = 'nonsense stuff';
- QUnit.equal(
- mediaSource.readyState,
- mediaSource.nativeMediaSource_.readyState,
- 'readyStates are equal'
- );
- });
- QUnit.test('addSeekableRange_ throws an error for media with known duration', function() {
- let mediaSource = new videojs.MediaSource();
- mediaSource.duration = 100;
- QUnit.throws(function() {
- mediaSource.addSeekableRange_(0, 100);
- }, 'cannot add seekable range');
- });
- QUnit.test('addSeekableRange_ adds to the native MediaSource duration', function() {
- let mediaSource = new videojs.MediaSource();
- mediaSource.duration = Infinity;
- mediaSource.addSeekableRange_(120, 240);
- QUnit.equal(mediaSource.nativeMediaSource_.duration, 240, 'set native duration');
- QUnit.equal(mediaSource.duration, Infinity, 'emulated duration');
- mediaSource.addSeekableRange_(120, 220);
- QUnit.equal(mediaSource.nativeMediaSource_.duration, 240, 'ignored the smaller range');
- QUnit.equal(mediaSource.duration, Infinity, 'emulated duration');
- });
- QUnit.test('appendBuffer error triggers on the player', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- let error = false;
- mediaSource.player_ = this.player;
- initializeNativeSourceBuffers(sourceBuffer);
- sourceBuffer.videoBuffer_.appendBuffer = () => {
- throw new Error();
- };
- this.player.on('error', () => error = true);
- // send fake data to the source buffer from the transmuxer to append to native buffer
- // initializeNativeSourceBuffers does the same thing to trigger the creation of
- // native source buffers.
- let fakeTransmuxerMessage = initializeNativeSourceBuffers;
- fakeTransmuxerMessage(sourceBuffer);
- this.clock.tick(1);
- QUnit.ok(error, 'error triggered on player');
- });
- QUnit.test('transmuxes mp2t segments', function() {
- let mp2tSegments = [];
- let mp4Segments = [];
- let data = new Uint8Array(1);
- let mediaSource;
- let sourceBuffer;
- mediaSource = new videojs.MediaSource();
- sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- sourceBuffer.transmuxer_.postMessage = function(segment) {
- if (segment.action === 'push') {
- let buffer = new Uint8Array(segment.data, segment.byteOffset, segment.byteLength);
- mp2tSegments.push(buffer);
- }
- };
- sourceBuffer.concatAndAppendSegments_ = function(segmentObj, destinationBuffer) {
- mp4Segments.push(segmentObj);
- };
- sourceBuffer.appendBuffer(data);
- QUnit.equal(mp2tSegments.length, 1, 'transmuxed one segment');
- QUnit.equal(mp2tSegments[0].length, 1, 'did not alter the segment');
- QUnit.equal(mp2tSegments[0][0], data[0], 'did not alter the segment');
- // an init segment
- sourceBuffer.transmuxer_.onmessage(createDataMessage('video', new Uint8Array(1)));
- // a media segment
- sourceBuffer.transmuxer_.onmessage(createDataMessage('audio', new Uint8Array(1)));
- // Segments are concatenated
- QUnit.equal(
- mp4Segments.length,
- 0,
- 'segments are not appended until after the `done` message'
- );
- // send `done` message
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- // Segments are concatenated
- QUnit.equal(mp4Segments.length, 2, 'appended the segments');
- });
- QUnit.test(
- 'handles typed-arrays that are subsets of their underlying buffer',
- function() {
- let mp2tSegments = [];
- let mp4Segments = [];
- let dataBuffer = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
- let data = dataBuffer.subarray(5, 7);
- let mediaSource;
- let sourceBuffer;
- mediaSource = new videojs.MediaSource();
- sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- sourceBuffer.transmuxer_.postMessage = function(segment) {
- if (segment.action === 'push') {
- let buffer = new Uint8Array(segment.data, segment.byteOffset, segment.byteLength);
- mp2tSegments.push(buffer);
- }
- };
- sourceBuffer.concatAndAppendSegments_ = function(segmentObj, destinationBuffer) {
- mp4Segments.push(segmentObj.segments[0]);
- };
- sourceBuffer.appendBuffer(data);
- QUnit.equal(mp2tSegments.length, 1, 'emitted the fragment');
- QUnit.equal(
- mp2tSegments[0].length,
- 2,
- 'correctly handled a typed-array that is a subset'
- );
- QUnit.equal(mp2tSegments[0][0], 5, 'fragment contains the correct first byte');
- QUnit.equal(mp2tSegments[0][1], 6, 'fragment contains the correct second byte');
- // an init segment
- sourceBuffer.transmuxer_.onmessage(createDataMessage('video', data));
- // Segments are concatenated
- QUnit.equal(
- mp4Segments.length,
- 0,
- 'segments are not appended until after the `done` message'
- );
- // send `done` message
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- // Segments are concatenated
- QUnit.equal(mp4Segments.length, 1, 'emitted the fragment');
- QUnit.equal(
- mp4Segments[0].length,
- 2,
- 'correctly handled a typed-array that is a subset'
- );
- QUnit.equal(mp4Segments[0][0], 5, 'fragment contains the correct first byte');
- QUnit.equal(mp4Segments[0][1], 6, 'fragment contains the correct second byte');
- });
- QUnit.test(
- 'only appends audio init segment for first segment or on audio/media changes',
- function() {
- let mp4Segments = [];
- let initBuffer = new Uint8Array([0, 1]);
- let dataBuffer = new Uint8Array([2, 3]);
- let mediaSource;
- let sourceBuffer;
- mediaSource = new videojs.MediaSource();
- sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- sourceBuffer.audioDisabled_ = false;
- mediaSource.player_ = this.player;
- mediaSource.url_ = this.url;
- mediaSource.trigger('sourceopen');
- sourceBuffer.concatAndAppendSegments_ = function(segmentObj, destinationBuffer) {
- let segment = segmentObj.segments.reduce((seg, arr) => seg.concat(Array.from(arr)),
- []);
- mp4Segments.push(segment);
- };
- QUnit.ok(sourceBuffer.appendAudioInitSegment_, 'will append init segment next');
- // an init segment
- sourceBuffer.transmuxer_.onmessage(createDataMessage('audio', dataBuffer, {
- initSegment: {
- data: initBuffer.buffer,
- byteOffset: initBuffer.byteOffset,
- byteLength: initBuffer.byteLength
- }
- }));
- // Segments are concatenated
- QUnit.equal(
- mp4Segments.length,
- 0,
- 'segments are not appended until after the `done` message'
- );
- // send `done` message
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- // Segments are concatenated
- QUnit.equal(mp4Segments.length, 1, 'emitted the fragment');
- // Contains init segment on first segment
- QUnit.equal(mp4Segments[0][0], 0, 'fragment contains the correct first byte');
- QUnit.equal(mp4Segments[0][1], 1, 'fragment contains the correct second byte');
- QUnit.equal(mp4Segments[0][2], 2, 'fragment contains the correct third byte');
- QUnit.equal(mp4Segments[0][3], 3, 'fragment contains the correct fourth byte');
- QUnit.ok(!sourceBuffer.appendAudioInitSegment_, 'will not append init segment next');
- dataBuffer = new Uint8Array([4, 5]);
- sourceBuffer.transmuxer_.onmessage(createDataMessage('audio', dataBuffer, {
- initSegment: {
- data: initBuffer.buffer,
- byteOffset: initBuffer.byteOffset,
- byteLength: initBuffer.byteLength
- }
- }));
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- QUnit.equal(mp4Segments.length, 2, 'emitted the fragment');
- // does not contain init segment on next segment
- QUnit.equal(mp4Segments[1][0], 4, 'fragment contains the correct first byte');
- QUnit.equal(mp4Segments[1][1], 5, 'fragment contains the correct second byte');
- // audio track change
- this.player.audioTracks().trigger('change');
- sourceBuffer.audioDisabled_ = false;
- QUnit.ok(sourceBuffer.appendAudioInitSegment_, 'audio change sets appendAudioInitSegment_');
- dataBuffer = new Uint8Array([6, 7]);
- sourceBuffer.transmuxer_.onmessage(createDataMessage('audio', dataBuffer, {
- initSegment: {
- data: initBuffer.buffer,
- byteOffset: initBuffer.byteOffset,
- byteLength: initBuffer.byteLength
- }
- }));
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- QUnit.equal(mp4Segments.length, 3, 'emitted the fragment');
- // contains init segment after audio track change
- QUnit.equal(mp4Segments[2][0], 0, 'fragment contains the correct first byte');
- QUnit.equal(mp4Segments[2][1], 1, 'fragment contains the correct second byte');
- QUnit.equal(mp4Segments[2][2], 6, 'fragment contains the correct third byte');
- QUnit.equal(mp4Segments[2][3], 7, 'fragment contains the correct fourth byte');
- QUnit.ok(!sourceBuffer.appendAudioInitSegment_, 'will not append init segment next');
- dataBuffer = new Uint8Array([8, 9]);
- sourceBuffer.transmuxer_.onmessage(createDataMessage('audio', dataBuffer, {
- initSegment: {
- data: initBuffer.buffer,
- byteOffset: initBuffer.byteOffset,
- byteLength: initBuffer.byteLength
- }
- }));
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- QUnit.equal(mp4Segments.length, 4, 'emitted the fragment');
- // does not contain init segment in next segment
- QUnit.equal(mp4Segments[3][0], 8, 'fragment contains the correct first byte');
- QUnit.equal(mp4Segments[3][1], 9, 'fragment contains the correct second byte');
- QUnit.ok(!sourceBuffer.appendAudioInitSegment_, 'will not append init segment next');
- // rendition switch
- this.player.trigger('mediachange');
- QUnit.ok(sourceBuffer.appendAudioInitSegment_, 'media change sets appendAudioInitSegment_');
- dataBuffer = new Uint8Array([10, 11]);
- sourceBuffer.transmuxer_.onmessage(createDataMessage('audio', dataBuffer, {
- initSegment: {
- data: initBuffer.buffer,
- byteOffset: initBuffer.byteOffset,
- byteLength: initBuffer.byteLength
- }
- }));
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- QUnit.equal(mp4Segments.length, 5, 'emitted the fragment');
- // contains init segment after audio track change
- QUnit.equal(mp4Segments[4][0], 0, 'fragment contains the correct first byte');
- QUnit.equal(mp4Segments[4][1], 1, 'fragment contains the correct second byte');
- QUnit.equal(mp4Segments[4][2], 10, 'fragment contains the correct third byte');
- QUnit.equal(mp4Segments[4][3], 11, 'fragment contains the correct fourth byte');
- QUnit.ok(!sourceBuffer.appendAudioInitSegment_, 'will not append init segment next');
- });
- QUnit.test(
- 'appends video init segment for every segment',
- function() {
- let mp4Segments = [];
- let initBuffer = new Uint8Array([0, 1]);
- let dataBuffer = new Uint8Array([2, 3]);
- let mediaSource;
- let sourceBuffer;
- mediaSource = new videojs.MediaSource();
- sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- mediaSource.player_ = this.player;
- mediaSource.url_ = this.url;
- mediaSource.trigger('sourceopen');
- sourceBuffer.concatAndAppendSegments_ = function(segmentObj, destinationBuffer) {
- let segment = segmentObj.segments.reduce((seg, arr) => seg.concat(Array.from(arr)),
- []);
- mp4Segments.push(segment);
- };
- // an init segment
- sourceBuffer.transmuxer_.onmessage(createDataMessage('video', dataBuffer, {
- initSegment: {
- data: initBuffer.buffer,
- byteOffset: initBuffer.byteOffset,
- byteLength: initBuffer.byteLength
- }
- }));
- // Segments are concatenated
- QUnit.equal(
- mp4Segments.length,
- 0,
- 'segments are not appended until after the `done` message'
- );
- // send `done` message
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- // Segments are concatenated
- QUnit.equal(mp4Segments.length, 1, 'emitted the fragment');
- // Contains init segment on first segment
- QUnit.equal(mp4Segments[0][0], 0, 'fragment contains the correct first byte');
- QUnit.equal(mp4Segments[0][1], 1, 'fragment contains the correct second byte');
- QUnit.equal(mp4Segments[0][2], 2, 'fragment contains the correct third byte');
- QUnit.equal(mp4Segments[0][3], 3, 'fragment contains the correct fourth byte');
- dataBuffer = new Uint8Array([4, 5]);
- sourceBuffer.transmuxer_.onmessage(createDataMessage('video', dataBuffer, {
- initSegment: {
- data: initBuffer.buffer,
- byteOffset: initBuffer.byteOffset,
- byteLength: initBuffer.byteLength
- }
- }));
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- QUnit.equal(mp4Segments.length, 2, 'emitted the fragment');
- QUnit.equal(mp4Segments[1][0], 0, 'fragment contains the correct first byte');
- QUnit.equal(mp4Segments[1][1], 1, 'fragment contains the correct second byte');
- QUnit.equal(mp4Segments[1][2], 4, 'fragment contains the correct third byte');
- QUnit.equal(mp4Segments[1][3], 5, 'fragment contains the correct fourth byte');
- dataBuffer = new Uint8Array([6, 7]);
- sourceBuffer.transmuxer_.onmessage(createDataMessage('video', dataBuffer, {
- initSegment: {
- data: initBuffer.buffer,
- byteOffset: initBuffer.byteOffset,
- byteLength: initBuffer.byteLength
- }
- }));
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- QUnit.equal(mp4Segments.length, 3, 'emitted the fragment');
- // contains init segment after audio track change
- QUnit.equal(mp4Segments[2][0], 0, 'fragment contains the correct first byte');
- QUnit.equal(mp4Segments[2][1], 1, 'fragment contains the correct second byte');
- QUnit.equal(mp4Segments[2][2], 6, 'fragment contains the correct third byte');
- QUnit.equal(mp4Segments[2][3], 7, 'fragment contains the correct fourth byte');
- });
- QUnit.test('handles empty codec string value', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer =
- mediaSource.addSourceBuffer('video/mp2t; codecs=""');
- initializeNativeSourceBuffers(sourceBuffer);
- QUnit.ok(mediaSource.videoBuffer_, 'created a video buffer');
- QUnit.equal(
- mediaSource.videoBuffer_.type,
- 'video/mp4;codecs="avc1.4d400d"',
- 'video buffer has the default codec'
- );
- QUnit.ok(mediaSource.audioBuffer_, 'created an audio buffer');
- QUnit.equal(
- mediaSource.audioBuffer_.type,
- 'audio/mp4;codecs="mp4a.40.2"',
- 'audio buffer has the default codec'
- );
- QUnit.equal(mediaSource.sourceBuffers.length, 1, 'created one virtual buffer');
- QUnit.equal(
- mediaSource.sourceBuffers[0],
- sourceBuffer,
- 'returned the virtual buffer'
- );
- });
- QUnit.test('can create an audio buffer by itself', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer =
- mediaSource.addSourceBuffer('video/mp2t; codecs="mp4a.40.2"');
- initializeNativeSourceBuffers(sourceBuffer);
- QUnit.ok(!mediaSource.videoBuffer_, 'did not create a video buffer');
- QUnit.ok(mediaSource.audioBuffer_, 'created an audio buffer');
- QUnit.equal(
- mediaSource.audioBuffer_.type,
- 'audio/mp4;codecs="mp4a.40.2"',
- 'audio buffer has the default codec'
- );
- QUnit.equal(mediaSource.sourceBuffers.length, 1, 'created one virtual buffer');
- QUnit.equal(
- mediaSource.sourceBuffers[0],
- sourceBuffer,
- 'returned the virtual buffer'
- );
- });
- QUnit.test('can create an video buffer by itself', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer =
- mediaSource.addSourceBuffer('video/mp2t; codecs="avc1.4d400d"');
- initializeNativeSourceBuffers(sourceBuffer);
- QUnit.ok(!mediaSource.audioBuffer_, 'did not create an audio buffer');
- QUnit.ok(mediaSource.videoBuffer_, 'created an video buffer');
- QUnit.equal(
- mediaSource.videoBuffer_.type,
- 'video/mp4;codecs="avc1.4d400d"',
- 'video buffer has the codec that was passed'
- );
- QUnit.equal(mediaSource.sourceBuffers.length, 1, 'created one virtual buffer');
- QUnit.equal(
- mediaSource.sourceBuffers[0],
- sourceBuffer,
- 'returned the virtual buffer'
- );
- });
- QUnit.test('handles invalid codec string', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer =
- mediaSource.addSourceBuffer('video/mp2t; codecs="nope"');
- initializeNativeSourceBuffers(sourceBuffer);
- QUnit.ok(mediaSource.videoBuffer_, 'created a video buffer');
- QUnit.equal(
- mediaSource.videoBuffer_.type,
- 'video/mp4;codecs="avc1.4d400d"',
- 'video buffer has the default codec'
- );
- QUnit.ok(mediaSource.audioBuffer_, 'created an audio buffer');
- QUnit.equal(
- mediaSource.audioBuffer_.type,
- 'audio/mp4;codecs="mp4a.40.2"',
- 'audio buffer has the default codec'
- );
- QUnit.equal(mediaSource.sourceBuffers.length, 1, 'created one virtual buffer');
- QUnit.equal(
- mediaSource.sourceBuffers[0],
- sourceBuffer,
- 'returned the virtual buffer'
- );
- });
- QUnit.test('handles codec strings in reverse order', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer =
- mediaSource.addSourceBuffer('video/mp2t; codecs="mp4a.40.5,avc1.64001f"');
- initializeNativeSourceBuffers(sourceBuffer);
- QUnit.ok(mediaSource.videoBuffer_, 'created a video buffer');
- QUnit.equal(
- mediaSource.videoBuffer_.type,
- 'video/mp4;codecs="avc1.64001f"',
- 'video buffer has the passed codec'
- );
- QUnit.ok(mediaSource.audioBuffer_, 'created an audio buffer');
- QUnit.equal(
- mediaSource.audioBuffer_.type,
- 'audio/mp4;codecs="mp4a.40.5"',
- 'audio buffer has the passed codec'
- );
- QUnit.equal(mediaSource.sourceBuffers.length, 1, 'created one virtual buffer');
- QUnit.equal(
- mediaSource.sourceBuffers[0],
- sourceBuffer,
- 'returned the virtual buffer'
- );
- QUnit.ok(sourceBuffer.transmuxer_, 'created a transmuxer');
- });
- QUnit.test('forwards codec strings to native buffers when specified', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer =
- mediaSource.addSourceBuffer('video/mp2t; codecs="avc1.64001f,mp4a.40.5"');
- initializeNativeSourceBuffers(sourceBuffer);
- QUnit.ok(mediaSource.videoBuffer_, 'created a video buffer');
- QUnit.equal(mediaSource.videoBuffer_.type,
- 'video/mp4;codecs="avc1.64001f"',
- 'passed the video codec along');
- QUnit.ok(mediaSource.audioBuffer_, 'created a video buffer');
- QUnit.equal(mediaSource.audioBuffer_.type,
- 'audio/mp4;codecs="mp4a.40.5"',
- 'passed the audio codec along');
- });
- QUnit.test('parses old-school apple codec strings to the modern standard', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer =
- mediaSource.addSourceBuffer('video/mp2t; codecs="avc1.100.31,mp4a.40.5"');
- initializeNativeSourceBuffers(sourceBuffer);
- QUnit.ok(mediaSource.videoBuffer_, 'created a video buffer');
- QUnit.equal(mediaSource.videoBuffer_.type,
- 'video/mp4;codecs="avc1.64001f"',
- 'passed the video codec along');
- QUnit.ok(mediaSource.audioBuffer_, 'created a video buffer');
- QUnit.equal(mediaSource.audioBuffer_.type,
- 'audio/mp4;codecs="mp4a.40.5"',
- 'passed the audio codec along');
- });
- QUnit.test('specifies reasonable codecs if none are specified', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- initializeNativeSourceBuffers(sourceBuffer);
- QUnit.ok(mediaSource.videoBuffer_, 'created a video buffer');
- QUnit.equal(mediaSource.videoBuffer_.type,
- 'video/mp4;codecs="avc1.4d400d"',
- 'passed the video codec along');
- QUnit.ok(mediaSource.audioBuffer_, 'created a video buffer');
- QUnit.equal(mediaSource.audioBuffer_.type,
- 'audio/mp4;codecs="mp4a.40.2"',
- 'passed the audio codec along');
- });
- QUnit.test('virtual buffers are updating if either native buffer is', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- initializeNativeSourceBuffers(sourceBuffer);
- mediaSource.videoBuffer_.updating = true;
- mediaSource.audioBuffer_.updating = false;
- QUnit.equal(sourceBuffer.updating, true, 'virtual buffer is updating');
- mediaSource.audioBuffer_.updating = true;
- QUnit.equal(sourceBuffer.updating, true, 'virtual buffer is updating');
- mediaSource.videoBuffer_.updating = false;
- QUnit.equal(sourceBuffer.updating, true, 'virtual buffer is updating');
- mediaSource.audioBuffer_.updating = false;
- QUnit.equal(sourceBuffer.updating, false, 'virtual buffer is not updating');
- });
- QUnit.test(
- 'virtual buffers have a position buffered if both native buffers do',
- function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- initializeNativeSourceBuffers(sourceBuffer);
- mediaSource.videoBuffer_.buffered = videojs.createTimeRanges([
- [0, 10],
- [20, 30]
- ]);
- mediaSource.audioBuffer_.buffered = videojs.createTimeRanges([
- [0, 7],
- [11, 15],
- [16, 40]
- ]);
- QUnit.equal(sourceBuffer.buffered.length, 2, 'two buffered ranges');
- QUnit.equal(sourceBuffer.buffered.start(0), 0, 'first starts at zero');
- QUnit.equal(sourceBuffer.buffered.end(0), 7, 'first ends at seven');
- QUnit.equal(sourceBuffer.buffered.start(1), 20, 'second starts at twenty');
- QUnit.equal(sourceBuffer.buffered.end(1), 30, 'second ends at 30');
- });
- QUnit.test('disabled audio does not affect buffered property', function() {
- let mediaSource = new videojs.MediaSource();
- let muxedBuffer = mediaSource.addSourceBuffer('video/mp2t');
- // creating a separate audio buffer disables audio on the muxed one
- let audioBuffer = mediaSource.addSourceBuffer('audio/mp2t; codecs="mp4a.40.2"');
- initializeNativeSourceBuffers(muxedBuffer);
- mediaSource.videoBuffer_.buffered = videojs.createTimeRanges([[1, 10]]);
- mediaSource.audioBuffer_.buffered = videojs.createTimeRanges([[2, 11]]);
- QUnit.equal(audioBuffer.buffered.length, 1, 'one buffered range');
- QUnit.equal(audioBuffer.buffered.start(0), 2, 'starts at two');
- QUnit.equal(audioBuffer.buffered.end(0), 11, 'ends at eleven');
- QUnit.equal(muxedBuffer.buffered.length, 1, 'one buffered range');
- QUnit.equal(muxedBuffer.buffered.start(0), 1, 'starts at one');
- QUnit.equal(muxedBuffer.buffered.end(0), 10, 'ends at ten');
- });
- QUnit.test('sets transmuxer baseMediaDecodeTime on appends', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- let resets = [];
- sourceBuffer.transmuxer_.postMessage = function(message) {
- if (message.action === 'setTimestampOffset') {
- resets.push(message.timestampOffset);
- }
- };
- sourceBuffer.timestampOffset = 42;
- QUnit.equal(
- resets.length,
- 1,
- 'reset called'
- );
- QUnit.equal(
- resets[0],
- 42,
- 'set the baseMediaDecodeTime based on timestampOffset'
- );
- });
- QUnit.test('aggregates source buffer update events', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- let updates = 0;
- let updateends = 0;
- let updatestarts = 0;
- initializeNativeSourceBuffers(sourceBuffer);
- mediaSource.player_ = this.player;
- sourceBuffer.addEventListener('updatestart', function() {
- updatestarts++;
- });
- sourceBuffer.addEventListener('update', function() {
- updates++;
- });
- sourceBuffer.addEventListener('updateend', function() {
- updateends++;
- });
- QUnit.equal(updatestarts, 0, 'no updatestarts before a `done` message is received');
- QUnit.equal(updates, 0, 'no updates before a `done` message is received');
- QUnit.equal(updateends, 0, 'no updateends before a `done` message is received');
- // the video buffer begins updating first:
- sourceBuffer.videoBuffer_.updating = true;
- sourceBuffer.audioBuffer_.updating = false;
- sourceBuffer.videoBuffer_.trigger('updatestart');
- QUnit.equal(updatestarts, 1, 'aggregated updatestart');
- sourceBuffer.audioBuffer_.updating = true;
- sourceBuffer.audioBuffer_.trigger('updatestart');
- QUnit.equal(updatestarts, 1, 'aggregated updatestart');
- // the audio buffer finishes first:
- sourceBuffer.audioBuffer_.updating = false;
- sourceBuffer.videoBuffer_.updating = true;
- sourceBuffer.audioBuffer_.trigger('update');
- QUnit.equal(updates, 0, 'waited for the second update');
- sourceBuffer.videoBuffer_.updating = false;
- sourceBuffer.videoBuffer_.trigger('update');
- QUnit.equal(updates, 1, 'aggregated update');
- // audio finishes first:
- sourceBuffer.videoBuffer_.updating = true;
- sourceBuffer.audioBuffer_.updating = false;
- sourceBuffer.audioBuffer_.trigger('updateend');
- QUnit.equal(updateends, 0, 'waited for the second updateend');
- sourceBuffer.videoBuffer_.updating = false;
- sourceBuffer.videoBuffer_.trigger('updateend');
- QUnit.equal(updateends, 1, 'aggregated updateend');
- });
- QUnit.test('translates caption events into WebVTT cues', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- let types = [];
- let hls608 = 0;
- mediaSource.player_ = {
- addRemoteTextTrack(options) {
- types.push(options.kind);
- return {
- track: {
- kind: options.kind,
- label: options.label,
- cues: [],
- addCue(cue) {
- this.cues.push(cue);
- }
- }
- };
- },
- textTracks() {
- return {
- getTrackById() {}
- };
- },
- remoteTextTracks() {
- },
- tech_: new videojs.EventTarget()
- };
- mediaSource.player_.tech_.on('usage', (event) => {
- if (event.name === 'hls-608') {
- hls608++;
- }
- });
- sourceBuffer.timestampOffset = 10;
- sourceBuffer.transmuxer_.onmessage(createDataMessage('video', new Uint8Array(1), {
- captions: [{
- startTime: 1,
- endTime: 3,
- text: 'This is an in-band caption in CC1',
- stream: 'CC1'
- }],
- captionStreams: {CC1: true}
- }));
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- let cues = sourceBuffer.inbandTextTracks_.CC1.cues;
- QUnit.equal(hls608, 1, 'one hls-608 event was triggered');
- QUnit.equal(types.length, 1, 'created one text track');
- QUnit.equal(types[0], 'captions', 'the type was captions');
- QUnit.equal(cues.length, 1, 'created one cue');
- QUnit.equal(cues[0].text, 'This is an in-band caption in CC1', 'included the text');
- QUnit.equal(cues[0].startTime, 11, 'started at eleven');
- QUnit.equal(cues[0].endTime, 13, 'ended at thirteen');
- });
- QUnit.test('captions use existing tracks with id equal to CC#', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- let addTrackCalled = 0;
- let tracks = {
- CC1: {
- kind: 'captions',
- label: 'CC1',
- id: 'CC1',
- cues: [],
- addCue(cue) {
- this.cues.push(cue);
- }
- },
- CC2: {
- kind: 'captions',
- label: 'CC2',
- id: 'CC2',
- cues: [],
- addCue(cue) {
- this.cues.push(cue);
- }
- }
- };
- mediaSource.player_ = {
- addRemoteTextTrack(options) {
- addTrackCalled++;
- },
- textTracks() {
- return {
- getTrackById(id) {
- return tracks[id];
- }
- };
- },
- remoteTextTracks() {
- },
- tech_: new videojs.EventTarget()
- };
- sourceBuffer.timestampOffset = 10;
- sourceBuffer.transmuxer_.onmessage(createDataMessage('video', new Uint8Array(1), {
- captions: [{
- stream: 'CC1',
- startTime: 1,
- endTime: 3,
- text: 'This is an in-band caption in CC1'
- }, {
- stream: 'CC2',
- startTime: 1,
- endTime: 3,
- text: 'This is an in-band caption in CC2'
- }],
- captionStreams: {CC1: true, CC2: true}
- }));
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- let cues = sourceBuffer.inbandTextTracks_.CC1.cues;
- QUnit.equal(addTrackCalled, 0, 'no tracks were created');
- QUnit.equal(tracks.CC1.cues.length, 1, 'CC1 contains 1 cue');
- QUnit.equal(tracks.CC2.cues.length, 1, 'CC2 contains 1 cue');
- QUnit.equal(tracks.CC1.cues[0].text, 'This is an in-band caption in CC1', 'CC1 contains the right cue');
- QUnit.equal(tracks.CC2.cues[0].text, 'This is an in-band caption in CC2', 'CC2 contains the right cue');
- });
- QUnit.test('translates metadata events into WebVTT cues', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- mediaSource.duration = Infinity;
- mediaSource.nativeMediaSource_.duration = 60;
- let types = [];
- let metadata = [{
- cueTime: 2,
- frames: [{
- url: 'This is a url tag'
- }, {
- value: 'This is a text tag'
- }]
- }, {
- cueTime: 12,
- frames: [{
- data: 'This is a priv tag'
- }]
- }];
- metadata.dispatchType = 0x10;
- mediaSource.player_ = {
- addRemoteTextTrack(options) {
- types.push(options.kind);
- return {
- track: {
- kind: options.kind,
- label: options.label,
- cues: [],
- addCue(cue) {
- this.cues.push(cue);
- }
- }
- };
- },
- remoteTextTracks() {
- }
- };
- sourceBuffer.timestampOffset = 10;
- sourceBuffer.transmuxer_.onmessage(createDataMessage('video', new Uint8Array(1), {
- metadata
- }));
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- QUnit.equal(
- sourceBuffer.metadataTrack_.inBandMetadataTrackDispatchType,
- 16,
- 'in-band metadata track dispatch type correctly set'
- );
- let cues = sourceBuffer.metadataTrack_.cues;
- QUnit.equal(types.length, 1, 'created one text track');
- QUnit.equal(types[0], 'metadata', 'the type was metadata');
- QUnit.equal(cues.length, 3, 'created three cues');
- QUnit.equal(cues[0].text, 'This is a url tag', 'included the text');
- QUnit.equal(cues[0].startTime, 12, 'started at twelve');
- QUnit.equal(cues[0].endTime, 22, 'ended at StartTime of next cue(22)');
- QUnit.equal(cues[1].text, 'This is a text tag', 'included the text');
- QUnit.equal(cues[1].startTime, 12, 'started at twelve');
- QUnit.equal(cues[1].endTime, 22, 'ended at the startTime of next cue(22)');
- QUnit.equal(cues[2].text, 'This is a priv tag', 'included the text');
- QUnit.equal(cues[2].startTime, 22, 'started at twenty two');
- QUnit.equal(cues[2].endTime, Number.MAX_VALUE, 'ended at the maximum value');
- mediaSource.duration = 100;
- mediaSource.trigger('sourceended');
- QUnit.equal(cues[2].endTime, mediaSource.duration, 'sourceended is fired');
- });
- QUnit.test('does not wrap mp4 source buffers', function() {
- let mediaSource = new videojs.MediaSource();
- mediaSource.addSourceBuffer('video/mp4;codecs=avc1.4d400d');
- mediaSource.addSourceBuffer('audio/mp4;codecs=mp4a.40.2');
- QUnit.equal(
- mediaSource.sourceBuffers.length,
- mediaSource.nativeMediaSource_.sourceBuffers.length,
- 'did not need virtual buffers'
- );
- QUnit.equal(mediaSource.sourceBuffers.length, 2, 'created native buffers');
- });
- QUnit.test('can get activeSourceBuffers', function() {
- let mediaSource = new videojs.MediaSource();
- // although activeSourceBuffers should technically be a SourceBufferList, we are
- // returning it as an array, and users may expect it to behave as such
- QUnit.ok(Array.isArray(mediaSource.activeSourceBuffers));
- });
- QUnit.test('active source buffers are updated on each buffer\'s updateend',
- function() {
- let mediaSource = new videojs.MediaSource();
- let updateCallCount = 0;
- let sourceBuffer;
- mediaSource.updateActiveSourceBuffers_ = () => {
- updateCallCount++;
- };
- sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- mediaSource.player_ = this.player;
- mediaSource.url_ = this.url;
- mediaSource.trigger('sourceopen');
- QUnit.equal(updateCallCount, 0,
- 'active source buffers not updated on adding source buffer');
- mediaSource.player_.audioTracks().trigger('addtrack');
- QUnit.equal(updateCallCount, 1,
- 'active source buffers updated after addtrack');
- sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- QUnit.equal(updateCallCount, 1,
- 'active source buffers not updated on adding second source buffer');
- mediaSource.player_.audioTracks().trigger('removetrack');
- QUnit.equal(updateCallCount, 2,
- 'active source buffers updated after removetrack');
- mediaSource.player_.audioTracks().trigger('change');
- QUnit.equal(updateCallCount, 3,
- 'active source buffers updated after change');
- });
- QUnit.test('combined buffer is the only active buffer when main track enabled',
- function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBufferAudio;
- let sourceBufferCombined;
- let audioTracks = [{
- enabled: true,
- kind: 'main',
- label: 'main'
- }, {
- enabled: false,
- kind: 'alternative',
- label: 'English (UK)'
- }];
- this.player.audioTracks = () => audioTracks;
- mediaSource.player_ = this.player;
- sourceBufferCombined = mediaSource.addSourceBuffer('video/m2pt');
- sourceBufferCombined.videoCodec_ = true;
- sourceBufferCombined.audioCodec_ = true;
- sourceBufferAudio = mediaSource.addSourceBuffer('video/m2pt');
- sourceBufferAudio.videoCodec_ = false;
- sourceBufferAudio.audioCodec_ = true;
- mediaSource.updateActiveSourceBuffers_();
- QUnit.equal(mediaSource.activeSourceBuffers.length, 1,
- 'active source buffers starts with one source buffer');
- QUnit.equal(mediaSource.activeSourceBuffers[0], sourceBufferCombined,
- 'active source buffers starts with combined source buffer');
- });
- QUnit.test('combined & audio buffers are active when alternative track enabled',
- function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBufferAudio;
- let sourceBufferCombined;
- let audioTracks = [{
- enabled: false,
- kind: 'main',
- label: 'main'
- }, {
- enabled: true,
- kind: 'alternative',
- label: 'English (UK)'
- }];
- this.player.audioTracks = () => audioTracks;
- mediaSource.player_ = this.player;
- sourceBufferCombined = mediaSource.addSourceBuffer('video/m2pt');
- sourceBufferCombined.videoCodec_ = true;
- sourceBufferCombined.audioCodec_ = true;
- sourceBufferAudio = mediaSource.addSourceBuffer('video/m2pt');
- sourceBufferAudio.videoCodec_ = false;
- sourceBufferAudio.audioCodec_ = true;
- mediaSource.updateActiveSourceBuffers_();
- QUnit.equal(mediaSource.activeSourceBuffers.length, 2,
- 'active source buffers includes both source buffers');
- // maintains same order as source buffers were created
- QUnit.equal(mediaSource.activeSourceBuffers[0], sourceBufferCombined,
- 'active source buffers starts with combined source buffer');
- QUnit.equal(mediaSource.activeSourceBuffers[1], sourceBufferAudio,
- 'active source buffers ends with audio source buffer');
- });
- QUnit.test('video only & audio only buffers are always active',
- function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBufferAudio;
- let sourceBufferCombined;
- let audioTracks = [{
- enabled: false,
- kind: 'main',
- label: 'main'
- }, {
- enabled: true,
- kind: 'alternative',
- label: 'English (UK)'
- }];
- this.player.audioTracks = () => audioTracks;
- mediaSource.player_ = this.player;
- sourceBufferCombined = mediaSource.addSourceBuffer('video/m2pt');
- sourceBufferCombined.videoCodec_ = true;
- sourceBufferCombined.audioCodec_ = false;
- sourceBufferAudio = mediaSource.addSourceBuffer('video/m2pt');
- sourceBufferAudio.videoCodec_ = false;
- sourceBufferAudio.audioCodec_ = true;
- mediaSource.updateActiveSourceBuffers_();
- QUnit.equal(mediaSource.activeSourceBuffers.length, 2,
- 'active source buffers includes both source buffers');
- // maintains same order as source buffers were created
- QUnit.equal(mediaSource.activeSourceBuffers[0], sourceBufferCombined,
- 'active source buffers starts with combined source buffer');
- QUnit.equal(mediaSource.activeSourceBuffers[1], sourceBufferAudio,
- 'active source buffers ends with audio source buffer');
- audioTracks[0].enabled = true;
- audioTracks[1].enabled = false;
- mediaSource.updateActiveSourceBuffers_();
- QUnit.equal(mediaSource.activeSourceBuffers.length, 2,
- 'active source buffers includes both source buffers');
- // maintains same order as source buffers were created
- QUnit.equal(mediaSource.activeSourceBuffers[0], sourceBufferCombined,
- 'active source buffers starts with combined source buffer');
- QUnit.equal(mediaSource.activeSourceBuffers[1], sourceBufferAudio,
- 'active source buffers ends with audio source buffer');
- });
- QUnit.test('Single buffer always active. Audio disabled depends on audio codec',
- function() {
- let mediaSource = new videojs.MediaSource();
- let audioTracks = [{
- enabled: true,
- kind: 'main',
- label: 'main'
- }];
- this.player.audioTracks = () => audioTracks;
- mediaSource.player_ = this.player;
- let sourceBuffer = mediaSource.addSourceBuffer('video/m2pt');
- // video only
- sourceBuffer.videoCodec_ = true;
- sourceBuffer.audioCodec_ = false;
- mediaSource.updateActiveSourceBuffers_();
- QUnit.equal(mediaSource.activeSourceBuffers.length, 1, 'sourceBuffer is active');
- QUnit.ok(mediaSource.activeSourceBuffers[0].audioDisabled_,
- 'audio is disabled on video only active sourceBuffer');
- // audio only
- sourceBuffer.videoCodec_ = false;
- sourceBuffer.audioCodec_ = true;
- mediaSource.updateActiveSourceBuffers_();
- QUnit.equal(mediaSource.activeSourceBuffers.length, 1, 'sourceBuffer is active');
- QUnit.notOk(mediaSource.activeSourceBuffers[0].audioDisabled_,
- 'audio not disabled on audio only active sourceBuffer');
- });
- QUnit.test('video segments with info trigger videooinfo event', function() {
- let data = new Uint8Array(1);
- let infoEvents = [];
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- let info = {width: 100};
- let newinfo = {width: 225};
- mediaSource.on('videoinfo', (e) => infoEvents.push(e));
- // send an audio segment with info, then send done
- sourceBuffer.transmuxer_.onmessage(createDataMessage('video', data, {info}));
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- QUnit.equal(infoEvents.length, 1, 'video info should trigger');
- QUnit.deepEqual(infoEvents[0].info, info, 'video info = muxed info');
- // send an audio segment with info, then send done
- sourceBuffer.transmuxer_.onmessage(createDataMessage('video', data, {info: newinfo}));
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- QUnit.equal(infoEvents.length, 2, 'video info should trigger');
- QUnit.deepEqual(infoEvents[1].info, newinfo, 'video info = muxed info');
- });
- QUnit.test('audio segments with info trigger audioinfo event', function() {
- let data = new Uint8Array(1);
- let infoEvents = [];
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer = mediaSource.addSourceBuffer('video/mp2t');
- let info = {width: 100};
- let newinfo = {width: 225};
- mediaSource.on('audioinfo', (e) => infoEvents.push(e));
- // send an audio segment with info, then send done
- sourceBuffer.transmuxer_.onmessage(createDataMessage('audio', data, {info}));
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- QUnit.equal(infoEvents.length, 1, 'audio info should trigger');
- QUnit.deepEqual(infoEvents[0].info, info, 'audio info = muxed info');
- // send an audio segment with info, then send done
- sourceBuffer.transmuxer_.onmessage(createDataMessage('audio', data, {info: newinfo}));
- sourceBuffer.transmuxer_.onmessage(doneMessage);
- QUnit.equal(infoEvents.length, 2, 'audio info should trigger');
- QUnit.deepEqual(infoEvents[1].info, newinfo, 'audio info = muxed info');
- });
- QUnit.test('creates native SourceBuffers immediately if a second ' +
- 'VirtualSourceBuffer is created', function() {
- let mediaSource = new videojs.MediaSource();
- let sourceBuffer =
- mediaSource.addSourceBuffer('video/mp2t; codecs="avc1.64001f,mp4a.40.5"');
- let sourceBuffer2 =
- mediaSource.addSourceBuffer('video/mp2t; codecs="mp4a.40.5"');
- QUnit.ok(mediaSource.videoBuffer_, 'created a video buffer');
- QUnit.equal(
- mediaSource.videoBuffer_.type,
- 'video/mp4;codecs="avc1.64001f"',
- 'video buffer has the specified codec'
- );
- QUnit.ok(mediaSource.audioBuffer_, 'created an audio buffer');
- QUnit.equal(
- mediaSource.audioBuffer_.type,
- 'audio/mp4;codecs="mp4a.40.5"',
- 'audio buffer has the specified codec'
- );
- QUnit.equal(mediaSource.sourceBuffers.length, 2, 'created two virtual buffers');
- QUnit.equal(
- mediaSource.sourceBuffers[0],
- sourceBuffer,
- 'returned the virtual buffer');
- QUnit.equal(
- mediaSource.sourceBuffers[1],
- sourceBuffer2,
- 'returned the virtual buffer');
- QUnit.equal(
- sourceBuffer.audioDisabled_,
- true,
- 'first source buffer\'s audio is automatically disabled');
- QUnit.ok(
- sourceBuffer2.audioBuffer_,
- 'second source buffer has an audio source buffer');
- });
- QUnit.module('VirtualSourceBuffer - Isolated Functions');
- QUnit.test('gopsSafeToAlignWith returns correct list', function() {
- // gopsSafeToAlignWith uses a 3 second safetyNet so that gops very close to the playhead
- // are not considered safe to append to
- const safetyNet = 3;
- const pts = (time) => Math.ceil(time * 90000);
- let mapping = 0;
- let currentTime = 0;
- let buffer = [];
- let player;
- let actual;
- let expected;
- expected = [];
- actual = gopsSafeToAlignWith(buffer, player, mapping);
- QUnit.deepEqual(actual, expected, 'empty array when player is undefined');
- player = { currentTime: () => currentTime };
- actual = gopsSafeToAlignWith(buffer, player, mapping);
- QUnit.deepEqual(actual, expected, 'empty array when buffer is empty');
- buffer = expected = [
- { pts: pts(currentTime + safetyNet + 1) },
- { pts: pts(currentTime + safetyNet + 2) },
- { pts: pts(currentTime + safetyNet + 3) }
- ];
- actual = gopsSafeToAlignWith(buffer, player, mapping);
- QUnit.deepEqual(actual, expected,
- 'entire buffer considered safe when all gops come after currentTime + safetyNet');
- buffer = [
- { pts: pts(currentTime + safetyNet) },
- { pts: pts(currentTime + safetyNet + 1) },
- { pts: pts(currentTime + safetyNet + 2) }
- ];
- expected = [
- { pts: pts(currentTime + safetyNet + 1) },
- { pts: pts(currentTime + safetyNet + 2) }
- ];
- actual = gopsSafeToAlignWith(buffer, player, mapping);
- QUnit.deepEqual(actual, expected, 'safetyNet comparison is not inclusive');
- currentTime = 10;
- mapping = -5;
- buffer = [
- { pts: pts(currentTime - mapping + safetyNet - 2) },
- { pts: pts(currentTime - mapping + safetyNet - 1) },
- { pts: pts(currentTime - mapping + safetyNet) },
- { pts: pts(currentTime - mapping + safetyNet + 1) },
- { pts: pts(currentTime - mapping + safetyNet + 2) }
- ];
- expected = [
- { pts: pts(currentTime - mapping + safetyNet + 1) },
- { pts: pts(currentTime - mapping + safetyNet + 2) }
- ];
- actual = gopsSafeToAlignWith(buffer, player, mapping);
- QUnit.deepEqual(actual, expected, 'uses mapping to shift currentTime');
- currentTime = 20;
- expected = [];
- actual = gopsSafeToAlignWith(buffer, player, mapping);
- QUnit.deepEqual(actual, expected,
- 'empty array when no gops in buffer come after currentTime');
- });
- QUnit.test('updateGopBuffer correctly processes new gop information', function() {
- let buffer = [];
- let gops = [];
- let replace = true;
- let actual;
- let expected;
- buffer = expected = [{ pts: 100 }, { pts: 200 }];
- actual = updateGopBuffer(buffer, gops, replace);
- QUnit.deepEqual(actual, expected, 'returns buffer when no new gops');
- gops = expected = [{ pts: 300 }, { pts: 400 }];
- actual = updateGopBuffer(buffer, gops, replace);
- QUnit.deepEqual(actual, expected, 'returns only new gops when replace is true');
- replace = false;
- buffer = [];
- gops = [{ pts: 100 }];
- expected = [{ pts: 100 }];
- actual = updateGopBuffer(buffer, gops, replace);
- QUnit.deepEqual(actual, expected, 'appends new gops to empty buffer');
- buffer = [{ pts: 100 }, { pts: 200 }];
- gops = [{ pts: 300 }, { pts: 400 }];
- expected = [{ pts: 100 }, { pts: 200 }, { pts: 300 }, { pts: 400 }];
- actual = updateGopBuffer(buffer, gops, replace);
- QUnit.deepEqual(actual, expected, 'appends new gops at end of buffer when no overlap');
- buffer = [{ pts: 100 }, { pts: 200 }, { pts: 300 }, { pts: 400 }];
- gops = [{ pts: 250 }, { pts: 300 }, { pts: 350 }];
- expected = [{ pts: 100 }, { pts: 200 }, { pts: 250 }, { pts: 300 }, { pts: 350 }];
- actual = updateGopBuffer(buffer, gops, replace);
- QUnit.deepEqual(actual, expected,
- 'slices buffer at point of overlap and appends new gops');
- buffer = [{ pts: 100 }, { pts: 200 }, { pts: 300 }, { pts: 400 }];
- gops = [{ pts: 200 }, { pts: 300 }, { pts: 350 }];
- expected = [{ pts: 100 }, { pts: 200 }, { pts: 300 }, { pts: 350 }];
- actual = updateGopBuffer(buffer, gops, replace);
- QUnit.deepEqual(actual, expected, 'overlap slice is inclusive');
- buffer = [{ pts: 300 }, { pts: 400 }, { pts: 500 }, { pts: 600 }];
- gops = [{ pts: 100 }, { pts: 200 }, { pts: 250 }];
- expected = [{ pts: 100 }, { pts: 200 }, { pts: 250 }];
- actual = updateGopBuffer(buffer, gops, replace);
- QUnit.deepEqual(actual, expected,
- 'completely replaces buffer with new gops when all gops come before buffer');
- });
- QUnit.test('removeGopBuffer correctly removes range from buffer', function() {
- const pts = (time) => Math.ceil(time * 90000);
- let buffer = [];
- let start = 0;
- let end = 0;
- let mapping = -5;
- let actual;
- let expected;
- expected = [];
- actual = removeGopBuffer(buffer, start, end, mapping);
- QUnit.deepEqual(actual, expected, 'returns empty array when buffer empty');
- start = 0;
- end = 8;
- buffer = expected = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- actual = removeGopBuffer(buffer, start, end, mapping);
- QUnit.deepEqual(actual, expected,
- 'no removal when remove range comes before start of buffer');
- start = 22;
- end = 30;
- buffer = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- expected = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) }
- ];
- actual = removeGopBuffer(buffer, start, end, mapping);
- QUnit.deepEqual(actual, expected,
- 'removes last gop when remove range is after end of buffer');
- start = 0;
- end = 10;
- buffer = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- expected = [
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- actual = removeGopBuffer(buffer, start, end, mapping);
- QUnit.deepEqual(actual, expected, 'clamps start range to begining of buffer');
- start = 0;
- end = 12;
- buffer = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- expected = [
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- actual = removeGopBuffer(buffer, start, end, mapping);
- QUnit.deepEqual(actual, expected, 'clamps start range to begining of buffer');
- start = 0;
- end = 14;
- buffer = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- expected = [
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- actual = removeGopBuffer(buffer, start, end, mapping);
- QUnit.deepEqual(actual, expected, 'clamps start range to begining of buffer');
- start = 15;
- end = 30;
- buffer = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- expected = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) }
- ];
- actual = removeGopBuffer(buffer, start, end, mapping);
- QUnit.deepEqual(actual, expected, 'clamps end range to end of buffer');
- start = 17;
- end = 30;
- buffer = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- expected = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) }
- ];
- actual = removeGopBuffer(buffer, start, end, mapping);
- QUnit.deepEqual(actual, expected, 'clamps end range to end of buffer');
- start = 20;
- end = 30;
- buffer = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- expected = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) }
- ];
- actual = removeGopBuffer(buffer, start, end, mapping);
- QUnit.deepEqual(actual, expected, 'clamps end range to end of buffer');
- buffer = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- start = 12;
- end = 15;
- expected = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- actual = removeGopBuffer(buffer, start, end, mapping);
- QUnit.deepEqual(actual, expected, 'removes gops that remove range intersects with');
- buffer = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- start = 12;
- end = 14;
- expected = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- actual = removeGopBuffer(buffer, start, end, mapping);
- QUnit.deepEqual(actual, expected, 'removes gops that remove range intersects with');
- buffer = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- start = 13;
- end = 14;
- expected = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- actual = removeGopBuffer(buffer, start, end, mapping);
- QUnit.deepEqual(actual, expected, 'removes gops that remove range intersects with');
- buffer = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- start = 13;
- end = 15;
- expected = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- actual = removeGopBuffer(buffer, start, end, mapping);
- QUnit.deepEqual(actual, expected, 'removes gops that remove range intersects with');
- buffer = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- start = 12;
- end = 17;
- expected = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- actual = removeGopBuffer(buffer, start, end, mapping);
- QUnit.deepEqual(actual, expected, 'removes gops that remove range intersects with');
- buffer = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- start = 13;
- end = 16;
- expected = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- actual = removeGopBuffer(buffer, start, end, mapping);
- QUnit.deepEqual(actual, expected, 'removes gops that remove range intersects with');
- start = 10;
- end = 20;
- buffer = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- expected = [];
- actual = removeGopBuffer(buffer, start, end, mapping);
- QUnit.deepEqual(actual, expected,
- 'removes entire buffer when buffer inside remove range');
- start = 0;
- end = 30;
- buffer = [
- { pts: pts(10 - mapping) },
- { pts: pts(11 - mapping) },
- { pts: pts(12 - mapping) },
- { pts: pts(15 - mapping) },
- { pts: pts(18 - mapping) },
- { pts: pts(20 - mapping) }
- ];
- expected = [];
- actual = removeGopBuffer(buffer, start, end, mapping);
- QUnit.deepEqual(actual, expected,
- 'removes entire buffer when buffer inside remove range');
- });
|