iT邦幫忙

2025 iThome 鐵人賽

DAY 19
0

前情提要

作為 【Day 4】 使用 Elemental MediaConvert 轉檔 的功能實踐,本篇將說明串接 API Gateway 達到透過 Web UI 一鍵觸發轉檔!!

說明

  • 如同前一篇提到,並不是所有的瀏覽器都支援播放 mov,作為 iPhone 預設綠影格式,要擺到瀏覽器中播放查看,需要轉換成 mp4

設置概述

  1. 將下列程式碼放到 Lambda
import os, json, boto3, jwt

SECRET = os.environ.get("JWT_SECRET", "mysecret")
BUCKET_NAME = os.environ.get("BUCKET_NAME", "exsky-backup-media")
REGION = os.environ.get("AWS_REGION", "ap-northeast-1")

mediaconvert = boto3.client("mediaconvert", region_name=REGION)

def lambda_handler(event, context):
    # --- JWT 驗證 ---
    headers = event.get("headers", {}) or {}
    auth = headers.get("authorization") or headers.get("Authorization") or ""
    if not auth.startswith("Bearer "):
        return _unauthorized("Missing token")
    token = auth.split(" ")[1]

    try:
        decoded = jwt.decode(token, SECRET, algorithms=["HS256"])
        username = decoded.get("username", "unknown")
    except Exception:
        return _unauthorized("Invalid token")

    # --- 解析 body ---
    try:
        body = json.loads(event.get("body", "{}"))
        key = body.get("key")
        if not key:
            return _bad_request("Missing key")
    except Exception:
        return _bad_request("Invalid body")

    # --- 準備 MediaConvert Job ---
    try:
        # 找到帳號專屬的 MediaConvert endpoint
        endpoints = mediaconvert.describe_endpoints(MaxResults=1)
        mediaconvert_ep = boto3.client("mediaconvert", endpoint_url=endpoints["Endpoints"][0]["Url"], region_name=REGION)

        job_settings = {
            "Inputs": [
                {
                    "FileInput": f"s3://{BUCKET_NAME}/{key}",
                    "AudioSelectors": {
                        "Audio Selector 1": {"DefaultSelection": "DEFAULT"}
                    },
                    "VideoSelector": {}
                }
            ],
            "OutputGroups": [
                {
                    "Name": "File Group",
                    "OutputGroupSettings": {
                        "Type": "FILE_GROUP_SETTINGS",
                        "FileGroupSettings": {
                            "Destination": f"s3://{BUCKET_NAME}/{username}/converted/"
                        }
                    },
                    "Outputs": [
                        {
                            "ContainerSettings": {"Container": "MP4"},
                            "VideoDescription": {
                                "CodecSettings": {
                                    "Codec": "H_264",
                                    "H264Settings": {"Bitrate": 5000000, "RateControlMode": "CBR"}
                                }
                            },
                            "AudioDescriptions": [
                                {"CodecSettings": {"Codec": "AAC", "AacSettings": {"Bitrate": 96000}}}
                            ]
                        }
                    ]
                }
            ]
        }

        resp = mediaconvert_ep.create_job(
            Role=os.environ["MEDIACONVERT_ROLE"],  # IAM role ARN
            Settings=job_settings
        )

        return {
            "statusCode": 200,
            "headers": {"Access-Control-Allow-Origin": "https://vlog.nipapa.tw"},
            "body": json.dumps({"jobId": resp["Job"]["Id"]})
        }

    except Exception as e:
        return _server_error(str(e))


# ---- Helpers ----
def _unauthorized(msg):
    return {
        "statusCode": 401,
        "headers": {"Access-Control-Allow-Origin": "https://vlog.nipapa.tw"},
        "body": json.dumps({"error": msg})
    }

def _bad_request(msg):
    return {
        "statusCode": 400,
        "headers": {"Access-Control-Allow-Origin": "https://vlog.nipapa.tw"},
        "body": json.dumps({"error": msg})
    }

def _server_error(msg):
    return {
        "statusCode": 500,
        "headers": {"Access-Control-Allow-Origin": "https://vlog.nipapa.tw"},
        "body": json.dumps({"error": msg})
    }

  1. 設定 role 的 Trust relationships,使這個 Lambda 可以呼叫 mediaconvert
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "lambda.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "mediaconvert.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
  1. 在前端加上按鈕,這邊我們不去預設全部轉檔,理由是因為,轉檔會花錢,所以確定有要轉,按下去再噴錢去轉檔。

結論

  • 今天也完成字幕產生了,後續再改善流程。

上一篇
【Day 18】 設計 Delete 按鈕給使用者刪除已上傳的影音
下一篇
【Day 20】 會員功能擴充 - 設定寄信重設密碼功能 (上)
系列文
無法成為片師也想拍 Vlog?!個人影音小工具的誕生!24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言