# -*- coding: utf-8 -*-
# 导入基础库模块
import logging # 日志记录模块,用于调试和错误追踪
import json # JSON数据处理模块
import oss2 # 阿里云OSS对象存储SDK
import os # 系统路径操作
import sys # 系统参数处理
from typing import List # 类型提示支持
from collections import namedtuple # 命名元组数据结构
import time # 时间处理模块
# 导入阿里云ICE视频处理SDK(网页5核心接口)
from alibabacloud_ice20201109.client import Client as ICE20201109Client
from alibabacloud_ice20201109 import models as ice20201109_models
# 凭证管理模块(网页1认证流程)
from alibabacloud_credentials.client import Client as CredClient
from alibabacloud_credentials.models import Config as CredConfig
# 阿里云SDK核心配置(网页3服务接入说明)
from alibabacloud_tea_openapi.models import Config
logger = logging.getLogger() # 初始化日志记录器
class Sample:
# 初始化阿里云ICE客户端(网页1认证配置)
@staticmethod
def create_client(context, region: str) -> ICE20201109Client:
# 构建STS临时凭证配置(网页3鉴权方式)
credconfig = CredConfig(
type='sts',
access_key_id=context.credentials.access_key_id, # 临时访问密钥ID
access_key_secret=context.credentials.access_key_secret, # 临时访问密钥
security_token=context.credentials.security_token # 安全令牌
)
# 创建凭证客户端实例
cred = CredClient(credconfig)
# 配置API端点(网页5区域配置规范)
config = Config(credential=cred)
config.endpoint = 'ice.' + region + '.aliyuncs.com' # 上海区域服务地址
return ICE20201109Client(config) # 返回初始化后的视频处理客户端
# 主处理流程(网页5的SubmitMediaProducingJob接口)
@staticmethod
def main(context, timeline, project_metadata, output_media_config):
region = 'cn-shanghai' # 指定华东2(上海)区域
client = Sample.create_client(context, region) # 初始化客户端
# 构建视频生产作业请求(网页5接口参数规范)
submit_media_producing_job_request = ice20201109_models.SubmitMediaProducingJobRequest()
# 设置时间线参数(网页5的Timeline数据结构)
submit_media_producing_job_request.timeline = timeline
# 设置项目元数据(网页5的ProjectMetadata参数)
submit_media_producing_job_request.project_metadata = project_metadata
# 设置输出配置(网页5的OutputMediaConfig参数)
submit_media_producing_job_request.output_media_config = output_media_config
# 提交合成作业请求
submit_media_producing_job_response = client.submit_media_producing_job(
submit_media_producing_job_request)
job_id = submit_media_producing_job_response.body.job_id # 获取作业ID
# 打印调试信息(生产环境建议改为logger输出)
print(submit_media_producing_job_response)
print('request id:', submit_media_producing_job_response.body.request_id)
print('project id:', submit_media_producing_job_response.body.project_id)
print('job id', job_id)
return waitFinish(client, job_id) # 进入作业状态轮询
def waitFinish(client, job_id):
"""轮询作业状态(网页5的GetMediaProducingJob接口)"""
max_cnt = 30 # 最大轮询次数(150秒超时)
while max_cnt > 0:
max_cnt -= 1
time.sleep(5) # 每5秒查询一次状态
# 构建作业查询请求
get_media_producing_job_request = ice20201109_models.GetMediaProducingJobRequest()
get_media_producing_job_request.job_id = job_id
# 查询作业状态
response = client.get_media_producing_job(get_media_producing_job_request)
# 成功状态处理(网页5状态码说明)
if response.body.media_producing_job.status == 'Success':
return {
'status': 0,
'job_id': job_id,
'duration': response.body.media_producing_job.duration, # 视频时长
'media_url': response.body.media_producing_job.media_url, # OSS输出地址
'error_code': '0'
}
# 失败状态处理
if response.body.media_producing_job.status == 'Failed':
error_code = response.body.media_producing_job.code
return {
'status': 1,
'job_id': job_id,
'media_url': response.body.media_producing_job.media_url,
'error_code': error_code
}
return {'status': 1, 'job_id': job_id, 'media_url': 'failed', 'error_code': 'exceed max limit' }
def to_seconds(time_str):
"""将HH:MM格式时间转换为秒数(网页5时间线参数要求)"""
return int(time_str[:2]) * 60 + int(time_str[3:])
def convert(event):
"""将输入事件转换为时间线素材(网页5时间线组装规范)"""
# 定义数据结构(网页5的VideoTrackClips/AudioTrackClips结构)
VideoClip = namedtuple('ImageClip', ['Type','MediaURL', 'TimelineIn','TimelineOut'])
AudioClip = namedtuple('AudioClip', ['MediaURL','TimelineIn', 'TimelineOut'])
VideoTrackClips = [] # 视频轨道片段集合
AudioTrackClips = [] # 音频轨道片段集合
tin, tout = 0, 0 # 时间线起始/结束时间
# 初始化素材容器(网页5素材管理规范)
clips = [{} for _ in range(len(event['gen_images']))]
# 处理图片素材(网页5的Image类型参数)
for img in event['gen_images']:
cur_obj = clips[int(img['id'])]
cur_obj['img_oss_url'] = img['img_oss_url'] # OSS图片地址
# 处理音频素材(网页5的AudioTrackClips参数)
for audio in event['gen_audios']:
cur_obj = clips[int(audio['id'])]
cur_obj['audio_url'] = audio['audio_url'] # OSS音频地址
cur_obj['audio_time'] = to_seconds(audio['audio_time']) # 音频时长
# 构建时间线片段(网页5时间线拼接逻辑)
for event_clip in clips:
audio_url = event_clip['audio_url']
audio_duration = event_clip['audio_time']
img_url = event_clip['img_oss_url']
tout = tout + audio_duration + 1 # 计算片段结束时间
# 创建视频片段对象(网页5的VideoTrackClips参数)
video_clip = VideoClip('Image', img_url, tin, tout)
# 创建音频片段对象(网页5的AudioTrackClips参数)
audio_clip = AudioClip(audio_url, tin, tout)
VideoTrackClips.append(video_clip._asdict())
AudioTrackClips.append(audio_clip._asdict())
tin = tout # 更新起始时间
return {'VideoTrackClips': VideoTrackClips, 'AudioTrackClips': AudioTrackClips}
def handler(event, context):
"""入口函数(网页5的云剪辑工程创建流程)"""
try:
event = json.loads(event) # 解析输入事件
logger = logging.getLogger()
# 生成时间线配置(网页5的Timeline结构)
clips = convert(event)
logger.info(clips)
# 构建完整时间线(网页5的多轨道配置规范)
timeline = {
'VideoTracks': [{'VideoTrackClips': clips['VideoTrackClips']}],
'AudioTracks': [{"MainTrack": True, 'AudioTrackClips': clips['AudioTrackClips']}]
}
# 项目元数据配置(网页5的ProjectMetadata参数)
project_metadata = {
'coverURL': 'sfs', # 封面图地址
'description': 'my test',
'title': 'test ice',
'tags': 'testicee'
}
# 输出配置(网页5的OutputMediaConfig参数)
output_media_config = {
'mediaURL': event['context']['oss_output'] # 输出OSS路径
}
# 提交合成任务(网页5的核心接口调用)
return Sample.main(context, json.dumps(timeline),
json.dumps(project_metadata),
json.dumps(output_media_config))
except Exception as e:
logger.error("图片合成视频失败~"+ str(e.__cause__))
raise Exception("图片合成视频失败~") # 错误处理(网页5的异常处理建议)
video
最新推荐文章于 2025-08-04 16:58:05 发布