Let us create a lambda handler function that will be executed when we upload an mp4 or mp3 to an AWS S3 bucket. This function will read the input file, convert it to .ts files and a playlist file (.m3u8) and then finally upload it to an output S3 bucket.
First you need to create two S3 buckets in AWS console. Let us call the first bucket input-bucket and the output bucket hls-ready.
Then install boto3 in your virtualenv. Boto3 is an AWS SDK that enables developers to configure and interact with AWS resources in Python. To be able to write our converted files to the output S3 bucket, we need an S3 client using boto3.
$ pip install boto3
Let us call the file converter.py
import boto3
import os
import tempfile
import subprocess
import urllib.parse
import glob
from datetime import datetime
import json
import sys
s3_client = boto3.client('s3')
media_out_bucket_name = 'hls-ready'
def convert_to_hls(event, context):
bucket = urllib.parse.unquote(event['Records'][0]['s3' ['bucket']['name'])
key = urllib.parse.unquote(event['Records'][0]['s3']['object']['key'])
path_no_ext, file_ext = os.path.splitext(key)
if file_ext == '.mp4' or file_ext == '.mp3':
file_name = os.path.basename(key)
file_name_no_ext = os.path.basename(path_no_ext)
os.chdir(tempfile.gettempdir())
presigned_file_url = s3_client.generate_presigned_url(
'get_object',
Params={
'Bucket': bucket,
'Key': key
})
# Delete all video/audio files in tmp
files = [f for f in os.listdir('.') if os.path.isfile(f)]
for f in files:
if f.endswith('.mp3') or f.endswith('.mp4') or f.endswith('.ts') or f.endswith('.m3u8'):
os.remove(f)
# Now transcode to 360p resolution
cmd = ['/opt/ffmpeg', '-i', presigned_file_url, '-profile:v', 'baseline', '-level', '3.0', '-s', '640x360', '-start_number', '0', '-hls_time', '10', '-hls_list_size', '0', '-f', 'hls', file_name_no_ext + '.m3u8']
if file_ext == '.mp3':
cmd = ['/opt/ffmpeg', '-i', presigned_file_url, '-vn', '-ac', '2', '-acodec', 'aac', '-f', 'segment', '-segment_format', 'mpegts', '-segment_time', '10', '-segment_list', file_name_no_ext + '.m3u8', file_name_no_ext + '-%05d.ts']
p = subprocess.call(cmd, stdin=subprocess.DEVNULL)
if p == 0:
for f in glob.glob(file_name_no_ext + "*.ts"):
s3_client.upload_file(f, media_out_bucket_name, file_name_no_ext + '/' + f)
s3_client.upload_file(file_name_no_ext + '.m3u8', media_out_bucket_name, file_name_no_ext + '/' + file_name_no_ext + '.m3u8')
In the subsequent sections, we will explain what is going on in the code above.