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