src/demux/sample-aes.js
/**
* SAMPLE-AES decrypter
*/
import Decrypter from '../crypt/decrypter';
class SampleAesDecrypter {
constructor(observer, config, decryptdata, discardEPB) {
this.decryptdata = decryptdata;
this.discardEPB = discardEPB;
this.decrypter = new Decrypter(observer, config, {
removePKCS7Padding: false,
});
}
decryptBuffer(encryptedData, callback) {
this.decrypter.decrypt(
encryptedData,
this.decryptdata.key.buffer,
this.decryptdata.iv.buffer,
callback
);
}
// AAC - encrypt all full 16 bytes blocks starting from offset 16
decryptAacSample(samples, sampleIndex, callback, sync) {
const curUnit = samples[sampleIndex].unit;
const encryptedData = curUnit.subarray(
16,
curUnit.length - (curUnit.length % 16)
);
const encryptedBuffer = encryptedData.buffer.slice(
encryptedData.byteOffset,
encryptedData.byteOffset + encryptedData.length
);
const localthis = this;
this.decryptBuffer(encryptedBuffer, function (decryptedData) {
decryptedData = new Uint8Array(decryptedData);
curUnit.set(decryptedData, 16);
if (!sync) {
localthis.decryptAacSamples(samples, sampleIndex + 1, callback);
}
});
}
decryptAacSamples(samples, sampleIndex, callback) {
for (; ; sampleIndex++) {
if (sampleIndex >= samples.length) {
callback();
return;
}
if (samples[sampleIndex].unit.length < 32) {
continue;
}
const sync = this.decrypter.isSync();
this.decryptAacSample(samples, sampleIndex, callback, sync);
if (!sync) {
return;
}
}
}
// AVC - encrypt one 16 bytes block out of ten, starting from offset 32
getAvcEncryptedData(decodedData) {
const encryptedDataLen =
Math.floor((decodedData.length - 48) / 160) * 16 + 16;
const encryptedData = new Int8Array(encryptedDataLen);
let outputPos = 0;
for (
let inputPos = 32;
inputPos <= decodedData.length - 16;
inputPos += 160, outputPos += 16
) {
encryptedData.set(
decodedData.subarray(inputPos, inputPos + 16),
outputPos
);
}
return encryptedData;
}
getAvcDecryptedUnit(decodedData, decryptedData) {
decryptedData = new Uint8Array(decryptedData);
let inputPos = 0;
for (
let outputPos = 32;
outputPos <= decodedData.length - 16;
outputPos += 160, inputPos += 16
) {
decodedData.set(
decryptedData.subarray(inputPos, inputPos + 16),
outputPos
);
}
return decodedData;
}
decryptAvcSample(samples, sampleIndex, unitIndex, callback, curUnit, sync) {
const decodedData = this.discardEPB(curUnit.data);
const encryptedData = this.getAvcEncryptedData(decodedData);
const localthis = this;
this.decryptBuffer(encryptedData.buffer, function (decryptedData) {
curUnit.data = localthis.getAvcDecryptedUnit(decodedData, decryptedData);
if (!sync) {
localthis.decryptAvcSamples(
samples,
sampleIndex,
unitIndex + 1,
callback
);
}
});
}
decryptAvcSamples(samples, sampleIndex, unitIndex, callback) {
for (; ; sampleIndex++, unitIndex = 0) {
if (sampleIndex >= samples.length) {
callback();
return;
}
const curUnits = samples[sampleIndex].units;
for (; ; unitIndex++) {
if (unitIndex >= curUnits.length) {
break;
}
const curUnit = curUnits[unitIndex];
if (
curUnit.data.length <= 48 ||
(curUnit.type !== 1 && curUnit.type !== 5)
) {
continue;
}
const sync = this.decrypter.isSync();
this.decryptAvcSample(
samples,
sampleIndex,
unitIndex,
callback,
curUnit,
sync
);
if (!sync) {
return;
}
}
}
}
}
export default SampleAesDecrypter;