抖声大项目的视频流和头像的文件上传功能|青训营笔记

215 阅读6分钟

这是我参与「第五届青训营」笔记创作活动的第10天。

今天主要是分享使用阿里云OSS对象存储技术实现视频流和头像的上传。

阿里OSS工作原理

OSS工作原理

数据以对象(Object)的形式存储在OSS的存储空间(Bucket )中。如果要使用OSS存储数据,需要先创建Bucket,并指定Bucket的地域、访问权限、存储类型等属性。创建Bucket后,您可以将数据以Object的形式上传到Bucket,并指定Object的文件名(Key)作为其唯一标识。

OSS以HTTP RESTful API的形式对外提供服务,访问不同地域需要不同的访问域名(Endpoint)。当您请求访问OSS时,OSS通过使用访问密钥(AccessKey ID和AccessKey Secret)对称加密的方法来验证某个请求的发送者身份。

Object操作在OSS上具有原子性和强一致性。

  • 存储空间

    存储空间是用户用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。存储空间具有各种配置属性,包括地域、访问权限、存储类型等。用户可以根据实际需求,创建不同类型的存储空间来存储不同的数据。

  • 对象

    对象是OSS存储数据的基本单元,也被称为OSS的文件。和传统的文件系统不同,对象没有文件目录层级结构的关系。对象由元信息(Object Meta),用户数据(Data)和文件名(Key)组成,并且由存储空间内部唯一的Key来标识。对象元信息是一组键值对,表示了对象的一些属性,比如最后修改时间、大小等信息,同时用户也可以在元信息中存储一些自定义的信息。

  • 对象名称

    在各语言SDK中,ObjectKey、Key以及ObjectName是同一概念,均表示对Object执行相关操作时需要填写的Object名称。例如向某一存储空间上传Object时,ObjectKey表示上传的Object所在存储空间的完整名称,即包含文件后缀在内的完整路径,如填写为abc/efg/123.jpg。

  • 地域

    Region表示OSS的数据中心所在物理位置。用户可以根据费用、请求来源等选择合适的地域创建Bucket。一般来说,距离用户更近的Region访问速度更快。详情请参见OSS已经开通的Region

  • 访问域名

    Endpoint表示OSS对外服务的访问域名。OSS以HTTP RESTful API的形式对外提供服务,当访问不同的Region的时候,需要不同的域名。通过内网和外网访问同一个Region所需要的Endpoint也是不同的。例如杭州Region的外网Endpoint是oss-cn-hangzhou.aliyuncs.com,内网Endpoint是oss-cn-hangzhou-internal.aliyuncs.com。具体的内容请参见各个Region对应的Endpoint

  • 访问密钥

    AccessKey简称AK,指的是访问身份验证中用到的AccessKeyId和AccessKeySecret。OSS通过使用AccessKeyId和AccessKeySecret对称加密的方法来验证某个请求的发送者身份。AccessKeyId用于标识用户;AccessKeySecret是用户用于加密签名字符串和OSS用来验证签名字符串的密钥,必须保密。对于OSS来说,AccessKey的来源有:

    • Bucket的拥有者申请的AccessKey。
    • 被Bucket的拥有者通过RAM授权给第三方请求者的AccessKey。
    • 被Bucket的拥有者通过STS授权给第三方请求者的AccessKey。

    更多AccessKey介绍请参见创建AccessKey

  • 强一致性

    Object操作在OSS上具有原子性,操作要么成功要么失败,不会存在有中间状态的Object。OSS保证用户一旦上传完成之后读到的Object是完整的,OSS不会返回给用户一个部分上传成功的Object。

    Object操作在OSS同样具有强一致性,用户一旦收到了一个上传(PUT)成功的响应,该上传的Object就已经立即可读,并且Object的冗余数据已经写成功。不存在一种上传的中间状态,即read-after-write却无法读取到数据。对于删除操作也是一样的,用户删除指定的Object成功之后,该Object立即变为不存在。

视频流和视频封面上传至阿里OSS对象存储

在阿里云OSS控制台创建一个公共读的bucket

如下图所示:

image.png

进行阿里云OSS代码的编写

阿里云OSS初始化相关代码的编写:

  1. 通过EndPoint,AccessKeyID,AccessKeySecret连接到个人的阿里云OSS账户,得到client。
  2. 利用该client连接到之前创建好的bucket
  3. 将这个bucket赋值给全局变量g.OssBucket,便于后续上传下载时的调用。
func OSSInit() {
   once.Do(func() {
      // 连接OSS账户
      client, err := oss.New(ossRelated.EndPoint, ossRelated.AccessKeyID, ossRelated.AccessKeySecret)

      if err != nil {
         g.Logger.Infof("连接OSS账户失败" + err.Error())
      } else { // OSS账户连接成功

         // 连接存储空间
         bucket, err = client.Bucket(ossRelated.BucketName)
         if err != nil {
            g.Logger.Infof("连接存储空间失败" + err.Error())
         } else { // 存储空间连接成功
            g.Logger.Infof("OSS初始化完成")
         }
      }
   })
   g.OssBucket = bucket

}

阿里云OSS上传视频、图片文件相关代码的编写:

指定需要上传的字节流文件和上传后的文件路径即可

在视频流模块,我们还需要通过ffmpeg截取视频的封面,然后将视频封面上传至阿里云OSS的bucket中。故fileType有video、picture两种。

func UploadFile(file []byte, filename string, fileType string) bool {
   var fileSuffix string
   if fileType == "video" {
      fileSuffix = ".mp4"
   } else if fileType == "picture" {
      fileSuffix = ".jpg"
   } else {
      g.Logger.Infof("无法上传" + fileType + "类型文件")
      return false
   }
   //指定需要上传的字节流文件和上传后的文件路径
   err := g.OssBucket.PutObject("video/"+filename+fileSuffix, bytes.NewReader(file))
   if err != nil {
      g.Logger.Infof("上传文件失败" + err.Error())
      return false
   } else {
      return true
   }
}

使用ffmpeg截取视频封面并上传至云端

首先需要下载ffmpeg至项目路径下:

image.png

cmd := exec.Command(ossRelated.FfmpegPath, "-i", videoURL, "-y", "-f", "image2", "-ss", "1", picturePath)
cmd.Run()

这两句代码可以将videoURL对应的云端video拉取下来,并截取该video的第一帧至本地的picturePath路径下。

然后以字节数组的形式读出本地的封面图,再调用前面编写好的UploadFile函数即可将封面图上传到云端。

openFile, err := os.Open(picturePath)
pictureBytes, err := ioutil.ReadAll(openFile)

视频头像上传至阿里OSS对象存储

在目前的抖声项目中,需要加入头像初始化的功能。

在此,我准备了10张系统预设头像,提前放入了项目路径下。

具体实现思路如下:

  1. 用户注册成功后会得到一个UserID,由UserID对10取模后的值决定选取哪张图片作为用户初始头像。
  2. 被选定的头像会被上传至阿里云OSS的bucket的avatar目录下,并以"userID_avatar.jpg"的格式来命名,每个用户在云端拥有一个唯一的头像文件名。

image.png

image.png

在其他服务接口需要获取auther或user的avatarURL时,只需要调用GetAvatar(userID int)函数对该UserID的avatarURL进行返回即可。

//user  Service层
// GetAvatar 获取用户头像
func GetAvatar(userID int) string {

   strUserID := strconv.Itoa(userID)
   avatarURL := ossRelated.OSSAvatarPreURL + strUserID + "_avatar.jpg"
   return avatarURL
}

总结

今天分享了使用阿里OSS对象存储实现大项目的视频、封面、头像的上传功能的具体流程。