Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
brainfood
/
videojs-contrib-hls
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Graphs
Network
Create a new issue
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
e37356d8
authored
2015-04-28 16:16:03 -0700
by
David LaPalomento
Browse Files
Options
Browse Files
Tag
Download
Plain Diff
Merge pull request #251 from videojs/hlse-perf
Optimize decryption
2 parents
77591534
48f0f290
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
318 additions
and
71 deletions
src/decrypter.js
src/videojs-hls.js
test/decrypter_test.js
test/videojs-hls_test.js
src/decrypter.js
View file @
e37356d
...
...
@@ -38,7 +38,18 @@
(
function
(
window
,
videojs
,
unpad
)
{
'use strict'
;
var
AES
,
decrypt
;
var
AES
,
AsyncStream
,
Decrypter
,
decrypt
,
ntoh
;
/**
* Convert network-order (big-endian) bytes into their little-endian
* representation.
*/
ntoh
=
function
(
word
)
{
return
(
word
<<
24
)
|
((
word
&
0xff00
)
<<
8
)
|
((
word
&
0xff0000
)
>>
8
)
|
(
word
>>>
24
);
};
/**
* Schedule out an AES key for both encryption and decryption. This
...
...
@@ -151,49 +162,51 @@ AES.prototype = {
},
/**
* Decrypt an array of 4 big-endian words.
* @param {Array} data The ciphertext.
* Decrypt 16 bytes, specified as four 32-bit words.
* @param encrypted0 {number} the first word to decrypt
* @param encrypted1 {number} the second word to decrypt
* @param encrypted2 {number} the third word to decrypt
* @param encrypted3 {number} the fourth word to decrypt
* @param out {Int32Array} the array to write the decrypted words
* into
* @param offset {number} the offset into the output array to start
* writing results
* @return {Array} The plaintext.
*/
decrypt
:
function
(
input
)
{
if
(
input
.
length
!==
4
)
{
throw
new
Error
(
"Invalid aes block size"
);
}
decrypt
:
function
(
encrypted0
,
encrypted1
,
encrypted2
,
encrypted3
,
out
,
offset
)
{
var
key
=
this
.
_key
[
1
],
// state variables a,b,c,d are loaded with pre-whitened data
a
=
input
[
0
]
^
key
[
0
],
b
=
input
[
3
]
^
key
[
1
],
c
=
input
[
2
]
^
key
[
2
],
d
=
input
[
1
]
^
key
[
3
],
a
=
encrypted0
^
key
[
0
],
b
=
encrypted3
^
key
[
1
],
c
=
encrypted2
^
key
[
2
],
d
=
encrypted1
^
key
[
3
],
a2
,
b2
,
c2
,
nInnerRounds
=
key
.
length
/
4
-
2
,
nInnerRounds
=
key
.
length
/
4
-
2
,
// key.length === 2 ?
i
,
kIndex
=
4
,
out
=
[
0
,
0
,
0
,
0
],
table
=
this
.
_tables
[
1
],
// load up the tables
t0
=
table
[
0
],
t1
=
table
[
1
],
t2
=
table
[
2
],
t3
=
table
[
3
],
t
able
0
=
table
[
0
],
t
able
1
=
table
[
1
],
t
able
2
=
table
[
2
],
t
able
3
=
table
[
3
],
sbox
=
table
[
4
];
// Inner rounds. Cribbed from OpenSSL.
for
(
i
=
0
;
i
<
nInnerRounds
;
i
++
)
{
a2
=
t
0
[
a
>>>
24
]
^
t1
[
b
>>
16
&
255
]
^
t2
[
c
>>
8
&
255
]
^
t
3
[
d
&
255
]
^
key
[
kIndex
];
b2
=
t
0
[
b
>>>
24
]
^
t1
[
c
>>
16
&
255
]
^
t2
[
d
>>
8
&
255
]
^
t
3
[
a
&
255
]
^
key
[
kIndex
+
1
];
c2
=
t
0
[
c
>>>
24
]
^
t1
[
d
>>
16
&
255
]
^
t2
[
a
>>
8
&
255
]
^
t
3
[
b
&
255
]
^
key
[
kIndex
+
2
];
d
=
t
0
[
d
>>>
24
]
^
t1
[
a
>>
16
&
255
]
^
t2
[
b
>>
8
&
255
]
^
t
3
[
c
&
255
]
^
key
[
kIndex
+
3
];
a2
=
t
able0
[
a
>>>
24
]
^
table1
[
b
>>
16
&
255
]
^
table2
[
c
>>
8
&
255
]
^
table
3
[
d
&
255
]
^
key
[
kIndex
];
b2
=
t
able0
[
b
>>>
24
]
^
table1
[
c
>>
16
&
255
]
^
table2
[
d
>>
8
&
255
]
^
table
3
[
a
&
255
]
^
key
[
kIndex
+
1
];
c2
=
t
able0
[
c
>>>
24
]
^
table1
[
d
>>
16
&
255
]
^
table2
[
a
>>
8
&
255
]
^
table
3
[
b
&
255
]
^
key
[
kIndex
+
2
];
d
=
t
able0
[
d
>>>
24
]
^
table1
[
a
>>
16
&
255
]
^
table2
[
b
>>
8
&
255
]
^
table
3
[
c
&
255
]
^
key
[
kIndex
+
3
];
kIndex
+=
4
;
a
=
a2
;
b
=
b2
;
c
=
c2
;
}
// Last round.
for
(
i
=
0
;
i
<
4
;
i
++
)
{
out
[
3
&
-
i
]
=
out
[
(
3
&
-
i
)
+
offset
]
=
sbox
[
a
>>>
24
]
<<
24
^
sbox
[
b
>>
16
&
255
]
<<
16
^
sbox
[
c
>>
8
&
255
]
<<
8
^
...
...
@@ -201,49 +214,152 @@ AES.prototype = {
key
[
kIndex
++
];
a2
=
a
;
a
=
b
;
b
=
c
;
c
=
d
;
d
=
a2
;
}
return
out
;
}
};
/**
* Decrypt bytes using AES-128 with CBC and PKCS#7 padding.
* @param encrypted {Uint8Array} the encrypted bytes
* @param key {Uint32Array} the bytes of the decryption key
* @param initVector {Uint32Array} the initialization vector (IV) to
* use for the first round of CBC.
* @return {Uint8Array} the decrypted bytes
*
* @see http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
* @see http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29
* @see https://tools.ietf.org/html/rfc2315
*/
decrypt
=
function
(
encrypted
,
key
,
initVector
)
{
var
encryptedView
=
new
DataView
(
encrypted
.
buffer
),
platformEndian
=
new
Uint32Array
(
encrypted
.
byteLength
/
4
),
// word-level access to the encrypted bytes
encrypted32
=
new
Int32Array
(
encrypted
.
buffer
,
encrypted
.
byteOffset
,
encrypted
.
byteLength
>>
2
),
decipher
=
new
AES
(
Array
.
prototype
.
slice
.
call
(
key
)),
// byte and word-level access for the decrypted output
decrypted
=
new
Uint8Array
(
encrypted
.
byteLength
),
decryptedView
=
new
DataView
(
decrypted
.
buffer
),
decryptedBlock
,
word
,
byte
;
decrypted32
=
new
Int32Array
(
decrypted
.
buffer
),
// temporary variables for working with the IV, encrypted, and
// decrypted data
init0
,
init1
,
init2
,
init3
,
encrypted0
,
encrypted1
,
encrypted2
,
encrypted3
,
// iteration variable
wordIx
;
// pull out the words of the IV to ensure we don't modify the
// passed-in reference and easier access
init0
=
initVector
[
0
];
init1
=
initVector
[
1
];
init2
=
initVector
[
2
];
init3
=
initVector
[
3
];
// convert big-endian input to platform byte order for decryption
for
(
byte
=
0
;
byte
<
encrypted
.
byteLength
;
byte
+=
4
)
{
platformEndian
[
byte
>>>
2
]
=
encryptedView
.
getUint32
(
byte
);
}
// decrypt four word sequences, applying cipher-block chaining (CBC)
// to each decrypted block
for
(
word
=
0
;
word
<
platformEndian
.
length
;
word
+=
4
)
{
for
(
wordIx
=
0
;
wordIx
<
encrypted32
.
length
;
wordIx
+=
4
)
{
// convert big-endian (network order) words into little-endian
// (javascript order)
encrypted0
=
ntoh
(
encrypted32
[
wordIx
]);
encrypted1
=
ntoh
(
encrypted32
[
wordIx
+
1
]);
encrypted2
=
ntoh
(
encrypted32
[
wordIx
+
2
]);
encrypted3
=
ntoh
(
encrypted32
[
wordIx
+
3
]);
// decrypt the block
decryptedBlock
=
decipher
.
decrypt
(
platformEndian
.
subarray
(
word
,
word
+
4
));
decipher
.
decrypt
(
encrypted0
,
encrypted1
,
encrypted2
,
encrypted3
,
decrypted32
,
wordIx
);
// XOR with the IV, and restore network byte-order to obtain the
// plaintext
byte
=
word
<<
2
;
decryptedView
.
setUint32
(
byte
,
decryptedBlock
[
0
]
^
initVector
[
0
]);
decryptedView
.
setUint32
(
byte
+
4
,
decryptedBlock
[
1
]
^
initVector
[
1
]);
decryptedView
.
setUint32
(
byte
+
8
,
decryptedBlock
[
2
]
^
initVector
[
2
]);
decryptedView
.
setUint32
(
byte
+
12
,
decryptedBlock
[
3
]
^
initVector
[
3
]);
decrypted32
[
wordIx
]
=
ntoh
(
decrypted32
[
wordIx
]
^
init0
);
decrypted32
[
wordIx
+
1
]
=
ntoh
(
decrypted32
[
wordIx
+
1
]
^
init1
);
decrypted32
[
wordIx
+
2
]
=
ntoh
(
decrypted32
[
wordIx
+
2
]
^
init2
);
decrypted32
[
wordIx
+
3
]
=
ntoh
(
decrypted32
[
wordIx
+
3
]
^
init3
);
// setup the IV for the next round
initVector
=
platformEndian
.
subarray
(
word
,
word
+
4
);
init0
=
encrypted0
;
init1
=
encrypted1
;
init2
=
encrypted2
;
init3
=
encrypted3
;
}
// remove any padding
return
unpad
(
decrypted
);
return
decrypted
;
};
AsyncStream
=
function
()
{
this
.
jobs
=
[];
this
.
delay
=
1
;
this
.
timeout_
=
null
;
};
AsyncStream
.
prototype
=
new
videojs
.
Hls
.
Stream
();
AsyncStream
.
prototype
.
processJob_
=
function
()
{
this
.
jobs
.
shift
()();
if
(
this
.
jobs
.
length
)
{
this
.
timeout_
=
setTimeout
(
videojs
.
bind
(
this
,
this
.
processJob_
),
this
.
delay
);
}
else
{
this
.
timeout_
=
null
;
}
};
AsyncStream
.
prototype
.
push
=
function
(
job
)
{
this
.
jobs
.
push
(
job
);
if
(
!
this
.
timeout_
)
{
this
.
timeout_
=
setTimeout
(
videojs
.
bind
(
this
,
this
.
processJob_
),
this
.
delay
);
}
};
Decrypter
=
function
(
encrypted
,
key
,
initVector
,
done
)
{
var
step
=
Decrypter
.
STEP
,
encrypted32
=
new
Int32Array
(
encrypted
.
buffer
),
decrypted
=
new
Uint8Array
(
encrypted
.
byteLength
),
i
=
0
;
this
.
asyncStream_
=
new
AsyncStream
();
// split up the encryption job and do the individual chunks asynchronously
this
.
asyncStream_
.
push
(
this
.
decryptChunk_
(
encrypted32
.
subarray
(
i
,
i
+
step
),
key
,
initVector
,
decrypted
,
i
));
for
(
i
=
step
;
i
<
encrypted32
.
length
;
i
+=
step
)
{
initVector
=
new
Uint32Array
([
ntoh
(
encrypted32
[
i
-
4
]),
ntoh
(
encrypted32
[
i
-
3
]),
ntoh
(
encrypted32
[
i
-
2
]),
ntoh
(
encrypted32
[
i
-
1
])
]);
this
.
asyncStream_
.
push
(
this
.
decryptChunk_
(
encrypted32
.
subarray
(
i
,
i
+
step
),
key
,
initVector
,
decrypted
));
}
// invoke the done() callback when everything is finished
this
.
asyncStream_
.
push
(
function
()
{
// remove pkcs#7 padding from the decrypted bytes
done
(
null
,
unpad
(
decrypted
));
});
};
Decrypter
.
prototype
=
new
videojs
.
Hls
.
Stream
();
Decrypter
.
prototype
.
decryptChunk_
=
function
(
encrypted
,
key
,
initVector
,
decrypted
)
{
return
function
()
{
var
bytes
=
decrypt
(
encrypted
,
key
,
initVector
);
decrypted
.
set
(
bytes
,
encrypted
.
byteOffset
);
};
};
// the maximum number of bytes to process at one time
Decrypter
.
STEP
=
4
*
8000
;
// exports
videojs
.
Hls
.
decrypt
=
decrypt
;
videojs
.
Hls
.
Decrypter
=
Decrypter
;
videojs
.
Hls
.
AsyncStream
=
AsyncStream
;
})(
window
,
window
.
videojs
,
window
.
pkcs7
.
unpad
);
...
...
src/videojs-hls.js
View file @
e37356d
...
...
@@ -637,6 +637,8 @@ videojs.Hls.prototype.loadSegment = function(segmentUri, offset) {
responseType
:
'arraybuffer'
,
withCredentials
:
settings
.
withCredentials
},
function
(
error
,
url
)
{
var
segmentInfo
;
// the segment request is no longer outstanding
tech
.
segmentXhr_
=
null
;
...
...
@@ -669,12 +671,26 @@ videojs.Hls.prototype.loadSegment = function(segmentUri, offset) {
// if the segment is the start of a timestamp discontinuity,
// we have to wait until the sourcebuffer is empty before
// aborting the source buffer processing
tech
.
segmentBuffer_
.
push
({
segmentInfo
=
{
// the segment's mediaIndex at the time it was received
mediaIndex
:
tech
.
mediaIndex
,
// the segment's playlist
playlist
:
tech
.
playlists
.
media
(),
// optionally, a time offset to seek to within the segment
offset
:
offset
,
bytes
:
new
Uint8Array
(
this
.
response
)
});
// unencrypted bytes of the segment
bytes
:
null
,
// when a key is defined for this segment, the encrypted bytes
encryptedBytes
:
null
,
// optionally, the decrypter that is unencrypting the segment
decrypter
:
null
};
if
(
segmentInfo
.
playlist
.
segments
[
segmentInfo
.
mediaIndex
].
key
)
{
segmentInfo
.
encryptedBytes
=
new
Uint8Array
(
this
.
response
);
}
else
{
segmentInfo
.
bytes
=
new
Uint8Array
(
this
.
response
);
}
tech
.
segmentBuffer_
.
push
(
segmentInfo
);
player
.
trigger
(
'progress'
);
tech
.
drainBuffer
();
...
...
@@ -689,12 +705,15 @@ videojs.Hls.prototype.loadSegment = function(segmentUri, offset) {
videojs
.
Hls
.
prototype
.
drainBuffer
=
function
(
event
)
{
var
i
=
0
,
segmentInfo
,
mediaIndex
,
playlist
,
offset
,
tags
,
bytes
,
segment
,
decrypter
,
segIv
,
ptsTime
,
segmentOffset
,
...
...
@@ -704,28 +723,45 @@ videojs.Hls.prototype.drainBuffer = function(event) {
return
;
}
mediaIndex
=
segmentBuffer
[
0
].
mediaIndex
;
playlist
=
segmentBuffer
[
0
].
playlist
;
offset
=
segmentBuffer
[
0
].
offset
;
bytes
=
segmentBuffer
[
0
].
bytes
;
segmentInfo
=
segmentBuffer
[
0
];
mediaIndex
=
segmentInfo
.
mediaIndex
;
playlist
=
segmentInfo
.
playlist
;
offset
=
segmentInfo
.
offset
;
bytes
=
segmentInfo
.
bytes
;
segment
=
playlist
.
segments
[
mediaIndex
];
if
(
segment
.
key
)
{
if
(
segment
.
key
&&
!
bytes
)
{
// this is an encrypted segment
// if the key download failed, we want to skip this segment
// but if the key hasn't downloaded yet, we want to try again later
if
(
keyFailed
(
segment
.
key
))
{
return
segmentBuffer
.
shift
();
}
else
if
(
!
segment
.
key
.
bytes
)
{
// trigger a key request if one is not already in-flight
return
this
.
fetchKeys_
();
}
else
if
(
segmentInfo
.
decrypter
)
{
// decryption is in progress, try again later
return
;
}
else
{
// if the media sequence is greater than 2^32, the IV will be incorrect
// assuming 10s segments, that would be about 1300 years
var
segIv
=
segment
.
key
.
iv
||
new
Uint32Array
([
0
,
0
,
0
,
mediaIndex
+
playlist
.
mediaSequence
]);
bytes
=
videojs
.
Hls
.
decrypt
(
bytes
,
segIv
=
segment
.
key
.
iv
||
new
Uint32Array
([
0
,
0
,
0
,
mediaIndex
+
playlist
.
mediaSequence
]);
// create a decrypter to incrementally decrypt the segment
decrypter
=
new
videojs
.
Hls
.
Decrypter
(
segmentInfo
.
encryptedBytes
,
segment
.
key
.
bytes
,
segIv
);
segIv
,
function
(
err
,
bytes
)
{
segmentInfo
.
bytes
=
bytes
;
});
segmentInfo
.
decrypter
=
decrypter
;
return
;
}
}
...
...
test/decrypter_test.js
View file @
e37356d
(
function
(
window
,
videojs
,
undefined
)
{
(
function
(
window
,
videojs
,
un
pad
,
un
defined
)
{
'use strict'
;
/*
======== A Handy Little QUnit Reference ========
...
...
@@ -46,7 +46,7 @@ test('decrypts a single AES-128 with PKCS7 block', function() {
0x82
,
0xa8
,
0xf0
,
0x67
]);
deepEqual
(
'howdy folks'
,
stringFromBytes
(
videojs
.
Hls
.
decrypt
(
encrypted
,
key
,
initVector
)),
stringFromBytes
(
unpad
(
videojs
.
Hls
.
decrypt
(
encrypted
,
key
,
initVector
)
)),
'decrypted with a byte array key'
);
});
...
...
@@ -68,8 +68,100 @@ test('decrypts multiple AES-128 blocks with CBC', function() {
]);
deepEqual
(
'0123456789abcdef01234'
,
stringFromBytes
(
videojs
.
Hls
.
decrypt
(
encrypted
,
key
,
initVector
)),
stringFromBytes
(
unpad
(
videojs
.
Hls
.
decrypt
(
encrypted
,
key
,
initVector
)
)),
'decrypted multiple blocks'
);
});
})(
window
,
window
.
videojs
);
var
clock
;
module
(
'Incremental Processing'
,
{
setup
:
function
()
{
clock
=
sinon
.
useFakeTimers
();
},
teardown
:
function
()
{
clock
.
restore
();
}
});
test
(
'executes a callback after a timeout'
,
function
()
{
var
asyncStream
=
new
videojs
.
Hls
.
AsyncStream
(),
calls
=
''
;
asyncStream
.
push
(
function
()
{
calls
+=
'a'
;
});
clock
.
tick
(
asyncStream
.
delay
);
equal
(
calls
,
'a'
,
'invoked the callback once'
);
clock
.
tick
(
asyncStream
.
delay
);
equal
(
calls
,
'a'
,
'only invoked the callback once'
);
});
test
(
'executes callback in series'
,
function
()
{
var
asyncStream
=
new
videojs
.
Hls
.
AsyncStream
(),
calls
=
''
;
asyncStream
.
push
(
function
()
{
calls
+=
'a'
;
});
asyncStream
.
push
(
function
()
{
calls
+=
'b'
;
});
clock
.
tick
(
asyncStream
.
delay
);
equal
(
calls
,
'a'
,
'invoked the first callback'
);
clock
.
tick
(
asyncStream
.
delay
);
equal
(
calls
,
'ab'
,
'invoked the second'
);
});
var
decrypter
;
module
(
'Incremental Decryption'
,
{
setup
:
function
()
{
clock
=
sinon
.
useFakeTimers
();
},
teardown
:
function
()
{
clock
.
restore
();
}
});
test
(
'asynchronously decrypts a 4-word block'
,
function
()
{
var
key
=
new
Uint32Array
([
0
,
0
,
0
,
0
]),
initVector
=
key
,
// the string "howdy folks" encrypted
encrypted
=
new
Uint8Array
([
0xce
,
0x90
,
0x97
,
0xd0
,
0x08
,
0x46
,
0x4d
,
0x18
,
0x4f
,
0xae
,
0x01
,
0x1c
,
0x82
,
0xa8
,
0xf0
,
0x67
]),
decrypted
;
decrypter
=
new
videojs
.
Hls
.
Decrypter
(
encrypted
,
key
,
initVector
,
function
(
error
,
result
)
{
decrypted
=
result
;
});
ok
(
!
decrypted
,
'asynchronously decrypts'
);
clock
.
tick
(
decrypter
.
asyncStream_
.
delay
*
2
);
ok
(
decrypted
,
'completed decryption'
);
deepEqual
(
'howdy folks'
,
stringFromBytes
(
decrypted
),
'decrypts and unpads the result'
);
});
test
(
'breaks up input greater than the step value'
,
function
()
{
var
encrypted
=
new
Int32Array
(
videojs
.
Hls
.
Decrypter
.
STEP
+
4
),
done
=
false
,
decrypter
=
new
videojs
.
Hls
.
Decrypter
(
encrypted
,
new
Uint32Array
(
4
),
new
Uint32Array
(
4
),
function
()
{
done
=
true
;
});
clock
.
tick
(
decrypter
.
asyncStream_
.
delay
*
2
);
ok
(
!
done
,
'not finished after two ticks'
);
clock
.
tick
(
decrypter
.
asyncStream_
.
delay
);
ok
(
done
,
'finished after the last chunk is decrypted'
);
});
})(
window
,
window
.
videojs
,
window
.
pkcs7
.
unpad
);
...
...
test/videojs-hls_test.js
View file @
e37356d
...
...
@@ -152,10 +152,8 @@ module('HLS', {
oldNativeHlsSupport
=
videojs
.
Hls
.
supportsNativeHls
;
oldDecrypt
=
videojs
.
Hls
.
decrypt
;
videojs
.
Hls
.
decrypt
=
function
()
{
return
new
Uint8Array
([
0
]);
};
oldDecrypt
=
videojs
.
Hls
.
Decrypter
;
videojs
.
Hls
.
Decrypter
=
function
()
{};
// fake XHRs
xhr
=
sinon
.
useFakeXMLHttpRequest
();
...
...
@@ -173,7 +171,7 @@ module('HLS', {
videojs
.
MediaSource
.
open
=
oldMediaSourceOpen
;
videojs
.
Hls
.
SegmentParser
=
oldSegmentParser
;
videojs
.
Hls
.
supportsNativeHls
=
oldNativeHlsSupport
;
videojs
.
Hls
.
decrypt
=
oldDecrypt
;
videojs
.
Hls
.
Decrypter
=
oldDecrypt
;
videojs
.
SourceBuffer
=
oldSourceBuffer
;
window
.
setTimeout
=
oldSetTimeout
;
window
.
clearTimeout
=
oldClearTimeout
;
...
...
@@ -1904,6 +1902,10 @@ test('a new key XHR is created when a the segment is received', function() {
'#EXT-X-ENDLIST\n'
);
standardXHRResponse
(
requests
.
shift
());
// segment 1
standardXHRResponse
(
requests
.
shift
());
// key 1
// "finish" decrypting segment 1
player
.
hls
.
segmentBuffer_
[
0
].
bytes
=
new
Uint8Array
(
16
);
player
.
hls
.
checkBuffer_
();
standardXHRResponse
(
requests
.
shift
());
// segment 2
strictEqual
(
requests
.
length
,
1
,
'a key XHR is created'
);
...
...
@@ -2009,6 +2011,9 @@ test('skip segments if key requests fail more than once', function() {
// key for second segment
requests
[
0
].
response
=
new
Uint32Array
([
0
,
0
,
0
,
0
]).
buffer
;
requests
.
shift
().
respond
(
200
,
null
,
''
);
// "finish" decryption
player
.
hls
.
segmentBuffer_
[
0
].
bytes
=
new
Uint8Array
(
16
);
player
.
hls
.
checkBuffer_
();
equal
(
bytes
.
length
,
2
,
'bytes from the second ts segment should be added'
);
equal
(
bytes
[
1
],
1
,
'the bytes from the second segment are added and not the first'
);
...
...
@@ -2033,9 +2038,8 @@ test('the key is supplied to the decrypter in the correct format', function() {
'http://media.example.com/fileSequence52-B.ts\n'
);
videojs
.
Hls
.
decrypt
=
function
(
bytes
,
key
)
{
videojs
.
Hls
.
Decrypter
=
function
(
encrypted
,
key
)
{
keys
.
push
(
key
);
return
new
Uint8Array
([
0
]);
};
standardXHRResponse
(
requests
.
shift
());
// segment
...
...
@@ -2043,7 +2047,7 @@ test('the key is supplied to the decrypter in the correct format', function() {
requests
[
0
].
respond
(
200
,
null
,
''
);
requests
.
shift
();
// key
equal
(
keys
.
length
,
1
,
'only one
call to decrypt was made
'
);
equal
(
keys
.
length
,
1
,
'only one
Decrypter was constructed
'
);
deepEqual
(
keys
[
0
],
new
Uint32Array
([
0
,
0x01000000
,
0x02000000
,
0x03000000
]),
'passed the specified segment key'
);
...
...
@@ -2068,9 +2072,8 @@ test('supplies the media sequence of current segment as the IV by default, if no
'http://media.example.com/fileSequence52-B.ts\n'
);
videojs
.
Hls
.
decrypt
=
function
(
bytes
,
key
,
iv
)
{
videojs
.
Hls
.
Decrypter
=
function
(
encrypted
,
key
,
iv
)
{
ivs
.
push
(
iv
);
return
new
Uint8Array
([
0
]);
};
requests
[
0
].
response
=
new
Uint32Array
([
0
,
0
,
0
,
0
]).
buffer
;
...
...
@@ -2078,7 +2081,7 @@ test('supplies the media sequence of current segment as the IV by default, if no
requests
.
shift
();
standardXHRResponse
(
requests
.
pop
());
equal
(
ivs
.
length
,
1
,
'only one
call to decrypt was made
'
);
equal
(
ivs
.
length
,
1
,
'only one
Decrypter was constructed
'
);
deepEqual
(
ivs
[
0
],
new
Uint32Array
([
0
,
0
,
0
,
5
]),
'the IV for the segment is the media sequence'
);
...
...
Please
register
or
sign in
to post a comment