
# 视频转码
![](https://support.huaweicloud.com/usermanual-obs/public_sys-resources/note_3.0-zh-cn.png)
文档已迁移至[数据工坊 DWR](https://support.huaweicloud.com/dwr/index.html)，请前往查看。
#### 场景介绍
针对使用Data+做视频转码的场景，如果需要**每个对象转码任务的参数不同**，可通过给对象增加对象元数据（例如：x-obs-meta-transcode-commands: base64(commands)），再使用Data+集成自定义函数的方式来实现。
具体的Data+工作流视图如[图1]所示。
图1Data+工作流视图   
![](https://support.huaweicloud.com/usermanual-obs/figure/zh-cn_image_0000001890015401.png "点击放大")
#### 资源和成本
![](https://support.huaweicloud.com/usermanual-obs/public_sys-resources/note_3.0-zh-cn.png)
算子就是具有数据处理能力的函数，详情参见[预置模板参数说明](https://support.huaweicloud.com/usermanual-obs/obs_03_0361.html#ZH-CN_TOPIC_0000001858344950)。
表1资源和成本规划 
| 资源              | 资源说明                                                                                     | 数量 | 每月费用                                                                                                                                                       |
|:---|:---|:---|:---|
| OBS             | 算子请求OBS API。                                                                             | 1  | 通过算子对数据进行处理，都会涉及到对OBS API的调用，每调用一次API都计算一次请求次数。对象存储服务OBS会根据调用API的请求次数进行费用收取，收取详情参见[OBS请求费用说明](https://support.huaweicloud.com/price-obs/obs_42_0004.html)。 |
| FunctionGraph函数 | 算子使用FunctionGraph函数工作流。                                                                  | 1  | 通过算子对数据进行处理，会使用到函数工作流的资源，比如算子执行时长，函数工作流会根据资源使用情况进行收费，收费详情参见[函数工作流计费说明](https://support.huaweicloud.com/price-functiongraph/functiongraph_00_0001.html)。    |
| 视频转码            | 新建转码任务可以将视频进行转码，并在转码过程中压制水印、视频截图等。视频转码前需要配置转码模板。 待转码的音视频需要存储在与媒体处理服务同区域的OBS桶中，且该OBS桶已授权。 | 1  | 由媒体处理服务MPC进行收费，详情查看[计费说明](https://support.huaweicloud.com/price-mpc/mpc_10_0001.html)。                                                                     |
   
#### 操作步骤
1. 创建解析对象元数据并封装MPC转码任务的函数。 
   在FunctionGraph创建函数，选择"Python 2.7"运行时语言，并为函数配置具有访问OBS权限的委托，最后配置函数环境变量：region_id=cn-north-4。
   图2创建函数   
   ![](https://support.huaweicloud.com/usermanual-obs/figure/zh-cn_image_0000001843734944.gif "点击放大")
   具体代码如下：
   ```
   # -*- coding:utf-8 -*-
   import urllib
   import os
   from obs import ObsClient  # Require public dependency:esdk_obs_python-3.x
   import base64
   class CreateTranscodingReq:
       def __init__(self, input=None, output=None, trans_template_id=None, av_parameters=None, output_filenames=None,
                    user_data=None, watermarks=None, thumbnail=None, priority=None, subtitle=None, encryption=None,
                    crop=None, audio_track=None, multi_audio=None, video_process=None, audio_process=None):
           if input is not None:
               self.input = input
           self.output = output
           if trans_template_id is not None:
               self.trans_template_id = trans_template_id
           if av_parameters is not None:
               self.av_parameters = av_parameters
           if output_filenames is not None:
               self.output_filenames = output_filenames
           if user_data is not None:
               self.user_data = user_data
           if watermarks is not None:
               self.watermarks = watermarks
           if thumbnail is not None:
               self.thumbnail = thumbnail
           if priority is not None:
               self.priority = priority
           if subtitle is not None:
               self.subtitle = subtitle
           if encryption is not None:
               self.encryption = encryption
           if crop is not None:
               self.crop = crop
           if audio_track is not None:
               self.audio_track = audio_track
           if multi_audio is not None:
               self.multi_audio = multi_audio
           if video_process is not None:
               self.video_process = video_process
           if audio_process is not None:
               self.audio_process = audio_process
   def handler(event, context):
       # 获取上传桶、对象信息
       bucketName = event['Records'][0]['obs']['bucket']['name']
       objectKey = urllib.unquote(event['Records'][0]['obs']['object']['key'])  # a/b/c
       prefix = os.path.basename(objectKey)
       obsServer = 'obs.cn-north-7.ulanqab.huawei.com'
       # 使用obs sdk
       obsClient = newObsClient(context, obsServer)
       # 获取对象元数据
       resp = obsClient.getObjectMetadata(bucketName, objectKey)
       if resp.status < 300:
           print('headers: {}'.format(resp.header))
       else:
           print('errorCode: %s, errorMessage: %s', resp.errorCode, resp.errorMessage)
           return "ERROR"
       # 获取转码命令元数据
       command_base64 = dict(resp.header)["transcode-command"]
       print("command base64 {}".format(command_base64))
       if not command_base64:
           return "Error"
       # base64反解析
       command = base64.b64decode(command_base64)
       print("command :{}".format(command))
       # 解析转码命令
       command_map = trans(command)
       # 封装MPC转码任务参数
       av_parameters = []
       watermarks = []
       if "avthumb" in command_map:
           av_param = {}
           _type = 4
           if command_map["avthumb"] == "mp4":
               _type = 4
               av_param["video"] = {
                   "output_policy": "transcode",
                   "codec": 1,
                   "bitrate": 40,
                   "max_iframes_interval": 5,
               }
           elif command_map["avthumb"] == "mp3":
               _type = 5
               av_param["audio"] = {}
           av_param["common"] = {
               "pack_type": _type,
               "PVC": False,
               "hls_interval": 2,
               "dash_interval": 2,
           }
           av_parameters.append(av_param)
       # 文字水印参数封装
       if "wmText" in command_map:
           watermarks.append({
               "text_context": command_map["wmText"],
               "text_watermark": {
                   "dx": command_map["wmOffsetX"],
                   "dy": command_map["wmOffsetY"],
                   "font_size": command_map["wmFontSize"],
               }
           })
       # 图片水印参数封装
       if "wmImage" in command_map:
           watermarks.append({
               "input": {
                   "location": context.getUserData('region_id'),
                   "bucket": bucketName,
                   "object": objectKey
               },
               "image_watermark": {
                   "dx": command_map["wmOffsetX"],
                   "dy": command_map["wmOffsetY"],
               }
           })
       transcode_req = CreateTranscodingReq(input={
           "location": context.getUserData('region_id'),
           "bucket": bucketName,
           "object": objectKey
       }, output={
           "location": context.getUserData('region_id'),
           "bucket": bucketName,
           "object": prefix,
           "file_name": "demo.mp4"
       }, av_parameters=av_parameters,
           watermarks=watermarks)
       event["dynamic_source"] = {
           "transcodes": [
               transcode_req.__dict__
           ]
       }
       return event
   def newObsClient(context, obsServer):
       ak = context.getAccessKey()
       sk = context.getSecretKey()
       return ObsClient(access_key_id=ak, secret_access_key=sk, server=obsServer)
   def trans(command):
       commands = str(command).split("/")
       ret = {}
       key = ''
       for i in range(0, len(commands)):
           if i % 2 == 0:
               key = commands[i]
               continue
           ret[key] = commands[i]
       return ret
   ```
   
   
2. 创建工作流。 
   关联步骤一的自定义函数和"媒资转码"算子。拓扑图如[图3]所示。
   ![](https://support.huaweicloud.com/usermanual-obs/public_sys-resources/notice_3.0-zh-cn.png)
   需要关闭自定义算子和"媒资转码"算子的动态参数开关。
   图3创建工作流   
   ![](https://support.huaweicloud.com/usermanual-obs/figure/zh-cn_image_0000001843576256.gif "点击放大")
   
   
3. 配置触发器。 
   触发器关联到需要做转码的桶，并根据业务需要指定对象前、后缀。
   图4配置触发器   
   ![](https://support.huaweicloud.com/usermanual-obs/figure/zh-cn_image_0000001889855869.gif "点击放大")
   
   
4. 上传对象。 
   上传对象时带上自定义对象元数据，具体代码如下：
   ```
   # -*- coding:utf-8 -*-
   from obs import ObsClient
   import base64
   if __name__ == '__main__':
       # 上传后使用Data+做转码的参数
       command = "avthumb/mp4/wmText/dGVzdF90ZXh0/wmGravityText/SouthEast/wmFontSize/20/wmOffsetX/10/wmOffsetY/38"
       client = ObsClient(
           access_key_id="XXX",
           secret_access_key="XXX",
           server="https://obs.cn-north-4.myhuaweicloud.com"
       )
       # 上传对象，并配置转码对象命令元数据
       resp = client.putObject("dataplus-test", "test.sh", "content", metadata={
           "x-obs-meta-transcode-command": base64.b64encode(command)
       })
       print resp
   ```
   
   
 
