123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523 |
- import {
- inheritAttributes,
- buildBaseUrls,
- parseCaptionServiceMetadata,
- getSegmentInformation,
- getPeriodStart,
- toEventStream
- } from '../src/inheritAttributes';
- import { stringToMpdXml } from '../src/stringToMpdXml';
- import errors from '../src/errors';
- import QUnit from 'qunit';
- import { toPlaylists } from '../src/toPlaylists';
- import decodeB64ToUint8Array from '@videojs/vhs-utils/es/decode-b64-to-uint8-array';
- import { findChildren } from '../src/utils/xml';
- QUnit.module('buildBaseUrls');
- QUnit.test('returns reference urls when no BaseURL nodes', function(assert) {
- const reference = ['https://example.com/', 'https://foo.com/'];
- assert.deepEqual(buildBaseUrls(reference, []), reference, 'returns reference urls');
- });
- QUnit.test('single reference url with single BaseURL node', function(assert) {
- const reference = ['https://example.com'];
- const node = [{ textContent: 'bar/' }];
- const expected = ['https://example.com/bar/'];
- assert.deepEqual(buildBaseUrls(reference, node), expected, 'builds base url');
- });
- QUnit.test('multiple reference urls with single BaseURL node', function(assert) {
- const reference = ['https://example.com/', 'https://foo.com/'];
- const node = [{ textContent: 'bar/' }];
- const expected = ['https://example.com/bar/', 'https://foo.com/bar/'];
- assert.deepEqual(
- buildBaseUrls(reference, node), expected,
- 'base url for each reference url'
- );
- });
- QUnit.test('multiple BaseURL nodes with single reference url', function(assert) {
- const reference = ['https://example.com/'];
- const nodes = [{ textContent: 'bar/' }, { textContent: 'baz/' }];
- const expected = ['https://example.com/bar/', 'https://example.com/baz/'];
- assert.deepEqual(buildBaseUrls(reference, nodes), expected, 'base url for each node');
- });
- QUnit.test('multiple reference urls with multiple BaseURL nodes', function(assert) {
- const reference = ['https://example.com/', 'https://foo.com/', 'http://example.com'];
- const nodes =
- [{ textContent: 'bar/' }, { textContent: 'baz/' }, { textContent: 'buzz/' }];
- const expected = [
- 'https://example.com/bar/',
- 'https://example.com/baz/',
- 'https://example.com/buzz/',
- 'https://foo.com/bar/',
- 'https://foo.com/baz/',
- 'https://foo.com/buzz/',
- 'http://example.com/bar/',
- 'http://example.com/baz/',
- 'http://example.com/buzz/'
- ];
- assert.deepEqual(buildBaseUrls(reference, nodes), expected, 'creates all base urls');
- });
- QUnit.test('absolute BaseURL overwrites reference', function(assert) {
- const reference = ['https://example.com'];
- const node = [{ textContent: 'https://foo.com/bar/' }];
- const expected = ['https://foo.com/bar/'];
- assert.deepEqual(
- buildBaseUrls(reference, node), expected,
- 'absolute url overwrites reference'
- );
- });
- QUnit.module('getPeriodStart');
- QUnit.test('gets period start when available', function(assert) {
- assert.equal(
- getPeriodStart({
- attributes: { start: 11 },
- priorPeriodAttributes: null,
- mpdType: 'static'
- }),
- 11,
- 'returned period start value'
- );
- });
- QUnit.test('gets period start when prior period and duration', function(assert) {
- assert.equal(
- getPeriodStart({
- attributes: {},
- priorPeriodAttributes: { start: 11, duration: 20 },
- mpdType: 'static'
- }),
- 31,
- 'returned correct period start value'
- );
- });
- QUnit.test('gets period start when no prior period and static', function(assert) {
- assert.equal(
- getPeriodStart({
- attributes: {},
- priorPeriodAttributes: null,
- mpdType: 'static'
- }),
- 0,
- 'returned correct period start value'
- );
- });
- QUnit.test('null when static and prior period but missing attributes', function(assert) {
- assert.equal(
- getPeriodStart({
- attributes: {},
- priorPeriodAttributes: { start: 11 },
- mpdType: 'static'
- }),
- null,
- 'null when no duration in prior period'
- );
- assert.equal(
- getPeriodStart({
- attributes: {},
- priorPeriodAttributes: { duration: 20 },
- mpdType: 'static'
- }),
- null,
- 'null when no start in prior period'
- );
- });
- QUnit.test('null when dynamic, no prior period, and no start attribute', function(assert) {
- assert.equal(
- getPeriodStart({
- attributes: {},
- priorPeriodAttributes: null,
- mpdType: 'dyanmic'
- }),
- null,
- 'null when no dynamic, no start attribute, and no prior period'
- );
- });
- QUnit.module('getSegmentInformation');
- QUnit.test('undefined Segment information when no Segment nodes', function(assert) {
- const adaptationSet = { childNodes: [] };
- const expected = {};
- assert.deepEqual(
- getSegmentInformation(adaptationSet), expected,
- 'undefined segment info'
- );
- });
- QUnit.test('gets SegmentTemplate attributes', function(assert) {
- const adaptationSet = {
- childNodes: [{
- tagName: 'SegmentTemplate',
- attributes: [{ name: 'media', value: 'video.mp4' }],
- childNodes: []
- }]
- };
- const expected = {
- template: { media: 'video.mp4' }
- };
- assert.deepEqual(
- getSegmentInformation(adaptationSet), expected,
- 'SegmentTemplate info'
- );
- });
- QUnit.test('gets SegmentList attributes', function(assert) {
- const adaptationSet = {
- childNodes: [{
- tagName: 'SegmentList',
- attributes: [{ name: 'duration', value: '10' }],
- childNodes: []
- }]
- };
- const expected = {
- list: {
- duration: 10,
- segmentUrls: [],
- initialization: {}
- }
- };
- assert.deepEqual(
- getSegmentInformation(adaptationSet), expected,
- 'SegmentList info'
- );
- });
- QUnit.test('gets SegmentBase attributes', function(assert) {
- const adaptationSet = {
- childNodes: [{
- tagName: 'SegmentBase',
- attributes: [{ name: 'duration', value: '10' }],
- childNodes: []
- }]
- };
- const expected = {
- base: { duration: 10, initialization: {} }
- };
- assert.deepEqual(
- getSegmentInformation(adaptationSet), expected,
- 'SegmentBase info'
- );
- });
- QUnit.test('gets SegmentTemplate and SegmentTimeline attributes', function(assert) {
- const adaptationSet = {
- childNodes: [{
- tagName: 'SegmentTemplate',
- attributes: [{ name: 'media', value: 'video.mp4' }],
- childNodes: [{
- tagName: 'SegmentTimeline',
- childNodes: [{
- tagName: 'S',
- attributes: [{ name: 'd', value: '10' }]
- }, {
- tagName: 'S',
- attributes: [{ name: 'd', value: '5' }]
- }, {
- tagName: 'S',
- attributes: [{ name: 'd', value: '7' }]
- }]
- }]
- }]
- };
- const expected = {
- template: { media: 'video.mp4' },
- segmentTimeline: [{ d: 10 }, { d: 5 }, { d: 7 }]
- };
- assert.deepEqual(
- getSegmentInformation(adaptationSet), expected,
- 'SegmentTemplate and SegmentTimeline info'
- );
- });
- QUnit.module('caption service metadata');
- QUnit.test('parsed 608 metadata', function(assert) {
- const getmd = (value) => ({
- schemeIdUri: 'urn:scte:dash:cc:cea-608:2015',
- value
- });
- const assertServices = (services, expected, message) => {
- if (!services) {
- assert.notOk(expected, message);
- return;
- }
- services.forEach((service, i) => {
- assert.deepEqual(service, expected[i], message);
- });
- };
- assertServices(parseCaptionServiceMetadata({
- schemeIdUri: 'random scheme',
- value: 'CC1'
- }), undefined, 'dont parse incorrect scheme ID for 608');
- assertServices(parseCaptionServiceMetadata(getmd('CC1')), [{
- channel: 'CC1',
- language: 'CC1'
- }], 'CC1');
- assertServices(parseCaptionServiceMetadata(getmd('CC2')), [{
- channel: 'CC2',
- language: 'CC2'
- }], 'CC2');
- assertServices(parseCaptionServiceMetadata(getmd('English')), [{
- channel: undefined,
- language: 'English'
- }], 'English');
- assertServices(parseCaptionServiceMetadata(getmd('CC1;CC2')), [{
- channel: 'CC1',
- language: 'CC1'
- }, {
- channel: 'CC2',
- language: 'CC2'
- }], 'CC1;CC2');
- assertServices(parseCaptionServiceMetadata(getmd('CC1=eng;CC3=swe')), [{
- channel: 'CC1',
- language: 'eng'
- }, {
- channel: 'CC3',
- language: 'swe'
- }], 'CC1=eng;CC3=swe');
- assertServices(parseCaptionServiceMetadata(getmd('CC1=Hello;CC3=World')), [{
- channel: 'CC1',
- language: 'Hello'
- }, {
- channel: 'CC3',
- language: 'World'
- }], 'CC1=Hello;CC3=World');
- assertServices(parseCaptionServiceMetadata(getmd('eng;swe')), [{
- channel: undefined,
- language: 'eng'
- }, {
- channel: undefined,
- language: 'swe'
- }], 'eng;CC3');
- });
- QUnit.test('parsed 708 metadata', function(assert) {
- const getmd = (value) => ({
- schemeIdUri: 'urn:scte:dash:cc:cea-708:2015',
- value
- });
- const assertServices = (services, expected, message) => {
- if (!services) {
- assert.notOk(expected, message);
- return;
- }
- services.forEach((service, i) => {
- assert.deepEqual(service, expected[i], message);
- });
- };
- assertServices(parseCaptionServiceMetadata({
- schemeIdUri: 'random scheme',
- value: 'eng'
- }), undefined, 'dont parse incorrect scheme for 708');
- assertServices(parseCaptionServiceMetadata(getmd('eng')), [{
- 'channel': undefined,
- 'language': 'eng',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }], 'simple eng');
- assertServices(parseCaptionServiceMetadata(getmd('eng;swe')), [{
- 'channel': undefined,
- 'language': 'eng',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': undefined,
- 'language': 'swe',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }], 'eng;swe');
- assertServices(parseCaptionServiceMetadata(getmd('1=lang:eng;2=lang:swe')), [{
- 'channel': 'SERVICE1',
- 'language': 'eng',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': 'SERVICE2',
- 'language': 'swe',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }], '1=lang:eng;2=lang:swe');
- assertServices(parseCaptionServiceMetadata(getmd('1=lang:eng;swe')), [{
- 'channel': 'SERVICE1',
- 'language': 'eng',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': undefined,
- 'language': 'swe',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }], 'mixed 1=lang:eng;swe');
- assertServices(parseCaptionServiceMetadata(getmd('1=lang:eng;2=lang:eng,war:1,er:1')), [{
- 'channel': 'SERVICE1',
- 'language': 'eng',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': 'SERVICE2',
- 'language': 'eng',
- 'aspectRatio': 1,
- 'easyReader': 1,
- '3D': 0
- }], '1=lang:eng;2=lang:eng,war:1,er:1');
- assertServices(parseCaptionServiceMetadata(getmd('1=lang:eng,war:0;2=lang:eng,3D:1,er:1')), [{
- 'channel': 'SERVICE1',
- 'language': 'eng',
- 'aspectRatio': 0,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': 'SERVICE2',
- 'language': 'eng',
- 'aspectRatio': 1,
- 'easyReader': 1,
- '3D': 1
- }], '1=lang:eng,war:0;2=lang:eng,3D:1,er:1');
- assertServices(parseCaptionServiceMetadata(getmd('eng;fre;spa;jpn;deu;swe;kor;lat;zho;heb;rus;ara;hin;por;tur')), [{
- 'channel': undefined,
- 'language': 'eng',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': undefined,
- 'language': 'fre',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': undefined,
- 'language': 'spa',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': undefined,
- 'language': 'jpn',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': undefined,
- 'language': 'deu',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': undefined,
- 'language': 'swe',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': undefined,
- 'language': 'kor',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': undefined,
- 'language': 'lat',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': undefined,
- 'language': 'zho',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': undefined,
- 'language': 'heb',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': undefined,
- 'language': 'rus',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': undefined,
- 'language': 'ara',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': undefined,
- 'language': 'hin',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': undefined,
- 'language': 'por',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }, {
- 'channel': undefined,
- 'language': 'tur',
- 'aspectRatio': 1,
- 'easyReader': 0,
- '3D': 0
- }], 'make sure that parsing 15 services works');
- });
- QUnit.module('inheritAttributes');
- QUnit.test('needs at least one Period', function(assert) {
- assert.throws(
- () => inheritAttributes(stringToMpdXml('<MPD></MPD>')),
- new RegExp(errors.INVALID_NUMBER_OF_PERIOD)
- );
- });
- QUnit.test('end to end - basic', function(assert) {
- const NOW = Date.now();
- const actual = inheritAttributes(stringToMpdXml(`
- <MPD mediaPresentationDuration="PT30S" >
- <BaseURL>https://www.example.com/base/</BaseURL>
- <Period>
- <AdaptationSet mimeType="video/mp4" >
- <Role value="main"></Role>
- <SegmentTemplate></SegmentTemplate>
- <Representation
- bandwidth="5000000"
- codecs="avc1.64001e"
- height="404"
- id="test"
- width="720">
- </Representation>
- </AdaptationSet>
- <AdaptationSet mimeType="text/vtt" lang="en">
- <Representation bandwidth="256" id="en">
- <BaseURL>https://example.com/en.vtt</BaseURL>
- </Representation>
- </AdaptationSet>
- </Period>
- </MPD>
- `), { NOW });
- const expected = {
- eventStream: [],
- locations: undefined,
- representationInfo: [{
- attributes: {
- bandwidth: 5000000,
- baseUrl: 'https://www.example.com/base/',
- codecs: 'avc1.64001e',
- height: 404,
- id: 'test',
- mediaPresentationDuration: 30,
- mimeType: 'video/mp4',
- periodStart: 0,
- role: {
- value: 'main'
- },
- sourceDuration: 30,
- type: 'static',
- width: 720,
- NOW,
- clientOffset: 0
- },
- segmentInfo: {
- template: {}
- }
- }, {
- attributes: {
- bandwidth: 256,
- baseUrl: 'https://example.com/en.vtt',
- id: 'en',
- lang: 'en',
- mediaPresentationDuration: 30,
- mimeType: 'text/vtt',
- periodStart: 0,
- role: {},
- sourceDuration: 30,
- type: 'static',
- NOW,
- clientOffset: 0
- },
- segmentInfo: {}
- }]
- };
- assert.equal(actual.representationInfo.length, 2);
- assert.deepEqual(actual, expected);
- });
- QUnit.test('end to end - basic dynamic', function(assert) {
- const NOW = Date.now();
- const actual = inheritAttributes(stringToMpdXml(`
- <MPD type="dyanmic">
- <BaseURL>https://www.example.com/base/</BaseURL>
- <Period start="PT0S">
- <AdaptationSet mimeType="video/mp4">
- <Role value="main"></Role>
- <SegmentTemplate></SegmentTemplate>
- <Representation
- bandwidth="5000000"
- codecs="avc1.64001e"
- height="404"
- id="test"
- width="720">
- </Representation>
- </AdaptationSet>
- <AdaptationSet mimeType="text/vtt" lang="en">
- <Representation bandwidth="256" id="en">
- <BaseURL>https://example.com/en.vtt</BaseURL>
- </Representation>
- </AdaptationSet>
- </Period>
- </MPD>
- `), { NOW });
- const expected = {
- eventStream: [],
- locations: undefined,
- representationInfo: [{
- attributes: {
- bandwidth: 5000000,
- baseUrl: 'https://www.example.com/base/',
- codecs: 'avc1.64001e',
- height: 404,
- id: 'test',
- mimeType: 'video/mp4',
- periodStart: 0,
- role: {
- value: 'main'
- },
- sourceDuration: 0,
- type: 'dyanmic',
- width: 720,
- NOW,
- clientOffset: 0
- },
- segmentInfo: {
- template: {}
- }
- }, {
- attributes: {
- bandwidth: 256,
- baseUrl: 'https://example.com/en.vtt',
- id: 'en',
- lang: 'en',
- mimeType: 'text/vtt',
- periodStart: 0,
- role: {},
- sourceDuration: 0,
- type: 'dyanmic',
- NOW,
- clientOffset: 0
- },
- segmentInfo: {}
- }]
- };
- assert.equal(actual.representationInfo.length, 2);
- assert.deepEqual(actual, expected);
- });
- QUnit.test('end to end - basic multiperiod', function(assert) {
- const NOW = Date.now();
- // no start time attributes on either period, should be inferred
- const actual = inheritAttributes(stringToMpdXml(`
- <MPD mediaPresentationDuration="PT60S" >
- <BaseURL>https://www.example.com/base/</BaseURL>
- <Period duration="PT30S">
- <AdaptationSet mimeType="video/mp4" >
- <Role value="main"></Role>
- <SegmentTemplate></SegmentTemplate>
- <Representation
- bandwidth="5000000"
- codecs="avc1.64001e"
- height="404"
- id="test"
- width="720">
- </Representation>
- </AdaptationSet>
- </Period>
- <Period>
- <AdaptationSet mimeType="video/mp4" >
- <Role value="main"></Role>
- <SegmentTemplate></SegmentTemplate>
- <Representation
- bandwidth="5000000"
- codecs="avc1.64001e"
- height="404"
- id="test"
- width="720">
- </Representation>
- </AdaptationSet>
- </Period>
- </MPD>
- `), { NOW });
- const expected = {
- eventStream: [],
- locations: undefined,
- representationInfo: [{
- attributes: {
- bandwidth: 5000000,
- baseUrl: 'https://www.example.com/base/',
- codecs: 'avc1.64001e',
- height: 404,
- id: 'test',
- mediaPresentationDuration: 60,
- mimeType: 'video/mp4',
- periodDuration: 30,
- // inferred start
- periodStart: 0,
- role: {
- value: 'main'
- },
- sourceDuration: 60,
- type: 'static',
- width: 720,
- NOW,
- clientOffset: 0
- },
- segmentInfo: {
- template: {}
- }
- }, {
- attributes: {
- bandwidth: 5000000,
- baseUrl: 'https://www.example.com/base/',
- codecs: 'avc1.64001e',
- height: 404,
- id: 'test',
- mediaPresentationDuration: 60,
- mimeType: 'video/mp4',
- // inferred start
- periodStart: 30,
- role: {
- value: 'main'
- },
- sourceDuration: 60,
- type: 'static',
- width: 720,
- NOW,
- clientOffset: 0
- },
- segmentInfo: {
- template: {}
- }
- }]
- };
- assert.equal(actual.representationInfo.length, 2);
- assert.deepEqual(actual, expected);
- });
- QUnit.test('end to end - inherits BaseURL from all levels', function(assert) {
- const NOW = Date.now();
- const actual = inheritAttributes(stringToMpdXml(`
- <MPD mediaPresentationDuration="PT30S" >
- <BaseURL>https://www.example.com/base/</BaseURL>
- <Period>
- <BaseURL>foo/</BaseURL>
- <AdaptationSet mimeType="video/mp4" >
- <BaseURL>bar/</BaseURL>
- <Role value="main"></Role>
- <SegmentTemplate></SegmentTemplate>
- <Representation
- bandwidth="5000000"
- codecs="avc1.64001e"
- height="404"
- id="test"
- width="720">
- <BaseURL>buzz/</BaseURL>
- </Representation>
- </AdaptationSet>
- <AdaptationSet mimeType="text/vtt" lang="en">
- <Representation bandwidth="256" id="en">
- <BaseURL>https://example.com/en.vtt</BaseURL>
- </Representation>
- </AdaptationSet>
- </Period>
- </MPD>
- `), { NOW });
- const expected = {
- eventStream: [],
- locations: undefined,
- representationInfo: [{
- attributes: {
- bandwidth: 5000000,
- baseUrl: 'https://www.example.com/base/foo/bar/buzz/',
- clientOffset: 0,
- codecs: 'avc1.64001e',
- height: 404,
- id: 'test',
- mediaPresentationDuration: 30,
- mimeType: 'video/mp4',
- periodStart: 0,
- role: {
- value: 'main'
- },
- sourceDuration: 30,
- type: 'static',
- width: 720,
- NOW
- },
- segmentInfo: {
- template: {}
- }
- }, {
- attributes: {
- bandwidth: 256,
- baseUrl: 'https://example.com/en.vtt',
- id: 'en',
- lang: 'en',
- mediaPresentationDuration: 30,
- mimeType: 'text/vtt',
- periodStart: 0,
- role: {},
- sourceDuration: 30,
- type: 'static',
- NOW,
- clientOffset: 0
- },
- segmentInfo: { }
- }]
- };
- assert.equal(actual.representationInfo.length, 2);
- assert.deepEqual(actual, expected);
- });
- QUnit.test('end to end - alternate BaseURLs', function(assert) {
- const NOW = Date.now();
- const actual = inheritAttributes(stringToMpdXml(`
- <MPD mediaPresentationDuration= "PT30S" >
- <BaseURL>https://www.example.com/base/</BaseURL>
- <BaseURL>https://www.test.com/base/</BaseURL>
- <Period>
- <AdaptationSet mimeType= "video/mp4" >
- <BaseURL>segments/</BaseURL>
- <BaseURL>media/</BaseURL>
- <Role value= "main" ></Role>
- <SegmentTemplate></SegmentTemplate>
- <Representation
- bandwidth= "5000000"
- codecs= "avc1.64001e"
- height= "404"
- id= "test"
- width= "720" >
- </Representation>
- </AdaptationSet>
- <AdaptationSet mimeType= "text/vtt" lang= "en" >
- <Representation bandwidth= "256" id= "en" >
- <BaseURL>https://example.com/en.vtt</BaseURL>
- </Representation>
- </AdaptationSet>
- </Period>
- </MPD>
- `), { NOW });
- const expected = {
- eventStream: [],
- locations: undefined,
- representationInfo: [{
- attributes: {
- bandwidth: 5000000,
- baseUrl: 'https://www.example.com/base/segments/',
- codecs: 'avc1.64001e',
- height: 404,
- id: 'test',
- mediaPresentationDuration: 30,
- mimeType: 'video/mp4',
- periodStart: 0,
- role: {
- value: 'main'
- },
- sourceDuration: 30,
- type: 'static',
- width: 720,
- NOW,
- clientOffset: 0
- },
- segmentInfo: {
- template: {}
- }
- }, {
- attributes: {
- bandwidth: 5000000,
- baseUrl: 'https://www.example.com/base/media/',
- codecs: 'avc1.64001e',
- height: 404,
- id: 'test',
- mediaPresentationDuration: 30,
- mimeType: 'video/mp4',
- periodStart: 0,
- role: {
- value: 'main'
- },
- sourceDuration: 30,
- type: 'static',
- width: 720,
- NOW,
- clientOffset: 0
- },
- segmentInfo: {
- template: {}
- }
- }, {
- attributes: {
- bandwidth: 5000000,
- baseUrl: 'https://www.test.com/base/segments/',
- codecs: 'avc1.64001e',
- height: 404,
- id: 'test',
- mediaPresentationDuration: 30,
- mimeType: 'video/mp4',
- periodStart: 0,
- role: {
- value: 'main'
- },
- sourceDuration: 30,
- type: 'static',
- width: 720,
- NOW,
- clientOffset: 0
- },
- segmentInfo: {
- template: {}
- }
- }, {
- attributes: {
- bandwidth: 5000000,
- baseUrl: 'https://www.test.com/base/media/',
- codecs: 'avc1.64001e',
- height: 404,
- id: 'test',
- mediaPresentationDuration: 30,
- mimeType: 'video/mp4',
- periodStart: 0,
- role: {
- value: 'main'
- },
- sourceDuration: 30,
- type: 'static',
- width: 720,
- NOW,
- clientOffset: 0
- },
- segmentInfo: {
- template: {}
- }
- }, {
- attributes: {
- bandwidth: 256,
- baseUrl: 'https://example.com/en.vtt',
- id: 'en',
- lang: 'en',
- mediaPresentationDuration: 30,
- mimeType: 'text/vtt',
- periodStart: 0,
- role: {},
- sourceDuration: 30,
- type: 'static',
- NOW,
- clientOffset: 0
- },
- segmentInfo: {}
- }, {
- attributes: {
- bandwidth: 256,
- baseUrl: 'https://example.com/en.vtt',
- id: 'en',
- lang: 'en',
- mediaPresentationDuration: 30,
- mimeType: 'text/vtt',
- periodStart: 0,
- role: {},
- sourceDuration: 30,
- type: 'static',
- NOW,
- clientOffset: 0
- },
- segmentInfo: {}
- }]
- };
- assert.equal(actual.representationInfo.length, 6);
- assert.deepEqual(actual, expected);
- });
- QUnit.test(
- ' End to End test for checking support of segments in representation',
- function(assert) {
- const NOW = Date.now();
- const actual = inheritAttributes(stringToMpdXml(`
- <MPD mediaPresentationDuration= "PT30S" >
- <BaseURL>https://www.example.com/base/</BaseURL>
- <Period>
- <AdaptationSet mimeType= "video/mp4" >
- <Role value= "main" ></Role>
- <SegmentBase indexRangeExact= "true" indexRange= "820-2087" >
- <Initialization range= "0-987" />
- </SegmentBase>
- <Representation
- mimeType= "video/mp6"
- bandwidth= "5000000"
- codecs= "avc1.64001e"
- height= "404"
- id= "test"
- width= "720" >
- <SegmentBase>
- <Initialization range= "0-567" />
- </SegmentBase>
- </Representation>
- <Representation
- height= "545" >
- </Representation>
- </AdaptationSet>
- <AdaptationSet mimeType= "text/vtt" lang= "en" >
- <Representation bandwidth= "256" id= "en" >
- <BaseURL>https://example.com/en.vtt</BaseURL>
- </Representation>
- </AdaptationSet>
- </Period>
- </MPD>
- `), { NOW });
- const expected = {
- eventStream: [],
- locations: undefined,
- representationInfo: [{
- attributes: {
- bandwidth: 5000000,
- baseUrl: 'https://www.example.com/base/',
- codecs: 'avc1.64001e',
- height: 404,
- id: 'test',
- mediaPresentationDuration: 30,
- mimeType: 'video/mp6',
- periodStart: 0,
- role: {
- value: 'main'
- },
- sourceDuration: 30,
- type: 'static',
- width: 720,
- NOW,
- clientOffset: 0
- },
- segmentInfo: {
- base: {
- indexRange: '820-2087',
- indexRangeExact: 'true',
- initialization: {
- range: '0-567'
- }
- }
- }
- }, {
- attributes: {
- baseUrl: 'https://www.example.com/base/',
- mediaPresentationDuration: 30,
- mimeType: 'video/mp4',
- periodStart: 0,
- height: 545,
- role: {
- value: 'main'
- },
- sourceDuration: 30,
- type: 'static',
- NOW,
- clientOffset: 0
- },
- segmentInfo: {
- base: {
- indexRange: '820-2087',
- indexRangeExact: 'true',
- initialization: {
- range: '0-987'
- }
- }
- }
- }, {
- attributes: {
- bandwidth: 256,
- baseUrl: 'https://example.com/en.vtt',
- id: 'en',
- lang: 'en',
- mediaPresentationDuration: 30,
- mimeType: 'text/vtt',
- periodStart: 0,
- role: {},
- sourceDuration: 30,
- type: 'static',
- NOW,
- clientOffset: 0
- },
- segmentInfo: {}
- }]
- };
- assert.equal(actual.representationInfo.length, 3);
- assert.deepEqual(actual, expected);
- }
- );
- QUnit.test(
- ' End to End test for checking support of segments in period ',
- function(assert) {
- const NOW = Date.now();
- const actual = inheritAttributes(stringToMpdXml(`
- <MPD mediaPresentationDuration= "PT30S" >
- <BaseURL>https://www.example.com/base/</BaseURL>
- <Period duration= "PT0H4M40.414S" >
- <SegmentBase indexRangeExact= "false" indexRange= "9999" >
- <Initialization range= "0-1111" />
- </SegmentBase>
- <AdaptationSet mimeType= "video/mp4" >
- <Role value= "main" ></Role>
- <Representation
- mimeType= "video/mp6"
- bandwidth= "5000000"
- codecs= "avc1.64001e"
- height= "404"
- id= "test"
- width= "720" >
- </Representation>
- <Representation
- height= "545" >
- </Representation>
- </AdaptationSet>
- <AdaptationSet mimeType= "text/vtt" lang= "en" >
- <Representation bandwidth= "256" id= "en" >
- <BaseURL>https://example.com/en.vtt</BaseURL>
- </Representation>
- </AdaptationSet>
- </Period>
- </MPD>
- `), { NOW });
- const expected = {
- eventStream: [],
- locations: undefined,
- representationInfo: [{
- attributes: {
- bandwidth: 5000000,
- baseUrl: 'https://www.example.com/base/',
- codecs: 'avc1.64001e',
- height: 404,
- id: 'test',
- mediaPresentationDuration: 30,
- mimeType: 'video/mp6',
- periodDuration: 280.414,
- periodStart: 0,
- role: {
- value: 'main'
- },
- sourceDuration: 30,
- type: 'static',
- width: 720,
- NOW,
- clientOffset: 0
- },
- segmentInfo: {
- base: {
- indexRange: '9999',
- indexRangeExact: 'false',
- initialization: {
- range: '0-1111'
- }
- }
- }
- }, {
- attributes: {
- baseUrl: 'https://www.example.com/base/',
- mediaPresentationDuration: 30,
- mimeType: 'video/mp4',
- periodDuration: 280.414,
- periodStart: 0,
- height: 545,
- role: {
- value: 'main'
- },
- sourceDuration: 30,
- type: 'static',
- NOW,
- clientOffset: 0
- },
- segmentInfo: {
- base: {
- indexRange: '9999',
- indexRangeExact: 'false',
- initialization: {
- range: '0-1111'
- }
- }
- }
- }, {
- attributes: {
- bandwidth: 256,
- baseUrl: 'https://example.com/en.vtt',
- id: 'en',
- lang: 'en',
- mediaPresentationDuration: 30,
- mimeType: 'text/vtt',
- periodDuration: 280.414,
- periodStart: 0,
- role: {},
- sourceDuration: 30,
- type: 'static',
- NOW,
- clientOffset: 0
- },
- segmentInfo: {
- base: {
- indexRange: '9999',
- indexRangeExact: 'false',
- initialization: {
- range: '0-1111'
- }
- }
- }
- }]
- };
- assert.equal(actual.representationInfo.length, 3);
- assert.deepEqual(actual, expected);
- }
- );
- QUnit.test(
- ' End to End test for checking support of Segments in Adaptation set',
- function(assert) {
- const NOW = Date.now();
- const actual = inheritAttributes(stringToMpdXml(`
- <MPD mediaPresentationDuration= "PT30S" >
- <BaseURL>https://www.example.com/base/</BaseURL>
- <Period>
- <AdaptationSet mimeType= "video/mp4" >
- <Role value= "main" ></Role>
- <SegmentBase indexRange= "1212" indexRangeExact= "true" >
- <Initialization range= "0-8888" />
- </SegmentBase>
- <Representation
- mimeType= "video/mp6"
- bandwidth= "5000000"
- codecs= "avc1.64001e"
- height= "404"
- id= "test"
- width= "720" >
- </Representation>
- <Representation
- height= "545" >
- </Representation>
- </AdaptationSet>
- <AdaptationSet mimeType= "text/vtt" lang= "en" >
- <Representation bandwidth= "256" id= "en" >
- <BaseURL>https://example.com/en.vtt</BaseURL>
- </Representation>
- </AdaptationSet>
- </Period>
- </MPD>
- `), { NOW });
- const expected = {
- eventStream: [],
- locations: undefined,
- representationInfo: [{
- attributes: {
- bandwidth: 5000000,
- baseUrl: 'https://www.example.com/base/',
- codecs: 'avc1.64001e',
- height: 404,
- id: 'test',
- mediaPresentationDuration: 30,
- mimeType: 'video/mp6',
- periodStart: 0,
- role: {
- value: 'main'
- },
- sourceDuration: 30,
- type: 'static',
- width: 720,
- NOW,
- clientOffset: 0
- },
- segmentInfo: {
- base: {
- indexRange: '1212',
- indexRangeExact: 'true',
- initialization: {
- range: '0-8888'
- }
- }
- }
- }, {
- attributes: {
- baseUrl: 'https://www.example.com/base/',
- mediaPresentationDuration: 30,
- mimeType: 'video/mp4',
- periodStart: 0,
- height: 545,
- role: {
- value: 'main'
- },
- sourceDuration: 30,
- type: 'static',
- NOW,
- clientOffset: 0
- },
- segmentInfo: {
- base: {
- indexRange: '1212',
- indexRangeExact: 'true',
- initialization: {
- range: '0-8888'
- }
- }
- }
- }, {
- attributes: {
- bandwidth: 256,
- baseUrl: 'https://example.com/en.vtt',
- id: 'en',
- lang: 'en',
- mediaPresentationDuration: 30,
- mimeType: 'text/vtt',
- periodStart: 0,
- role: {},
- sourceDuration: 30,
- type: 'static',
- NOW,
- clientOffset: 0
- },
- segmentInfo: {}
- }]
- };
- assert.equal(actual.representationInfo.length, 3);
- assert.deepEqual(actual, expected);
- }
- );
- // Although according to the Spec, at most one set of Segment information should be
- // present at each level, this test would still handle the case and prevent errors if
- // multiple set of segment information are present at any particular level.
- QUnit.test(
- 'Test for checking use of only one set of Segment Information when multiple are present',
- function(assert) {
- const NOW = Date.now();
- const actual = toPlaylists(inheritAttributes(stringToMpdXml(`
- <MPD mediaPresentationDuration= "PT30S" >
- <BaseURL>https://www.example.com/base</BaseURL>
- <Period>
- <AdaptationSet
- mimeType= "video/mp4"
- segmentAlignment= "true"
- startWithSAP= "1"
- lang= "es" >
- <Role value= "main" ></Role>
- <SegmentTemplate
- duration= "95232"
- initialization= "$RepresentationID$/es/init.m4f"
- media= "$RepresentationID$/es/$Number$.m4f"
- startNumber= "0"
- timescale= "48000" >
- </SegmentTemplate>
- <SegmentList timescale= "1000" duration= "1000" >
- <RepresentationIndex sourceURL= "representation-index-low" />
- <SegmentURL media= "low/segment-1.ts" />
- <SegmentURL media= "low/segment-2.ts" />
- <SegmentURL media= "low/segment-3.ts" />
- <SegmentURL media= "low/segment-4.ts" />
- <SegmentURL media= "low/segment-5.ts" />
- <SegmentURL media= "low/segment-6.ts" />
- </SegmentList>
- <Representation
- mimeType= "video/mp6"
- bandwidth= "5000000"
- codecs= "avc1.64001e"
- height= "404"
- id= "125000"
- width= "720" >
- </Representation>
- <Representation
- height= "545"
- id="125000" >
- </Representation>
- </AdaptationSet>
- </Period>
- </MPD>
- `), { NOW }).representationInfo);
- const expected = [{
- attributes: {
- NOW,
- bandwidth: 5000000,
- baseUrl: 'https://www.example.com/base',
- duration: 1.984,
- codecs: 'avc1.64001e',
- height: 404,
- id: '125000',
- lang: 'es',
- mediaPresentationDuration: 30,
- mimeType: 'video/mp6',
- periodStart: 0,
- startNumber: 0,
- timescale: 48000,
- role: {
- value: 'main'
- },
- clientOffset: 0,
- initialization: {
- sourceURL: '$RepresentationID$/es/init.m4f'
- },
- media: '$RepresentationID$/es/$Number$.m4f',
- segmentAlignment: 'true',
- sourceDuration: 30,
- type: 'static',
- width: 720,
- startWithSAP: '1'
- },
- segments: [{
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/0.m4f',
- timeline: 0,
- uri: '125000/es/0.m4f',
- number: 0,
- presentationTime: 0
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/1.m4f',
- timeline: 0,
- uri: '125000/es/1.m4f',
- number: 1,
- presentationTime: 1.984
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/2.m4f',
- timeline: 0,
- uri: '125000/es/2.m4f',
- number: 2,
- presentationTime: 3.968
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/3.m4f',
- timeline: 0,
- uri: '125000/es/3.m4f',
- number: 3,
- presentationTime: 5.952
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/4.m4f',
- timeline: 0,
- uri: '125000/es/4.m4f',
- number: 4,
- presentationTime: 7.936
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/5.m4f',
- timeline: 0,
- uri: '125000/es/5.m4f',
- number: 5,
- presentationTime: 9.92
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/6.m4f',
- timeline: 0,
- uri: '125000/es/6.m4f',
- number: 6,
- presentationTime: 11.904
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/7.m4f',
- timeline: 0,
- uri: '125000/es/7.m4f',
- number: 7,
- presentationTime: 13.888
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/8.m4f',
- timeline: 0,
- uri: '125000/es/8.m4f',
- number: 8,
- presentationTime: 15.872
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/9.m4f',
- timeline: 0,
- uri: '125000/es/9.m4f',
- number: 9,
- presentationTime: 17.856
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/10.m4f',
- timeline: 0,
- uri: '125000/es/10.m4f',
- number: 10,
- presentationTime: 19.84
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/11.m4f',
- timeline: 0,
- uri: '125000/es/11.m4f',
- number: 11,
- presentationTime: 21.824
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/12.m4f',
- timeline: 0,
- uri: '125000/es/12.m4f',
- number: 12,
- presentationTime: 23.808
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/13.m4f',
- timeline: 0,
- uri: '125000/es/13.m4f',
- number: 13,
- presentationTime: 25.792
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/14.m4f',
- timeline: 0,
- uri: '125000/es/14.m4f',
- number: 14,
- presentationTime: 27.776
- }, {
- duration: 0.240000000000002,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/15.m4f',
- timeline: 0,
- uri: '125000/es/15.m4f',
- number: 15,
- presentationTime: 29.76
- }]
- }, {
- attributes: {
- NOW,
- baseUrl: 'https://www.example.com/base',
- duration: 1.984,
- lang: 'es',
- height: 545,
- id: '125000',
- mediaPresentationDuration: 30,
- mimeType: 'video/mp4',
- periodStart: 0,
- role: {
- value: 'main'
- },
- segmentAlignment: 'true',
- sourceDuration: 30,
- type: 'static',
- startWithSAP: '1',
- clientOffset: 0,
- initialization: {
- sourceURL: '$RepresentationID$/es/init.m4f'
- },
- media: '$RepresentationID$/es/$Number$.m4f',
- startNumber: 0,
- timescale: 48000
- },
- segments: [{
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/0.m4f',
- timeline: 0,
- uri: '125000/es/0.m4f',
- number: 0,
- presentationTime: 0
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/1.m4f',
- timeline: 0,
- uri: '125000/es/1.m4f',
- number: 1,
- presentationTime: 1.984
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/2.m4f',
- timeline: 0,
- uri: '125000/es/2.m4f',
- number: 2,
- presentationTime: 3.968
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/3.m4f',
- timeline: 0,
- uri: '125000/es/3.m4f',
- number: 3,
- presentationTime: 5.952
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/4.m4f',
- timeline: 0,
- uri: '125000/es/4.m4f',
- number: 4,
- presentationTime: 7.936
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/5.m4f',
- timeline: 0,
- uri: '125000/es/5.m4f',
- number: 5,
- presentationTime: 9.92
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/6.m4f',
- timeline: 0,
- uri: '125000/es/6.m4f',
- number: 6,
- presentationTime: 11.904
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/7.m4f',
- timeline: 0,
- uri: '125000/es/7.m4f',
- number: 7,
- presentationTime: 13.888
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/8.m4f',
- timeline: 0,
- uri: '125000/es/8.m4f',
- number: 8,
- presentationTime: 15.872
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/9.m4f',
- timeline: 0,
- uri: '125000/es/9.m4f',
- number: 9,
- presentationTime: 17.856
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/10.m4f',
- timeline: 0,
- uri: '125000/es/10.m4f',
- number: 10,
- presentationTime: 19.84
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/11.m4f',
- timeline: 0,
- uri: '125000/es/11.m4f',
- number: 11,
- presentationTime: 21.824
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/12.m4f',
- timeline: 0,
- uri: '125000/es/12.m4f',
- number: 12,
- presentationTime: 23.808
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/13.m4f',
- timeline: 0,
- uri: '125000/es/13.m4f',
- number: 13,
- presentationTime: 25.792
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/14.m4f',
- timeline: 0,
- uri: '125000/es/14.m4f',
- number: 14,
- presentationTime: 27.776
- }, {
- duration: 0.240000000000002,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/15.m4f',
- timeline: 0,
- uri: '125000/es/15.m4f',
- number: 15,
- presentationTime: 29.76
- }]
- }];
- assert.equal(actual.length, 2);
- assert.deepEqual(actual, expected);
- }
- );
- // Although the Spec states that if SegmentTemplate or SegmentList is present on one
- // level of the hierarchy the other one shall not be present on any lower level, this
- // test would still handle the case if both are present in the hierarchy and would
- // prevent throwing errors.
- QUnit.test('Test to check use of either Segment Template or Segment List when both are' +
- ' present in the hierarchy', function(assert) {
- const NOW = Date.now();
- const actual = toPlaylists(inheritAttributes(stringToMpdXml(`
- <MPD mediaPresentationDuration= "PT30S" >
- <BaseURL>https://www.example.com/base</BaseURL>
- <Period>
- <AdaptationSet
- mimeType= "video/mp4"
- segmentAlignment= "true"
- startWithSAP= "1"
- lang= "es" >
- <Role value= "main" ></Role>
- <SegmentTemplate
- duration= "95232"
- initialization= "$RepresentationID$/es/init.m4f"
- media= "$RepresentationID$/es/$Number$.m4f"
- startNumber= "0"
- timescale= "48000" >
- </SegmentTemplate>
- <Representation
- mimeType= "video/mp6"
- bandwidth= "5000000"
- codecs= "avc1.64001e"
- height= "404"
- id= "125000"
- width= "720" >
- <SegmentList timescale= "1000" duration= "1000" >
- <RepresentationIndex sourceURL= "representation-index-low" />
- <SegmentURL media= "low/segment-1.ts" />
- <SegmentURL media= "low/segment-2.ts" />
- <SegmentURL media= "low/segment-3.ts" />
- <SegmentURL media= "low/segment-4.ts" />
- <SegmentURL media= "low/segment-5.ts" />
- <SegmentURL media= "low/segment-6.ts" />
- </SegmentList>
- </Representation>
- </AdaptationSet>
- </Period>
- </MPD>
- `), { NOW }).representationInfo);
- const expected = [{
- attributes: {
- NOW,
- clientOffset: 0,
- initialization: {
- sourceURL: '$RepresentationID$/es/init.m4f'
- },
- media: '$RepresentationID$/es/$Number$.m4f',
- bandwidth: 5000000,
- baseUrl: 'https://www.example.com/base',
- duration: 1.984,
- codecs: 'avc1.64001e',
- height: 404,
- id: '125000',
- lang: 'es',
- mediaPresentationDuration: 30,
- mimeType: 'video/mp6',
- periodStart: 0,
- role: {
- value: 'main'
- },
- segmentAlignment: 'true',
- sourceDuration: 30,
- type: 'static',
- width: 720,
- startWithSAP: '1',
- startNumber: 0,
- timescale: 48000
- },
- segments: [{
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/0.m4f',
- timeline: 0,
- uri: '125000/es/0.m4f',
- number: 0,
- presentationTime: 0
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/1.m4f',
- timeline: 0,
- uri: '125000/es/1.m4f',
- number: 1,
- presentationTime: 1.984
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/2.m4f',
- timeline: 0,
- uri: '125000/es/2.m4f',
- number: 2,
- presentationTime: 3.968
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/3.m4f',
- timeline: 0,
- uri: '125000/es/3.m4f',
- number: 3,
- presentationTime: 5.952
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/4.m4f',
- timeline: 0,
- uri: '125000/es/4.m4f',
- number: 4,
- presentationTime: 7.936
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/5.m4f',
- timeline: 0,
- uri: '125000/es/5.m4f',
- number: 5,
- presentationTime: 9.92
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/6.m4f',
- timeline: 0,
- uri: '125000/es/6.m4f',
- number: 6,
- presentationTime: 11.904
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/7.m4f',
- timeline: 0,
- uri: '125000/es/7.m4f',
- number: 7,
- presentationTime: 13.888
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/8.m4f',
- timeline: 0,
- uri: '125000/es/8.m4f',
- number: 8,
- presentationTime: 15.872
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/9.m4f',
- timeline: 0,
- uri: '125000/es/9.m4f',
- number: 9,
- presentationTime: 17.856
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/10.m4f',
- timeline: 0,
- uri: '125000/es/10.m4f',
- number: 10,
- presentationTime: 19.84
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/11.m4f',
- timeline: 0,
- uri: '125000/es/11.m4f',
- number: 11,
- presentationTime: 21.824
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/12.m4f',
- timeline: 0,
- uri: '125000/es/12.m4f',
- number: 12,
- presentationTime: 23.808
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/13.m4f',
- timeline: 0,
- uri: '125000/es/13.m4f',
- number: 13,
- presentationTime: 25.792
- }, {
- duration: 1.984,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/14.m4f',
- timeline: 0,
- uri: '125000/es/14.m4f',
- number: 14,
- presentationTime: 27.776
- }, {
- duration: 0.240000000000002,
- map: {
- resolvedUri: 'https://www.example.com/125000/es/init.m4f',
- uri: '125000/es/init.m4f'
- },
- resolvedUri: 'https://www.example.com/125000/es/15.m4f',
- timeline: 0,
- uri: '125000/es/15.m4f',
- number: 15,
- presentationTime: 29.76
- }]
- }];
- assert.equal(actual.length, 1);
- assert.deepEqual(actual, expected);
- });
- QUnit.test('keySystem info for representation - lowercase UUIDs', function(assert) {
- const NOW = Date.now();
- const widevinePsshB64 = 'AAAANHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABQIARIQCHJ4bvnnRl+jok5bDvj6RQ==';
- const playreadyPsshB64 = 'AAAB5HBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAAcTEAQAAAQABALoBPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgBiAG4AaAB5AEMATwBmADUAWAAwAGEAagBvAGsANQBiAEQAdgBqADYAUgBRAD0APQA8AC8ASwBJAEQAPgA8AC8ARABBAFQAQQA+ADwALwBXAFIATQBIAEUAQQBEAEUAUgA+AA==';
- const widevinePsshBytes = decodeB64ToUint8Array(widevinePsshB64);
- const playreadyPsshBytes = decodeB64ToUint8Array(playreadyPsshB64);
- // Content protection info from dash.js demo
- const actual = inheritAttributes(stringToMpdXml(`
- <MPD mediaPresentationDuration="PT30S" xmlns:cenc="urn:mpeg:cenc:2013">
- <BaseURL>https://www.example.com/base/</BaseURL>
- <Period>
- <AdaptationSet mimeType="video/mp4" >
- <ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" cenc:default_KID="0872786e-f9e7-465f-a3a2-4e5b0ef8fa45" />
- <ContentProtection value="MSPR 2.0" schemeIdUri="urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95">
- <cenc:pssh>AAAB5HBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAAcTEAQAAAQABALoBPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgBiAG4AaAB5AEMATwBmADUAWAAwAGEAagBvAGsANQBiAEQAdgBqADYAUgBRAD0APQA8AC8ASwBJAEQAPgA8AC8ARABBAFQAQQA+ADwALwBXAFIATQBIAEUAQQBEAEUAUgA+AA==</cenc:pssh>
- <pro xmlns="urn:microsoft:playready">xAEAAAEAAQC6ATwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4AYgBuAGgAeQBDAE8AZgA1AFgAMABhAGoAbwBrADUAYgBEAHYAagA2AFIAUQA9AD0APAAvAEsASQBEAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA=</pro>
- </ContentProtection>
- <ContentProtection value="Widevine" schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
- <cenc:pssh>AAAANHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABQIARIQCHJ4bvnnRl+jok5bDvj6RQ==</cenc:pssh>
- </ContentProtection>
- <Role value="main"></Role>
- <SegmentTemplate></SegmentTemplate>
- <Representation
- bandwidth="5000000"
- codecs="avc1.64001e"
- height="404"
- id="test"
- width="720">
- </Representation>
- </AdaptationSet>
- </Period>
- </MPD>
- `), { NOW });
- // inconsistent quoting because of quote-props
- const expected = {
- eventStream: [],
- locations: undefined,
- representationInfo: [{
- attributes: {
- 'bandwidth': 5000000,
- 'baseUrl': 'https://www.example.com/base/',
- 'codecs': 'avc1.64001e',
- 'contentProtection': {
- 'com.microsoft.playready': {
- attributes: {
- schemeIdUri: 'urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95',
- value: 'MSPR 2.0'
- },
- pssh: playreadyPsshBytes
- },
- 'com.widevine.alpha': {
- attributes: {
- schemeIdUri: 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed',
- value: 'Widevine'
- },
- pssh: widevinePsshBytes
- }
- },
- 'height': 404,
- 'id': 'test',
- 'mediaPresentationDuration': 30,
- 'mimeType': 'video/mp4',
- 'periodStart': 0,
- 'role': {
- value: 'main'
- },
- 'sourceDuration': 30,
- 'type': 'static',
- 'width': 720,
- NOW,
- 'clientOffset': 0,
- 'xmlns:cenc': 'urn:mpeg:cenc:2013'
- },
- segmentInfo: {
- template: {}
- }
- }]
- };
- assert.equal(actual.representationInfo.length, 1);
- assert.deepEqual(actual, expected);
- });
- QUnit.test('keySystem info for representation - uppercase UUIDs', function(assert) {
- const NOW = Date.now();
- const widevinePsshB64 = 'AAAANHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABQIARIQCHJ4bvnnRl+jok5bDvj6RQ==';
- const playreadyPsshB64 = 'AAAB5HBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAAcTEAQAAAQABALoBPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgBiAG4AaAB5AEMATwBmADUAWAAwAGEAagBvAGsANQBiAEQAdgBqADYAUgBRAD0APQA8AC8ASwBJAEQAPgA8AC8ARABBAFQAQQA+ADwALwBXAFIATQBIAEUAQQBEAEUAUgA+AA==';
- const widevinePsshBytes = decodeB64ToUint8Array(widevinePsshB64);
- const playreadyPsshBytes = decodeB64ToUint8Array(playreadyPsshB64);
- // Content protection info from dash.js demo
- const actual = inheritAttributes(stringToMpdXml(`
- <MPD mediaPresentationDuration="PT30S" xmlns:cenc="urn:mpeg:cenc:2013">
- <BaseURL>https://www.example.com/base/</BaseURL>
- <Period>
- <AdaptationSet mimeType="video/mp4" >
- <ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" cenc:default_KID="0872786E-F9E7-465F-A3A2-4E5B0EF8FA45" />
- <ContentProtection value="MSPR 2.0" schemeIdUri="urn:uuid:9A04F079-9840-4286-AB92-E65BE0885F95">
- <cenc:pssh>AAAB5HBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAAcTEAQAAAQABALoBPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgBiAG4AaAB5AEMATwBmADUAWAAwAGEAagBvAGsANQBiAEQAdgBqADYAUgBRAD0APQA8AC8ASwBJAEQAPgA8AC8ARABBAFQAQQA+ADwALwBXAFIATQBIAEUAQQBEAEUAUgA+AA==</cenc:pssh>
- <pro xmlns="urn:microsoft:playready">xAEAAAEAAQC6ATwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4AYgBuAGgAeQBDAE8AZgA1AFgAMABhAGoAbwBrADUAYgBEAHYAagA2AFIAUQA9AD0APAAvAEsASQBEAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA=</pro>
- </ContentProtection>
- <ContentProtection value="Widevine" schemeIdUri="urn:uuid:EDEF8BA9-79D6-4ACE-A3C8-27DCD51D21ED">
- <cenc:pssh>AAAANHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABQIARIQCHJ4bvnnRl+jok5bDvj6RQ==</cenc:pssh>
- </ContentProtection>
- <Role value="main"></Role>
- <SegmentTemplate></SegmentTemplate>
- <Representation
- bandwidth="5000000"
- codecs="avc1.64001e"
- height="404"
- id="test"
- width="720">
- </Representation>
- </AdaptationSet>
- </Period>
- </MPD>
- `), { NOW });
- // inconsistent quoting because of quote-props
- const expected = {
- eventStream: [],
- locations: undefined,
- representationInfo: [{
- attributes: {
- 'bandwidth': 5000000,
- 'baseUrl': 'https://www.example.com/base/',
- 'codecs': 'avc1.64001e',
- 'contentProtection': {
- 'com.microsoft.playready': {
- attributes: {
- schemeIdUri: 'urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95',
- value: 'MSPR 2.0'
- },
- pssh: playreadyPsshBytes
- },
- 'com.widevine.alpha': {
- attributes: {
- schemeIdUri: 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed',
- value: 'Widevine'
- },
- pssh: widevinePsshBytes
- }
- },
- 'height': 404,
- 'id': 'test',
- 'mediaPresentationDuration': 30,
- 'mimeType': 'video/mp4',
- 'periodStart': 0,
- 'role': {
- value: 'main'
- },
- 'sourceDuration': 30,
- 'type': 'static',
- 'width': 720,
- NOW,
- 'clientOffset': 0,
- 'xmlns:cenc': 'urn:mpeg:cenc:2013'
- },
- segmentInfo: {
- template: {}
- }
- }]
- };
- assert.equal(actual.representationInfo.length, 1);
- assert.deepEqual(actual, expected);
- });
- QUnit.test('gets EventStream data from toEventStream', function(assert) {
- const mpd = stringToMpdXml(`
- <MPD mediaPresentationDuration="PT30S" xmlns:cenc="urn:mpeg:cenc:2013">
- <Period id="dai_pod-0001065804-ad-1" start="PT17738H17M14.156S" duration="PT9.977S">
- <BaseURL>https://www.example.com/base/</BaseURL>
- <SegmentTemplate media="$RepresentationID$/$Number$.mp4" initialization="$RepresentationID$/init.mp4"/>
- <EventStream schemeIdUri="urn:google:dai:2018" timescale="1000" contentEncoding="foo" presentationTimeOffset="1">
- <Event presentationTime="100" duration="0" id="0" messageData="foo"/>
- <Event presentationTime="900" duration="0" id="5" messageData="bar"/>
- <Event presentationTime="1900" duration="0" id="6" messageData="foo_bar"/>
- </EventStream>
- </Period>
- </MPD>`);
- const expected = [
- {
- end: 2.1,
- id: '0',
- messageData: 'foo',
- schemeIdUri: 'urn:google:dai:2018',
- start: 2.1,
- value: undefined,
- contentEncoding: 'foo',
- presentationTimeOffset: 1
- },
- {
- end: 2.9,
- id: '5',
- messageData: 'bar',
- schemeIdUri: 'urn:google:dai:2018',
- start: 2.9,
- value: undefined,
- contentEncoding: 'foo',
- presentationTimeOffset: 1
- },
- {
- end: 3.9,
- id: '6',
- messageData: 'foo_bar',
- schemeIdUri: 'urn:google:dai:2018',
- start: 3.9,
- value: undefined,
- contentEncoding: 'foo',
- presentationTimeOffset: 1
- }
- ];
- const firstPeriod = { node: findChildren(mpd, 'Period')[0], attributes: { start: 2 } };
- const eventStreams = toEventStream(firstPeriod);
- assert.deepEqual(eventStreams, expected, 'toEventStream returns the expected object');
- });
- QUnit.test('can get EventStream data from toEventStream with no schemeIdUri', function(assert) {
- const mpd = stringToMpdXml(`
- <MPD mediaPresentationDuration="PT30S" xmlns:cenc="urn:mpeg:cenc:2013">
- <Period id="dai_pod-0001065804-ad-1" start="PT17738H17M14.156S" duration="PT9.977S">
- <BaseURL>https://www.example.com/base/</BaseURL>
- <SegmentTemplate media="$RepresentationID$/$Number$.mp4" initialization="$RepresentationID$/init.mp4"/>
- <EventStream timescale="1000">
- <Event presentationTime="100" duration="0" id="0" messageData="foo"/>
- <Event presentationTime="900" duration="0" id="5" messageData="bar"/>
- <Event presentationTime="1900" duration="0" id="6" messageData="foo_bar"/>
- </EventStream>
- </Period>
- </MPD>`);
- const expected = [
- {
- end: 2.1,
- id: '0',
- messageData: 'foo',
- schemeIdUri: undefined,
- start: 2.1,
- value: undefined,
- contentEncoding: undefined,
- presentationTimeOffset: 0
- },
- {
- end: 2.9,
- id: '5',
- messageData: 'bar',
- schemeIdUri: undefined,
- start: 2.9,
- value: undefined,
- contentEncoding: undefined,
- presentationTimeOffset: 0
- },
- {
- end: 3.9,
- id: '6',
- messageData: 'foo_bar',
- schemeIdUri: undefined,
- start: 3.9,
- value: undefined,
- contentEncoding: undefined,
- presentationTimeOffset: 0
- }
- ];
- const firstPeriod = { node: findChildren(mpd, 'Period')[0], attributes: { start: 2} };
- const eventStreams = toEventStream(firstPeriod);
- assert.deepEqual(eventStreams, expected, 'toEventStream returns the expected object');
- });
- QUnit.test('gets eventStream from inheritAttributes', function(assert) {
- const mpd = stringToMpdXml(`
- <MPD mediaPresentationDuration="PT30S" xmlns:cenc="urn:mpeg:cenc:2013">
- <Period id="dai_pod-0001065804-ad-1" start="PT0H0M14.9S" duration="PT9.977S">
- <BaseURL>https://www.example.com/base/</BaseURL>
- <SegmentTemplate media="$RepresentationID$/$Number$.mp4" initialization="$RepresentationID$/init.mp4"/>
- <EventStream schemeIdUri="urn:google:dai:2018" timescale="1000" value="foo">
- <Event presentationTime="100" duration="0" id="0" messageData="foo"/>
- <Event presentationTime="1100" duration="0" id="5" messageData="bar"/>
- <Event presentationTime="2100" duration="0" id="6" messageData="foo_bar"/>
- </EventStream>
- </Period>
- </MPD>`);
- const expected = {
- eventStream: [
- {
- end: 15,
- id: '0',
- messageData: 'foo',
- schemeIdUri: 'urn:google:dai:2018',
- start: 15,
- value: 'foo',
- contentEncoding: undefined,
- presentationTimeOffset: 0
- },
- {
- end: 16,
- id: '5',
- messageData: 'bar',
- schemeIdUri: 'urn:google:dai:2018',
- start: 16,
- value: 'foo',
- contentEncoding: undefined,
- presentationTimeOffset: 0
- },
- {
- end: 17,
- id: '6',
- messageData: 'foo_bar',
- schemeIdUri: 'urn:google:dai:2018',
- start: 17,
- value: 'foo',
- contentEncoding: undefined,
- presentationTimeOffset: 0
- }
- ],
- locations: undefined,
- representationInfo: []
- };
- const eventStreams = inheritAttributes(mpd);
- assert.deepEqual(eventStreams, expected, 'inheritAttributes returns the expected object');
- });
- QUnit.test('can get EventStream data from toEventStream with data in Event tags', function(assert) {
- const mpd = stringToMpdXml(`
- <MPD mediaPresentationDuration="PT30S" xmlns:cenc="urn:mpeg:cenc:2013">
- <Period id="dai_pod-0001065804-ad-1" start="PT17738H17M14.156S" duration="PT9.977S">
- <BaseURL>https://www.example.com/base/</BaseURL>
- <SegmentTemplate media="$RepresentationID$/$Number$.mp4" initialization="$RepresentationID$/init.mp4"/>
- <EventStream timescale="1000">
- <Event presentationTime="100" duration="0" id="0">foo</Event>
- <Event presentationTime="900" duration="0" id="5">bar</Event>
- <Event presentationTime="1900" duration="0" id="6">foo_bar</Event>
- </EventStream>
- </Period>
- </MPD>`);
- const expected = [
- {
- end: 2.1,
- id: '0',
- messageData: 'foo',
- schemeIdUri: undefined,
- start: 2.1,
- value: undefined,
- contentEncoding: undefined,
- presentationTimeOffset: 0
- },
- {
- end: 2.9,
- id: '5',
- messageData: 'bar',
- schemeIdUri: undefined,
- start: 2.9,
- value: undefined,
- contentEncoding: undefined,
- presentationTimeOffset: 0
- },
- {
- end: 3.9,
- id: '6',
- messageData: 'foo_bar',
- schemeIdUri: undefined,
- start: 3.9,
- value: undefined,
- contentEncoding: undefined,
- presentationTimeOffset: 0
- }
- ];
- const firstPeriod = { node: findChildren(mpd, 'Period')[0], attributes: { start: 2} };
- const eventStreams = toEventStream(firstPeriod);
- assert.deepEqual(eventStreams, expected, 'toEventStream returns the expected object');
- });
- QUnit.test('gets eventStream from inheritAttributes with data in Event tags', function(assert) {
- const mpd = stringToMpdXml(`
- <MPD mediaPresentationDuration="PT30S" xmlns:cenc="urn:mpeg:cenc:2013">
- <Period id="dai_pod-0001065804-ad-1" start="PT0H0M14.9S" duration="PT9.977S">
- <BaseURL>https://www.example.com/base/</BaseURL>
- <SegmentTemplate media="$RepresentationID$/$Number$.mp4" initialization="$RepresentationID$/init.mp4"/>
- <EventStream schemeIdUri="urn:google:dai:2018" timescale="1000" value="foo">
- <Event presentationTime="100" duration="0" id="0">foo</Event>
- <Event presentationTime="1100" duration="0" id="5">bar</Event>
- <Event presentationTime="2100" duration="0" id="6">foo_bar</Event>
- </EventStream>
- </Period>
- </MPD>`);
- const expected = {
- eventStream: [
- {
- end: 15,
- id: '0',
- messageData: 'foo',
- schemeIdUri: 'urn:google:dai:2018',
- start: 15,
- value: 'foo',
- contentEncoding: undefined,
- presentationTimeOffset: 0
- },
- {
- end: 16,
- id: '5',
- messageData: 'bar',
- schemeIdUri: 'urn:google:dai:2018',
- start: 16,
- value: 'foo',
- contentEncoding: undefined,
- presentationTimeOffset: 0
- },
- {
- end: 17,
- id: '6',
- messageData: 'foo_bar',
- schemeIdUri: 'urn:google:dai:2018',
- start: 17,
- value: 'foo',
- contentEncoding: undefined,
- presentationTimeOffset: 0
- }
- ],
- locations: undefined,
- representationInfo: []
- };
- const eventStreams = inheritAttributes(mpd);
- assert.deepEqual(eventStreams, expected, 'inheritAttributes returns the expected object');
- });
|