MediaRecorder does not produce a valid WebM file - google-chrome

MediaRecorder.isTypeSupported() returns true for 'video/webm', 'video/webm;codecs=avc1', and 'video/webm;codecs=vp9'.
However, only mimeType='video/webm;codecs=vp9' results in a valid webm file ('video/webm;codecs=vp9,opus').
Setting mimeType to either 'video/webm' and 'video/webm;codecs=avc1' results in 'video/x-matroska;codecs=avc1,opus' file, which is not a valid webm video.
Is this a MediaRecorder bug, Chrome bug or am I missing something?\
Software: Chrome 85, MacOS 10.15. I have not tried this on Windows or Linux.

Reproduction:
const wantMimeType = 'video/webm;codecs=h264,opus';
if (MediaRecorder.isTypeSupported(wantMimeType)) {
let mediaRecorder = new MediaRecorder(stream, {
mimeType: wantMimeType,
});
// ...drive the recorder
mediaRecorder.onstop = (event) => {
try {
// returns 'video/x-matroska;codecs=avc1,opus' in Chrome,
// and the binary file content also says Matroska instead of WebM
let mimetype = mediaRecorder.mimeType;
if (!mimeType.startsWith('video/webm')) {
throw new Error(`We requested "${wantMimeType},
but the browser gave us "${mediaRecorder.mimeType}"`);
}
let blob = new Blob(chunks, { type: mimeType });
// ...convert to data: URL
// ...play it in <video src="data:..."> // won't work, if Matroska
} catch (ex) {
alert(ex);
}
};
}
Observations:
Chrome responds true to isTypeSupported('video/webm;codecs=h264,opus'), but Chrome actually does not support this combination, i.e. the response is factually incorrect and defeats the entire purpose of isTypeSupported().
Chrome ignores the mimetype that we pass in the MediaRecorder constructor, and instead returns video/x-matroska;codecs=avc1,opus. Which then doesn't work, because <video> won't play the Matroska mimetype.
2 solutions:
Hacky: After recording, just change the mimetype back to video/webm;codecs=h264,opus. The file content will still say "Matroska", but <video> on Chrome will play it. It's a bad solution, because we're passing in the wrong mimetype, it doesn't match the content. Other software - or Chrome in later versions - might break over it.
Proper: Don't use H.264, but VP9 or VP8. Chrome supports both, and Firefox supports VP8, and they work properly. As a bonus, they are open, while H.264 is riddled with software patents. Depending on the hardware encoder implementation, VP8/9 also may give better image quality results.

However, only mimeType='video/webm;codecs=vp9' results in a valid webm file.
Is this a MediaRecorder bug, Chrome bug or am I missing something?
WebM is the correct a/v media container for the VP8 and VP9 video codecs.
AVC1 video codec belongs into an MPEG container (.mp4, .m4v).
This video codec can also be contained inside an MKV media file (Matroska .mkv).

Related

MediaRecorder captured on Chrome not playable on Mobile or Safari

Goal: use MediaRecorder (or else) api to produce video files that are viewable cross platforms.
Fail: current api falls back to container/codec on google chrome which is only viewable on chrome and advanced desktop media players but not on Safari or mobile devices.
! Same code when running on safari generates a working video file on all platforms.
const mimeType = 'video/webm;codecs=H264'
rec = new MediaRecorder(stream.current, { mimeType })
rec.ondataavailable = e => blobs.push(e.data)
rec.onstop = async () => {
saveToFile(new Blob(blobs, { type: mimeType }))
}
Tried all different combinations of containers and codecs.
also tried to override the mimeType of the Blob with MP4 file container.
No success what so ever.
also tried:
https://github.com/streamproc/MediaStreamRecorder
https://github.com/muaz-khan/RecordRTC
Same issues. iI seems like chrome's container/codec combinations always fall back to a format that is only viewable out of the box on chrome or a powerful desktop video player like vlc.
The only cross platform working video for me is the one taken from safari browser and is the 5th from left in the picture above.
What is the correct container/codac to be used in MediaCapture api to make the output file playable cross platform.
Edit -
We ended up building a transcoding pipeline with AWS ElasticTranscoder, which takes the uploaded video and transcodes it with a general preset that is playable on all platforms thus creating a converted video file.
unfortunately the bounty I offered expired, but if someone answers the original question I would gladly reward him with the bounty again.
I think your problem may be in the first line:
const mimeType = 'video/webm;codecs=H264'
The container you are using is webm, which typically uses codecs VP8, VP9. H264 is a codec used in the mp4 container.
Chrome supports webm. Safari does not (and all iOS browsers are based on Safari - hence your mobile issue).
You say that run on Safari, this outputs a playable video. use ffprobe to see what codec/containers are outputted on Safari - I am guessing that there is a change in container/codec.
Since your video is h264, you must simply change the container to mp4, and it will play everywhere. This is a 'copy' from one container to the other, not a transcoding, but you'll still need ffmpeg :)
Here's a post that might help: Recording cross-platform (H.264?) videos using WebRTC MediaRecorder

Cannot replay MP3 in Firefox using MediaSource even though it works in Chrome

I have implemented a simple audio player in my web application and noticed that it is not working in Firefox (let me just ... 🎉).
What I get is an error:
ERROR DOMException: MediaSource.addSourceBuffer: Type not supported in MediaSource
This is followed by a warning:
Cannot play media. No decoders for requested formats: audio/mpeg
This is the implementation for the sourceopen event handler:
private onSourceOpen = (e) => {
this.logger.debug('onSourceOpen');
if (!this.sourceBuffer) {
this.sourceBuffer = this.mediaSource.addSourceBuffer('audio/mpeg');
}
this.mediaSource.removeEventListener('sourceopen', this.onSourceOpen);
this.fetchRange(this.trackPlayUrl, 0, this.segmentLength, (chunk) => this.appendSegment(chunk));
}
Where
// Create the media source object
this.mediaSource = new MediaSource();
this.mediaSource.addEventListener('sourceopen', this.onSourceOpen);
Why does it hate me?
Before you try to create a SourceBuffer, you should always call MediaSource.isTypeSupported to determine whether it is likely to play. If that returns false, the user agent is telling you it definitely won't work.
On the latest Firefox:
>> MediaSource.isTypeSupported('audio/mpeg')
<- false
It hates you because Firefox's MediaSource implementation can't play content with that MIME type, whereas Chrome's can.
AAC in ISOBMFF has very broad support, though this would require transcoding and repackaging your audio - try:
MediaSource.isTypeSupported('audio/mp4; codecs="mp4a.40.2"')

Video recording with Edge using HTML5

I am trying to record video using HTML5 API. I want this solution to be cross platform and it should atleast work on Chrome, Firefox and Edge browser. I tried with following code
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
}).then((mediaStream) => {
const video = document.querySelector('video');
const url = window.URL.createObjectURL(mediaStream);
video.src = url;
});
Above code displays video in Chrome and Edge. When I try to capture bytes using MediaRecorder API, it only works in Chrome and not in Edge. Please suggest what can be done.
const recorder = new MediaRecorder(mediaStream);
recorder.ondataavailable = onDataAvailable
...
function onDataAvailable(d){
//d.data is populated in Chrome but not in Edge.
}
Please suggest, how can I capture bytes so that it can be saved on server.
I tried MediaStreamRecorder but that too didn't work with Edge.
Update : I found few approaches which indicate use of Canvas as an option to render frames and capture the bytes. Then use requestAnimationFrame to continue capturing video. While this might work, I am still open to any other better suggestions.
The MediaRecorder API seem to be only implemented in FireFox & Chrome
https://caniuse.com/#search=MediaRecorder
I'd always check caniuse.com for browser support for new APIs!

Firefox doesn't play mp4 file in HTML5 video

I recorded a video with my mobile which had the format ".mp4". Now if I load that video in HTML5 video tag, I get an error HTTP "Content-Type" of "video/3gpp" is not supported. Why does Firefox consider the file as 3gpp although it is an mp4 file?
If I log the file properties when it is loaded on to browser, I see the following
{ name: "test.mp4", lastModified: 1434536249000, lastModifiedDate: Date 2015-06-17T10:17:29.000Z, size: 41151959, type: "video/mp4" }
This means firefox identifies the type as mp4 only. But doesn't play it giving the error HTTP "Content-Type" of "video/3gpp" is not supported.
Try converting the mp4 to a mp4 with another codec. I recommend xMediaRecode. If the converted file is working, it must have something to do with your mobile.

Read webm video from blob on firefox

I'm testing WebRTC API. More precisely the webcam part.
So I read the W3C draft and used it in firefox to record myself from a webpage. It works (not as good as expected, but it does). I mean that I can download a video formated as webm that is readable by my computer.
I want to previsualize my video before sending it to the server. So I madethis code:
var url = URL.createObjectURL(e.data);
video.innerHTML = '<source src="' + url + '" type="video/webm"></source>';
video.play();
This does'nt work at all. I got just a blank element on my webpage...
Any suggestion to make it work ?
The problem was an issue of Firefox. With e.data we get a blob but we have to redefine a new blob to make it work:
var new_blob = new Blob([e.data], { type: e.data.type });
Notice that for now (2014-09-30) firefox does not support officialy the video encoding and the specification is in draft that is not validated by the W3C.
the proble is I do not understand the what is the object you get in e.data, also you can check if the mime is correct console.log(e.data);;console.log(e.data.type); , what are the output of these,
also have you tried this, firefox webm capture, they show preview of the video.