Created
November 22, 2020 08:17
-
-
Save fanfare/0fa525af28b275fd6623942d7e9d70dd to your computer and use it in GitHub Desktop.
mp3 inside mp4 via javascript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// input MUST be 128kbps cbr mp3 with no album art (and probably no id3, untested) | |
const encapsulatemp3insidemp4 = (function() { | |
// firefox mediasource extensions support | |
// encapsulate cbr 128 kbps mp3 inside audio/mp4 | |
// jollo.org 0BSD or LNT | |
const encapsulation = (function() { | |
function bumpsum(prev, pad, inc) { | |
let hex = prev | |
hex = "0x" + hex | |
hex = parseInt(hex,16) | |
hex = hex + inc | |
hex = hex.toString(16) | |
return pad.substring(0, pad.length - hex.length) + hex | |
} | |
const header = [ | |
0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70, 0x69, 0x73, | |
0x6F, 0x6D, 0x00, 0x00, 0x02, 0x00, 0x69, 0x73, 0x6F, 0x6D, | |
0x69, 0x73, 0x6F, 0x36, 0x69, 0x73, 0x6F, 0x32, 0x6D, 0x70, | |
0x34, 0x31, 0x00, 0x00, 0x02, 0x9F, 0x6D, 0x6F, 0x6F, 0x76, | |
0x00, 0x00, 0x00, 0x6C, 0x6D, 0x76, 0x68, 0x64, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x03, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | |
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, | |
0x01, 0xA1, 0x74, 0x72, 0x61, 0x6B, 0x00, 0x00, 0x00, 0x5C, | |
0x74, 0x6B, 0x68, 0x64, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | |
0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x01, 0x3D, 0x6D, 0x64, 0x69, 0x61, 0x00, 0x00, 0x00, 0x20, | |
0x6D, 0x64, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, 0x44, | |
0x00, 0x00, 0x00, 0x00, 0x55, 0xC4, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x2D, 0x68, 0x64, 0x6C, 0x72, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x73, 0x6F, 0x75, 0x6E, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x53, 0x6F, 0x75, 0x6E, 0x64, 0x48, 0x61, 0x6E, 0x64, 0x6C, | |
0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x6D, 0x69, 0x6E, | |
0x66, 0x00, 0x00, 0x00, 0x10, 0x73, 0x6D, 0x68, 0x64, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x24, 0x64, 0x69, 0x6E, 0x66, 0x00, 0x00, 0x00, 0x1C, 0x64, | |
0x72, 0x65, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x01, 0x00, 0x00, 0x00, 0x0C, 0x75, 0x72, 0x6C, 0x20, 0x00, | |
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAC, 0x73, 0x74, 0x62, | |
0x6C, 0x00, 0x00, 0x00, 0x60, 0x73, 0x74, 0x73, 0x64, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | |
0x50, 0x6D, 0x70, 0x34, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0xAC, | |
0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x65, 0x73, 0x64, | |
0x73, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x80, 0x80, 0x1B, | |
0x00, 0x01, 0x00, 0x04, 0x80, 0x80, 0x80, 0x0D, 0x6B, 0x15, | |
0x00, 0x00, 0x00, 0x00, 0x01, 0xF4, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x06, 0x80, 0x80, 0x80, 0x01, 0x02, 0x00, 0x00, 0x00, | |
0x10, 0x73, 0x74, 0x74, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x73, 0x74, 0x73, | |
0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x14, 0x73, 0x74, 0x73, 0x7A, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x10, 0x73, 0x74, 0x63, 0x6F, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6D, | |
0x76, 0x65, 0x78, 0x00, 0x00, 0x00, 0x20, 0x74, 0x72, 0x65, | |
0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, | |
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x75, | |
0x64, 0x74, 0x61, 0x00, 0x00, 0x00, 0x5A, 0x6D, 0x65, 0x74, | |
0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x68, | |
0x64, 0x6C, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x6D, 0x64, 0x69, 0x72, 0x61, 0x70, 0x70, 0x6C, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x2D, 0x69, 0x6C, 0x73, 0x74, 0x00, 0x00, 0x00, 0x25, | |
0xA9, 0x74, 0x6F, 0x6F, 0x00, 0x00, 0x00, 0x1D, 0x64, 0x61, | |
0x74, 0x61, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, | |
0x4C, 0x61, 0x76, 0x66, 0x35, 0x38, 0x2E, 0x34, 0x38, 0x2E, | |
0x31, 0x30, 0x30 | |
] | |
let s = [] | |
let sendheader = true | |
let granularever = false | |
let granularpad = "000000000000" | |
let framepad = "00000000" | |
let sums = { | |
frame: "1", | |
granular: "0" | |
} | |
const tick = function(begseg, midseg, endseg) { | |
let info = [ | |
0x00, 0x00, 0x01, 0x00, 0x6D, 0x6F, 0x6F, 0x66, 0x00, 0x00, | |
0x00, 0x10, 0x6D, 0x66, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xE8, 0x74, 0x72, | |
0x61, 0x66, 0x00, 0x00, 0x00, 0x1C, 0x74, 0x66, 0x68, 0x64, | |
0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, | |
0x04, 0x80, 0x00, 0x00, 0x01, 0xA2, 0x02, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x14, 0x74, 0x66, 0x64, 0x74, 0x01, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x80, | |
0x00, 0x00, 0x00, 0xB0, 0x74, 0x72, 0x75, 0x6E, 0x00, 0x00, | |
0x02, 0x01, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x01, 0x08, | |
0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, | |
0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, | |
0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, | |
0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, | |
0x00, 0x00, 0x01, 0xA1, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, | |
0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, | |
0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, | |
0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, | |
0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, | |
0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, | |
0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, | |
0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, | |
0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, | |
0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, | |
0x00, 0x00, 0x01, 0xA1, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, | |
0x01, 0xA2, 0x00, 0x00, 0x01, 0xA2, 0x00, 0x00, 0x3F, 0xB4, | |
0x6D, 0x64, 0x61, 0x74 | |
] | |
let pxframe = "" | |
let pxgranular = "" | |
if (!granularever) { | |
granularever = true | |
pxframe = "00000001", | |
pxgranular = "000000000000" | |
} | |
else { | |
var granularbump = bumpsum(sums.granular, granularpad, 44928) | |
var framebump = bumpsum(sums.frame, framepad, 1) | |
var granularusable = granularbump | |
var frameusable = framebump | |
sums["granular"] = granularbump | |
sums["frame"] = framebump | |
pxframe = frameusable, | |
pxgranular = granularusable | |
} | |
for (let i=0,f=20;i<8;i+=2,f++) { | |
let sub = pxframe.slice(i,i+2) | |
info[f] = parseInt("0x"+sub, "hex") | |
} | |
info[55] = begseg | |
for (let i=0,f=74;i<12;i+=2,f++) { | |
let sub = pxgranular.slice(i,i+2) | |
info[f] = parseInt("0x"+sub, "hex") | |
} | |
for (let i=0,f=103;i<midseg.length;i++,f++) { | |
info[f] = midseg[i] | |
} | |
info[259] = endseg | |
return info | |
} | |
let segments = [] | |
let pattern = "" | |
let sync = false | |
let segment = "" | |
const interlace = function(mp3bytearray) { | |
s.push(...mp3bytearray) | |
if (s.length < 2500) { | |
return null | |
} | |
let seekable = true | |
while (seekable) { | |
for (let i=0;i<s.length-900;i++) { | |
if (s[i] !== 0xFF || s[i+1] !== 0xFB | |
|| (s[i+2] !== 0x92 && s[i+2] !== 0x90)) { | |
continue | |
} | |
let es = s[i+2] === 0x92 ? 418 : 417 | |
if (s[i+es] !== 0xFF || s[i+es+1] !== 0xFB | |
|| (s[i+es+2] !== 0x92 && s[i+es+2] !== 0x90)) { | |
continue | |
} | |
let ys = s[i+es+2] === 0x92 ? 418 : 417 | |
if (s[i+es+ys] !== 0xFF || s[i+es+ys+1] !== 0xFB | |
|| (s[i+es+ys+2] !== 0x92 && s[i+es+ys+2] !== 0x90)) { | |
continue | |
} | |
sync = true | |
pattern += s[i+2] === 0x92 ? "-" : "x" | |
s.splice(0,i) | |
segment = s.splice(0,es) | |
segments.push(...segment) | |
break | |
} | |
if (!sync) { | |
s.splice(0,s.length-900) | |
} | |
if (pattern.length > 38 || s.length < 900) { | |
seekable = false | |
} | |
} | |
if (pattern.length > 38) { | |
let midseg = [] | |
for (let j=0;j<pattern.length;j++) { | |
if (pattern[j] === "x") { | |
midseg.push(...[161,0,0,1]) | |
} | |
else { | |
midseg.push(...[162,0,0,1]) | |
} | |
} | |
midseg.pop() | |
let begseg = pattern.substring(0,1) === "x" ? 0xA1 : 0xA2 | |
let endseg = 182 - (pattern.replace(/\-/g, "")).length | |
let response = [] | |
if (sendheader) { | |
sendheader = false | |
response.push(...header) | |
} | |
let box = tick(begseg, midseg, endseg) | |
response.push(...box) | |
response.push(...segments) | |
sync = false | |
pattern = "" | |
segments = [] | |
segment = "" | |
return response | |
} | |
else { | |
return null | |
} | |
} | |
return { | |
interlace | |
} | |
})() | |
return encapsulation.interlace | |
})(); | |
// e.g. | |
// let mp4 = encapsulatemp3insidemp4(Uint8Array) | |
// if (mp4) { | |
// mp4 = Uint8Array.from(mp4) | |
// } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment