npm install --save webm-duration-fix
callCamera () {
let _this = this;
MediaUtils.getUserMedia(true, true, function (err, stream) {
if (err) {
throw err;
} else {
// 通过 MediaRecorder 记录获取到的媒体流
const mimeType = 'video/webm;codecs=vp8,opus';
mediaRecorder = new MediaRecorder(stream, {
// mimeType: "video/webm;codecs=vp9",
mimeType: mimeType,
});
mediaStream = stream;
var chunks = []
var video = _this.$refs.videos;
video["srcObject"] = stream;
video.play();// 播放实时画面
mediaRecorder.ondataavailable = function (e) {
mediaRecorder.blobs.push(e.data);
chunks.push(e.data);
};
mediaRecorder.blobs = [];
mediaRecorder.onstop = async () => {
recorderFile = await fixWebmDuration(new Blob(chunks, { type: mimeType }));
console.log(recorderFile);
var url = URL.createObjectURL(recorderFile)
var videosreplay = _this.$refs.videosreplay;
videosreplay.setAttribute("src", url);
console.log('url', url)
chunks = [];
if (null != stopRecordCallback) {
stopRecordCallback();
}
};
_this.record()
}
});
},
record () {
if (this.recordtype == "ING") {
this.stopRecord(() => {
console.log("结束录制");
this.toggleReplayVideo()
});
}
else if (this.recordtype == "BEGIN") {
console.log("开始录制");
this.startAudio();
mediaRecorder.start();
startTime = Date.now();
this.recordtype = "ING";
}
},
startAudio () {
this.timer = setInterval(() => {
this.recordtime += 1000;
if (this.recordtime == 1000000) {
this.stopRecord();
}
this.second++;
if (this.second >= 60) {
this.second = 0;
this.minute = this.minute + 1;
}
if (this.minute >= 60) {
this.minute = 0;
this.hour = this.hour + 1;
}
console.log(this.recordtime)
}, 1000);
},
stopRecord (callback) {
this.recordtype = "END";
this.showReplay = true;
stopRecordCallback = callback;
clearInterval(this.timer);
// 终止录制器
mediaRecorder.stop();
// 关闭媒体流
MediaUtils.closeStream(mediaStream);
var videosreplay = this.$refs.videosreplay;
videosreplay.onended = () => {
this.playtime = 0;
this.replayVideo = false;
clearInterval(this.playtimer);
};
videosreplay.onclick = () => {
this.showReplay = !this.showReplay;
};
},
toggleReplayVideo () {
console.log('播放中...')
this.replayVideo = !this.replayVideo;
this.showReplay = false;
var videosreplay = this.$refs.videosreplay;
if (this.replayVideo) {
videosreplay.play().catch(err => {
this.$message.error(err.message);
console.log(err);
});
this.playtimer = setInterval(() => {
this.playtime += 1000;
}, 1000);
} else {
videosreplay.pause();
clearInterval(this.playtimer);
}
},
指定且只能指定,下载后的默认文件名字和文件后缀。注意,可以不指定后缀名,浏览器会根据数据类型自动为其匹配后缀名,但是最好指定后缀。
<a href="base64..." download="after">SAVE</a>
下载后的文件名为after.jpg
download属性不能指定下载路径;
当 download 属性值为空时,下载的文件的名字和扩展名与源文件一致;当href为base64编码的图像数据时,则下载后文件名也是那么离谱得长。
<a href="base64..." download>SAVE</a>
下载后的文件名为data_image_jpeg;base64,… .jpg
download () {
var url = URL.createObjectURL(recorderFile)
console.log("URLLLLLL", url)
const a = document.createElement("a");
document.body.appendChild(a);
a.style.display = "none";
a.href = url;
if (this.fileName) {
a.download = this.fileName + ".mp4";
} else {
a.download = new Date() + ".mp4";
}
a.click();
window.URL.revokeObjectURL(url);
},
submit () {
let that = this;
console.log(recorderFile)
// 下载
this.download()
let file = new File(
[recorderFile],
"msr-" + new Date().toISOString().replace(/:|\./g, "-") + ".mp4",
{
type: "video/mp4",
}
);
let config = {
headers: { "Content-Type": "multipart/form-data" }
}
console.log('file', file)
const formdata = new FormData()
formdata.append("file", file);
// 传给后端
// axios.post('/video', formdata, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } },) //请求头要为表单
// .then(response => {
// console.log('video', response.data);
// this.yy_score = parseInt(response.data.data + 0.5)
// that.progress = response.data.data * 1.0 / 23 * 100
// })
// .catch(function (error) {
// that.$message({
// message: error,
// type: 'error'
// });
// console.log(error);
// })
},
var MediaUtils = {
/**
* 获取用户媒体设备(处理兼容的问题)
* @param videoEnable {boolean} - 是否启用摄像头
* @param audioEnable {boolean} - 是否启用麦克风
* @param callback {Function} - 处理回调
*/
getUserMedia: function (videoEnable, audioEnable, callback) {
navigator.getUserMedia =
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia ||
window.getUserMedia;
var constraints = { video: videoEnable, audio: audioEnable };
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices
.getUserMedia(constraints)
.then(function (stream) {
callback(false, stream);
})
["catch"](function (err) {
callback(err);
});
} else if (navigator.getUserMedia) {
navigator.getUserMedia(
constraints,
function (stream) {
callback(false, stream);
},
function (err) {
callback(err);
}
);
} else {
callback(new Error("Not support userMedia"));
}
},
/**
* 关闭媒体流
* @param stream {MediaStream} - 需要关闭的流
*/
closeStream: function (stream) {
if (typeof stream.stop === "function") {
stream.stop();
} else {
let trackList = [stream.getAudioTracks(), stream.getVideoTracks()];
for (let i = 0; i < trackList.length; i++) {
let tracks = trackList[i];
if (tracks && tracks.length > 0) {
for (let j = 0; j < tracks.length; j++) {
let track = tracks[j];
if (typeof track.stop === "function") {
track.stop();
}
}
}
}
}
},
};
var startTime, mediaRecorder, mediaStream, stopRecordCallback, recorderFile;
<template>
<div>
<video id="video" autoplay ref="videos" style="width: 400px;height: 400px;" muted></video>
<video style="width: 400px;height: 400px;" id="videosreplay" src="" ref="videosreplay"></video>
<button @click="callCamera()">开始录制</button>
<button @click="record()">结束录制</button>
<button @click="submit()">下载或上传</button>
</div>
</template>
<script>
import axios from 'axios'
import fixWebmDuration from 'webm-duration-fix'
export default {
name: "Test",
data () {
return {
progress: 0,
replayVideo: false,
recordtype: "BEGIN",
showReplay: true,
timer: 0,
recordtime: 0,
second: 0,
minute: 0,
hour: 0,
playtime: 0,
playtimer: 0,
yy_score: 0,
cnt_sum: 0,
ansMaxTime: 0,
ansBeginTime: 0,
ansMaxBeginTime: 0,
}
},
methods: {
// 调用摄像头
callCamera () {
let _this = this;
MediaUtils.getUserMedia(true, true, function (err, stream) {
if (err) {
throw err;
} else {
// 通过 MediaRecorder 记录获取到的媒体流
const mimeType = 'video/webm;codecs=vp8,opus';
mediaRecorder = new MediaRecorder(stream, {
// mimeType: "video/webm;codecs=vp9",
mimeType: mimeType,
});
mediaStream = stream;
var chunks = []
var video = _this.$refs.videos;
video["srcObject"] = stream;
video.play();// 播放实时画面
mediaRecorder.ondataavailable = function (e) {
mediaRecorder.blobs.push(e.data);
chunks.push(e.data);
};
mediaRecorder.blobs = [];
mediaRecorder.onstop = async () => {
recorderFile = await fixWebmDuration(new Blob(chunks, { type: mimeType }));
console.log(recorderFile);
var url = URL.createObjectURL(recorderFile)
var videosreplay = _this.$refs.videosreplay;
videosreplay.setAttribute("src", url);
console.log('url', url)
chunks = [];
if (null != stopRecordCallback) {
stopRecordCallback();
}
};
_this.record()
}
});
},
record () {
if (this.recordtype == "ING") {
this.stopRecord(() => {
console.log("结束录制");
this.toggleReplayVideo()
});
}
else if (this.recordtype == "BEGIN") {
console.log("开始录制");
this.startAudio();
mediaRecorder.start();
startTime = Date.now();
this.recordtype = "ING";
}
},
// 对录像时长进行记录
startAudio () {
this.timer = setInterval(() => {
this.recordtime += 1000;
if (this.recordtime == 1000000) {
this.stopRecord();
}
this.second++;
if (this.second >= 60) {
this.second = 0;
this.minute = this.minute + 1;
}
if (this.minute >= 60) {
this.minute = 0;
this.hour = this.hour + 1;
}
console.log(this.recordtime)
}, 1000);
},
// 停止录像时终止录制器,关闭媒体流并清除时长记录定时器
stopRecord (callback) {
this.recordtype = "END";
this.showReplay = true;
stopRecordCallback = callback;
clearInterval(this.timer);
// 终止录制器
mediaRecorder.stop();
// 关闭媒体流
MediaUtils.closeStream(mediaStream);
var videosreplay = this.$refs.videosreplay;
videosreplay.onended = () => {
this.playtime = 0;
this.replayVideo = false;
clearInterval(this.playtimer);
};
videosreplay.onclick = () => {
this.showReplay = !this.showReplay;
};
},
// 回放
toggleReplayVideo () {
console.log('播放中...')
this.replayVideo = !this.replayVideo;
this.showReplay = false;
var videosreplay = this.$refs.videosreplay;
if (this.replayVideo) {
videosreplay.play().catch(err => {
this.$message.error(err.message);
console.log(err);
});
this.playtimer = setInterval(() => {
this.playtime += 1000;
}, 1000);
} else {
videosreplay.pause();
clearInterval(this.playtimer);
}
},
// 下载视频
download () {
var url = URL.createObjectURL(recorderFile)
console.log("URLLLLLL", url)
const a = document.createElement("a");
document.body.appendChild(a);
a.style.display = "none";
a.href = url;
if (this.fileName) {
a.download = this.fileName + ".mp4";
} else {
a.download = new Date() + ".mp4";
}
a.click();
window.URL.revokeObjectURL(url);
},
// 下载或上传
submit () {
let that = this;
console.log(recorderFile)
// 下载
this.download()
let file = new File(
[recorderFile],
"msr-" + new Date().toISOString().replace(/:|\./g, "-") + ".mp4",
{
type: "video/mp4",
}
);
let config = {
headers: { "Content-Type": "multipart/form-data" }
}
console.log('file', file)
const formdata = new FormData()
formdata.append("file", file);
// 传给后端
// axios.post('/video', formdata, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } },) //请求头要为表单
// .then(response => {
// console.log('video', response.data);
// this.yy_score = parseInt(response.data.data + 0.5)
// that.progress = response.data.data * 1.0 / 23 * 100
// })
// .catch(function (error) {
// that.$message({
// message: error,
// type: 'error'
// });
// console.log(error);
// })
},
}
}
var MediaUtils = {
/**
* 获取用户媒体设备(处理兼容的问题)
* @param videoEnable {boolean} - 是否启用摄像头
* @param audioEnable {boolean} - 是否启用麦克风
* @param callback {Function} - 处理回调
*/
getUserMedia: function (videoEnable, audioEnable, callback) {
navigator.getUserMedia =
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia ||
window.getUserMedia;
var constraints = { video: videoEnable, audio: audioEnable };
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices
.getUserMedia(constraints)
.then(function (stream) {
callback(false, stream);
})
["catch"](function (err) {
callback(err);
});
} else if (navigator.getUserMedia) {
navigator.getUserMedia(
constraints,
function (stream) {
callback(false, stream);
},
function (err) {
callback(err);
}
);
} else {
callback(new Error("Not support userMedia"));
}
},
/**
* 关闭媒体流
* @param stream {MediaStream} - 需要关闭的流
*/
closeStream: function (stream) {
if (typeof stream.stop === "function") {
stream.stop();
} else {
let trackList = [stream.getAudioTracks(), stream.getVideoTracks()];
for (let i = 0; i < trackList.length; i++) {
let tracks = trackList[i];
if (tracks && tracks.length > 0) {
for (let j = 0; j < tracks.length; j++) {
let track = tracks[j];
if (typeof track.stop === "function") {
track.stop();
}
}
}
}
}
},
};
var startTime, mediaRecorder, mediaStream, stopRecordCallback, recorderFile;
</script>
https://gitee.com/yuan-hongting/video