Skip to content

Instantly share code, notes, and snippets.

@hsiaosiyuan0
Created April 5, 2020 06:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hsiaosiyuan0/a7b215b53b48b9e66d2e0bad9eb8d1dd to your computer and use it in GitHub Desktop.
Save hsiaosiyuan0/a7b215b53b48b9e66d2e0bad9eb8d1dd to your computer and use it in GitHub Desktop.
function toAscii(i: number) {
return [i >> 24, (i & 0xff0000) >> 16, (i & 0xff00) >> 8, i & 0xff]
.map((c) => String.fromCharCode(c))
.join("");
}
type Optional<T> = { r: T; e: null } | { r: null; e: Error };
export async function deflate<T>(p: Promise<T>): Promise<Optional<T>> {
return p
.then((res) => Promise.resolve<{ r: T; e: null }>({ r: res, e: null }))
.catch((err) =>
Promise.resolve<{ r: null; e: Error }>({ r: null, e: err })
);
}
const rRange = /(\d+)-(\d+)\/(\d+)/;
interface FetchRangeParams {
from: number;
to: number;
url: string;
}
interface FetchRangeResult {
begin: number;
end: number;
total: number;
bytes: ArrayBuffer;
}
async function fetchRange({
from,
to,
url,
}: FetchRangeParams): Promise<Optional<FetchRangeResult>> {
const resp = await deflate(
fetch(url, {
headers: {
Range: `bytes=${from}-${to}`,
},
})
);
if (resp.e) return { r: null, e: resp.e };
const mathResults = resp.r.headers.get("Content-Range")?.match(rRange);
if (!mathResults) return { r: null, e: new Error("deformed response") };
const [, begin, end, total] = mathResults;
const bytes = await resp.r.arrayBuffer();
return {
r: {
begin: parseInt(begin, 10),
end: parseInt(end, 10),
total: parseInt(total, 10),
bytes,
},
e: null,
};
}
interface FindMoovResult {
size: number;
from: number;
times: number;
}
async function locateMoov(url: string): Promise<Optional<FindMoovResult>> {
const times = 10;
let i = times;
let from = 0;
let to = 8;
while (times) {
const resp = await fetchRange({
from,
to,
url,
});
if (resp.e) return { r: null, e: resp.e };
const dv = new DataView(resp.r.bytes, 0, resp.r.bytes.byteLength);
const size = dv.getUint32(0);
const boxtype = toAscii(dv.getUint32(4));
if (boxtype === "moov") {
return { r: { size, from, times: times - i }, e: null };
}
console.log(`box is [${boxtype}], continue seeking...`);
from = from + size;
to = from + 8;
i--;
}
return { r: null, e: new Error("cannot find moov") };
}
(async () => {
const url = "https://www.dropbox.com/s/fl02xpyhz8693b0/mv.mp?dl=1";
const resp = await locateMoov(url);
if (resp.e) {
console.error(resp.e);
return;
}
console.log(
`found moov at ${resp.r.from}, size is ${resp.r.size} after ${resp.r.times} times seeking`
);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment