Bladeren bron

前端利用 canvas 获取视频的宽高和时长信息, 截取第 1 秒的内容作为封面并自动上传

reghao 3 jaren geleden
bovenliggende
commit
ed1278a203
1 gewijzigde bestanden met toevoegingen van 109 en 2 verwijderingen
  1. 109 2
      src/components/upload/publish-video.vue

+ 109 - 2
src/components/upload/publish-video.vue

@@ -177,7 +177,10 @@ export default {
         description: null,
         categoryId: null,
         tags: [],
-        scope: 1
+        scope: 1,
+        width: null,
+        height: null,
+        duration: null
       },
       categoryMap: {
         Set: function(key, value) { this[key] = value },
@@ -203,9 +206,89 @@ export default {
     this.getVideoCategory()
   },
   methods: {
+    // 选择视频后获取视频的分辨率和时长, 并截取第一秒的内容作为封面
+    processVideo(file) {
+      return new Promise(function(resolve, reject) {
+        const canvas = document.createElement('canvas')
+        const canvasCtx = canvas.getContext('2d')
+
+        const videoElem = document.createElement('video')
+        const dataUrl = window.URL.createObjectURL(file)
+        // 当前帧的数据是可用的
+        videoElem.onloadeddata = function() {
+          resolve(videoElem)
+        }
+        videoElem.onerror = function() {
+          reject('video 后台加载失败')
+        }
+        // 设置 auto 预加载数据, 否则会出现截图为黑色图片的情况
+        videoElem.setAttribute('preload', 'auto')
+        videoElem.src = dataUrl
+        videoElem.addEventListener('canplay', function() {
+          setTimeout(() => {
+            // 视频视频分辨率
+            const videoWidth = videoElem.videoWidth
+            const videoHeight = videoElem.videoHeight
+
+            videoElem.pause()
+            /* const ratio = window.devicePixelRatio || 1
+            canvasCtx.scale(ratio, ratio)*/
+            // 设置画布尺寸
+            canvas.width = videoWidth
+            canvas.height = videoHeight
+            canvasCtx.drawImage(videoElem, 0, 0, canvas.width, canvas.height)
+            // 把图标base64编码后变成一段url字符串
+            const urlData = canvas.toDataURL('image/jpeg')
+            if (typeof urlData !== 'string') {
+              alert('urlData不是字符串')
+              return
+            }
+
+            var arr = urlData.split(',')
+            var bstr = atob(arr[1])
+            var n = bstr.length
+            var u8arr = new Uint8Array(n)
+            while (n--) {
+              u8arr[n] = bstr.charCodeAt(n)
+            }
+            const coverFile = new File([u8arr], 'cover.jpg', { type: 'image/jpeg' })
+
+            if (coverFile instanceof File) {
+              const formData = new FormData()
+              formData.append('file', coverFile)
+              fetch(`//api.reghao.cn/api/file/upload/image`, {
+                headers: {},
+                method: 'POST',
+                credentials: 'include',
+                body: formData
+              }).then(response => response.json())
+                .then(json => {
+                  if (json.code === 0) {
+                    this.message = '封面已上传'
+                    this.showMessage = true
+                    this.videoPost.coverFileId = json.data.imageFileId
+                  } else {
+                    this.message = '上传失败,请重试!' + json.message
+                    this.showMessage = true
+                  }
+                })
+                .catch(e => {
+                  return null
+                })
+            }
+          }, 1000) // 1000毫秒,就是截取第一秒,2000毫秒就是截取第2秒,视频1秒通常24帧,也可以换算成截取第几帧。
+          // 防止拖动进度条的时候重复触发
+          // videoElem.removeEventListener('canplay', arguments.callee)
+        })
+      })
+    },
     onFileAdded(file) {
       this.setTitle(file.file.name)
-
+      this.processVideo(file.file).then(video => {
+        this.videoPost.width = video.videoWidth
+        this.videoPost.height = video.videoHeight
+        this.videoPost.duration = video.duration
+      })
       /* file.pause()
       hashFile(file.file).then(res => {
         const formData = new FormData()
@@ -309,6 +392,30 @@ export default {
         this.videoPost.title = title
       }
     },
+    uploadVideoCover1(coverFile) {
+      const formData = new FormData()
+      formData.append('file', coverFile)
+      fetch(`//api.reghao.cn/api/file/upload/image`, {
+        headers: {
+          'Authorization': 'Bearer ' + this.$store.getters.token
+        },
+        method: 'POST',
+        credentials: 'include',
+        body: formData
+      }).then(response => response.json())
+        .then(json => {
+          if (json.code === 0) {
+            this.message = '封面已上传'
+            this.showMessage = true
+          } else {
+            this.message = '上传失败,请重试!' + json.message
+            this.showMessage = true
+          }
+        })
+        .catch(e => {
+          return null
+        })
+    },
     uploadVideoCover() {
       if (this.coverFile === null) {
         this.message = '请先选择视频封面,然后上传!'