Reputation: 3428
I'm capturing video using the webcam. Below is my code. I'm able to save the video as an mp4 file, but none of the video players are able to play it. I keep getting an unsupported file error.
What could be the issue here?
Here is the error screenshot
Here is the HTML source code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MediaCapture and Streams API</title>
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="main.css">
</head>
<body>
<header>
<h1>MediaCapture, MediaRecorder and Streams API</h1>
</header>
<main>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Impedit molestiae itaque facere totam saepe tempore esse temporibus, quae reprehenderit aliquid iusto ea laborum, iure eligendi odio exercitationem sapiente illum quos.</p>
<p><button id="btnStart">START RECORDING</button><br/>
<button id="btnStop">STOP RECORDING</button></p>
<video controls></video>
<video id="vid2" controls></video>
<!-- could save to canvas and do image manipulation and saving too -->
</main>
<script>
let constraintObj = {
audio: false,
video: {
facingMode: "user",
width: { min: 640, ideal: 1280, max: 1920 },
height: { min: 480, ideal: 720, max: 1080 }
}
};
// width: 1280, height: 720 -- preference only
// facingMode: {exact: "user"}
// facingMode: "environment"
//handle older browsers that might implement getUserMedia in some way
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
navigator.mediaDevices.getUserMedia = function(constraintObj) {
let getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
if (!getUserMedia) {
return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
}
return new Promise(function(resolve, reject) {
getUserMedia.call(navigator, constraintObj, resolve, reject);
});
}
}else{
navigator.mediaDevices.enumerateDevices()
.then(devices => {
devices.forEach(device=>{
console.log(device.kind.toUpperCase(), device.label);
//, device.deviceId
})
})
.catch(err=>{
console.log(err.name, err.message);
})
}
navigator.mediaDevices.getUserMedia(constraintObj)
.then(function(mediaStreamObj) {
//connect the media stream to the first video element
let video = document.querySelector('video');
if ("srcObject" in video) {
video.srcObject = mediaStreamObj;
} else {
//old version
video.src = window.URL.createObjectURL(mediaStreamObj);
}
video.onloadedmetadata = function(ev) {
//show in the video element what is being captured by the webcam
video.play();
};
//add listeners for saving video/audio
let start = document.getElementById('btnStart');
let stop = document.getElementById('btnStop');
let vidSave = document.getElementById('vid2');
let mediaRecorder = new MediaRecorder(mediaStreamObj);
let chunks = [];
start.addEventListener('click', (ev)=>{
mediaRecorder.start();
console.log(mediaRecorder.state);
})
stop.addEventListener('click', (ev)=>{
mediaRecorder.stop();
console.log(mediaRecorder.state);
});
mediaRecorder.ondataavailable = function(ev) {
chunks.push(ev.data);
}
mediaRecorder.onstop = (ev)=>{
let blob = new Blob(chunks, { 'type' : 'video/mp4;' });
chunks = [];
let videoURL = window.URL.createObjectURL(blob);
vidSave.src = videoURL;
}
})
.catch(function(err) {
console.log(err.name, err.message);
});
/*********************************
getUserMedia returns a Promise
resolve - returns a MediaStream Object
reject returns one of the following errors
AbortError - generic unknown cause
NotAllowedError (SecurityError) - user rejected permissions
NotFoundError - missing media track
NotReadableError - user permissions given but hardware/OS error
OverconstrainedError - constraint video settings preventing
TypeError - audio: false, video: false
*********************************/
</script>
</body>
</html>
Upvotes: 2
Views: 2835
Reputation: 2268
I was having the same issue too. From my analysis, even if you set the chunk type like you have done here ...
let blob = new Blob(chunks, { 'type' : 'video/mp4;' });
... the actual content will still be webm.
I proved this by running an FFProbe on the uploaded data
Accepted answer I think is to re-mux it on the server.
For reference here is my .NET code using the Xabe FFMpeg Nuget package
// Convert .webm media to mp4
public async Task<string> ConvertWebmToMp4(string ffMpegPath, string srcWebm)
{
FFmpeg.SetExecutablesPath(ffMpegPath);
string outputFileName = Path.ChangeExtension(srcWebm, ".mp4");
var conversion = await FFmpeg.Conversions.FromSnippet.Convert(srcWebm, outputFileName);
await conversion.Start();
return outputFileName;
}
Upvotes: 0
Reputation: 146630
There is nothing wrong with your code. The format is actually not supported by QuickTime player.
If you use VLC or Chrome/Firefox browser to play the file it will work.
Upvotes: 7