- From: guest271314 via GitHub <sysbot+gh@w3.org>
- Date: Fri, 09 Mar 2018 17:48:59 +0000
- To: public-html-media@w3.org
guest271314 has just created a new issue for https://github.com/w3c/media-source:
== 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/media-source/issues/207 using your GitHub account
Received on Friday, 9 March 2018 17:49:01 UTC