Skip to content

Commit

Permalink
feat: support load file url
Browse files Browse the repository at this point in the history
  • Loading branch information
ForeverSc committed Oct 10, 2024
1 parent 96f474a commit 311916c
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 50 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ Parameters:
> ⚠️ You must ensure that the wasm and JavaScript loader files are placed in the same accessible directory, the JavaScript loader will default to requesting the wasm file in the same directory.
```typescript
load(file: File): Promise<void>
load(source: File | string): Promise<void>
```
Loads a file and waits for the wasm worker to finish loading. The subsequent methods can only be called after the `load` method has been successfully executed.

Parameters:
- `file`: Required, the `File` object to be processed.
- `source`: Required, support the `File` object or file URL to be processed.

```typescript
getVideoDecoderConfig(): Promise<VideoDecoderConfig>
Expand Down
4 changes: 2 additions & 2 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ new WebDemuxer(options: WebDemuxerOptions)
> ⚠️ 你需要确保将wasm 和js loader文件放在同一个可访问目录下,js loader会默认去请求同目录下的wasm文件
```typescript
load(file: File): Promise<void>
load(source: File | string): Promise<void>
```
加载文件并等待wasm worker加载完成。需要等待load方法执行成功后,才可以继续调用后续的方法

参数:
- `file`: 必填,需要处理的`File`对象
- `source`: 必填,需要处理的`File`对象或者文件URL

```typescript
getVideoDecoderConfig(): Promise<VideoDecoderConfig>
Expand Down
109 changes: 96 additions & 13 deletions lib/web-demuxer/post.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,88 @@
function sleep(duration) {
const start = Date.now();

while (Date.now() - start < duration) {
// sync wait
}
}

function retry(fn, retries = 3, delay = 500) {
let attempt = 0;

while (attempt < retries) {
try {
return fn();
} catch (error) {
console.warn(`Attempt ${attempt + 1} failed: ${error.message}`);
attempt++;
if (attempt >= retries) {
throw new Error(`Failed after ${retries} attempts`);
}
sleep(delay)
}
}
}

function getFileSize(url) {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
xhr.setRequestHeader('Range', 'bytes=0-1');
xhr.send();

if (xhr.status !== 206 && xhr.status !== 200) {
throw new Error(`getFileSize request failed: ${url}`);
}

const range = xhr.getResponseHeader('Content-Range');
const size = parseInt(range.split('/')[1], 10);

return size;
}

function fetchArrayBuffer(url, position, length) {
const xhr = new XMLHttpRequest();

xhr.open('GET', url, false);
xhr.setRequestHeader('Range', `bytes=${position}-${position + length - 1}`);
xhr.responseType = 'arraybuffer';
xhr.send();

if (xhr.status !== 206 && xhr.status !== 200) {
throw new Error(`fetchArrayBuffer request failed: ${url}`);
}

return xhr.response;
}

class WorkerFile {
constructor(file) {
constructor(source) {
let file

if (typeof source === 'string') {
file = new File([], encodeURIComponent(source)); // create a placeholder file

// rewrite WORKERFS.stream_ops.read to support read from url
// https://github.com/emscripten-core/emscripten/blob/main/src/library_workerfs.js#L127-L133
FS.filesystems.WORKERFS.stream_ops.read = function read(stream, buffer, offset, length, position) {
const url = decodeURIComponent(stream.node.contents.name);

if (stream.node.size === 0) {
stream.node.size = retry(() => getFileSize(url)) // rewrite the size
}

if (position >= stream.node.size) return 0;

const ab = retry(() => fetchArrayBuffer(url, position, length));
const byteLength = ab.byteLength;

buffer.set(new Uint8Array(ab), offset);

return byteLength;
}
} else {
file = source;
}

this.mountPoint = "/data";
this.mountOpts = {
files: [file],
Expand Down Expand Up @@ -81,8 +164,8 @@ function avPacketToObject(avPacket) {
return result;
}

function getAVStream(file, type = 0, streamIndex = -1) {
const workerFile = new WorkerFile(file);
function getAVStream(source, type = 0, streamIndex = -1) {
const workerFile = new WorkerFile(source);

workerFile.mount();

Expand All @@ -97,8 +180,8 @@ function getAVStream(file, type = 0, streamIndex = -1) {
}
}

function getAVStreams(file) {
const workerFile = new WorkerFile(file);
function getAVStreams(source) {
const workerFile = new WorkerFile(source);

workerFile.mount();

Expand All @@ -120,8 +203,8 @@ function getAVStreams(file) {
}
}

function getMediaInfo(file) {
const workerFile = new WorkerFile(file);
function getMediaInfo(source) {
const workerFile = new WorkerFile(source);

workerFile.mount();

Expand Down Expand Up @@ -150,8 +233,8 @@ function getMediaInfo(file) {
}
}

function getAVPacket(file, time, type = 0, streamIndex = -1, seekFlag = 1) {
const workerFile = new WorkerFile(file);
function getAVPacket(source, time, type = 0, streamIndex = -1, seekFlag = 1) {
const workerFile = new WorkerFile(source);

workerFile.mount();

Expand All @@ -166,8 +249,8 @@ function getAVPacket(file, time, type = 0, streamIndex = -1, seekFlag = 1) {
}
}

function getAVPackets(file, time, seekFlag = 1) {
const workerFile = new WorkerFile(file);
function getAVPackets(source, time, seekFlag = 1) {
const workerFile = new WorkerFile(source);

workerFile.mount();

Expand All @@ -191,14 +274,14 @@ function getAVPackets(file, time, seekFlag = 1) {

async function readAVPacket(
msgId,
file,
source,
start = 0,
end = 0,
type = 0,
streamIndex = -1,
seekFlag = 1
) {
const workerFile = new WorkerFile(file);
const workerFile = new WorkerFile(source);

workerFile.mount();

Expand Down
24 changes: 12 additions & 12 deletions src/ffmpeg.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ async function handleLoadWASM(data: LoadWASMMessageData) {
}

function handleGetAVStream(data: GetAVStreamMessageData, msgId: number) {
const { file, streamType, streamIndex } = data;
const result = Module.getAVStream(file, streamType, streamIndex);
const { source, streamType, streamIndex } = data;
const result = Module.getAVStream(source, streamType, streamIndex);

self.postMessage(
{
Expand All @@ -60,8 +60,8 @@ function handleGetAVStream(data: GetAVStreamMessageData, msgId: number) {
}

function handleGetAVStreams(data: GetAVStreamsMessageData, msgId: number) {
const { file } = data;
const result = Module.getAVStreams(file);
const { source } = data;
const result = Module.getAVStreams(source);

self.postMessage(
{
Expand All @@ -74,8 +74,8 @@ function handleGetAVStreams(data: GetAVStreamsMessageData, msgId: number) {
}

function handleGetMediaInfo(data: GetMediaInfoMessageData, msgId: number) {
const { file } = data;
const result = Module.getMediaInfo(file);
const { source } = data;
const result = Module.getMediaInfo(source);

self.postMessage(
{
Expand All @@ -88,8 +88,8 @@ function handleGetMediaInfo(data: GetMediaInfoMessageData, msgId: number) {
}

function handleGetAVPacket(data: GetAVPacketMessageData, msgId: number) {
const { file, time, streamType, streamIndex, seekFlag } = data;
const result = Module.getAVPacket(file, time, streamType, streamIndex, seekFlag);
const { source, time, streamType, streamIndex, seekFlag } = data;
const result = Module.getAVPacket(source, time, streamType, streamIndex, seekFlag);

self.postMessage(
{
Expand All @@ -102,8 +102,8 @@ function handleGetAVPacket(data: GetAVPacketMessageData, msgId: number) {
}

function handleGetAVPackets(data: GetAVPacketsMessageData, msgId: number) {
const { file, time, seekFlag } = data;
const result = Module.getAVPackets(file, time, seekFlag);
const { source, time, seekFlag } = data;
const result = Module.getAVPackets(source, time, seekFlag);

self.postMessage(
{
Expand All @@ -116,10 +116,10 @@ function handleGetAVPackets(data: GetAVPacketsMessageData, msgId: number) {
}

async function handleReadAVPacket(data: ReadAVPacketMessageData, msgId: number) {
const { file, start, end, streamType, streamIndex, seekFlag } = data;
const { source, start, end, streamType, streamIndex, seekFlag } = data;
const result = await Module.readAVPacket(
msgId,
file,
source,
start,
end,
streamType,
Expand Down
12 changes: 6 additions & 6 deletions src/types/ffmpeg-worker-message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,31 @@ export type FFMpegWorkerMessageData =
| GetMediaInfoMessageData;

export interface GetAVStreamMessageData {
file: File;
source: File | string;
streamType: AVMediaType;
streamIndex: number;
}

export interface GetAVStreamsMessageData {
file: File;
source: File | string;
}

export interface GetAVPacketMessageData {
file: File;
source: File | string;
time: number;
streamType: AVMediaType;
streamIndex: number;
seekFlag: AVSeekFlag;
}

export interface GetAVPacketsMessageData {
file: File;
source: File | string;
time: number;
seekFlag: AVSeekFlag;
}

export interface ReadAVPacketMessageData {
file: File;
source: File | string;
start: number;
end: number;
streamType: AVMediaType;
Expand All @@ -64,7 +64,7 @@ export interface LoadWASMMessageData {
}

export interface GetMediaInfoMessageData {
file: File;
source: File | string;
}

export interface SetAVLogLevelMessageData {
Expand Down
Loading

0 comments on commit 311916c

Please sign in to comment.