视频网站的存储与媒体处理方案
教程耗时:40分钟
查看方案详情

方案概览

1

部署准备

2

一键部署

3

验证及清理

方案概览

一键部署

40

https://www.aliyun.com/solution/tech-solution/vsaps

方案概览

视频存储与处理是指基于阿里云服务提供高可靠存储和实时自动化服务,能够满足用户对视频存储、转码、截图、播放、直播等功能的需求。本技术解决方案以搭建一个视频存储和处理服务为例,为您演示:

  • 如何搭建一个视频存储和处理服务。

  • 观察添加水印后的视频。

方案架构

方案提供的默认设置完成部署后在阿里云上搭建的网站运行环境如下图所示。实际部署时您可以根据资源规划修改部分设置,但最终形成的运行环境与下图相似。

p833951

本方案的技术架构包括以下基础设施和云服务:

  • 2个云服务器ECS:部署上传和下载视频网站服务。

  • 1个负载均衡ALB:对外提供访问并将用户请求分配到不同云服务器ECS上的博客网站服务。

  • 1个专有网络VPC:为应用型负载均衡ALB、云服务器ECS等云资源形成云上私有网络。

  • 2台交换机:将2台云服务器ECS连接在同一网络上,实现它们之间的通信,并提供基本的网络分段和隔离功能。

  • 视频点播VOD:将客户端上传视频的消息推送到轻量消息队列(原MNS)。

  • 轻量消息队列(原MNS):接收VOD推送的消息并将其发送给FC。

  • 函数计算FC:收到客户端上传视频的消息后,调用函数从Bucket中获取视频并处理,然后将其上传到另一个Bucket。

  • 对象存储OSS:1Bucket作为视频点播服务的存储服务,用于存储客户端上传的视频,另1Bucket用于存储处理后的视频。

  • 2RAM角色:1RAM角色用于云服务ECS获取STS临时访问凭证,另一个RAM角色用于视频上传服务获取STS临时访问凭证并上传视频到VOD。

部署准备

10

开始部署前,请按以下指引完成账号申请、账号充值、RAM用户创建和授权。

准备账号

  1. 如果您还没有阿里云账号,请访问阿里云账号注册页面,根据页面提示完成注册。阿里云账号是您使用云资源的付费实体,因此是部署方案的必要前提。

  2. 开通以下云服务:轻量消息队列(原MNS)OSSVODFCEventBridge

    说明
    • 因为本方案中的FC Trigger依赖EventBridge,所以您还需要开通EventBridge。

    • 如果点开MNS链接提示开通报错,说明已经开通,您可以直接登录轻量消息队列(原MNS)控制台进行确认。

  3. 完成一键授权:AliyunVODDefaultRoleAliyunFCServerlessDevsRole

  4. 为阿里云账号充值

    1. 为节省成本,本方案默认全部选择使用按量付费资源,使用按量付费资源需要确保账户余额不小于100元。

    2. 完成本方案的部署及体验,预计产生费用不超过5元(假设您选择最低规格资源,且资源运行时间不超过30分钟。实际情况中可能部分实例无法购买需要根据实际情况调整资源规格,同时因您操作过程中实际使用的流量差异,会导致费用有所变化,请以控制台显示的实际报价以及最终账单为准)。

      序号

      产品

      费用来源

      规格

      地域

      预估费用参考

      说明

      1

      应用型负载均衡ALB

      ALB实例费

      基础版

      华东2(上海)

      0.042元/时

      -

      2

      ALB容量费

      -

      0.042元/LCU

      -

      3

      云服务器ECS

      ECS1配置费

      实例:ecs.c7.large (按量付费,2 vCPU 4 GiB)

      系统盘:cloud_efficiency 40GiB

      华东2(上海)

      0.450元/时

      -

      4

      ECS2配置费

      0.450元/时

      -

      5

      轻量消息队列(原MNS)

      Queue占用费

      -

      华东2(上海)

      0.5元/日

      -

      6

      API请求次数费

      -

      2.0元/百万次

      -

      7

      对象存储OSS

      标准存储(本地冗余)容量(Storage)费

      -

      华东2(上海)

      0.12元/GB/月

      PUT类或GET类请求费

      -

      华东2(上海)

      0.01元/万次

      8

      函数计算FC

      函数调用次数费

      -

      华东2(上海)

      0.01元/万次

      -

      GPU使用量费

      -

      0.0007元/GB*秒

      -

      活跃vCPU使用量费

      -

      0.000127元/vCPU*秒

      -

      内存使用量费

      -

      0.0000127元/GB*秒

      -

      公网出流量费

      -

      0.50元/GB

      -

      9

      视频点播VOD

      媒资管理费

      -

      华东2(上海)

      0.12元/GB/月

      按量费用:6.55元/时

一键部署

15

一键部署基于阿里云资源编排服务ROS(Resource Orchestration Service)实现,ROS模板已定义好脚本,可自动化地完成云资源的创建和配置,提高资源的创建和部署效率。ROS模板完成的内容包括:

操作步骤

您可以通过下方提供的ROS一键部署链接,来自动化地完成这些资源的创建和配置:

  • 创建2个云服务器ECS。

  • 创建1个负载均衡ALB。

  • 创建1个专有网络VPC。

  • 创建2台交换机。

  • 创建1个视频点播VOD。

  • 创建1个轻量消息队列(原MNS).

  • 创建1个函数计算FC服务。

  • 创建2个对象存储OSS Bucket。

  • 创建2RAM角色。

  1. 一键部署资源。

    1. 单击一键部署,并选择华东2(上海)地域。

      重要

      为避免因地域不支持云服务而导致部署失败,建议您参考本方案选择进行部署测试。实际部署生产时,请确保您选择的地域已支持以上云服务。

    2. 配置模板参数页面修改资源栈名称,配置ECS实例、OSS Bucket。填写完所有必选信息并确认后单击创建开始一键配置。

    3. 资源栈信息页面的状态显示为创建成功时表示一键配置完成。

  2. 部署函数计算代码。

    1. 在资源栈页面选择事件页签,找到FcTrigger,在其右侧单击资源ID。

    2. 函数 VideoWatermark 详情页面,选择函数代码页签。

    3. 函数代码页签下的index.py文件的内容,替换为以下代码示例,在替换代码示例时,将bucket_src替换为启用视频点播服务时配置的Bucket的名称,将bucket_target替换为存储处理后的视频使用的Bucket的名称。

      示例代码

      # -*- coding: utf-8 -*-
      import subprocess
      import oss2
      import logging
      import json
      import os
      import time
      import base64
      
      logging.getLogger("oss2.api").setLevel(logging.ERROR)
      logging.getLogger("oss2.auth").setLevel(logging.ERROR)
      
      LOGGER = logging.getLogger()
      
      '''
      1. function and bucket locate in same region
      2. service's role has OSSFullAccess
      3. event format
      {
          "bucket_name" : "test-bucket",
          "object_key" : "a.mp4",
          "output_dir" : "output/",
          "vf_args" : "drawtext=fontfile=/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc:text='hello函数计算':x=100:y=50:fontsize=24:fontcolor=red:shadowy=2",
          "filter_complex_args": "overlay=0:0:1"
      }
      
      filter_complex_args 优先级 > vf_args
      
      vf_args:
      - 文字水印
      vf_args = "drawtext=fontfile=/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc:text='hello函数计算':x=50:y=50:fontsize=24:fontcolor=red:shadowy=1"
      - 图片水印, 静态图片
      vf_args = "movie=/code/logo.png[watermark];[in][watermark]overlay=10:10[out]"
      
      filter_complex_args: 图片水印, 动态图片gif
      filter_complex_args = "overlay=0:0:1"
      '''
      
      # a decorator for print the excute time of a function
      
      
      def print_excute_time(func):
          def wrapper(*args, **kwargs):
              local_time = time.time()
              ret = func(*args, **kwargs)
              LOGGER.info('current Function [%s] excute time is %.2f seconds' %
                          (func.__name__, time.time() - local_time))
              return ret
          return wrapper
      
      
      def get_fileNameExt(filename):
          (fileDir, tempfilename) = os.path.split(filename)
          (shortname, extension) = os.path.splitext(tempfilename)
          return fileDir, shortname, extension
      
      
      @print_excute_time
      def handler(event, context):
          # 解析消息获取上传视频地址
          evt = json.loads(event)
          message = evt[0]["messageBody"]
          parsed_message = message.encode("utf-8").decode("unicode_escape")
          info_bytes = base64.urlsafe_b64decode(parsed_message)
          infoData = json.loads(info_bytes)
          fileUrl = infoData["FileUrl"]
          oss_bucket_name = "bucket_src"
      
          # 从上传视频地址fileUrl解析object key,fileUrl 如 bucketname.oss-cn-shanghai.aliyuncs.com/object-key.mp4
          url_split_array = fileUrl.split('com/', 1)
          object_key = url_split_array[1]
      
          output_dir = "output/"
          vf_args = "movie=/code/logo.png[watermark];[in][watermark]overlay=10:10[out]"
          filter_complex_args = "overlay=0:0:1"
      
          LOGGER.info('object_key:{}'.format(object_key))
      
          if not (vf_args or filter_complex_args):
              assert "at least one of 'vf_args' and 'filter_complex_args' has value"
      
          # 初始化oss client
          creds = context.credentials
          auth = oss2.StsAuth(creds.accessKeyId,
                              creds.accessKeySecret, creds.securityToken)
          oss_client = oss2.Bucket(
              auth, 'oss-%s-internal.aliyuncs.com' % context.region, oss_bucket_name)
      
          exist = oss_client.object_exists(object_key)
          LOGGER.info('exist:{}'.format(exist))
          if not exist:
              raise Exception("object {} is not exist".format(object_key))
      
          # 生成包含签名的url地址,允许ffmpeg命令临时访问视频
          input_path = oss_client.sign_url('GET', object_key, 3600)
      
          # 生成输出文件路径
          fileDir, shortname, extension = get_fileNameExt(object_key)
          dst_video_path = os.path.join("/tmp", "watermark_" + shortname + extension)
      
          # 构造添加水印命令并执行
          cmd = ["ffmpeg", "-y", "-i", input_path,
                 "-vf", vf_args, dst_video_path]
      
          if filter_complex_args:  # gif
              cmd = ["ffmpeg", "-y", "-i", input_path, "-ignore_loop", "0",
                     "-i", "/code/logo.gif", "-filter_complex", filter_complex_args, dst_video_path]
      
          LOGGER.info("cmd = {}".format(" ".join(cmd)))
          try:
              subprocess.run(
                  cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
          except subprocess.CalledProcessError as exc:
              LOGGER.error('returncode:{}'.format(exc.returncode))
              LOGGER.error('cmd:{}'.format(exc.cmd))
              LOGGER.error('output:{}'.format(exc.output))
              LOGGER.error('stderr:{}'.format(exc.stderr))
              LOGGER.error('stdout:{}'.format(exc.stdout))
      
          video_key = os.path.join(output_dir, fileDir, shortname + extension)
      
          # 初始化目标oss client,并上传带水印视频
          oss_client2 = oss2.Bucket(
              auth, 'oss-%s-internal.aliyuncs.com' % context.region, "bucket_target")
          oss_client2.put_object_from_file(video_key, dst_video_path)
      
          LOGGER.info("Uploaded {} to {} ".format(dst_video_path, video_key))
      
          # 移除本地文件
          os.remove(dst_video_path)
      
          return "ok"
    4. 单击部署代码

验证及清理

15

方案验证

部署云服务后,可以通过测试上传视频文件并获取添加水印的视频文件来进行验证。

一、通过函数计算FC日志,监控任务执行

  1. 开启函数计算FC日志

登录函数计算控制台,在左侧导航栏选择服务及函数,在服务列表页面找到目标服务,点击服务名进入服务详情,然后点击VideoWatermark函数,找到调用日志标签,按照页面提示点击一键启用开启日志功能

image

  1. 上传视频文件

登录应用型负载均衡ALB控制台,在实例页面的DNS名称,复制应用型负载均衡ALB实例的DNS地址,在浏览器访问上传视频页面地址DNS名称:8000

image

在上传视频页面,选择上海地域,选择并上传视频文件。

image

  1. 查看转码任务进度

登录函数计算控制台,进入VideoWatermark函数详情页,点击调用日志 > 函数日志,确认函数计算是否成功调用并处理上传的视频文件。

image

当任务执行完毕,可以在请求列表中看到调用结果和执行时间。

image

  1. 监控轻量消息队列(原MNS)

登录轻量消息队列(原MNS)控制台,在队列列表中点击 video-website-mns-queue,在云监控中查看消息队列中的消息流转情况,确保视频上传消息已成功推送并被函数计算FC消费。

image

二、通过查看OSS中的文件,验证视频水印添加效果

  1. 查看上传文件

登录视频点播管理控制台,在左侧导航栏,选择媒资库>音/视频,可以看到上传成功的视频文件。

image

  1. 查看处理后的文件

登录OSS管理控制台,在顶部菜单栏选择华东2(上海)地域。在左侧导航栏选择Bucket列表,单击“vod-bucket-target”。在文件列表页面找到添加水印的视频,可以下载到本地查看添加水印后的视频效果。

image

清理资源

在本方案中,您创建了2台云服务器ECS实例、1个应用型负载均衡ALB实例、2个交换机、1个专有网络VPC、1个云数据库PolarDB MySQL版实例。测试完方案后,您可以参考以下规则处理对应产品的实例,避免继续产生费用:

  1. 手动删除对象存储OSS Bucket。

    登录OSS管理控制台,在左侧导航栏,选择Bucket列表,单击目标Bucket,在文件列表,选择目标文件,然后单击彻底删除。在左侧导航栏,选择删除Bucket,单击删除Bucket,根据页面提示删除Bucket。

  2. 手动删除FC服务。

    登录函数计算控制台,在左侧导航栏,选择服务及函数,在服务列表页面,找到目标服务,在其右侧操作列,单击删除,根据页面提示删除服务。

  3. 手动删除VOD服务。

    登录视频点播管理控制台,在左侧导航栏,选择媒资库>音/视频,删除目标文件。在左侧导航栏,选择配置管理 > 媒资管理配置 > 存储管理,在目标Bucket右侧操作列,单击删除,根据页面提示删除Bucket。

  4. 一键自动删除其他资源。

    1. 登录ROS控制台

    2. 在左侧导航栏,选择资源栈

    3. 资源栈页面的顶部选择部署的资源栈所在地域,找到资源栈,然后在其右侧操作列,单击删除

    4. 删除资源栈对话框,选择删除方式释放资源,然后单击确定,根据提示完成资源释放。

AI助理

点击开启售前

在线咨询服务

你好,我是AI助理

可以解答问题、推荐解决方案等