W3C home > Mailing lists > Public > public-media-capture@w3.org > March 2018

[mediacapture-record] Capturing MediaStream from HTMLMediaElement where src is set to MediaSource crashes tab

From: guest271314 via GitHub <sysbot+gh@w3.org>
Date: Fri, 09 Mar 2018 17:48:17 +0000
To: public-media-capture@w3.org
Message-ID: <issues.opened-303924746-1520617696-sysbot+gh@w3.org>
guest271314 has just created a new issue for https://github.com/w3c/mediacapture-record:

== Capturing MediaStream from HTMLMediaElement where src is set to MediaSource crashes tab ==
Attempting to capture `MediaStream` from `HTMLMediaElement` where `src` is set to `MediaSource` consistently crashes tab at Chromium 64, see https://github.com/w3c/web-platform-tests/issues/9947

```
<!DOCTYPE html>
<html>
<head>
  <title>Record media fragments of any MIME type to single video using HTMLMediaElement.captureStream(), MediaRecorder, and MediaSource</title>
</head>
<body>
  <script>
    class MediaFragmentRecorder {
      constructor({
        urls = [], video = document.createElement("video"), width = 320, height = 280
      } = {}) {
        if (urls.length === 0) {
          throw new TypeError("no urls passed to MediaFragmentRecorder");
        }
        return (async() => {
          video.height = height;
          video.width = width;
          video.autoplay = true;
          video.preload = "auto";
          const chunks = [];
          let duration = 0;
          let media = await Promise.all(
            urls.map(async({
              from, to, src
            }, index) => {
              const url = new URL(src);
              // get media fragment hash from `src`
              if (url.hash.length) {
                [from, to] = url.hash.match(/\d+/g);
              }
              return {
                blob: await fetch(src).then(response => response.blob()),
                from,
                to
              }
            }));         
          // using `Promise.all()` here apparently is not the same
          // as recording the media in sequence as the next video
          // is not played when a buffer is added to `MediaSource`
          for (let {
              from, to, blob
            }
            of media) {
            await new Promise(async(resolve) => {
              let recorder;
              const blobURL = URL.createObjectURL(blob);
              video.addEventListener("playing", e => {
                const stream = video.captureStream();
                recorder = new MediaRecorder(stream, {
                  mimeType: "video/webm"
                });
                recorder.start();
                recorder.addEventListener("stop", e => {
                  resolve();
                  console.log(e);
                }, {
                  once: true
                });
                recorder.addEventListener("dataavailable", async(e) => {
                  console.log(e);
                  chunks.push(await new Response(e.data).arrayBuffer());
                  URL.revokeObjectURL(blobURL);
                });
                video.addEventListener("pause", e => {
                  if (recorder.state === "recording") {
                    recorder.stop();
                  } else {
                    recorder.requestData();
                  }
                  duration += video.currentTime - from;
                }, {
                  once: true
                });

              }, {
                once: true
              });
              video.src = `${blobURL}#t=${from},${to}`;
            })
          };
          // using same `<video>` element at `.then()` does not
          // return expected result as to `autoplay`
          video.src = "";
          return {
            chunks, duration, width, height
          }
        })()
      }
    }
    let urls = [{
      src: "https://upload.wikimedia.org/wikipedia/commons/a/a4/Xacti-AC8EX-Sample_video-001.ogv",
      from: 0,
      to: 4
    }, {
      src: "https://mirrors.creativecommons.org/movingimages/webm/ScienceCommonsJesseDylan_240p.webm#t=10,20"
    }, {
      from: 55,
      to: 60,
      src: "https://nickdesaulniers.github.io/netfix/demo/frag_bunny.mp4"
    }, {
      from: 0,
      to: 5,
      src: "https://raw.githubusercontent.com/w3c/web-platform-tests/master/media-source/mp4/test.mp4"
    }, {
      from: 0,
      to: 5,
      src: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4"
    }, {
      from: 0,
      to: 5,
      src: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4"
    }, {
      src: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerMeltdowns.mp4#t=0,6"
    }];

    new MediaFragmentRecorder({
        urls
      })
      .then(({
        chunks, duration, width, height
      }) => {
        let recorder, mediaStream;
        console.log(chunks, duration);
        const video = document.createElement("video");
        document.body.appendChild(video);
        video.controls = true;
        video.preload = "auto";
        video.autoplay = true;
        video.width = width;
        video.height = height;
        const mediaSource = new MediaSource();
        const mimeCodec = "video/webm;codecs=vp8,opus";
        const sourceOpen = e => {
          console.log(e);
          const sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
          sourceBuffer.mode = "sequence";
          sourceBuffer.addEventListener("updateend", e => {
            console.log(e);
          });
          sourceBuffer.appendBuffer(chunks.shift());
        }
        const handleWaiting = e => {
          console.log(e);
          if (chunks.length) {
            mediaSource.sourceBuffers[0].appendBuffer(chunks.shift())
          } else {
            console.log(e);
            video.autoplay = false;
            video.removeEventListener("waiting", handleWaiting);
            // https://bugs.chromium.org/p/chromium/issues/detail?id=642012
            // `seeked` is not dispatched here
            /*
            video.addEventListener("seeked", e => {
                video.currentTime = 0;
                console.info(e, video.duration);
            }, {once:true});
            video.currentTime = 1e5;
            */
            // we do not get this far before tab crashes
            recorder.stop();
          }
        }
        mediaSource.sourceBuffers.addEventListener("addsourcebuffer", e => {
          console.log(e)
        });
        video.addEventListener("canplay", e => {
          console.log(e, duration, video.buffered.end(0), video.duration, mediaSource.duration);
        });
        video.addEventListener("playing", e => {
          // consistently crashes tab at Chromium 64       
          mediaStream = video.captureStream();
          recorder = new MediaRecorder(mediaStream, {mimeType:"video/webm"});
          recorder.addEventListener("dataavailable", e => {
            console.log(e);
          });
          recorder.start();         
          console.log(e, duration, video.buffered.end(0), video.duration, mediaSource.duration);
        }, {
          once: true
        });
        video.addEventListener("waiting", handleWaiting);
        video.addEventListener("pause", e => console.log(e));
        mediaSource.addEventListener("sourceopen", sourceOpen);
        video.src = URL.createObjectURL(mediaSource);
      })
  </script>
</body>
</html>
```

Please view or discuss this issue at https://github.com/w3c/mediacapture-record/issues/146 using your GitHub account
Received on Friday, 9 March 2018 17:48:20 UTC

This archive was generated by hypermail 2.4.0 : Friday, 17 January 2020 16:26:41 UTC