ea13a59a by David LaPalomento

Pass codecs along into source buffer creation

If a codecs attribute is present on a variant stream, use it when adding a source buffer. Wait to create the source buffer until the variant playlist is downloaded and the media source is open.
1 parent e8371f66
......@@ -180,6 +180,8 @@ videojs.Hls.prototype.src = function(src) {
});
}
this.setupSourceBuffer_();
selectedPlaylist = this.selectPlaylist();
oldBitrate = oldMediaPlaylist.attributes &&
oldMediaPlaylist.attributes.BANDWIDTH || 0;
......@@ -281,16 +283,7 @@ videojs.Hls.getMediaIndexForLive_ = function(selectedPlaylist) {
};
videojs.Hls.prototype.handleSourceOpen = function() {
this.sourceBuffer = this.mediaSource.addSourceBuffer('video/mp2t');
// transition the sourcebuffer to the ended state if we've hit the end of
// the playlist
this.sourceBuffer.addEventListener('updateend', function() {
if (this.duration() !== Infinity &&
this.mediaIndex === this.playlists.media().segments.length) {
this.mediaSource.endOfStream();
}
}.bind(this));
this.setupSourceBuffer_();
// if autoplay is enabled, begin playback. This is duplicative of
// code in video.js but is required because play() must be invoked
......@@ -303,6 +296,31 @@ videojs.Hls.prototype.handleSourceOpen = function() {
}
};
videojs.Hls.prototype.setupSourceBuffer_ = function() {
var media = this.playlists.media(), mimeType;
// wait until a media playlist is available and the Media Source is
// attached
if (!media || this.mediaSource.readyState !== 'open') {
return;
}
mimeType = 'video/mp2t';
if (media.attributes && media.attributes.CODECS) {
mimeType += '; codecs="' + media.attributes.CODECS + '"';
}
this.sourceBuffer = this.mediaSource.addSourceBuffer(mimeType);
// transition the sourcebuffer to the ended state if we've hit the end of
// the playlist
this.sourceBuffer.addEventListener('updateend', function() {
if (this.duration() !== Infinity &&
this.mediaIndex === this.playlists.media().segments.length) {
this.mediaSource.endOfStream();
}
}.bind(this));
};
// register event listeners to transform in-band metadata events into
// VTTCues on a text track
videojs.Hls.prototype.setupMetadataCueTranslation_ = function() {
......@@ -310,12 +328,6 @@ videojs.Hls.prototype.setupMetadataCueTranslation_ = function() {
metadataStream = this.segmentParser_.metadataStream,
textTrack;
// only expose metadata tracks to video.js versions that support
// dynamic text tracks (4.12+)
if (!this.tech_.addTextTrack) {
return;
}
// add a metadata cue whenever a metadata event is triggered during
// segment parsing
metadataStream.on('data', function(metadata) {
......
......@@ -207,7 +207,7 @@
'the title is parsed');
});
test('parses #EXTINF tags with carriage returns', function() {
var
var
manifest = '#EXTINF:13,Does anyone really use the title attribute?\r\n',
element;
parseStream.on('data', function(elem) {
......@@ -480,6 +480,16 @@
strictEqual(element.tagType, 'stream-inf', 'the tag type is stream-inf');
strictEqual(element.attributes.RESOLUTION.width, 396, 'width is parsed');
strictEqual(element.attributes.RESOLUTION.height, 224, 'heigth is parsed');
manifest = '#EXT-X-STREAM-INF:CODECS="avc1.4d400d, mp4a.40.2"\n';
lineStream.push(manifest);
ok(element, 'an event was triggered');
strictEqual(element.type, 'tag', 'the line type is tag');
strictEqual(element.tagType, 'stream-inf', 'the tag type is stream-inf');
strictEqual(element.attributes.CODECS,
'avc1.4d400d, mp4a.40.2',
'codecs are parsed');
});
test('parses #EXT-X-STREAM-INF with arbitrary attributes', function() {
var
......
......@@ -383,6 +383,26 @@ test('duration is set when the source opens after the playlist is loaded', funct
equal(player.tech.hls.mediaSource.duration , 40, 'set the duration');
});
test('codecs are passed to the source buffer', function() {
var codecs = [];
player.src({
src: 'custom-codecs.m3u8',
type: 'application/vnd.apple.mpegurl'
});
openMediaSource(player);
player.tech.hls.mediaSource.addSourceBuffer = function(codec) {
codecs.push(codec);
};
requests.shift().respond(200, null,
'#EXTM3U\n' +
'#EXT-X-STREAM-INF:CODECS="video, audio"\n' +
'media.m3u8\n');
standardXHRResponse(requests.shift());
equal(codecs.length, 1, 'created a source buffer');
equal(codecs[0], 'video/mp2t; codecs="video, audio"', 'specified the codecs');
});
test('including HLS as a tech does not error', function() {
var player = createPlayer({
techOrder: ['hls', 'html5']
......@@ -565,11 +585,11 @@ test('re-initializes the handler for each source', function() {
openMediaSource(player);
firstPlaylists = player.tech.hls.playlists;
firstMSE = player.tech.hls.mediaSource;
standardXHRResponse(requests.shift());
standardXHRResponse(requests.shift());
player.tech.hls.sourceBuffer.abort = function() {
aborts++;
};
standardXHRResponse(requests.shift());
standardXHRResponse(requests.shift());
player.src({
src: 'manifest/master.m3u8',
......@@ -2346,6 +2366,17 @@ test('aborts the source buffer on disposal', function() {
type: 'application/vnd.apple.mpegurl'
});
openMediaSource(player);
player.dispose();
ok(true, 'disposed before creating the source buffer');
requests.length = 0;
player = createPlayer();
player.src({
src: 'manifest/media.m3u8',
type: 'application/vnd.apple.mpegurl'
});
openMediaSource(player);
standardXHRResponse(requests.shift());
player.tech.hls.sourceBuffer.abort = function() {
aborts++;
};
......@@ -2708,9 +2739,6 @@ test('skip segments if key requests fail more than once', function() {
type: 'application/vnd.apple.mpegurl'
});
openMediaSource(player);
player.tech.hls.sourceBuffer.appendBuffer = function(chunk) {
bytes.push(chunk);
};
player.tech.trigger('play');
requests.shift().respond(200, null,
......@@ -2721,6 +2749,9 @@ test('skip segments if key requests fail more than once', function() {
'#EXT-X-KEY:METHOD=AES-128,URI="htts://priv.example.com/key.php?r=53"\n' +
'#EXTINF:15.0,\n' +
'http://media.example.com/fileSequence53-A.ts\n');
player.tech.hls.sourceBuffer.appendBuffer = function(chunk) {
bytes.push(chunk);
};
standardXHRResponse(requests.shift()); // segment 1
requests.shift().respond(404); // fail key
requests.shift().respond(404); // fail key, again
......@@ -2878,9 +2909,6 @@ test('treats invalid keys as a key request failure', function() {
type: 'application/vnd.apple.mpegurl'
});
openMediaSource(player);
player.tech.hls.sourceBuffer.appendBuffer = function(chunk) {
bytes.push(chunk);
};
player.tech.trigger('play');
requests.shift().respond(200, null,
'#EXTM3U\n' +
......@@ -2891,6 +2919,9 @@ test('treats invalid keys as a key request failure', function() {
'#EXT-X-KEY:METHOD=NONE\n' +
'#EXTINF:15.0,\n' +
'http://media.example.com/fileSequence52-B.ts\n');
player.tech.hls.sourceBuffer.appendBuffer = function(chunk) {
bytes.push(chunk);
};
// segment request
standardXHRResponse(requests.shift());
// keys should be 16 bytes long
......