第四次课:阿里云视频点播

飞一样的编程
飞一样的编程
擅长邻域:Java,MySQL,Linux,nginx,springboot,mongodb,微信小程序,vue

分类: springboot 专栏: 在线教育项目实战 标签: 阿里云视频点播

2023-05-05 20:59:11 1342浏览

阿里云视频点播

视频点播

视频点播(ApsaraVideo for VoD)是集音视频采集、编辑、上传、自动化转码处理、媒体资源管理、分发加速于一体的一站式音视频点播解决方案。

应用场景

  • 音视频网站:无论是初创视频服务企业,还是已拥有海量视频资源,可定制化的点播服务帮助客户快速搭建拥有极致观看体验、安全可靠的视频点播应用。

  • 短视频:集音视频拍摄、特效编辑、本地转码、高速上传、自动化云端转码、媒体资源管理、分发加速、播放于一体的完整短视频解决方案。目前已帮助1000+APP快速实现手机短视频功能。

  • 直播转点播:将直播流同步录制为点播视频,用于回看。并支持媒资管理、媒体处理(转码及内容审核/智能首图等AI处理)、内容制作(云剪辑)、CDN分发加速等一系列操作。

  • 在线教育:为在线教育客户提供简单易用、安全可靠的视频点播服务。可通过控制台/API等多种方式上传教学视频,强大的转码能力保证视频可以快速发布,覆盖全网的加速节点保证学生观看的流畅度。防盗链、视频加密等版权保护方案保护教学内容不被窃取。

  • 视频生产制作:提供在线可视化剪辑平台及丰富的OpenAPI,帮助客户高效处理、制作视频内容。除基础的剪切拼接、混音、遮标、特效、合成等一系列功能外,依托云剪辑及点播一体化服务还可实现标准化、智能化剪辑生产,大大降低视频制作的槛,缩短制作时间,提升内容生产效率。

  • 内容审核:应用于短视频平台、传媒行业审核等场景,帮助客户从从语音、文字、视觉等多维度精准识别视频、封面、标题或评论的违禁内容进行AI智能审核与人工审核。

功能介绍


视频转码:比如普通原画视频可以转成高清,标清等

分发加速:播放的速度更快,尽量少提示正在缓存中

主要用到:上传和管理

开通视频点播云平台

选择视频点播服务

产品->企业应用->视频云->视频点播

开通视频点播

选择使用流量计费

资费说明

https://www.aliyun.com/price/product?spm=a2c4g.11186623.2.12.7fbd59b9vmXVN6#/vod/detail

整体流程

使用视频点播实现音视频上传、存储、处理和播放的整体流程如下:



  • 用户获取上传授权。

  • VoD下发 上传地址和凭证 及 VideoId。

  • 用户上传视频保存视频ID(VideoId)。

  • 用户服务端获取播放凭证。

  • VoD下发带时效的播放凭证。

  • 用户服务端将播放凭证下发给客户端完成视频播放。

视频点播服务的基本使用

完整的参考文档

https://help.aliyun.com/product/29932.html?spm=a2c4g.11186623.6.540.3c356a58OEmVZJ

设置转码模板并加密

选择全局设置 > 转码设置,单击添加转码模板组。

在视频转码模板组页面,根据业务需求选择封装格式和清晰度。

或直接将已有的模板设置为默认即可

可以设置视频加密,这样别人拿到我的播放地址也无法播放

分类管理

选择全局设置 > 分类管理

上传视频文件

选择媒资库 > 音视频,单击上传音视频

配置域名

加密的视频最好是设置一下这个域名

在控制台查看视频

此时视频可以在阿里云控制台播放

获取web播放器代码



java上传视频到阿里云

看着官方的文档操作即可

    @ApiOperation(value = "上传视频到阿里云视频点播")
    @PostMapping
    public ResultDto uploadVod(MultipartFile vod){


        try {
            String fileName = vod.getOriginalFilename();
            String title = fileName.substring(0, fileName.lastIndexOf("."));
            UploadStreamRequest request = new UploadStreamRequest(accessKeyId, accessKeySecret, title, fileName, vod.getInputStream());
           
          	/* 是否使用默认水印(可选),指定模板组ID时,根据模板组配置确定是否使用默认水印*/
            //request.setShowWaterMark(true);
            /* 自定义消息回调设置及上传加速设置(可选), Extend为自定义扩展设置,MessageCallback为消息回调设置,AccelerateConfig为上传加速设置(上传加速功能需要先申请开通后才能使用)*/
            //request.setUserData("{\"Extend\":{\"test\":\"www\",\"localId\":\"xxxx\"},\"MessageCallback\":{\"CallbackType\":\"http\",\"CallbackURL\":\"http://example.aliyundoc.com\"},\"AccelerateConfig\":{\"Type\":\"oss\",\"Domain\":\"****Bucket.oss-accelerate.aliyuncs.com\"}}");
            /* 视频分类ID(可选) */
            //request.setCateId(0);
            /* 视频标签,多个用逗号分隔(可选) */
            //request.setTags("标签1,标签2");
            /* 视频描述(可选)*/
            //request.setDescription("视频描述");
            /* 封面图片(可选)*/
            //request.setCoverURL("http://cover.example.com/image_01.jpg");
            /* 模板组ID(可选)*/
            //request.setTemplateGroupId("8c4792cbc8694e7084fd5330e56****");
            /* 工作流ID(可选)*/
            //request.setWorkflowId("d4430d07361f0*be1339577859b0****");
            /* 存储区域(可选)*/
            //request.setStorageLocation("in-201703232118266-5sejd****.oss-cn-shanghai.aliyuncs.com");
            /* 开启默认上传进度回调 */
            // request.setPrintProgress(true);
            /* 设置自定义上传进度回调(必须继承 VoDProgressListener) */
            /*默认关闭。如果开启了这个功能,上传过程中服务端会在日志中返回上传详情。如果不需要接收此消息,需关闭此功能*/
            // request.setProgressListener(new PutObjectProgressListener());
             /* 设置应用ID*/
            //request.setAppId("app-100****");
            /* 点播服务接入点 */
            //request.setApiRegionId("cn-shanghai");
            /* ECS部署区域*/
            // request.setEcsRegionId("cn-shanghai");
            
        	UploadVideoImpl uploader = new UploadVideoImpl();
            UploadStreamResponse response = uploader.uploadStream(request);
            System.out.print("RequestId=" + response.getRequestId() + "\n");  //请求视频点播服务的请求ID
            if (response.isSuccess()) {
                System.out.print("VideoId=" + response.getVideoId() + "\n");
            } else { //如果设置回调URL无效,不影响视频上传,可以返回VideoId同时会返回错误码。其他情况上传失败时,VideoId为空,此时需要根据返回错误码分析具体错误原因
                System.out.print("VideoId=" + response.getVideoId() + "\n");
                System.out.print("ErrorCode=" + response.getCode() + "\n");
                System.out.print("ErrorMessage=" + response.getMessage() + "\n");
                throw new JfException(Integer.valueOf(response.getCode()),response.getMessage());
            }

            return ResultDto.success("上传成功",response.getVideoId());
        } catch (IOException e) {
            e.printStackTrace();
            return ResultDto.error("上传失败");

        }


    }

设置文件上传大小的限制

spring.servlet.multipart.maxFileSize=10MB
spring.servlet.multipart.maxRequestSize=10MB

java获取视频播放地址

备注:根据视频id获取到

对于不加密的视频来说,只要拿到播放地址就可以直接播放。但对于加密的视频来说,拿到播放地址也无法播放。

java获取播放凭证(重要)

备注:根据视频id获取到

对于加密视频的播放,只能用这个凭证的方式

java删除视频

删除的时候可以批量删除多个

视频播放测试

分两种:根据地址播放和根据凭证播放

  • 根据地址播放
var player = new Aliplayer({
        id: 'J_prismPlayer',
        source: '<your play URL>',//播放地址,可以是第三方点播地址,或阿里云点播服务中的播放地址。
      },function(player){
        console.log('The player is created.')
     });
  • 根据凭证播放
<!DOCTYPE html>
  <html>
      <head>
       <meta charset="UTF-8">
       <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
       <title>点播私有加密播放测试用例</title>
       <link rel="stylesheet" href="https://g.alicdn.com/de/prismplayer/2.9.19/skins/default/aliplayer-min.css" />
       <script charset="utf-8" type="text/javascript" src="https://g.alicdn.com/de/prismplayer/2.9.19/aliplayer-min.js"></script>
      </head>
      <body>
          <div class="prism-player" id="J_prismPlayer"></div>
          <script>
              var player = new Aliplayer({
                id: 'J_prismPlayer',
                width: '100%',
                vid : '<your video ID>',//必选参数。可以通过点播控制台(路径:媒资库>音/视频)查询。示例:1e067a2831b641db90d570b6480f****。
                playauth : '<your PlayAuth>',//必选参数。参数值可通过调用GetVideoPlayAuth接口获取。
                encryptType: 1, //当播放私有加密流时需要设置本参数值为1。其它情况无需设置。
                playConfig:{EncryptType:'AliyunVoDEncryption'}, //当您输出的M3U8流中,含有其他非私有加密流时,需要指定此参数。
              },function(player){
                console.log('The player is created.')
             });
          </script>
      </body>
  </html>

以上写法都是html里的写法,下面是vue的写法

参考文章:

https://developer.aliyun.com/article/646391

整理如下:

播放器组件vue代码

<template>
  <div class="prism-player" :id="playerId" :style="playStyle"></div>
</template>
 
<script>
  export default {
    name: "Aliplayer",
    props: {
     
      //媒体转码服务的媒体Id。
      vid: {
        type: String,
        default: ""
      },
      //播放权证
      playauth: {
        type: String,
        default: ""
      },
      //容器的大小
      height: {
        type: String,
        default: "460px"
      },
      //容器的大小
      width: {
        type: String,
        default: "100%"
      },
      //视频的高度大小
      videoWidth: {
        type: String,
        default: "100%"
      },
      //视频的宽度大小
      videoHeight: {
        type: String,
        default: "100%"
      },
      //播放器自动加载,目前仅h5可用
      preload: {
        type: Boolean,
        default: false
      },
      //播放器默认封面图片,请填写正确的图片url地址。需要autoplay为’false’时,才生效
      cover: {
        type: String,
        default: ""
      },
      //播放内容是否为直播,直播时会禁止用户拖动进度条。
      isLive: {
        type: Boolean,
        default: false
      },
      //播放器是否自动播放,在移动端autoplay属性会失效。
      autoplay: {
        type: Boolean,
        default: false
      },
      //播放器自动循环播放。
      rePlay: {
        type: Boolean,
        default: false
      },
      //指定使用H5播放器。
      useH5Prism: {
        type: Boolean,
        default: false
      },
     
      //H5是否内置播放,有的Android浏览器不起作用。
      playsinline: {
        type: Boolean,
        default: false
      },
     
      
      
      //默认为‘hover’。可选的值为:‘click’、‘hover’、‘always’。
      controlBarVisibility: {
        type: String,
        default: "hover"
      },
      
 
      /***
       *
       *指定播放地址格式,只有使用vid的播放方式时支持
       可选值为’mp4’、’m3u8’、’flv’、’mp3’,默认为空,仅H5支持。
       * */
      format: {
        type: String,
        default: "m3u8"
      },
      /***
       *
       * 指定返回音频还是视频,只有使用vid的播放方式时支持。
       可选值为’video’和’audio’,默认为’video’
       ‘audio’主要是针对只包含音频的视频格式,比如音频的mp4,仅H5支持。
       * */
      mediaType: {
        type: String,
        default: "video"
      },
      /***
       * 指定排序方式,只有使用vid + plauth播放方式时支持。
       ‘desc’表示按倒序排序(即:从大到小排序)
       ‘asc’表示按正序排序(即:从小到大排序)
       默认值:‘asc’,仅H5支持。
       * */
      qualitySort: {
        type: String,
        default: "asc"
      },
     
    
     
      /**
       * 加密类型,播放点播私有加密视频时,设置值为1,默认值为0。
       * */
      encryptType: {
        type: Number,
        default: 1
      },
     
 
      playStyle: {
        type: String,
        default: ""
      },
      aliplayerSdkPath: {
        // Aliplayer 代码的路径
        type: String,
        default: "https://g.alicdn.com/de/prismplayer/2.9.3/aliplayer-min.js"
      },
 
 
    },
    data() {
      return {
        playerId: "aliplayer_" + Math.random().toString(36).substr(2),
        scriptTagStatus: 0,
        isReload: false,
        instance: null
      };
    },
    created() {
      if (window.Aliplayer !== undefined) {
        // 如果全局对象存在,说明编辑器代码已经初始化完成,直接加载编辑器
        this.scriptTagStatus = 2;
        this.initAliplayer();
      } else {
        // 如果全局对象不存在,说明编辑器代码还没有加载完成,需要加载编辑器代码
        this.insertScriptTag();
      }
    },
    mounted() {
      if (window.Aliplayer !== undefined) {
        // 如果全局对象存在,说明编辑器代码已经初始化完成,直接加载编辑器
        this.scriptTagStatus = 2;
        this.initAliplayer();
      } else {
        // 如果全局对象不存在,说明编辑器代码还没有加载完成,需要加载编辑器代码
        this.insertScriptTag();
      }
    },
    methods: {
      insertScriptTag() {
        const _this = this;
        let playerScriptTag = document.getElementById("playerScriptTag");
        // 如果这个tag不存在,则生成相关代码tag以加载代码
        if (playerScriptTag === null) {
          playerScriptTag = document.createElement("script");
          playerScriptTag.type = "text/javascript";
          playerScriptTag.src = this.aliplayerSdkPath;
          playerScriptTag.id = "playerScriptTag";
          let s = document.getElementsByTagName("head")[0];
          s.appendChild(playerScriptTag);
        }
        if (playerScriptTag.loaded) {
          _this.scriptTagStatus++;
        } else {
          playerScriptTag.addEventListener("load", () => {
            _this.scriptTagStatus++;
            playerScriptTag.loaded = true;
            _this.initAliplayer();
          });
        }
        _this.initAliplayer();
      },
      initAliplayer() {
        const _this = this;
        // scriptTagStatus 为 2 的时候,说明两个必需引入的 js 文件都已经被引入,且加载完成
        if (
          _this.scriptTagStatus === 2 &&
          (_this.instance === null || _this.reloadPlayer)
        ) {
          _this.instance && _this.instance.dispose();
 
        //   document.querySelector("#" +_this.playerId).innerHTML = "";
 
          // Vue 异步执行 DOM 更新,这样一来代码执行到这里的时候可能 template 里面的 script 标签还没真正创建
          // 所以,我们只能在 nextTick 里面初始化 Aliplayer
          _this.$nextTick(() => {
            _this.instance = window.Aliplayer({
              id: _this.playerId,
              qualitySort:_this.qualitySort,
              format:_this.format,
              mediaType:_this.mediaType,
              vid: _this.vid,
              playauth: _this.playauth,
              width: _this.width,
              height: _this.height,
              videoWidth: _this.videoWidth,
              videoHeight: _this.videoHeight,
              preload: _this.preload,
              playsinline:_this.playsinline,
              isLive: _this.isLive,
              rePlay: _this.rePlay,
              autoplay: _this.autoplay,
              useH5Prism: _this.useH5Prism,        
              controlBarVisibility: _this.controlBarVisibility,
              encryptType: _this.encryptType,
              
            });
 
            // 绑定事件,当 AliPlayer 初始化完成后,将编辑器实例通过自定义的 ready 事件交出去
            _this.instance.on("ready", () => {
              this.$emit("ready", _this.instance);
            });
 
            _this.instance.on("play", () => {
              this.$emit("play", _this.instance);
            });
 
            _this.instance.on("pause", () => {
              this.$emit("pause", _this.instance);
            });
 
            _this.instance.on("ended", () => {
              this.$emit("ended", _this.instance);
            });
 
            _this.instance.on("liveStreamStop", () => {
              this.$emit("liveStreamStop", _this.instance);
            });
 
            _this.instance.on("m3u8Retry", () => {
              this.$emit("m3u8Retry", _this.instance);
            });
 
            _this.instance.on("hideBar", () => {
              this.$emit("hideBar", _this.instance);
            });
 
            _this.instance.on("waiting", () => {
              this.$emit("waiting", _this.instance);
            });
 
            _this.instance.on("snapshoted", () => {
              this.$emit("snapshoted", _this.instance);
            });
 
            _this.instance.on("timeupdate", () => {
              this.$emit("timeupdate", _this.instance);
            });
 
            _this.instance.on("requestFullScreen", () => {
              this.$emit("requestFullScreen", _this.instance);
            });
 
            _this.instance.on("cancelFullScreen", () => {
              this.$emit("cancelFullScreen", _this.instance);
            });
 
            _this.instance.on("error", () => {
              this.$emit("error", _this.instance);
            });
            
          });
        }
      },
      /**
       * 播放视频
       */
      play: function () {
        this.instance.play();
      },
      /**
       * 暂停视频
       */
      pause: function () {
        this.instance.pause();
      },
      /**
       * 重播视频
       */
      replay: function () {
        this.instance.replay();
      },
      /**
       * 跳转到某个时刻进行播放
       * @argument time 的单位为秒
       */
      seek: function (time) {
        this.instance.seek(time);
      },
      /**
       * 获取当前时间 单位秒
       */
      getCurrentTime: function () {
        return this.instance.getCurrentTime();
      },
      /**
       *获取视频总时长,返回的单位为秒
       * @returns 返回的单位为秒
       */
      getDuration: function () {
        return this.instance.getDuration();
      },
      /**
       获取当前的音量,返回值为0-1的实数ios和部分android会失效
       */
      getVolume: function () {
        return this.instance.getVolume();
      },
      /**
       设置音量,vol为0-1的实数,ios和部分android会失效
       */
      setVolume: function (vol) {
        this.instance.setVolume(vol);
      },
      /**
       *直接播放视频url,time为可选值(单位秒)目前只支持同种格式(mp4/flv/m3u8)之间切换暂不支持直播rtmp流切换
       *@argument url 视频地址
       *@argument time 跳转到多少秒
       */
      loadByUrl: function (url, time) {
        this.instance.loadByUrl(url, time);
      },
      /**
       * 设置播放速度
       *@argument speed 速度
       */
      setSpeed: function (speed) {
        this.instance.setSpeed(speed);
      },
      /**
       * 设置播放器大小w,h可分别为400px像素或60%百分比chrome浏览器下flash播放器分别不能小于397x297
       *@argument w 播放器宽度
       *@argument h 播放器高度
       */
      setPlayerSize: function (w, h) {
        this.instance.setPlayerSize(w, h);
      },
      /**
       *目前只支持H5播放器。
       暂不支持不同格式视频间的之间切换。
       暂不支持直播rtmp流切换。
       */
      replayByVidAndPlayAuth: function (vid, accId, accSecret, stsToken, authInfo, domainRegion) {
        this.instance.replayByVidAndPlayAuth(vid, accId, accSecret, stsToken, authInfo, domainRegion);
      },
 
      /***
       * 重新设置vid和权限,目前只支持H5播放器。
       暂不支持不同格式视频间的之间切换。
       暂不支持直播rtmp流切换。
       * @param vid 视频ID
       * @param playauth 播放权限
       */
      replayByVidAndAuthInfo: function (vid, playauth) {
        this.instance.replayByVidAndAuthInfo(vid, playauth);
      },
 
      /**
       * 目前只支持HTML5界面上的重载功能,暂不支持直播rtmp流切换m3u8)之间切换,暂不支持直播rtmp流切换
       *@argument vid 视频id
       *@argument playauth 播放凭证
       */
      reloaduserPlayInfoAndVidRequestMts: function (vid, playauth) {
        this.instance.reloaduserPlayInfoAndVidRequestMts(vid, playauth);
      },
 
      /***
       *设置截图参数
       * @param width 宽度
       * @param height 高度
       * @param rate 截图质量
       */
      setSanpshotProperties: function (width, height, rate) {
        this.instance.setSanpshotProperties(width, height, rate);
      },
      /**
       * 设置封面地址
       * @param cover 封面地址
       */
      setCover: function (cover) {
        this.instance.setCover(cover);
      },
 
 
      reloadPlayer: function () {
        this.isReload = true;
        this.initAliplayer();
        this.isReload = false;
      }
    }
  };
</script>
 
<style>
  @import url(https://g.alicdn.com/de/prismplayer/2.9.3/skins/default/aliplayer-min.css);
</style> 

特别注意:

image.png


在线播放视频的vue代码

<template>
  <div class="app-container">

    <el-button type="" @click="seeVideo('e4113840ee0e71ed804f0764a0fd0102')">查看第一个视频</el-button>
    <el-button type="" @click="seeVideo('34ae63b0ee0371ed80380675b3ed0102')">查看第二个视频</el-button>
    <!--阿里云播放器-->
    <el-dialog
      class="video"
      @close="colseVideo()"
      :visible.sync="playShow"
      >
      
      <ali-player
       v-if="playAuth"  
       :vid="vid" 
       :playauth="playAuth"
       qualitySort="asc"
       format="m3u8"
       mediaType="video"
       :encryptType=1
       ref="player"
      :autoplay=false
      :isLive=false
      :rePlay=false
      :preload=true
      controlBarVisibility="hover"
      :useH5Prism=true
      >
    </ali-player>
      
    </el-dialog>
   


  </div>
</template>

<script>
import { getAuth } from '@/api/vod'

import VueAliplayer from '@/components/AliPlayer'

export default {
  
  components: { "ali-player": VueAliplayer },

  data() {
    return {
      
      playShow: false,
      vid: '', //视频vid
      playAuth: '', //鉴权地址

    };
  },


  methods: {

 
    colseVideo(){
    
      // //重新子组件初始化
      
      this.$refs.player.initAliplayer()

    },
  
    seeVideo(vid) {
     
      
      
      var that = this
      that.vid=''
      that.playAuth=''
      
      //根据vid去查凭证
      getAuth(vid).then(res => {
        
        that.vid = vid
        that.playAuth = res.data
        that.playShow = true
        
      })


    },


  }

}
</script>
<style >
.video .el-dialog__header {
    padding: 0;
}

.video .el-dialog__body {
    padding: 0;
}



</style>

遇到的坑:明明已经获取到了凭证但就是无法播放!!!

原因是:子组件里面需要用到父组件传过来的播放凭证 ,而我们父组件的凭证是发送ajax请求到后台拿到的,还没等到父组件拿到这个凭证的时候,子组件就已经加载了,导致始终播放不了。

解决思路:让子组件延迟加载。


最终的demo效果如下

删除课程

如果用户确定删除,则首先删除视频,小节,章节,描述,课程

可以考虑加个事务

好博客就要一起分享哦!分享海报

此处可发布评论

评论(2展开评论

周杰伦 能力:10

2023-05-15 11:14:46

李灿你好帅我好爱
蓝色妖姬 能力:10

2023-05-09 10:29:40

学习中
点击查看更多评论

展开评论

您可能感兴趣的博客

客服QQ 1913284695