yusitnikov / fix-webm-duration

navigator.mediaDevices.getUserMedia + MediaRecorder create WEBM files without duration metadata. This library appends missing metadata section right to the file blob.
MIT License
248 stars 48 forks source link

[fix-webm-duration] Duration section is present #1

Closed losnappas closed 5 years ago

losnappas commented 5 years ago

I'm recording a webm from a video element with HTMLMediaElement.mozCaptureStream and, long story short, the resulting duration is N/A according to ffmpeg. File explorer (nautilus) reports the duration as 0 seconds as well.

As the title implies, I get the "Duration section is present" error anyway. Can I get around this? Maybe remove the duration section first, if that's possible?

I also tried removing the return false from that part. ffmpeg gave a proper duration after that, but Nautilus still says 0 seconds, and firefox reports that the file is corrupt.

losnappas commented 5 years ago

I fixed it like this:

var durationSection = infoSection.getSectionById(0x489);
if (!durationSection) {
    console.log('[fix-webm-duration] Duration section is missing');
    // set default time scale to 1 millisecond (1000000 nanoseconds)
    timeScaleSection.setValue(1000000);
}

Well I'm not sure if that's a goood fix. But for my case timeScaleSection.setValue was breaking it.

losnappas commented 5 years ago

Oh, and by the way. There's no license on this. Is it okay if I use it? You should put in a license. It's a good library^^.

yusitnikov commented 5 years ago

Hi @losnappas , I want to move this fix into the repo. Can you provide me with some reproduction details please? Recorder code and/or recorded video example (before fixing it), browser name / version.

And yep, it's totally free to use. I'll add a license soon :)

Thanks for a feedback!

yusitnikov commented 5 years ago

I tried example from here and added fix-webm-duration on top of it: https://jsfiddle.net/Lkzs824y/ Latest Firefox: mozCaptureStream already generates a file with "duration" and "time scale" sections, and the time scale is correct. Nothing left to fix. Latest Chrome from dev channel: captureStream generates a file without "duration" section, but time scale is correct. The "fixer" script appends duration section. So I wasn't able to reproduce the issue. Example file would help a lot.

losnappas commented 5 years ago

I made an example. Can't run it on jsfiddle because the video needs to be 1st party.

I don't know why your fiddle worked, but this example doesn't...

Just pasting it. page.html:

<html>
    <body>
<video id="videoElement" src="YOURWEBMVIDEO.webm" autoplay width="120"></video>
<a href="" id="downloadButton" download="test.webm">wait for it to finish first</a>

<script src="https://cdn.jsdelivr.net/gh/yusitnikov/fix-webm-duration/fix-webm-duration.js"></script>
<script src="main.js"></script>
</body>
</html>

main.js

var log = console.log
let recordingTimeMS = 2000;
function wait(delayInMS) {
  return new Promise(resolve => setTimeout(resolve, delayInMS));
}
function startRecording(stream, lengthInMS) {
  let recorder = new MediaRecorder(stream);
  let data = [];
  recorder.ondataavailable = event => data.push(event.data);
  recorder.start();
  log(recorder.state + " for " + (lengthInMS/1000) + " seconds...");
  let stopped = new Promise((resolve, reject) => {
    recorder.onstop = resolve;
    recorder.onerror = event => reject(event.name);
  });
  let recorded = wait(lengthInMS).then(
    () => recorder.state == "recording" && recorder.stop()
  );
  return Promise.all([
    stopped,
    recorded
  ])
  .then(() => data);
} 
let stream = videoElement.mozCaptureStream()
startRecording(stream, recordingTimeMS).then(data => {
    let recordedBlob = new Blob(data, {type: 'video/webm'})

    log('done', recordedBlob, ysFixWebmDuration)
    ysFixWebmDuration(recordedBlob, recordingTimeMS, function(fixedBlob) {
        log('done')
        downloadButton.href = URL.createObjectURL(fixedBlob);
        downloadButton.download = "RecordedVideo.webm";
        downloadButton.innerHTML = 'finished'
    })
})

Download it, then using ffmpeg to check the metadata: ffmpeg -i RecordedVideo.webm -f ffmetadata "Duration: N/A"

yusitnikov commented 5 years ago

@losnappas , issue fixed in the main branch. FF records a file with a "Duration" section, but the value there is 0. The new version of the script sets the right duration value in that case.