Comments (12)
Sorry, I haven't been very available in recent weeks. Thanks for finding the problem to you @Vanilagy and @nsharma1396
from webm-muxer.
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)
})
from webm-muxer.
@Vanilagy Sorry for the late response.
Thank you for your work
- OK I see clearly. I'll put it after finalize.
- Everything works fine with the ArrayBufferTarget.
I'll take care of making a repository for you and sending you an example of a broken file. Give me a few days.
from webm-muxer.
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.
from webm-muxer.
I also have two good practice questions.
- Is it better to move everything into the end callback of the muxer?
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' })
}
...
})
- I saw that you never close the VideoEncoder in the demos with the close() method. Is there a reason for that?
from webm-muxer.
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 finalize
. Honestly, there isn't much you need to do in that onDone
callback - you could do it all right after you call finalize
- same effect.
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 ArrayBufferTarget
instead, does the seeking remain broken? If it works, then there's an issue with the StreamTarget
. Either a bug on my side or an error in your usage which I have yet to spot.
Would be awesome if you could send me some of the incorrect files, and also try out the ArrayBufferTarget
thing and see if that fixes seeking :)
from webm-muxer.
Still need help?
from webm-muxer.
I am getting the same issue where saved files is not seekable after saving via the StreamTarget
approach. At times, file was having incorrect seeking info, for example, it produced duration of 10 seconds for a 20 seconds file.
Files are seekable with the ArrayBufferTarget
from webm-muxer.
Understood, it seems like there might be a bug with StreamTarget
. Alternatively, it could be that we're using Node's API wrong, but I don't see how.
Let's try to test StreamTarget
by using its output to construct a single ArrayBuffer
, which we'll then write to disk. If StreamTarget
works fine, this should be identical to using ArrayBufferTarget
- if not, we'll know the culprit.
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 output.webm
contains the same issue.
from webm-muxer.
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?
from webm-muxer.
Sorry for the late response
I tried this out and it worked!! Thanks so much once again!
Although, just for reference for others:
We cannot call fileHandle.close
in the onDone callback as the flushed data buffer from webm-muxer
will still not be written to the file yet.
Also as per nodejs doc:
It is unsafe to use filehandle.write() multiple times on the same file without waiting for the promise to be resolved (or rejected).
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 fileHandle.close
once the following two conditions are met:
- All data chunks are flushed (onDone callback)
- All data chunks are written
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.
from webm-muxer.
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
),
// ...
});
from webm-muxer.
Related Issues (20)
- Need help with YouTube Live Ingest using HLS HOT 1
- Support transparency / alpha by encoding stream HOT 8
- Timeline for Firefox VideoEncoder support HOT 4
- Can microphone audio be synthesized when recording screen? HOT 2
- Are there plans to support demux webm fileοΌ HOT 2
- Provide package as ESM module HOT 2
- VideoDecoder? HOT 1
- How to use with PHP? HOT 10
- Writing to disk via node HOT 3
- Help with multimedia file (muxing audio and video) HOT 12
- is one chunk equals to one segment ? HOT 23
- webmmuxer throws Matroska cluster too big error even with 10 seconds keyframe interval. HOT 8
- Chrome throwing error and failing to export video HOT 2
- Dynamic browser support HOT 6
- StreamTarget onDone not available anymore since v4.0.0 HOT 1
- Stream to web storage HOT 2
- Video is flickering, seems to be related to slow Android device HOT 6
- comparison HOT 5
- Create webm/audio HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from webm-muxer.