video

# -*- 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的异常处理建议)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值