-
-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using with nodejs fs #25
Comments
Hey! This is totally possible by using the StreamTarget instead of the ArrayBufferTarget, as specified in the README. Here's a way you could do it with Node: const fs = require('fs');
import { Muxer, StreamTarget } from 'webm-muxer';
const fileStream = fs.createWriteStream('output.webm', { flags: 'r+' });
let muxer = new Muxer({
target: new StreamTarget(
(data, position) => {
fileStream.pos = position;
fileStream.write(data);
},
() => {
fileStream.end();
}
),
// ...
}); Let me know if this works for you. |
Thank you for your help! I just pay you a ko-fi. It works well but there is just one thing that doesn't work anymore, it's the seeking. Normally with firstTimestampBehavior set to 'offset'` it should work normally right? I should be able to have a seekable player bar ? const [ track ] = stream.value.getTracks()
const trackSettings = track.getSettings()
processor = new MediaStreamTrackProcessor(track)
inputStream = processor.readable
worker.postMessage({
command: 'init',
...
stream: inputStream
}, [ inputStream ]) worker fileStream = createWriteStream(join(DIRECTORY_PATH, `${newFilename}_${nanoid()}.webm`))
muxer = new Muxer({
target: new StreamTarget(
(data, position) => {
fileStream.pos = position
fileStream.write(data)
},
() => fileStream.end()
),
video: {...},
audio: false,
firstTimestampBehavior: 'offset'
})
encoder = new VideoEncoder({
output: (chunk, meta) => muxer.addVideoChunk(chunk, meta),
error: ({message}) => postMessage({ command: 'error', message })
})
...
frameReader = stream.getReader()
if (!existsSync(DIRECTORY_PATH)) {
mkdirSync(DIRECTORY_PATH, { recursive: true })
}
let frameCounter = 0
frameReader.read().then(async function processFrame({ done, value: frame }) {
if (done) {
postMessage({ command: 'finishing' })
await encoder.flush()
await muxer.finalize()
encoder.close()
return postMessage({ command: 'completed' })
}
if (encoder.encodeQueueSize <= config.framerate) {
++frameCounter % 20
const insert_keyframe = (frameCounter % 150) == 0
encoder.encode(frame, { keyFrame: insert_keyframe })
}
frame.close()
frameReader.read().then(processFrame)
}) |
I also have two good practice questions.
new Muxer({
target: new StreamTarget(
(data, position) => {
fileStream.pos = position
fileStream.write(data)
},
async () => {
// put here ?
postMessage({ command: 'finishing' })
await encoder.flush()
muxer.finalize()
fileStream.end()
postMessage({ command: 'completed' })
}
),
...
}) or it better here ? frameReader.read().then(async function processFrame({ done, value: frame }) {
if (done) {
// or here ?
postMessage({ command: 'finishing' })
await encoder.flush()
muxer.finalize()
return postMessage({ command: 'completed' })
}
...
})
|
Thank you for the Ko-fi!! <3 🐡 To your best practice questions: Moving everything into the end callback of the muxer doesn't make sense, as it will only be called when you call Now regarding the seeking: Strange; typically, in my experience, dysfunctional seeking means the file was written incorrectly. If you encode the file as you are right now, but use the Would be awesome if you could send me some of the incorrect files, and also try out the |
Still need help? |
@Vanilagy Sorry for the late response. Thank you for your work
I'll take care of making a repository for you and sending you an example of a broken file. Give me a few days. |
I am getting the same issue where saved files is not seekable after saving via the |
Understood, it seems like there might be a bug with Let's try to test Can you try using this sort of setup to test this? import { Muxer, StreamTarget } from 'webm-muxer';
let chunkArray: { data: Uint8Array; position: number }[] = [];
let totalLength = 0;
const onData = (data: Uint8Array, position: number) => {
chunkArray.push({ data, position });
totalLength = Math.max(totalLength, position + data.length);
};
const onDone = () => {
let finalBuffer = new ArrayBuffer(totalLength);
let finalUint8 = new Uint8Array(finalBuffer);
for (const { data, position } of chunkArray) {
finalUint8.set(data, position);
}
fs.writeFile('output.webm', finalUint8);
};
let muxer = new Muxer({
target: new StreamTarget(onData, onDone),
// ...
}); Check if |
Oh, I think we're using Node's streams wrong, don't think they support switching position. Let's try this again: import { open } from 'fs/promises';
import { Muxer, StreamTarget } from 'webm-muxer';
let fileHandle = await open('output.webm', 'w+');
let muxer = new Muxer({
target: new StreamTarget(
(data, position) => {
fileHandle.write(data, 0, data.length, position);
},
() => {
fileHandle.close();
},
{ chunked: true } // Writes larger chunks at once for better performance
),
// ...
}); Can you try this? |
Sorry for the late response Although, just for reference for others: Also as per nodejs doc:
So, I had to implement this in a way that waits for the write to be completed before writing the next data chunk and calls
I may be wrong in any of my above assumptions due to lesser familiarity with fileHandles, but I did this to make things work properly. |
Awesome, and good that you caught this detail. For completion, here's one way to implement this using a Promise chain: import { open } from 'fs/promises';
import { Muxer, StreamTarget } from 'webm-muxer';
let lastPromise = Promise.resolve();
let fileHandle = await open('output.webm', 'w+');
let muxer = new Muxer({
target: new StreamTarget(
(data, position) => {
lastPromise = lastPromise.then(() =>
fileHandle.write(data, 0, data.length, position)
);
},
() => {
lastPromise = lastPromise.then(() =>
fileHandle.close()
);
},
{ chunked: true } // Writes larger chunks at once for better performance
),
// ...
}); |
Sorry, I haven't been very available in recent weeks. Thanks for finding the problem to you @Vanilagy and @nsharma1396 |
Hi Vanilagy,
For an electronjs app, I have to stream the creation of a video without being able to use the Web File System API.
So I use "fs" and I wanted to know if there is a possibility to stream like the Web File System API? Currently I'm using the buffer but it's not ideal because I have long 4K videos.
Do you have the possibility to do something?
Thank you !
The text was updated successfully, but these errors were encountered: