- From: guest271314 via GitHub <sysbot+gh@w3.org>
- Date: Sat, 17 Mar 2018 15:47:04 +0000
- To: public-media-capture-logs@w3.org
Since this issue is still open the inquiry appears to have not been resolved. If a `MediaStream` is active `MediaRecorder` should record the existing video and audio `MediaStreamTrack`s, instread of only recording the initial track, or possibly recording only portions of subsequent tracks added to the active `MediaStream`. Given the code Chromium ``` <!DOCTYPE html> <html> <head> <title>Record media fragments to single video using HTMLMediaElement.captureStream(), MediaRecorder, and MediaSource</title> </head> <body> <video width="320" height="280" autoplay="true"></video> <script> // https://github.com/guest271314/MediaFragmentRecorder/ 3-11-2018 // https://github.com/w3c/media-source/issues/190 const captureStream = mediaElement => !!mediaElement.mozCaptureStream ? mediaElement.mozCaptureStream() : mediaElement.captureStream(); 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"; video.controls = true; // video.muted = true; let videoStream = document.querySelector("video"); const chunks = []; let duration = 0; let mediaStream = new MediaStream(); videoStream.srcObject = mediaStream; let recorder; mediaStream.addEventListener("inactive", e => { console.log(e) }); mediaStream.addEventListener("active", e => { console.log(e); recorder = new MediaRecorder(e.target, { mimeType: "video/webm;codecs=vp8,opus" }); recorder.start(); recorder.addEventListener("dataavailable", e => { console.log(e, e.data); let media = document.createElement("video"); media.width = width; media.height = height; media.controls = true; document.body.appendChild(media); media.src = URL.createObjectURL(e.data); }); recorder.addEventListener("stop", e => { console.log(e) }); }); mediaStream.addEventListener("addtrack", e => { console.log(e) }); mediaStream.addEventListener("removetrack", e => { console.log(e) }); 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 } })); for (let { from, to, blob } of media) { await new Promise(async(resolve) => { const blobURL = URL.createObjectURL(blob); video.addEventListener("playing", e => { let stream = captureStream(video); let tracks = stream.getTracks(); for (let track of tracks) { mediaStream.addTrack(track) } for (let track of mediaStream.getTracks()) { if (tracks.find(({ id }) => track.id === id) === undefined) { mediaStream.removeTrack(track); } } video.addEventListener("pause", e => { resolve(); console.log(video.played.end(0) - video.played.start(0), video.currentTime - from, video.currentTime); duration += video.currentTime - from; }, { once: true }); }, { once: true }); video.addEventListener("canplay", e => video.play(), { once: true }); video.src = `${blobURL}#t=${from},${to}`; }) }; recorder.stop(); video.load(); return { chunks, duration, width, height, video } })() } } 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 }) </script> </body> </html> ``` Firefox ``` <!DOCTYPE html> <html> <head> <title>Record media fragments to single video using HTMLMediaElement.captureStream(), MediaRecorder, and MediaSource</title> </head> <body> <video width="320" height="280" autoplay="true"></video> <script> // https://github.com/guest271314/MediaFragmentRecorder/ 3-11-2018 // https://github.com/w3c/media-source/issues/190 const captureStream = mediaElement => !!mediaElement.mozCaptureStream ? mediaElement.mozCaptureStream() : mediaElement.captureStream(); 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"; video.controls = true; // video.muted = true; let videoStream = document.querySelector("video"); const chunks = []; let duration = 0; let mediaStream = new MediaStream(); videoStream.srcObject = mediaStream; let recorder; mediaStream.addEventListener("inactive", e => { console.log(e) }); mediaStream.addEventListener("active", e => { console.log(e); }); mediaStream.addEventListener("addtrack", e => { console.log(e) }); mediaStream.addEventListener("removetrack", e => { console.log(e) }); 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 } })); for (let { from, to, blob } of media) { await new Promise(async(resolve) => { const blobURL = URL.createObjectURL(blob); video.addEventListener("playing", e => { let stream = captureStream(video); let tracks = stream.getTracks(); //if (recorder) recorder.pause(); for (let track of tracks) { mediaStream.addTrack(track) } if (!recorder) { recorder = new MediaRecorder(mediaStream, { mimeType: "video/webm;codecs=vp8,opus" }); recorder.addEventListener("start", e => { console.log(e) }); recorder.start(); recorder.addEventListener("dataavailable", e => { console.log(e, e.data); let media = document.createElement("video"); media.width = width; media.height = height; media.controls = true; document.body.appendChild(media); media.src = URL.createObjectURL(e.data); }); recorder.addEventListener("stop", e => { console.log(e) }); } for (let track of mediaStream.getTracks()) { if (tracks.find(({ id }) => track.id === id) === undefined) { mediaStream.removeTrack(track); } } // if (recorder) recorder.resume(); video.addEventListener("pause", e => { resolve(); console.log(video.played.end(0) - video.played.start(0), video.currentTime - from, video.currentTime); duration += video.currentTime - from; }, { once: true }); }, { once: true }); video.addEventListener("canplay", e => video.play(), { once: true }); video.src = `${blobURL}#t=${from},${to}`; }) }; recorder.stop(); video.load(); return; })() } } 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 }) </script> </body> </html> ``` the `MediaStream` `state` is `active` throughout the procedure. Though all of the `MediaStreamTrack`s are not recorded. If it is not possible to record an array of `MediaStreamTrack`s in sequence, then `MediaRecorder` should at least be able to recognize that the new (only video or audio) track should be recorded "seamlessly" concatenated to the recorded media of the previous tracks, similar to `.pause()` and `.resume()` functionality. -- GitHub Notification of comment by guest271314 Please view or discuss this issue at https://github.com/w3c/mediacapture-record/issues/4#issuecomment-373930061 using your GitHub account
Received on Saturday, 17 March 2018 15:47:10 UTC