使用场景
快速生成回放文件
直播回放可以将优质资源的价值进行放大,降低优质资源的成本,从而提升收益,通过全景录制功能可以在用户的视角将上课的内容实时录制下来,课程结束之后可以根据 Serverless 庞大的算力池快速转码,形成录制文件,实时生成回放。
精彩瞬间
家长很少有时间全程观看孩子的上课视频,通过精彩瞬间可以将孩子上课过程精彩表现呈现给家长,提升家长对课程的认知度和认可感,针对上课过程中录制的文件,可以使用 H5 平台将上课的精彩内容截取下来,然后采取全景录制生成 mp4 文件,通过 CDN 快速分发,形成孩子上课过程的精彩集锦。
文件合成
常规的文件合成需要转码,对于算力的消耗较大,将视频、声音、图片等,在一个前端页面进行合成,进行布局调整,采取全景录制进行录制,多路解码,一路编码,快速生成视频文件,最大程度使用算力资源。
架构原理
腾讯云自研的全景录制,主打所见即所得的录制理念,只需要用户提供一个可供访问的公网链接,采取 Chrome 进行页面渲染录制,ffmpeg 转码,同时直接上传到 COS,实时生成录制文件。结合直播、点播、 TRTC 等腾讯云产品,提供教育,游戏,互娱等一站式数据解决方案。
应用优势
更低成本
通过 Chrome 完成多路解码,一路解码,算力消耗降低,与传统录制方案相比,成本可以降低60%以上。
高度还原
客户端上课过程中所有的特效等外部信息都可以捕捉到,达到100%实现课堂实际效果。
自由切换
录制过程中可以灵活调整浏览器布局,灵活操作和切换老师,学生等视角。
超高并发
云函数计算实例支持快速启动,高并发承载能力稳定,轻松面对突发的业务峰值。
即刻出片
用户直播结束之后可以直接拿到回放,不需要进行复杂的合成工作,省时高效。
应用资源
全景录制应用部署后,将为您创建以下资源:
云函数:获取外部链接数据,通过全景录制实时进行录制。
CLS 日志:处理过程的日志会存储在日志服务 CLS 中,可能会产生一定计费,详情请参见 CLS 计费规则。
API 网关/函数 URL:通过 API 网关触发器或函数 URL 进行事件触发。
前提条件
1. 配置部署账号权限。详情请参见 账号和权限配置。
2. 配置 运行角色 权限。
3. 全景录制需要和其他服务关联使用,需要添加以下策略:QcloudRedisFullAccess、QcloudVPCFullAccess、QcloudCFSFullAcces、QcloudSCFFullAccess、QcloudCOSFullAccess、QcloudAccessForScfRole 权限。详情请参见 策略绑定。
操作步骤
创建依赖资源
创建全景录制应用
1. 登录 Serverless 控制台,选择左侧导航栏中的 Serverless 应用。
2. 在 Serverless 应用页面,单击新建应用。
3. 在新建应用页面,根据页面相关信息提示进行配置。
创建方式:选择应用市场。
模糊搜索:输入“全景”进行搜索,选择全景录制。如下图所示:
单击模板中的查看详情,即可在弹出的“模板详情”窗口中查看相关信息,支持下载操作。
4. 单击下一步,根据页面相关信息提示进行配置。如下图所示:
应用名:例如,“record-app”。
地域:例如,“上海”。
中间结果存储:录制过程临时文件存放位置,可以根据自己需求选择 COS 或者 CFS。
目标存储:录制结果的最终存放位置,可以根据需要选择 VOD 或者 COS。
文件系统:按需选择即可。
Redis:按需选择即可。
5. 单击完成即可完成应用创建、函数创建以及 API 网关触发器或函数 URL 创建。
如需根据业务场景修改函数配置,可通过 Serverless 应用 > 资源列表 > 函数详情 进行修改。如下图所示:
接口使用说明
使用前提
准备一个可以通过 URL 访问的 WEB 页面作为录制内容来源,此页面需兼容 Chrome。
用于录制的页面需要自行处理可能存在的登录态或者鉴权。
用于录制的页面如果需要播放多媒体,需要自行处理多媒体的播放、跳转、停止等操作。
用于录制的页面需要在指定的宽高内完整的显示所有内容,不能有滚动条,因为 WEB 全景录制只能录制浏览器窗口的可见区域,超出可见区的内容不会被录制下来。
接口请求路径
1. 登录 Serverless 控制台,选择左侧导航栏中的 Serverless 应用。
2. 在 Serverless 应用列表页,单击应用名称。
3. 在应用详情页,获取触发器访问入口。如下图所示:
POST
Content-Type: application/json
全景录制服务接口由云函数实现,采用了 API 网关触发器或函数 URL 方式对外提供服务,API 网关触发器鉴权采用应用认证方式(ApiAppKey 和 ApiAppSecret),详情请参见 应用鉴权。
开始录制接口
通过此接口可以发起全景录制,在接口参数中指定录制 URL,录制分辨率,录制结果回调地址等参数。
参数 | 类型 | 必填 | 说明 |
Action | string | 是 | 请求操作类型,开始录制为 Start 。 |
Data | object | 是 | 请求协议参数。 |
RecordURL | string | 是 | 需要录制的 WEB 页面访问 URL,需要 Chrome 浏览器能够访问。 |
ManualStart | bool | 是 | 创建的录制任务是否需要等待页面主动调用 window.startRecord 方法触发开始录制,默认为 false,录制任务会自动开始录制,当值被设置为 true 时,录制函数加载页面后,不会自动开始录制,而是等待页面主动调用 window.startRecord 方法才会触发开始录制。 |
Width | number | 否 | 录制画面宽度,默认为1280,合法取值范围 [0, 2560]。 |
Height | number | 否 | 录制画面高度,默认为720,合法取值范围 [0, 2560]。 |
CallbackURL | string | 否 | 录制结果通知回调地址。 |
MaxDurationLimit | int | 否 | 录制最大时长限制,单位s,合法取值范围 [0, 36000],默认21600s(6小时),超过6小时需要配置永久密钥。 |
StorageType | string | 否 | 录制过程中中间态 webm 文件的存储位置,可选参数为 cos ,不填写默认为cfs 。(如果环境变量配置了COS_BUCKET_RAW这个参数,会写在这个桶里面,不配置会写在目标存储桶的 raw 路径下)。 |
Output | object | 否 | 请求协议参数。 |
Cos | object | 否 | 请求协议参数。 |
Domain | string | 否 | 录制文件回放域名,不设置为默认源站域名。 |
Bucket | string | 否 | 录制文件存放空间,不设置默认为创建函数时设置的存储空间。 |
Region | string | 否 | 录制文件存放区域,默认为存储空间所在区域。 |
TargetDir | string | 否 | 录制文件存放路径,不设置默认为 Taskid。 |
TargetName | string | 否 | 录制文件名称,不设置为结束时间戳。 |
Vod | object | 否 | VOD 配置参数。 |
MediaInfo | object | 否 | VOD 配置媒体信息。 |
MediaName | string | 否 | 媒体名称。 |
ExpireTime | Timestamp ISO8601 | 否 | |
StorageRegion | string | 否 | 指定上传园区,仅适用于对上传地域有特殊需求的用户。 |
ClassId | Integer | 否 | |
SourceContext | string | 否 | 来源上下文,用于透传用户请求信息,VOD 的上传完成回调 将返回该字段值,最长 250 个字符。 |
ProcedureInfo | object | 否 | 任务流信息。 |
Procedure | string | 否 | |
SessionContext | string | 否 | 会话上下文,用于透传用户请求信息,当指定 Procedure 参数后,任务流状态变更回调 将返回该字段值,最长 1000 个字符。 |
SubAppId | string | 否 | |
Video | object | 否 | 请求协议参数。 |
Muxer | string | 否 | 录制文件格式,可选 hls、mp4,不写默认为 mp4。 |
EncryptKey | string | 否 | hls加密公钥,不设置默认不加密。 |
AuthUrl | string | 否 | 解密私钥地址,设置公钥的情况下必填参数。 |
{"Action": "Start","Data": {"RecordURL": "https://web-record-12596******.cos.ap-chengdu.myqcloud.com/test/ponyo.mp4","Width": 1280,"Height": 720,"CallbackURL": "http://xxx/webrecord/callback","MaxDurationLimit": 21600,"Output":{"Cos":{"Domain":"abc.xxx.com","Bucket":"webrecord-xxx","Region":"ap-shanghai","TargetDir":"11234/","TargetName":"record-file-name.mp4"},"Vod": {"MediaInfo": {"MediaName": "test","ExpireTime": "2023-10-01T10:00:00Z","StorageRegion": "ap-shanghai","ClassId": 1},"ProcedureInfo": {"Procedure": "","SessionContext": ""},"SubAppId": 1500007120},"Video": {"Muxer": "hls","EncryptKey": "21834cca41778803e1afba3f41******","AuthUrl": "https://hls-web-record-125******.cos.ap-shanghai.myqcloud.com/m3u8-encrypt/enc.key"}}}}
参数 | 类型 | 必填 | 说明 |
ErrorCode | string | 否 | 错误类型,只有请求出错的时候才会返回此字段。 |
ErrorMessage | string | 否 | 错误说明,只有请求出错的时候才会返回此字段。 |
TaskID | string | 否 | 录制任务 ID,只有开始录制成功的时候才会返回此字段。 |
RequestID | string | 否 | 请求 ID。 |
// 成功返回{"TaskID": "d1806f20-25b8-4c30-8176-c0832b******","RequestID": "95941e2c85898384a95b81c2a5******"}// 失败返回{"ErrorCode": "InvalidParam","ErrorMessage": "RecordURL missing","RequestID": "95941e2c85898384a95b81c2a5******"}
暂停录制接口
使用暂停录制接口可以将已经开始录制的任务暂时停止录制。
参数 | 类型 | 必填 | 说明 |
Action | string | 是 | 请求操作类型,暂停录制为 Pause 。 |
Data | object | 是 | 请求协议参数。 |
Data.TaskID | string | 是 | 需要暂停录制的录制任务 ID,录制任务 ID 可以在开始录制的接口返回参数中获取到。 |
{"Action": "Pause","Data": {"TaskID": "0f7d9522-a1a3-4517-b5ad-7a6eca******"}}
参数 | 类型 | 必填 | 说明 |
ErrorCode | string | 否 | 错误类型,只有请求出错的时候才会返回此字段。 |
ErrorMessage | string | 否 | 错误说明,只有请求出错的时候才会返回此字段。 |
TaskID | string | 否 | 录制任务 ID,只有开始录制成功的时候才会返回此字段。 |
RequestID | string | 否 | 请求 ID。 |
// 成功返回{"TaskID": "d1806f20-25b8-4c30-8176-c0832b******","RequestID": "95941e2c85898384a95b81c2a5******"}// 失败返回{"ErrorCode": "InvalidParam","ErrorMessage": "TaskID missing","RequestID": "95941e2c85898384a95b81c2a5******"}
恢复录制接口
使用恢复录制接口可以将已暂停的录制任务重新开始录制。重新开始录制的视频内容将直接追加在暂停之前的内容后面,不会产生视频分段。
参数 | 类型 | 必填 | 说明 |
Action | string | 是 | 请求操作类型,恢复暂停录制为 Resume 。 |
Data | object | 是 | 请求协议参数。 |
Data.TaskID | string | 是 | 需要恢复录制的录制任务 ID,录制任务 ID 可以在开始录制的接口返回参数中获取到。 |
{"Action": "Resume","Data": {"TaskID": "0f7d9522-a1a3-4517-b5ad-7a6eca******"}}
参数 | 类型 | 必填 | 说明 |
ErrorCode | string | 否 | 错误类型,只有请求出错的时候才会返回此字段。 |
ErrorMessage | string | 否 | 错误说明,只有请求出错的时候才会返回此字段。 |
TaskID | string | 否 | 录制任务 ID,只有开始录制成功的时候才会返回此字段。 |
RequestID | string | 否 | 请求 ID。 |
// 成功返回{"TaskID": "d1806f20-25b8-4c30-8176-c0832b******","RequestID": "95941e2c85898384a95b81c2a5******"}// 失败返回{"ErrorCode": "InvalidParam","ErrorMessage": "TaskID missing","RequestID": "95941e2c85898384a95b81c2a5******"}
刷新录制页面
使用刷新录制接口发起刷新录制页面请求。
参数 | 类型 | 必填 | 说明 |
Action | string | 是 | 请求操作类型,刷新录制为 Refresh 。 |
Data | object | 是 | 请求协议参数。 |
Data.TaskID | string | 是 | 需要刷新的录制任务 ID,录制任务 ID 可以在开始录制的接口返回参数中获取到。 |
{"Action": "Refresh","Data": {"TaskID": "0f7d9522-a1a3-4517-b5ad-7a6eca******"}}
参数 | 类型 | 必填 | 说明 |
ErrorCode | string | 否 | 错误类型,只有请求出错的时候才会返回此字段。 |
ErrorMessage | string | 否 | 错误说明,只有请求出错的时候才会返回此字段。 |
TaskID | string | 否 | 录制任务 ID,只有开始录制成功的时候才会返回此字段。 |
RequestID | string | 否 | 请求 ID。 |
// 成功返回{"TaskID": "d1806f20-25b8-4c30-8176-c0832b******","RequestID": "95941e2c85898384a95b81c2a5******"}// 失败返回{"ErrorCode": "InvalidParam","ErrorMessage": "TaskID missing","RequestID": "95941e2c85898384a95b81c2a5******"}
停止录制接口
使用停止录制接口发起结束录制请求。
参数 | 类型 | 必填 | 说明 |
Action | string | 是 | 请求操作类型,结束录制为 Stop 。 |
Data | object | 是 | 请求协议参数。 |
Data.TaskID | string | 是 | 需要取消的录制任务 ID,录制任务 ID 可以在开始录制的接口返回参数中获取到。 |
{"Action": "Stop","Data": {"TaskID": "0f7d9522-a1a3-4517-b5ad-7a6eca******"}}
参数 | 类型 | 必填 | 说明 |
ErrorCode | string | 否 | 错误类型,只有请求出错的时候才会返回此字段。 |
ErrorMessage | string | 否 | 错误说明,只有请求出错的时候才会返回此字段。 |
TaskID | string | 否 | 录制任务 ID,只有开始录制成功的时候才会返回此字段。 |
RequestID | string | 否 | 请求 ID。 |
// 成功返回{"TaskID": "d1806f20-25b8-4c30-8176-c0832b******","RequestID": "95941e2c85898384a95b81c2a5******"}// 失败返回{"ErrorCode": "InvalidParam","ErrorMessage": "TaskID missing","RequestID": "95941e2c85898384a95b81c2a5******"}
查询录制任务信息接口
使用查询任务信息接口发起查询录制任务信息请求。
参数 | 类型 | 必填 | 说明 |
Action | string | 是 | 请求操作类型,查询录制任务信息为 Describe 。 |
Data | object | 是 | 请求协议参数。 |
Data.TaskID | string | 是 | 需要查询的录制任务 ID,录制任务 ID 可以在开始录制的接口返回参数中获取到。 |
{"Action": "Describe","Data": {"TaskID": "0f7d9522-a1a3-4517-b5ad-7a6ec******"}}
参数 | 类型 | 必填 | 说明 |
ErrorCode | string | 否 | 错误类型,只有请求出错的时候才会返回。 |
ErrorMessage | string | 否 | 错误说明,只有请求出错的时候才会返回。 |
TaskID | string | 否 | 录制任务 ID,只有开始录制成功的时候才会返回。 |
RequestID | string | 否 | 请求 ID。 |
Status | string | 否 | 录制任务当前状态,可能的取值及其含义如下: normal:录制任务创建成功,但录制任务还没有开始录制。 recording:录制任务正在录制中。 paused:录制任务被暂停。 canceled:录制任务已经被取消。 transcode:录制任务正在对录制视频进行拼接、转码等操作。 upload:录制任务正在上传录制视频到云存储。 callback:录制任务正在把录制结果通过发起录制时配置的回调地址进行通知。 finished:录制任务的所有操作已经完成。 |
CreateTime | int | 否 | 录制任务创建时间戳,单位s。 |
StartTime | int | 否 | 录制任务开始录制时间戳,单位s,只有开始录制后才会返回此字段。 |
CancelTime | int | 否 | 录制任务被取消的时间戳,单位s,只有发起过取消录制请求才会返回此字段。 |
StopTime | int | 否 | 录制任务结束录制时间戳,单位s,只有录制任务停止后才会返回此字段。 |
FinishTime | int | 否 | 录制任务完成录制时间戳,单位s,只有录制任务完成所有录制处理后才会返回此字段。 |
Result | object | 否 | 录制任务结果。 |
Result.ErrorCode | string | 否 | 录制任务出错类型,只有录制任务执行过程中出现错误时才会返回此字段。 |
Result.ErrorMessage | string | 否 | 录制任务出错信息,只有录制任务执行过程中出现错误时才会返回此字段。 |
Result.Videos | []object | 否 | 录制视频文件列表。 |
Result.Videos.Filename | string | 否 | 视频文件名称。 |
Result.Videos.FileSize | int | 否 | 视频文件大小。 |
Result.Videos.FileDuration | string | 否 | 视频文件长度。 |
Result.Videos.FileId | string | 否 | 如果目标为 VOD,该参数为 VOD 中媒体文件的唯一标识。 |
Result.Videos.FileURL | string | 否 | 视频文件链接。 |
// 成功返回{"TaskID": "7a035551-d9d6-494e-b604-fa787b******","RequestID": "95941e2c85898384a95b81c2a5******","CreateTime": 1620982173,"Status": "finished","StartTime": 1620982177,"CancelTime": 1620982203,"StopTime": 1620982203,"FinishTime": 1620982210,"Result": {"Videos": [{"Filename": "1621406865789.mp4","FileSize": 169780,"FileDuration": 9,"FileId": 31235664578998,"FileURL": "http://web-record-125******.cos.ap-chengdu.myqcloud.com/4d0f336d-4de4-4fc8-b505-d1f790974909/162140******.mp4"}]}}// 请求出错返回{"ErrorCode": "InvalidParam","ErrorMessage": "TaskID missing","RequestID": "95941e2c85898384a95b81c2a5******"}// 录制任务出错返回{"TaskID": "7a035551-d9d6-494e-b604-fa787b******","RequestID": "95941e2c85898384a95b81c2a5******","CreateTime": 1620982173,"Status": "finished","StartTime": 1620982177,"CancelTime": 1620982203,"StopTime": 1620982203,"FinishTime": 1620982210,"Result": {"ErrorCode": "CallbackFailed","ErrorMessage": "Callback failed even all tries. last error message:ECONNABORTED:timeout of 2000ms exceeded"}}