Camera Recorder
Take a picture or record a video from your webcam or camera.
Install Relative Package
install vue
、@vueuse/core
、lodash
、axios
Initial Device
JS
import { reactive, provide, ref, markRaw, watchEffect, computed, onMounted, onBeforeUnmount } from 'vue'
import { useDevicesList, useUserMedia } from '@vueuse/core'
import _ from 'lodash'
const {
videoInputs: cameras,
audioInputs: microphones,
permissionGranted,
isSupported,
ensurePermissions,
} = useDevicesList({
requestPermissions: true,
constraints: { video: true, audio: true },
onUpdated() {
refreshCurrentDevices()
},
})
const currentCamera = ref(cameras.value[0]?.deviceId)
function refreshCurrentDevices() {
if (_.isNil(currentCamera) || !cameras.value.find((i) => i.deviceId === currentCamera.value)) {
currentCamera.value = cameras.value[0]?.deviceId
}
}
Start Video Stream
JS
import { useUserMedia } from '@vueuse/core'
const {
stream,
start,
stop,
enabled: isMediaStreamAvailable,
} = useUserMedia({
constraints: computed(() => ({
video: { deviceId: currentCamera.value },
})),
autoSwitch: true,
})
start()
Get Video Stream
Vue
<script lang="ts" setup>
import { useMediaRecorder } from './useMediaRecorder'
const { onRecordAvailable } = useMediaRecorder({
stream,
})
</script>
TS
import { type Ref, computed, ref } from 'vue'
import { createEventHook } from '@vueuse/core'
export { useMediaRecorder }
function useMediaRecorder({ stream }: { stream: Ref<MediaStream | undefined> }): {
isRecordingSupported: Ref<boolean>
recordingState: Ref<'stopped' | 'recording' | 'paused'>
startRecording: () => void
stopRecording: () => void
pauseRecording: () => void
resumeRecording: () => void
onRecordAvailable: (cb: (url: string) => void) => void
} {
const isRecordingSupported = computed(() => MediaRecorder.isTypeSupported('video/webm'))
const mediaRecorder = ref<MediaRecorder | null>(null)
const recordedChunks = ref<Blob[]>([])
const recordAvailable = createEventHook()
const recordingState = ref<'stopped' | 'recording' | 'paused'>('stopped')
const createVideo = () => {
const blob = new Blob(recordedChunks.value, { type: 'video/webm' })
const url = URL.createObjectURL(blob)
recordedChunks.value = []
return url
}
const startRecording = () => {
if (!isRecordingSupported.value) {
return
}
if (!stream.value) {
return
}
if (recordingState.value !== 'stopped') {
return
}
mediaRecorder.value = new MediaRecorder(stream.value, { mimeType: 'video/webm' })
mediaRecorder.value.ondataavailable = (e) => {
if (e.data.size > 0) {
recordedChunks.value.push(e.data)
}
}
mediaRecorder.value.onstop = () => {
recordAvailable.trigger(createVideo())
}
if (mediaRecorder.value.state !== 'inactive') {
return
}
mediaRecorder.value.start()
recordingState.value = 'recording'
}
const stopRecording = () => {
if (!isRecordingSupported.value) {
return
}
if (!mediaRecorder.value) {
return
}
if (recordingState.value === 'stopped') {
return
}
mediaRecorder.value.stop()
recordingState.value = 'stopped'
}
const pauseRecording = () => {
if (!isRecordingSupported.value) {
return
}
if (!mediaRecorder.value) {
return
}
if (recordingState.value !== 'recording') {
return
}
mediaRecorder.value.pause()
recordingState.value = 'paused'
}
const resumeRecording = () => {
if (!isRecordingSupported.value) {
return
}
if (!mediaRecorder.value) {
return
}
if (recordingState.value !== 'paused') {
return
}
mediaRecorder.value.resume()
recordingState.value = 'recording'
}
return {
isRecordingSupported,
startRecording,
stopRecording,
pauseRecording,
resumeRecording,
recordingState,
onRecordAvailable: recordAvailable.on,
}
}
Apply Camera Permission
If the permission dialog does not pop up due to an unexpected situation, you can add a click button to request permissions.
Vue
<template>
<el-button type="success" @click="requestPermissions">Permission</el-button>
</template>
<script lang="ts" setup>
async function requestPermissions() {
try {
await ensurePermissions()
} catch (e) {
permissionCannotBePrompted.value = true
}
}
</script>
Barcode scanner scan barcode, take a photo, and upload
Vue
<template>
<div>
<video ref="video" autoplay controls />
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
const video = ref<HTMLVideoElement>()
onMounted(() => {
document.addEventListener('keypress', handleKeypress)
})
onBeforeUnmount(() => {
document.removeEventListener('keypress', handleKeypress)
})
// Press Scan Key
const handleKeypress = (event) => {
if (event.key === 'Enter') {
takeScreenshot()
} else if (event.key == undefined) {
} else {
scanData.value += event.key
}
}
async function takeScreenshot() {
if (!video.value) {
return
}
const canvas = document.createElement('canvas')
canvas.width = video.value.videoWidth
canvas.height = video.value.videoHeight
canvas.getContext('2d')?.drawImage(video.value, 0, 0)
canvas.toBlob((blob) => {
const tempFile = new File([blob], 'img.png', { type: 'image/png' })
let fd = new FormData()
fd.append('file', tempFile)
// fileUpload() should replace your real upload method
fileUpload(fd).then((res) => {
if (res.code == 200) {
// upload success
}
})
})
}
</script>