segmentList.test.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. import QUnit from 'qunit';
  2. import {
  3. segmentsFromList
  4. } from '../../src/segment/segmentList';
  5. import errors from '../../src/errors';
  6. QUnit.module('segmentList - segmentsFromList');
  7. QUnit.test('uses segmentTimeline to set segments', function(assert) {
  8. const inputAttributes = {
  9. segmentUrls: [{
  10. media: '1.fmp4'
  11. }, {
  12. media: '2.fmp4'
  13. }, {
  14. media: '3.fmp4'
  15. }, {
  16. media: '4.fmp4'
  17. }, {
  18. media: '5.fmp4'
  19. }],
  20. initialization: { sourceURL: 'init.fmp4' },
  21. periodIndex: 0,
  22. periodStart: 0,
  23. startNumber: 1,
  24. baseUrl: 'http://example.com/',
  25. type: 'static'
  26. };
  27. const inputTimeline = [{
  28. t: 1000,
  29. d: 1000,
  30. r: 4
  31. }];
  32. assert.deepEqual(segmentsFromList(inputAttributes, inputTimeline), [{
  33. duration: 1000,
  34. map: {
  35. resolvedUri: 'http://example.com/init.fmp4',
  36. uri: 'init.fmp4'
  37. },
  38. resolvedUri: 'http://example.com/1.fmp4',
  39. timeline: 0,
  40. presentationTime: 1000,
  41. uri: '1.fmp4',
  42. number: 1
  43. }, {
  44. duration: 1000,
  45. map: {
  46. resolvedUri: 'http://example.com/init.fmp4',
  47. uri: 'init.fmp4'
  48. },
  49. resolvedUri: 'http://example.com/2.fmp4',
  50. timeline: 0,
  51. presentationTime: 2000,
  52. uri: '2.fmp4',
  53. number: 2
  54. }, {
  55. duration: 1000,
  56. map: {
  57. resolvedUri: 'http://example.com/init.fmp4',
  58. uri: 'init.fmp4'
  59. },
  60. resolvedUri: 'http://example.com/3.fmp4',
  61. timeline: 0,
  62. presentationTime: 3000,
  63. uri: '3.fmp4',
  64. number: 3
  65. }, {
  66. duration: 1000,
  67. map: {
  68. resolvedUri: 'http://example.com/init.fmp4',
  69. uri: 'init.fmp4'
  70. },
  71. resolvedUri: 'http://example.com/4.fmp4',
  72. timeline: 0,
  73. presentationTime: 4000,
  74. uri: '4.fmp4',
  75. number: 4
  76. }, {
  77. duration: 1000,
  78. map: {
  79. resolvedUri: 'http://example.com/init.fmp4',
  80. uri: 'init.fmp4'
  81. },
  82. resolvedUri: 'http://example.com/5.fmp4',
  83. timeline: 0,
  84. presentationTime: 5000,
  85. uri: '5.fmp4',
  86. number: 5
  87. }]);
  88. });
  89. QUnit.test(
  90. 'truncates if segmentTimeline does not apply for all segments',
  91. function(assert) {
  92. const inputAttributes = {
  93. segmentUrls: [{
  94. media: '1.fmp4'
  95. }, {
  96. media: '2.fmp4'
  97. }, {
  98. media: '3.fmp4'
  99. }, {
  100. media: '4.fmp4'
  101. }, {
  102. media: '5.fmp4'
  103. }],
  104. initialization: { sourceURL: 'init.fmp4' },
  105. periodIndex: 0,
  106. periodStart: 0,
  107. startNumber: 1,
  108. baseUrl: 'http://example.com/',
  109. type: 'static'
  110. };
  111. const inputTimeline = [{
  112. t: 1000,
  113. d: 1000,
  114. r: 1
  115. }];
  116. assert.deepEqual(segmentsFromList(inputAttributes, inputTimeline), [{
  117. duration: 1000,
  118. map: {
  119. resolvedUri: 'http://example.com/init.fmp4',
  120. uri: 'init.fmp4'
  121. },
  122. resolvedUri: 'http://example.com/1.fmp4',
  123. timeline: 0,
  124. presentationTime: 1000,
  125. uri: '1.fmp4',
  126. number: 1
  127. }, {
  128. duration: 1000,
  129. map: {
  130. resolvedUri: 'http://example.com/init.fmp4',
  131. uri: 'init.fmp4'
  132. },
  133. resolvedUri: 'http://example.com/2.fmp4',
  134. timeline: 0,
  135. presentationTime: 2000,
  136. uri: '2.fmp4',
  137. number: 2
  138. }]);
  139. }
  140. );
  141. QUnit.test(
  142. 'if segment timeline is too long does not add extra blank segments',
  143. function(assert) {
  144. const inputAttributes = {
  145. segmentUrls: [{
  146. media: '1.fmp4'
  147. }, {
  148. media: '2.fmp4'
  149. }, {
  150. media: '3.fmp4'
  151. }, {
  152. media: '4.fmp4'
  153. }, {
  154. media: '5.fmp4'
  155. }],
  156. initialization: { sourceURL: 'init.fmp4' },
  157. periodIndex: 0,
  158. periodStart: 0,
  159. startNumber: 1,
  160. baseUrl: 'http://example.com/',
  161. type: 'static'
  162. };
  163. const inputTimeline = [{
  164. t: 1000,
  165. d: 1000,
  166. r: 10
  167. }];
  168. assert.deepEqual(segmentsFromList(inputAttributes, inputTimeline), [{
  169. duration: 1000,
  170. map: {
  171. resolvedUri: 'http://example.com/init.fmp4',
  172. uri: 'init.fmp4'
  173. },
  174. resolvedUri: 'http://example.com/1.fmp4',
  175. timeline: 0,
  176. presentationTime: 1000,
  177. uri: '1.fmp4',
  178. number: 1
  179. }, {
  180. duration: 1000,
  181. map: {
  182. resolvedUri: 'http://example.com/init.fmp4',
  183. uri: 'init.fmp4'
  184. },
  185. resolvedUri: 'http://example.com/2.fmp4',
  186. timeline: 0,
  187. presentationTime: 2000,
  188. uri: '2.fmp4',
  189. number: 2
  190. }, {
  191. duration: 1000,
  192. map: {
  193. resolvedUri: 'http://example.com/init.fmp4',
  194. uri: 'init.fmp4'
  195. },
  196. resolvedUri: 'http://example.com/3.fmp4',
  197. timeline: 0,
  198. presentationTime: 3000,
  199. uri: '3.fmp4',
  200. number: 3
  201. }, {
  202. duration: 1000,
  203. map: {
  204. resolvedUri: 'http://example.com/init.fmp4',
  205. uri: 'init.fmp4'
  206. },
  207. resolvedUri: 'http://example.com/4.fmp4',
  208. timeline: 0,
  209. presentationTime: 4000,
  210. uri: '4.fmp4',
  211. number: 4
  212. }, {
  213. duration: 1000,
  214. map: {
  215. resolvedUri: 'http://example.com/init.fmp4',
  216. uri: 'init.fmp4'
  217. },
  218. resolvedUri: 'http://example.com/5.fmp4',
  219. timeline: 0,
  220. presentationTime: 5000,
  221. uri: '5.fmp4',
  222. number: 5
  223. }]);
  224. }
  225. );
  226. QUnit.test('uses duration to set segments', function(assert) {
  227. const inputAttributes = {
  228. segmentUrls: [{
  229. media: '1.fmp4'
  230. }, {
  231. media: '2.fmp4'
  232. }, {
  233. media: '3.fmp4'
  234. }, {
  235. media: '4.fmp4'
  236. }, {
  237. media: '5.fmp4'
  238. }],
  239. initialization: { sourceURL: 'init.fmp4' },
  240. duration: 10,
  241. periodIndex: 0,
  242. periodStart: 0,
  243. startNumber: 1,
  244. sourceDuration: 50,
  245. baseUrl: 'http://example.com/',
  246. type: 'static'
  247. };
  248. assert.deepEqual(segmentsFromList(inputAttributes), [{
  249. duration: 10,
  250. map: {
  251. resolvedUri: 'http://example.com/init.fmp4',
  252. uri: 'init.fmp4'
  253. },
  254. resolvedUri: 'http://example.com/1.fmp4',
  255. timeline: 0,
  256. presentationTime: 0,
  257. uri: '1.fmp4',
  258. number: 1
  259. }, {
  260. duration: 10,
  261. map: {
  262. resolvedUri: 'http://example.com/init.fmp4',
  263. uri: 'init.fmp4'
  264. },
  265. resolvedUri: 'http://example.com/2.fmp4',
  266. timeline: 0,
  267. presentationTime: 10,
  268. uri: '2.fmp4',
  269. number: 2
  270. }, {
  271. duration: 10,
  272. map: {
  273. resolvedUri: 'http://example.com/init.fmp4',
  274. uri: 'init.fmp4'
  275. },
  276. resolvedUri: 'http://example.com/3.fmp4',
  277. timeline: 0,
  278. presentationTime: 20,
  279. uri: '3.fmp4',
  280. number: 3
  281. }, {
  282. duration: 10,
  283. map: {
  284. resolvedUri: 'http://example.com/init.fmp4',
  285. uri: 'init.fmp4'
  286. },
  287. resolvedUri: 'http://example.com/4.fmp4',
  288. timeline: 0,
  289. presentationTime: 30,
  290. uri: '4.fmp4',
  291. number: 4
  292. }, {
  293. duration: 10,
  294. map: {
  295. resolvedUri: 'http://example.com/init.fmp4',
  296. uri: 'init.fmp4'
  297. },
  298. resolvedUri: 'http://example.com/5.fmp4',
  299. timeline: 0,
  300. presentationTime: 40,
  301. uri: '5.fmp4',
  302. number: 5
  303. }]);
  304. });
  305. QUnit.test('uses timescale to set segment duration', function(assert) {
  306. const inputAttributes = {
  307. segmentUrls: [{
  308. media: '1.fmp4'
  309. }, {
  310. media: '2.fmp4'
  311. }, {
  312. media: '3.fmp4'
  313. }, {
  314. media: '4.fmp4'
  315. }, {
  316. media: '5.fmp4'
  317. }],
  318. initialization: { sourceURL: 'init.fmp4' },
  319. duration: 10,
  320. timescale: 2,
  321. periodIndex: 0,
  322. periodStart: 0,
  323. startNumber: 1,
  324. sourceDuration: 25,
  325. baseUrl: 'http://example.com/',
  326. type: 'static'
  327. };
  328. assert.deepEqual(segmentsFromList(inputAttributes), [{
  329. duration: 5,
  330. map: {
  331. resolvedUri: 'http://example.com/init.fmp4',
  332. uri: 'init.fmp4'
  333. },
  334. resolvedUri: 'http://example.com/1.fmp4',
  335. timeline: 0,
  336. presentationTime: 0,
  337. uri: '1.fmp4',
  338. number: 1
  339. }, {
  340. duration: 5,
  341. map: {
  342. resolvedUri: 'http://example.com/init.fmp4',
  343. uri: 'init.fmp4'
  344. },
  345. resolvedUri: 'http://example.com/2.fmp4',
  346. timeline: 0,
  347. presentationTime: 5,
  348. uri: '2.fmp4',
  349. number: 2
  350. }, {
  351. duration: 5,
  352. map: {
  353. resolvedUri: 'http://example.com/init.fmp4',
  354. uri: 'init.fmp4'
  355. },
  356. resolvedUri: 'http://example.com/3.fmp4',
  357. timeline: 0,
  358. presentationTime: 10,
  359. uri: '3.fmp4',
  360. number: 3
  361. }, {
  362. duration: 5,
  363. map: {
  364. resolvedUri: 'http://example.com/init.fmp4',
  365. uri: 'init.fmp4'
  366. },
  367. resolvedUri: 'http://example.com/4.fmp4',
  368. timeline: 0,
  369. presentationTime: 15,
  370. uri: '4.fmp4',
  371. number: 4
  372. }, {
  373. duration: 5,
  374. map: {
  375. resolvedUri: 'http://example.com/init.fmp4',
  376. uri: 'init.fmp4'
  377. },
  378. resolvedUri: 'http://example.com/5.fmp4',
  379. timeline: 0,
  380. presentationTime: 20,
  381. uri: '5.fmp4',
  382. number: 5
  383. }]);
  384. });
  385. QUnit.test('timescale sets duration of last segment correctly', function(assert) {
  386. const inputAttributes = {
  387. segmentUrls: [{
  388. media: '1.fmp4'
  389. }, {
  390. media: '2.fmp4'
  391. }],
  392. initialization: { sourceURL: 'init.fmp4' },
  393. duration: 10,
  394. timescale: 1,
  395. periodIndex: 0,
  396. periodStart: 0,
  397. startNumber: 1,
  398. sourceDuration: 15,
  399. baseUrl: 'http://example.com/',
  400. type: 'static'
  401. };
  402. assert.deepEqual(segmentsFromList(inputAttributes), [{
  403. duration: 10,
  404. map: {
  405. resolvedUri: 'http://example.com/init.fmp4',
  406. uri: 'init.fmp4'
  407. },
  408. resolvedUri: 'http://example.com/1.fmp4',
  409. timeline: 0,
  410. presentationTime: 0,
  411. uri: '1.fmp4',
  412. number: 1
  413. }, {
  414. duration: 5,
  415. map: {
  416. resolvedUri: 'http://example.com/init.fmp4',
  417. uri: 'init.fmp4'
  418. },
  419. resolvedUri: 'http://example.com/2.fmp4',
  420. timeline: 0,
  421. presentationTime: 10,
  422. uri: '2.fmp4',
  423. number: 2
  424. }]);
  425. });
  426. QUnit.test('segmentUrl translates ranges correctly', function(assert) {
  427. const inputAttributes = {
  428. segmentUrls: [{
  429. media: '1.fmp4',
  430. mediaRange: '0-200'
  431. }, {
  432. media: '1.fmp4',
  433. mediaRange: '201-400'
  434. }],
  435. initialization: { sourceURL: 'init.fmp4' },
  436. duration: 10,
  437. timescale: 1,
  438. periodIndex: 0,
  439. periodStart: 0,
  440. startNumber: 1,
  441. sourceDuration: 20,
  442. baseUrl: 'http://example.com/',
  443. type: 'static'
  444. };
  445. assert.deepEqual(segmentsFromList(inputAttributes), [{
  446. duration: 10,
  447. map: {
  448. resolvedUri: 'http://example.com/init.fmp4',
  449. uri: 'init.fmp4'
  450. },
  451. byterange: {
  452. length: 201,
  453. offset: 0
  454. },
  455. resolvedUri: 'http://example.com/1.fmp4',
  456. timeline: 0,
  457. presentationTime: 0,
  458. uri: '1.fmp4',
  459. number: 1
  460. }, {
  461. duration: 10,
  462. byterange: {
  463. length: 200,
  464. offset: 201
  465. },
  466. map: {
  467. resolvedUri: 'http://example.com/init.fmp4',
  468. uri: 'init.fmp4'
  469. },
  470. resolvedUri: 'http://example.com/1.fmp4',
  471. timeline: 0,
  472. presentationTime: 10,
  473. uri: '1.fmp4',
  474. number: 2
  475. }]);
  476. });
  477. QUnit.test(
  478. 'throws error if more than 1 segment and no duration or timeline',
  479. function(assert) {
  480. const inputAttributes = {
  481. segmentUrls: [{
  482. media: '1.fmp4'
  483. }, {
  484. media: '2.fmp4'
  485. }],
  486. duration: 10,
  487. initialization: { sourceURL: 'init.fmp4' },
  488. timescale: 1,
  489. periodIndex: 0,
  490. startNumber: 1,
  491. sourceDuration: 20,
  492. baseUrl: 'http://example.com/',
  493. type: 'static'
  494. };
  495. const inputTimeline = [{
  496. t: 1000,
  497. d: 1000,
  498. r: 4
  499. }];
  500. assert.throws(
  501. () => segmentsFromList(inputAttributes, inputTimeline),
  502. new Error(errors.SEGMENT_TIME_UNSPECIFIED)
  503. );
  504. }
  505. );
  506. QUnit.test('throws error if timeline and duration are both defined', function(assert) {
  507. const inputAttributes = {
  508. segmentUrls: [{
  509. media: '1.fmp4'
  510. }, {
  511. media: '2.fmp4'
  512. }],
  513. initialization: { sourceURL: 'init.fmp4' },
  514. timescale: 1,
  515. periodIndex: 0,
  516. startNumber: 1,
  517. sourceDuration: 20,
  518. baseUrl: 'http://example.com/',
  519. type: 'static'
  520. };
  521. assert.throws(
  522. () => segmentsFromList(inputAttributes),
  523. new Error(errors.SEGMENT_TIME_UNSPECIFIED)
  524. );
  525. });
  526. QUnit.test('translates ranges in <Initialization> node', function(assert) {
  527. const inputAttributes = {
  528. segmentUrls: [{
  529. media: '1.fmp4'
  530. }, {
  531. media: '1.fmp4'
  532. }],
  533. initialization: { sourceURL: 'init.fmp4', range: '121-125' },
  534. duration: 10,
  535. timescale: 1,
  536. periodIndex: 0,
  537. periodStart: 0,
  538. startNumber: 1,
  539. sourceDuration: 20,
  540. baseUrl: 'http://example.com/',
  541. type: 'static'
  542. };
  543. assert.deepEqual(segmentsFromList(inputAttributes), [{
  544. duration: 10,
  545. map: {
  546. resolvedUri: 'http://example.com/init.fmp4',
  547. uri: 'init.fmp4',
  548. byterange: {
  549. length: 5,
  550. offset: 121
  551. }
  552. },
  553. resolvedUri: 'http://example.com/1.fmp4',
  554. timeline: 0,
  555. presentationTime: 0,
  556. uri: '1.fmp4',
  557. number: 1
  558. }, {
  559. duration: 10,
  560. map: {
  561. resolvedUri: 'http://example.com/init.fmp4',
  562. uri: 'init.fmp4',
  563. byterange: {
  564. length: 5,
  565. offset: 121
  566. }
  567. },
  568. resolvedUri: 'http://example.com/1.fmp4',
  569. timeline: 0,
  570. presentationTime: 10,
  571. uri: '1.fmp4',
  572. number: 2
  573. }]);
  574. });