Browse Source

Use handelbars to make templates for the manifest files. Add tests for media_sequence, playlist_type, and target_duration.

pull/80/head
Lee Whitaker 12 years ago
parent
commit
81c90a70d8
  1. 2595
      libs/handlebars/handlebars-v1.1.2.js
  2. 258
      test/m3u8_test.js
  3. 15
      test/manifest/playlist_media_sequence_template.js
  4. 14
      test/manifest/playlist_target_duration_template.js
  5. 17
      test/manifest/playlist_type_template.js
  6. 6
      test/video-js-hls.html

2595
libs/handlebars/handlebars-v1.1.2.js
File diff suppressed because it is too large
View File

258
test/m3u8_test.js

@ -87,6 +87,264 @@
equal(data.hasEndTag, true, 'should have ENDLIST tag'); equal(data.hasEndTag, true, 'should have ENDLIST tag');
}); });
/*3.4.7. EXT-X-PLAYLIST-TYPE
The EXT-X-PLAYLIST-TYPE tag provides mutability information about the
Playlist file. It applies to the entire Playlist file. It is
OPTIONAL. Its format is:
#EXT-X-PLAYLIST-TYPE:<EVENT|VOD>
Section 6.2.1 defines the implications of the EXT-X-PLAYLIST-TYPE
tag.
The EXT-X-PLAYLIST-TYPE tag MUST NOT appear in a Master Playlist.
*/
test('should have parsed VOD playlist type', function() {
var
playlistTemplate = Handlebars.compile(window.playlist_type_template),
testData = {playlistType: 'VOD'},
playlistData = playlistTemplate(testData),
data = m3u8parser.parse(playlistData);
notEqual(data, null, 'data is not NULL');
equal(data.invalidReasons.length, 0, 'data has 0 invalid reasons');
equal(data.playlistType, "VOD", 'acceptable PLAYLIST TYPE');
});
test('should have parsed EVENT playlist type', function() {
var
playlistTemplate = Handlebars.compile(window.playlist_type_template),
testData = {playlistType: 'EVENT'},
playlistData = playlistTemplate(testData),
data = m3u8parser.parse(playlistData);
notEqual(data, null, 'data is not NULL');
equal(data.invalidReasons.length, 0, 'data has 0 invalid reasons');
equal(data.playlistType, "EVENT", 'acceptable PLAYLIST TYPE');
});
test('should have assumed VOD playlist type if not defined', function() {
var
playlistTemplate = Handlebars.compile(window.playlist_type_template),
testData = {},
playlistData = playlistTemplate(testData),
data = m3u8parser.parse(playlistData);
notEqual(data, null, 'data is not NULL');
equal(data.invalidReasons.length, 0, 'data has 0 invalid reasons');
equal(data.playlistType, "VOD", 'acceptable PLAYLIST TYPE');
});
test('should have an invalid reason due to invalid playlist type', function() {
var
playlistTemplate = Handlebars.compile(window.playlist_type_template),
testData = {playlistType: 'baklsdhfajsdf'},
playlistData = playlistTemplate(testData),
data = m3u8parser.parse(playlistData);
notEqual(data, null, 'data is not NULL');
equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
equal(data.invalidReasons[0], 'Invalid Playlist Type Value: baklsdhfajsdf');
});
test('should have an invalid reason due to invalid playlist type', function() {
var
playlistTemplate = Handlebars.compile(window.playlist_type_template),
testData = {playlistType: ''},
playlistData = playlistTemplate(testData),
data = m3u8parser.parse(playlistData);
notEqual(data, null, 'data is not NULL');
equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
equal(data.invalidReasons[0], 'Invalid Playlist Type Value: \'\'');
});
/*3.4.2. EXT-X-TARGETDURATION
The EXT-X-TARGETDURATION tag specifies the maximum media segment
duration. The EXTINF duration of each media segment in the Playlist
file, when rounded to the nearest integer, MUST be less than or equal
to the target duration. This tag MUST appear once in a Media
Playlist file. It applies to the entire Playlist file. Its format
is:
#EXT-X-TARGETDURATION:<s>
where s is a decimal-integer indicating the target duration in
seconds.
The EXT-X-TARGETDURATION tag MUST NOT appear in a Master Playlist.
*/
test('valid target duration', function() {
var
playlistTemplate = Handlebars.compile(window.playlist_target_duration_template),
testData = {targetDuration: '10'},
playlistData = playlistTemplate(testData),
data = m3u8parser.parse(playlistData);
notEqual(data, null, 'data is not NULL');
equal(data.targetDuration, 10, 'data has correct TARGET DURATION');
equal(data.invalidReasons.length, 0, 'data has 1 invalid reasons');
});
test('NaN target duration', function() {
var
playlistTemplate = Handlebars.compile(window.playlist_target_duration_template),
testData = {targetDuration: '10'},
playlistData = playlistTemplate(testData),
data = m3u8parser.parse(playlistData);
notEqual(data, null, 'data is not NULL');
equal(data.targetDuration, 10, 'data has correct TARGET DURATION');
equal(data.invalidReasons.length, 0, 'data has 1 invalid reasons');
testData = {targetDuration: 'string'};
playlistData = playlistTemplate(testData),
data = m3u8parser.parse(playlistData);
notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
equal(data.invalidReasons[0], 'Invalid Target Duration Value: string');
testData = {targetDuration: ''};
playlistData = playlistTemplate(testData),
data = m3u8parser.parse(playlistData);
notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
equal(data.invalidReasons[0], 'Invalid Target Duration Value: \'\'');
testData = {}
playlistData = playlistTemplate(testData),
notEqual(data, null, 'data is not NULL');
notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
equal(data.invalidReasons[0], 'Invalid Target Duration Value: '+ undefined);
});
test('target duration lower than segment', function() {
var
playlistTemplate = Handlebars.compile(window.playlist_target_duration_template),
testData = {targetDuration: '4'},
playlistData = playlistTemplate(testData),
data = m3u8parser.parse(playlistData);
notEqual(data, null, 'data is not NULL');
notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
equal(data.invalidReasons[0], 'Invalid Target Duration Value: 4 is lower than segments');
});
/*3.4.3. EXT-X-MEDIA-SEQUENCE
Each media segment in a Playlist has a unique integer sequence
number. The sequence number of a segment is equal to the sequence
number of the segment that preceded it plus one. The EXT-X-MEDIA-
SEQUENCE tag indicates the sequence number of the first segment that
appears in a Playlist file. Its format is:
#EXT-X-MEDIA-SEQUENCE:<number>
where number is a decimal-integer. The sequence number MUST NOT
decrease.
A Media Playlist file MUST NOT contain more than one EXT-X-MEDIA-
SEQUENCE tag. If the Media Playlist file does not contain an EXT-X-
MEDIA-SEQUENCE tag then the sequence number of the first segment in
the playlist SHALL be considered to be 0. A client MUST NOT assume
that segments with the same sequence number in different Media
Playlists contain matching content.
A media URI is not required to contain its sequence number.
*/
test('media sequence is valid in the playlist', function() {
var
playlistTemplate = Handlebars.compile(window.playlist_media_sequence_template),
testData = {mediaSequence: '0'},
playlistData = playlistTemplate(testData),
data = m3u8parser.parse(playlistData);
notEqual(data, null, 'data is not NULL');
notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
equal(data.invalidReasons.length, 0, 'data has 0 invalid reasons');
equal(data.mediaSequence, 0, 'MEDIA SEQUENCE is correct');
});
test('media sequence is encountered twice in the playlist', function() {
var
playlistTemplate = Handlebars.compile(window.playlist_media_sequence_template),
testData = {mediaSequence: '0', mediaSequence1: '1'},
playlistData = playlistTemplate(testData),
data = m3u8parser.parse(playlistData);
notEqual(data, null, 'data is not NULL');
notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
equal(data.invalidReasons.length, 0, 'data has 0 invalid reasons');
equal(data.mediaSequence, 0, 'MEDIA SEQUENCE tags after the first should be ignored');
});
test('media sequence is undefined in the playlist', function() {
var
playlistTemplate = Handlebars.compile(window.playlist_media_sequence_template),
testData = {mediaSequence: ''},
playlistData = playlistTemplate(testData),
data = m3u8parser.parse(playlistData);
notEqual(data, null, 'data is not NULL');
notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
equal(data.invalidReasons.length, 0, 'data has 0 invalid reasons');
equal(data.mediaSequence, 0, 'MEDIA SEQUENCE should default to 0 when not present.');
});
test('media sequence is empty in the playlist', function() {
var
playlistTemplate = Handlebars.compile(window.playlist_media_sequence_template),
testData = {mediaSequence: ''},
playlistData = playlistTemplate(testData),
data = m3u8parser.parse(playlistData);
notEqual(data, null, 'data is not NULL');
notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
equal(data.mediaSequence, 0, 'Invalid Media Sequence Value: \'\'');
});
test('media sequence is high (non-zero in first file) in the playlist', function() {
var
playlistTemplate = Handlebars.compile(window.playlist_media_sequence_template),
testData = {mediaSequence: '1'},
playlistData = playlistTemplate(testData),
data = m3u8parser.parse(playlistData);
notEqual(data, null, 'data is not NULL');
notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
equal(data.invalidReasons[0], 'Invalid Media Sequence Value: 1');
});
test('media sequence (-1) in the playlist', function() {
var
playlistTemplate = Handlebars.compile(window.playlist_media_sequence_template),
testData = {mediaSequence: '-1'},
playlistData = playlistTemplate(testData),
data = m3u8parser.parse(playlistData);
notEqual(data, null, 'data is not NULL');
notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
equal(data.invalidReasons[0], 'Invalid Media Sequence Value: -1');
});
test('media sequence invalid (string) in the playlist', function() {
var
playlistTemplate = Handlebars.compile(window.playlist_media_sequence_template),
testData = {mediaSequence: 'asdfkasdkfl'},
playlistData = playlistTemplate(testData),
data = m3u8parser.parse(playlistData);
notEqual(data, null, 'data is not NULL');
notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
equal(data.invalidReasons[0], 'Invalid Media Sequence Value: asdfkasdkfl');
});
module('brightcove playlist', { module('brightcove playlist', {
setup: function() { setup: function() {
m3u8parser = new window.videojs.hls.M3U8Parser(); m3u8parser = new window.videojs.hls.M3U8Parser();

15
test/manifest/playlist_media_sequence_template.js

@ -0,0 +1,15 @@
window.playlist_media_sequence_template = '#EXTM3U\n'+
'#EXT-X-PLAYLIST-TYPE:VOD\n'+
'{{#if mediaSequence}}#EXT-X-MEDIA-SEQUENCE:{{{mediaSequence}}}{{/if}}\n'+
'{{#if mediaSequence2}}#EXT-X-MEDIA-SEQUENCE:{{{mediaSequence2}}}{{/if}}\n'+
'#EXT-X-ALLOW-CACHE:YES\n'+
'#EXT-X-TARGETDURATION:8\n'+
'#EXTINF:6.640,{}\n'+
'/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts\n'+
'#EXTINF:6.080,{}\n'+
'/test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts\n'+
'#EXTINF:6.600,{}\n'+
'/test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts\n'+
'#EXTINF:5.000,{}\n'+
'/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts\n'+
'#EXT-X-ENDLIST'

14
test/manifest/playlist_target_duration_template.js

@ -0,0 +1,14 @@
window.playlist_target_duration_template = '#EXTM3U\n'+
'#EXT-X-PLAYLIST-TYPE:VOD\n'+
'#EXT-X-MEDIA-SEQUENCE:0\n'+
'#EXT-X-ALLOW-CACHE:YES\n'+
'{{#if targetDuration}}#EXT-X-TARGETDURATION:{{{targetDuration}}}{{/if}}\n'+
'#EXTINF:6.640,{}\n'+
'/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts\n'+
'#EXTINF:6.080,{}\n'+
'/test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts\n'+
'#EXTINF:6.600,{}\n'+
'/test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts\n'+
'#EXTINF:5.000,{}\n'+
'/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts\n'+
'#EXT-X-ENDLIST'

17
test/manifest/playlist_type_template.js

@ -0,0 +1,17 @@
window.playlist_type_template = '#EXTM3U\n' +
'{{#if playlistType}}#EXT-X-PLAYLIST-TYPE:{{{playlistType}}}{{/if}}\n' +
'#EXT-X-TARGETDURATION:10\n' +
'#EXTINF:10,\n' +
'/test/ts-files/zencoder/haze/Haze_Mantel_President_encoded_1200-00001.ts\n' +
'#EXTINF:10,\n' +
'/test/ts-files/zencoder/haze/Haze_Mantel_President_encoded_1200-00002.ts\n' +
'#EXTINF:10,\n' +
'/test/ts-files/zencoder/haze/Haze_Mantel_President_encoded_1200-00003.ts\n' +
'#EXTINF:10,\n' +
'/test/ts-files/zencoder/haze/Haze_Mantel_President_encoded_1200-00004.ts\n' +
'#EXTINF:10,\n' +
'/test/ts-files/zencoder/haze/Haze_Mantel_President_encoded_1200-00005.ts\n' +
'#EXTINF:8,\n' +
'/test/ts-files/zencoder/haze/Haze_Mantel_President_encoded_1200-00006.ts\n' +
'#ZEN-TOTAL-DURATION:57.9911\n' +
'#EXT-X-ENDLIST';

6
test/video-js-hls.html

@ -7,6 +7,9 @@
<link rel="stylesheet" href="../libs/qunit/qunit.css" media="screen"> <link rel="stylesheet" href="../libs/qunit/qunit.css" media="screen">
<script src="../libs/qunit/qunit.js"></script> <script src="../libs/qunit/qunit.js"></script>
<!-- handlebars.js -->
<script src="../libs/handlebars/handlebars-v1.1.2.js"></script>
<!-- video.js --> <!-- video.js -->
<script src="../node_modules/video.js/video.dev.js"></script> <script src="../node_modules/video.js/video.dev.js"></script>
@ -26,6 +29,9 @@
<!-- M3U8 TEST DATA --> <!-- M3U8 TEST DATA -->
<script src="manifest/playlistM3U8data.js"></script> <script src="manifest/playlistM3U8data.js"></script>
<script src="manifest/brightcove_playlist_m3u8.js"></script> <script src="manifest/brightcove_playlist_m3u8.js"></script>
<script src="manifest/playlist_type_template.js"></script>
<script src="manifest/playlist_media_sequence_template.js"></script>
<script src="manifest/playlist_target_duration_template.js"></script>
<!-- M3U8 --> <!-- M3U8 -->
<!-- SEGMENT --> <!-- SEGMENT -->
<script src="tsSegment-bc.js"></script> <script src="tsSegment-bc.js"></script>

Loading…
Cancel
Save