阿里云視頻點播

1、視頻播放

  • mixin混入 采用sts方式播放
  • accessKeyId accessKeySecret securityToken region 均為后端crypto加密配置,進行解密
  • skinLayout為皮膚配置欄,可刪除對應(yīng)組件,使用自定義組件components
  • 更多配置可查看阿里云播放器SDK--web播放器--屬性和接口說明

1-1、main.js

//main.js
Vue.mixin({
  methods: {
    //創(chuàng)建視頻
    $createPlayer(id, key, vid, picUrl) {
      key.accessKeyId = decrypt(key.accessKeyId)
      key.accessKeySecret = decrypt(key.accessKeySecret)
      key.securityToken = decrypt(key.securityToken)
      key.region = decrypt(key.region)
      return new Aliplayer({
        id,
        autoplay: false,
        width: "100%",
        //支持播放地址播放,此播放優(yōu)先級最高
        // source,
        //播放方式四:使用STS方式播放
        vid,
        region: key.region,
        controlBarVisibility: "always",
        // vid: '10c0875db475494b891a8fc7f9b259d2',
        accessKeyId: key.accessKeyId,
        accessKeySecret: key.accessKeySecret,
        securityToken: key.securityToken,
        isLive: false,
        defaultDefinition: 'LD',
        cover: picUrl,
        controlBarVisibility: 'always',
        components: [{
          name: 'RateComponent',
          type: AliPlayerComponent.RateComponent,
        }, ],
        // https://help.aliyun.com/document_detail/62948.html#-
        skinLayout: [{
            name: 'bigPlayButton',
            align: 'blabs',
            x: 328,
            y: '50%'
          },
          {
            name: 'H5Loading',
            align: 'cc',
          },
          {
            name: 'errorDisplay',
            align: 'tlabs',
            x: 0,
            y: 0
          },
          {
            name: 'infoDisplay'
          },
          {
            name: 'tooltip',
            align: 'blabs',
            x: 0,
            y: 56
          }, // 懸浮在按鈕上的提示
          {
            name: 'thumbnail'
          },
          {
            name: 'controlBar',
            align: 'blabs',
            x: 0,
            y: 0, // 控制視頻的控件
            children: [{
                name: 'progress',
                align: 'blabs',
                x: 0,
                y: 44
              }, // 進度
              {
                name: 'playButton',
                align: 'tl',
                x: 15,
                y: 12
              }, // 播放按鈕
              {
                name: 'timeDisplay',
                align: 'tl',
                x: 10,
                y: 7
              }, // 時間線
              // {
              //   name: 'fullScreenButton',
              //   align: 'tr',
              //   x: 10,
              //   y: 12
              // }, // 全屏按鈕按鈕
              // {name:"subtitle", align:"tr",x:5, y:12},                // 字幕
              // {name:"setting", align:"tr",x:15, y:12},                // 設(shè)置
              {
                name: 'volume',
                align: 'tr',
                x: 5,
                y: 10
              }, // 音量
              // {name: "snapshot", align: "tr", x: 5, y: 12 }
            ],
          },

        ],
        // components: [{
        //   name: 'ProgressComponent',
        //   type: ProgressComponent
        // }, ]
      }, )
    },
  }
})

1-2、相關(guān)頁面播放(進度條不是很流暢,后期手寫進度條videoProgress.js)

//相關(guān)頁面播放
 if (this.player) {
        this.player.dispose() //銷毀
        this.player = null
      }
      let list =this.videoList[this.videoIndex]
      this.videoKey = storage.get('videosts')
      this.player = this.$createPlayer('my_video', this.videoKey, list.videoId, list.picUrl)
      this.player.on('ended', (e) => {
        if (item) item.canClick = true
      })
      let progressPlaied = document.querySelector('.prism-progress-played')
      let currentText = document.querySelector('.prism-time-display .current-time')
      //快進快退10s
      document.onkeydown = (e) => {
        let videotimes = this.player.getDuration() //視頻時長
        let playnum = Math.ceil(this.player.getCurrentTime()) //視頻當前時間,單位:s
        if (e && e.keyCode === 37) {
          // 按 向左鍵
          playnum = parseInt(playnum - 10)
          if (playnum >= 0) {
            this.player.seek(playnum)
            progressPlaied.style.width = `${((playnum / videotimes) * 100).toFixed(6)}%`
          } else {
            this.player.seek(0)
            progressPlaied.style.width = 0
            currentText.innerText = '00:00'
          }
        } else if (e && e.keyCode === 39) {
          // 按 向右鍵
          playnum = parseInt(playnum + 10)
          if (playnum <= videotimes) {
            this.player.seek(playnum)
            progressPlaied.style.width = `${((playnum / videotimes) * 100).toFixed(6)}%`
          } else {
            this.player.seek(Math.ceil(videotimes))
            progressPlaied.style.width = `100%`
          }
        }
      }

2、富文本編輯器上傳視頻 (未完)

2-1、擴展視頻按鈕

// html
    <input
      type='file'
      style='display: none;'
      id='getVideoFile'
      @change="selectVideoSource($event)"
      multiple
      accept='video/*'
    >

// js 初始化編輯器中
      // 擴展視頻按鈕
      class InsertVideoMenu extends BtnMenu {
        constructor(editor) {
          const $elem = E.$(`<div class="w-e-menu" data-title="插入視頻">
              <i class="iconfont">&#xe6c3;</i>
          </div>`);
          super($elem, editor);
        }
        // 菜單點擊事件
        clickHandler() {
          var aPlayers = self.$refs.wangEditorContainer.getElementsByClassName('aliyun-video-player');
          if(aPlayers.length >= 10){
            self.$message.error('最多可添加10個視頻')
          }else{
            document.getElementById('getVideoFile').click()
          }
        }
        tryChangeActive() {

        }
      }

3、上傳視頻

3-1、需求

  • 后臺管理系統(tǒng)上傳視頻(可多個),上傳時顯示進度,上傳完成顯示視頻標題。hover時可以選擇刪除
初始狀態(tài)

視頻上傳中

上傳成功

3-2、代碼

html

  <el-form-item class="video-form-item" label="視頻文件:">
          <div ref="videoBox" id="video-box">
            <!-- 添加的視頻 -->
            <div class="item flex-box" v-for="(item, idx) in videoList" :key="idx">
              <div class="aliyun-video-player">
                <div v-if="item.progress == 100 || item.progress > 100">
                  <i class="el-icon-video-play"></i>
                  <div class="video-name">{{ item.videoName }}</div>
                  <div class="edit-player-tip">此處不支持視頻播放</div>
                  <div class="edit-player-masker"></div>
                  <div class="aliyun-video-close-btn" @click="deleteVideo(item, idx)">
                    <span class="iconfont iconguanbi4"></span>
                  </div>
                </div>
                <div class="aliyun-video-progress-box" v-else>
                  <div class="current">{{ item.progress }}%</div>
                  <div class="aliyun-video-progress-total"><div class="aliyun-video-progress-current" :style="{ width: item.progress + '%' }"></div></div>
                </div>
              </div>
            </div>
            <!-- 視頻上傳 (input file的樣式修改麻煩 uploadClick用于點擊這個隱藏的input)-->
            <div class="upload-div" @click="uploadClick">
              <i class="el-icon-plus"></i>
              <p>點擊上傳視頻</p>
            </div>
            <input type="file" style="display: none" id="getVideoFile" multiple accept="video/*" @change="selectVideoSource($event)" />
          </div>
        </el-form-item>

js

/*
*  上傳SDK 詳見官網(wǎng) https://help.aliyun.com/document_detail/52204.html 視頻信息,進度等均可以在回調(diào)中拿到
*   paramData -- 可以攜帶自己想要的信息 title:"標題",CateId:"分類ID", 
*   videoMap:判斷所有上傳是否結(jié)束的對象 { uid:boolean }
*/ 
// mounted 中根據(jù)正式環(huán)境的不同選擇不同的分類
mounted() {
    this.CateId = window.location.host == '正式環(huán)境host' ? '2057' : '2056'
  },
// 上傳視頻
    selectVideoSource(e, insertVideoFn) {
      var file = e.target.files
      if (file.length > 0) {
        var large = file.length
        this.setJavascriptUpload(file, large)
        e.target.value = ''
      }
    },
    setJavascriptUpload(file, large) {
      // 初始化上傳 
      this.toAliyunUpload()

      // 添加文件
      for (let i = 0; i < large; i++) {
        if (file[i].type.indexOf('video') < 0 && file[i].type.indexOf('flash') < 0) {
          this.$message.error('有一個文件格式不對')
          continue
        }
        // 視頻文件過大
        if (file[i].size / 1024 / 1024 > 1 * 1024) {
          this.$message.error('有一個文件過大')
          continue
        }
        var uid = Math.random().toString().slice(2)
        var paramsData = {
          Vod: {
            Title: file[i].name,
            CateId: this.CateId, // 分類id
            uid: uid,
            TemplateGroupId: 'c9f0925ae6b5386c8681729d19985f47', // 指定轉(zhuǎn)碼模板組
          },
        }
        this.videoMap[uid] = false
        this.uploader.addFile(file[i], '', '', '', JSON.stringify(paramsData))
        let obj = {
          uid,
          progress: 0,
          videoName: '',
        }
        this.videoList.push(obj)
      }
      this.uploader.startUpload()
    },
    toAliyunUpload() {
      var self = this
      this.uploader = new AliyunUpload.Vod({
        userId: '245578911051344621',
        region: 'cn-shenzhen',
        //分片大小默認1 MB,不能小于100 KB
        partSize: 1048576,
        //并行上傳分片個數(shù),默認5
        parallel: 10,
        //網(wǎng)絡(luò)原因失敗時,重新上傳次數(shù),默認為3
        retryCount: 3,
        //網(wǎng)絡(luò)原因失敗時,重新上傳間隔時間,默認為2秒
        retryDuration: 2,
        //是否上報上傳日志到視頻點播,默認為true
        enableUploadProgress: true,
        //開始上傳
        onUploadstarted: function (uploadInfo) {
          //獲取STSToken
          self.$api
            .getVideoStsToken()
            .then((res) => {
              if (res.data) {
                if (res.data.code == 200 && res.data.data) {
                  var data = res.data.data
                  self.sts = {
                    accessKeyId: decrypt(data.accessKeyId, ''),
                    accessKeySecret: decrypt(data.accessKeySecret, ''),
                    secretToken: decrypt(data.securityToken, ''),
                  }
                  self.uploader.setSTSToken(uploadInfo, self.sts.accessKeyId, self.sts.accessKeySecret, self.sts.secretToken)
                } else {
                  var uid = uploadInfo.videoInfo.uid
                  self.videoMap[uid] = true
                  self.videoList.forEach((item, idx) => {
                    if (item.uid == uid) {
                      self.videoList.splice(idx, 1)
                    }
                  })
                  self.$message.error(res.data.msg || '獲取STSToken失敗')
                }
              } else {
                var uid = uploadInfo.videoInfo.uid
                self.videoMap[uid] = true
                self.videoList.forEach((item, idx) => {
                  if (item.uid == uid) {
                    self.videoList.splice(idx, 1)
                  }
                })
                self.$message.error('一個視頻上傳失敗')
              }
            })
            .catch((err) => {
              console.log(err)
              var uid = uploadInfo.videoInfo.uid
              self.videoMap[uid] = true
              self.videoList.forEach((item, idx) => {
                if (item.uid == uid) {
                  self.videoList.splice(idx, 1)
                }
              })
              self.$message.error(JSON.stringify(err) || '獲取STSToken失敗')
            })
        },
        //文件上傳成功
        onUploadSucceed: function (uploadInfo) {
          var uid = uploadInfo.videoInfo.uid
          self.videoMap[uid] = true
          self.videoList.forEach((item) => {
            if (item.uid == uid) {
              item['videoId'] = uploadInfo.videoId
              item.videoName = uploadInfo.file.name
            }
          })
          self.$message.success('您有一個視頻已上傳完成')
        },
        //文件上傳失敗
        onUploadFailed: function (uploadInfo, code, message) {
          self.$message.error('一個視頻上傳失敗')
          var uid = uploadInfo.videoInfo.uid
          self.videoList.forEach((item, idx) => {
            if (item.uid == uid) {
              self.videoList.splice(idx, 1)
            }
          })
        },
        //文件上傳進度,單位:字節(jié)
        onUploadProgress: function (uploadInfo, totalSize, loadedPercent) {
          var uid = uploadInfo.videoInfo.uid
          self.videoList.forEach((item) => {
            if (item.uid == uid) {
              item.progress = Math.ceil(loadedPercent * 100)
            }
          })
        },
        //STS token超時
        onUploadTokenExpired: function (uploadInfo) {
          //重新獲取STS token,恢復(fù)上傳
          self.$axios
            .get('/kd-group/medio/stsToken')
            .then((res) => {
              if (res && res.data.code == 200 && res.data.data) {
                var data = res.data.data
                self.sts = {
                  accessKeyId: decrypt(data.accessKeyId, ''),
                  accessKeySecret: decrypt(data.accessKeySecret, ''),
                  secretToken: decrypt(data.securityToken, ''),
                }
                self.uploader.setSTSToken(uploadInfo, self.sts.accessKeyId, self.sts.accessKeySecret, self.sts.secretToken)
              } else {
                self.$message.error(res.data.msg || '獲取STSToken失敗')
              }
            })
            .catch((err) => {
              self.$message.error(JSON.stringify(err) || '獲取STSToken失敗')
            })
        },
        //全部文件上傳結(jié)束
        onUploadEnd: function (uploadInfo) {
          // console.log("onUploadEnd: uploaded all the files");
        },
      })
    },
    showVideoLoading() {
      var flag = true
      for (var key in this.videoMap) {
        if (!this.videoMap[key]) {
          flag = false
          return
        }
      }
      return flag
    },

3-3、關(guān)于官網(wǎng)的配置

  • 入口


    注冊開通

    視頻點播入口

    模塊
  • 分類管理 所謂CateId (區(qū)分生產(chǎn)環(huán)境和測試環(huán)境視頻存放的位置)


    分類管理 1.png

    分類管理 2.png
  • 轉(zhuǎn)碼模板組 (格式、清晰度等)


    轉(zhuǎn)碼模板組
  • 回調(diào)設(shè)置


    回調(diào)設(shè)置.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容