برنامه نویسی

GO – تابع Lambda برای تبدیل صدا از S3 (AWS) – ffmpeg

من روی یک پروژه شخصی کار کردم، جایی که باید یک فایل wav (صوتی با حداکثر کیفیت، بدون فشرده سازی) را به mp3 تبدیل کنم.

در این پست، گام به گام نحوه انجام “ناهمزمان” از آپلود به سطل در S3 (سرویس ذخیره سازی فایل) AWS را نشان خواهم داد.

در نقاشی زیر، زمینه ای از آنچه انجام خواهد شد و در این پست توضیح داده شده است:

ایجاد سطل

در کنسول AWS خود، به سرویس بروید S3، 2 مورد جدید ایجاد کنید سطل ها. اولین سطل، مقصد بارگذاری فایل صوتی «خام»، با فرمت wav. خواهد بود. دومی برای فایل فشرده خواهد بود و به mp3. تبدیل می شود. در مورد من از این نام ها استفاده کردم:

توضیحات تصویر

ایجاد لامبدا

بله، اجازه دهید با ایجاد تابع لامبدا که وظیفه تبدیل فایل های صوتی خام به فرمت صوتی فشرده را بر عهده دارد، ادامه دهیم. برای این، در شما کنسول AWS، در جستجویی که به دنبال آن هستم لامبدا. کلیک کنید ایجاد تابع

همانطور که در صفحه زیر نشان داده شده است، از زبان GO استفاده خواهیم کرد:

توضیحات تصویر

مجوزهای دسترسی لامبدا – S3

ایجاد پلیس و پیوند آن با نقش ایجاد شده در ایجاد لامبدا ضروری خواهد بود.

برای این کار به کنسول the دسترسی خواهیم داشت من هستم، سپس به منو بروید پلیس ها > پلیس را اضافه کنید. حالت را به JSON تغییر می دهیم و کد زیر را وارد می کنیم:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:CreateLogGroup",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::mgm-wav-files/*"
        },
        {
            "Sid": "VisualEditor2",
            "Effect": "Allow",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::mgm-mp3-files/*"
        }
    ]
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

خط مشی بالا اجازه خواندن را می دهد سطل از فایل ها موج و نوشته شده است سطل برای فایل ها mp3، تبدیل شده است. بیایید این یکی را ذخیره کنیم پلیس.

هیچ کنسولی انجام نمی دهد من هستم، بریم سراغ منو نقش ها، بیایید انتخاب کنیم نقش ایجاد شده برای لامبدا. پس بیایید ادامه دهیم مجوزها را اضافه کنید > حمله پلیس. در جستجو، نام خط مشی ایجاد شده را جستجو کرده و ذخیره کنید.

Runtime Lambda. اون چیه؟

توابع لامبدا، در زبان Go (در میان دیگران)، در زمینه محیط لینوکس، در مورد توزیع لینوکس AWS اجرا می‌شوند. در این زمینه، ما نیاز به “بارگذاری” یک lib داریم که وظیفه تبدیل صدا را بر عهده خواهد داشت.

این lib FFMPEG است. که با فرمت های مختلف رسانه ای، صوتی، تصویری سروکار دارد.

برای این کار از ویژگی توابع لامبدا در AWS به نام استفاده خواهیم کرد لایه، ترجمه: لایه

با یکی لایه، موفق شدیم تعدادی را اجرا کنیم لب در زمان اجرای یک یا چند تابع لامبدا. مانند؟

ایجاد لایه FFMPEG

بیایید باینری های این lib را در ماشین محلی خود دانلود کنیم و فقط موارد لازم را به یک فایل ZIP که در یک لایه Lambda درج می شود، انتقال دهیم.

برای این کار، از مثال زیر از یک محیط Linux/MacOS استفاده خواهم کرد:

wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz

wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz.md5

md5sum -c ffmpeg-release-amd64-static.tar.xz.md5

tar xvf ffmpeg-release-amd64-static.tar.xz
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پس از دانلود و خارج کردن فایل از حالت فشرده، بیایید یک فایل جدید ایجاد کنیم تا محتویات باینری ffmpeg را کپی کنیم و زیپ محتوای:

mkdir -p ffmpeg/bin

cp ffmpeg-4.3.1-amd64-static/ffmpeg ffmpeg/bin/

cd ffmpeg

zip -r ../ffmpeg.zip .
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

حالا بیایید یک مورد جدید ایجاد کنیم لایه در محیط Lambdas ما در AWS، فایل را پیوست کنید زیپ در مرحله بالا مانند مثال زیر ایجاد شده است:

توضیحات تصویر

پیوستن لایه FFMPEG به تابع Lambda ما

بیایید به منو برگردیم کارکرد در داخل لامبدا در ما کنسول. و شکم کد بیایید از صفحه پایین برویم و به جلسه برویم لایه های و بر روی کلیک کنید افزودن لایه. مانند تصویر زیر فرم را پر کرده و انتخاب می کنیم

توضیحات تصویر

و (در نهایت) بیایید به کد ما برسیم!

برای زبان Go، ما یک ویرایشگر آنلاین در مورد توابع لامبدا در AWS نداریم. بنابراین بیایید کد خود را به صورت محلی تولید کنیم، آن را بسازیم و یک فایل فشرده از طریق کنسول آپلود کنیم.

package main

func main() {
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در محیط توسعه محلی Go، اجازه دهید یک پوشه جدید ایجاد کنیم. در این پوشه، پروژه را با دستور معروف “go mod” شروع می کنیم تا فایل کنترل ماژول go Project خود را ایجاد کنیم.

سپس فایل main.go را با محتوای زیر ایجاد می کنیم:

package main

import "github.com/aws/aws-lambda-go/lambda"

func handler()  {

}
func main() {
    lambda.Start(handler)
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در بالا ما کتابخانه رسمی را وارد کردیم لامبدا، برای استفاده در برو. ما یک تابع به نام ایجاد می کنیم کنترل کننده جایی که ساختار تبدیل صوتی آینده خود را در زیر تابع وارد می کنیم اصلی، فقط تابع را اجرا کنید کنترل کننده در محیط اجرا لامبدا.

حالا بیایید کتابخانه رسمی s3 را برای اتصال به سطلی که عملکرد را شروع می کند بارگذاری کنیم (این اطلاعات مهم است، زیرا شروع کنید اطلاعات را از سطل به لامبدا). در مرحله بعد، اجازه دهید یک دایرکتوری موقت در داخل محیط اجرای لامبدا ایجاد کنیم تا فایل را دانلود کنیم، جایی که بتوان آن را دستکاری کرد. سپس دانلود را با استفاده از یک گزارش برای تأیید انجام دهید:

package main

import (
    "context"
    "fmt"
    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3"
    "github.com/aws/aws-sdk-go/service/s3/s3manager"
    "log"
    "os"
)

func handler(_ context.Context, s3Event events.S3Event) {
    record := s3Event.Records[0]
    key := record.S3.Object.Key
    sess, _ := session.NewSession(&aws.Config{Region: &record.AWSRegion})
    downloader := s3manager.NewDownloader(sess)
    file, err := os.Create(fmt.Sprintf("/tmp/%s", key))
    if err != nil {
        panic(err)
    }
    defer file.Close()
    _, err = downloader.Download(file,
        &s3.GetObjectInput{
            Bucket: &record.S3.Bucket.Name,
            Key:    &key,
        })
    if err != nil {
        panic(err)
    }
    log.Printf("Downloaded %s", file.Name())
}

func main() {
    lambda.Start(handler)
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تابع کنترل کننده ما 2 پارامتر را از Context و رویدادها دریافت می کند.
در این مرحله، جالب است که اولین بارگذاری کد ساخته شده را برای انجام یک آزمایش “دستی” انجام می دهیم. ابتدا بیلد این اپلیکیشن را با دستور زیر ایجاد می کنیم:

go build -o main
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

بعد، بیایید فایل را در یک فایل فشرده برای آپلود بسته بندی کنیم:

zip main.zip main
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

حالا بیایید به کنسول برویم، آپلود را انجام دهیم:

توضیحات تصویر

قبل از آزمایش کد، باید تریگر را ایجاد کنیم، که لامبدای ایجاد شده را شروع می کند.

در تابع ما، در کنسول AWS روی آن کلیک خواهیم کرد ماشه را اضافه کنید.

بیایید طبق 3 تصویر زیر فرم را پر کنیم:

توضیحات تصویر

در این مرحله، بیایید سطل فایل های خام را انتخاب کنیم:
توضیحات تصویر

سپس همه انواع فایل های ورودی را انتخاب کنید
توضیحات تصویر

در نهایت، اجازه دهید یک فیلتر برای شروع لامبدا، برای فایل‌های wav. بگذاریم
توضیحات تصویر

حالا بیایید به سطل خود برویم، یک فایل wav. آپلود کنیم و وضعیت را در CloudWatch بررسی کنیم و بعدا بررسی کنیم که آیا فایل mp3 در سطل دیگر ایجاد شده است یا خیر.

توضیحات تصویر

در بالا ما 2 را می بینیم سطل ها در پروژه ما استفاده شده است. بیایید به فایل های mgm-wav برای انجام آپلود پس از آپلود، اجازه دهید به CloudWatch دسترسی پیدا کنیم، به Logs > Logs Groups بروید. یک گروه log با نام Lambda ما وجود خواهد داشت. در مورد ما به این صورت است:

توضیحات تصویر

با ورود به گزارش خود، پیام “دانلود FILENAME” را به صورت زیر جستجو می کنیم:

توضیحات تصویر

در این مورد، بسیار خوب، بیایید ادامه دهیم!

تبدیل فایل .wav با FFMPEG

بیایید از lib Go بومی استفاده کنیم سیستم عامل، برای استفاده از تابع exec.Command که به ما اجازه می دهد دستورات سطح bash را اجرا کنیم. و از آنجا، از ffmpeg برای تبدیل فایل .wav به mp3. استفاده کنید و آن را در دایرکتوری موقت ایجاد شده قبلی ضبط کنید:

outputFile := strings.Replace(file.Name(), filepath.Ext(file.Name()), ".mp3", 1)
    cmd := exec.Command("ffmpeg", "-i", file.Name(), outputFile)
    out, err := cmd.CombinedOutput()
    if err != nil {
        log.Fatalf("cmd.Run() failed with %s\n", err)
    }
    log.Printf("Execution output:\n%s\n", string(out))
    output, err := os.Open(outputFile)
    if err != nil {
        panic(err)
    }
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نوشتن فایل تبدیل شده به سطل دیگر

حالا بیایید به فایل ایجاد شده دسترسی پیدا کنیم و آن را در سطل ایجاد شده آپلود کنیم تا فایل های تبدیل شده را دریافت کنیم. کد نمونه در مستندات AWS وجود دارد:

//put mp3 file in converted bucket
    destinationBucket := "mgm-mp3-files"
    _, err = s3.New(sess).PutObject(&s3.PutObjectInput{
        Bucket: &destinationBucket,
        Key:    aws.String(filepath.Base(outputFile)),
        Body:   output,
    })
    log.Printf("Copied %s to %s", outputFile, record.S3.Bucket.Name)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کد نهایی

package main

import (
    "context"
    "fmt"
    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3"
    "github.com/aws/aws-sdk-go/service/s3/s3manager"
    "log"
    "os"
    "os/exec"
    "path/filepath"
    "strings"
)

func handler(_ context.Context, s3Event events.S3Event) {
    record := s3Event.Records[0]
    key := record.S3.Object.Key
    sess, _ := session.NewSession(&aws.Config{Region: &record.AWSRegion})

    //Download file to a temporary folder
    downloader := s3manager.NewDownloader(sess)
    file, err := os.Create(fmt.Sprintf("/tmp/%s", key))
    if err != nil {
        panic(err)
    }
    defer file.Close()
    _, err = downloader.Download(file,
        &s3.GetObjectInput{
            Bucket: &record.S3.Bucket.Name,
            Key:    &key,
        })
    if err != nil {
        panic(err)
    }
    log.Printf("Downloaded %s", file.Name())

    //transform wav file to a compress mp3 file
    outputFile := strings.Replace(file.Name(), filepath.Ext(file.Name()), ".mp3", 1)
    cmd := exec.Command("ffmpeg", "-i", file.Name(), outputFile)
    out, err := cmd.CombinedOutput()
    if err != nil {
        log.Fatalf("cmd.Run() failed with %s\n", err)
    }
    log.Printf("Execution output:\n%s\n", string(out))
    output, err := os.Open(outputFile)
    if err != nil {
        panic(err)
    }

    //put mp3 file in converted bucket
    destinationBucket := "mgm-mp3-files"
    _, err = s3.New(sess).PutObject(&s3.PutObjectInput{
        Bucket: &destinationBucket,
        Key:    aws.String(filepath.Base(outputFile)),
        Body:   output,
    })
    log.Printf("Copied %s to %s", outputFile, record.S3.Bucket.Name)
}

func main() {
    lambda.Start(handler)
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

PLUS – پیام پایان ناهمزمان فعالیت

در نهایت می خواهیم مطمئن شویم که در پایان اجرای لامبدا در صورت موفقیت یک صف SQS با یک پیام ارائه شود تا مصرف کنندگان (برنامه ها، وب و غیره) از پایان فرآیند و در دسترس بودن فایل مطلع شوند. mp3 تبدیل شده است.

حالا بریم سراغ کنسول AWS، جستجو کنید SQS. سرویس صف ساده خود آمازون. بیایید یک موضوع ایجاد کنیم، به نام mp3 آماده

توضیحات تصویر

اکنون، با بازگشت به تابع لامبدا، به منوی افزودن مقصد دسترسی پیدا می کنیم.

توضیحات تصویر

فرم ما باید به این صورت پر شود، با انتخاب صف SQS ایجاد شده (پیام عدم مجوز استفاده از SQS توسط لامبدا در مرحله بعد حل خواهد شد)

توضیحات تصویر

اکنون با ایجاد هدف lambda ما، باید مجوز IAM را به نقش اجرای lambda خود بدهیم، پیامی را در موضوع ایجاد شده در SQS ایجاد کنیم.

توضیحات تصویر

مجوز Lambda > SQS

در کنسول IAM، روی منو کلیک کنید نقش ها. نقش ایجاد شده برای لامبدا را جستجو کنید. در این نقش، به منو بروید مجوزها را اضافه کنید > حمله پلیس. در جستجو، جستجو کنید SQS، و انتخاب کنید AmazonSQSFullAccess(می دانیم که ایده آل نیست.) و روی Add Permissions کلیک کنید.

مخزن

مخزن Github

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

همچنین ببینید
بستن
دکمه بازگشت به بالا