Demand profile

Requirements: Upload a video file and capture the first frame of the video as the cover image using vue+ Vant

File upload

1. In Safari, the LoadedData event of video cannot be triggered because there is no click event. Therefore, upload the video file and manually click to generate poster

<van-uploader v-if="! form.videoUrl" accept="video/*" v-model="videoList" max-count="1" :preview-image="false" :after-read="onVideoUpload" />Copy the code

Listen for the after-read hook to get the file instance

async onVideoUpload(file) { try { this.videoUploading = true; const blob = new Blob([file.file]); const localUrl = URL.createObjectURL(blob); Const video = await validateVideo(localUrl); if (! Video) {this.videoloadError = true; } else {// convert video to file const res = await videoCapture(video); const picFile = await base64toFile(res); const picUrl = await uploadFile(picFile); this.form.videoCoverImg = picUrl; } const resultUrl = await uploadFile(file.file); file.url = resultUrl; this.form.videoUrl = resultUrl; this.videoUploading = false; } catch (err) { this.videoUploading = false; this.videoLoadError = false; this.videoList = []; this.$toast({ position: 'bottom', message: err.message }); }},Copy the code

Validates the video loadedData event and returns the video itself

Note 1. If the video needs cross-domain processing, that is, external links, the video tag should add crossOrigin=”anonymous” attribute

export const validateVideo = videourl => { const video = document.createElement('video'); video.src = videourl; Video. CurrentTime = 0.1; video.load(); return new Promise((resolve, reject) => { video.addEventListener('loadeddata', Function () {if (video.duration > 16) {reject({message: 'upload video not acceptable'}); } else { resolve(video); }}); // Exit setTimeout(() => {resolve(false); }, 3000); }); };Copy the code

Draw the first frame on canvas and save it in Base64 format

export default video => { return new Promise((res, rej) => { try { const vw = video.videoWidth; const vh = video.videoHeight; Const scale = 0.25; const canvas = document.createElement('canvas'); canvas.width = vw * scale; canvas.height = vh * scale; const fill = canvas.getContext('2d'); fill.drawImage(video, 0, 0, canvas.width, canvas.height); res(canvas.toDataURL('image/png')); } catch (err) { rej(err); }}); };Copy the code

Converts the base64 image to file and uploads it to the server

1. There is a catch if the regular expression is in Safari due to decoding

[Works in Chrome, but breaks in Safari: Invalid regular expression: Invalid group specifiers name / < = (?) ([^ #] +)/(? = # *) / [duplicate]] (stackoverflow.com/questions/5…).

export const base64toFile = base64 => { return new Promise((resolve, reject) => { try { var arr = base64.split(','); var mime = arr[0].match(/:(.*?) ; / [1]); var bstr = atob(arr[1]); var n = bstr.length; var u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } resolve(new File([u8arr], 'poster.png', { type: mime })); // resolve(new Blob([u8arr], { type: mime })); } catch (err) {reject({message: 'transcode failed'}); }}); };Copy the code

If the loadedData event is not responded to for more than 3 seconds, a preview image is generated using the click event

<video ref="video" crossOrigin="anonymous" :src="form.videoUrl" :poster="form.videoCoverImg" ></video> <van-button V-if ="videoError" class="preview-butn" native type="button" @click="genereteVideoPoster" > Generate preview </van-button> async genereteVideoPoster() { try { const video = this.$refs.video; const videoDom = await videoLoadeddata(video); const res = await videoCapture(videoDom); const picFile = await base64toFile(res); const picUrl = await uploadFile(picFile); this.form.videoCoverImg = picUrl; this.videoPaused = false; } catch (err) { this.$toast({ position: 'bottom', message: err.message }); }}Copy the code

conclusion

1, the article with pasted code, my level is limited

  • In Safari, the LoadedData event of video cannot be triggered because there is no click event, so it is necessary to manually click to generate Poster after uploading the video file
  • If the video requires cross-domain processing, that is, external linksvideoLabels need to be addedcrossOrigin="anonymous"attribute
  • An error is reported if the regular expression is decoded on SafariInvalid regular expression: invalid group specifier name

2. Links to references

  • Stackoverflow.com/questions/5…