Created
July 17, 2013 16:19
-
-
Save tomdyson/6022098 to your computer and use it in GitHub Desktop.
Use Zencoder to convert mp4 files into HTTP Live segments and playlist, e.g. to meet Apple's requirements for iOS video streaming apps.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Check an FTP directory for new files, send any to Zencoder for | |
| # conversion to HTTPLive playlists, tell Zencoder to put converted files | |
| # in FTP or S3 | |
| # Installation: | |
| # pip install zencoder | |
| # Usage: | |
| # Add S3 credentials to Zencoder - https://app.zencoder.com/account/credentials | |
| # Configure Zencoder, S3 and FTP details | |
| # python rsa-zencoder.py | |
| from zencoder import Zencoder | |
| from ftplib import FTP | |
| # Access details | |
| ZENCODER_API_KEY = '' | |
| ZENCODER_CREDENTIALS = '' # the label you assign your S3 credentials to, in Zencoder's admin UI | |
| FTP_USER = '' | |
| FTP_PASS = '' | |
| FTP_HOST = '' | |
| FTP_DIR = '' | |
| FTP_SOURCE_URL= 'ftp://%s:%s@%s/cds/IPOD/' % (FTP_USER, FTP_PASS, FTP_HOST) | |
| ZENCODER_DESTINATION_URL = 's3://your-bucket-name.s3.amazonaws.com/' | |
| ENCODED_DB = '/var/encoded-videos.db' | |
| def make_outputs(base_url): | |
| # generate segments and playlist recommended by Zencoder | |
| # https://app.zencoder.com/docs/guides/encoding-settings/http-live-streaming | |
| outputs = [ | |
| { | |
| "audio_bitrate": 56, | |
| "audio_sample_rate": 22050, | |
| "base_url": base_url, | |
| "credentials": ZENCODER_CREDENTIALS, | |
| "filename": "file-64k.m3u8", | |
| "format": "aac", | |
| "public": 1, | |
| "type": "segmented" | |
| }, | |
| { | |
| "audio_bitrate": 56, | |
| "audio_sample_rate": 22050, | |
| "base_url": base_url, | |
| "credentials": ZENCODER_CREDENTIALS, | |
| "decoder_bitrate_cap": 300, | |
| "decoder_buffer_size": 800, | |
| "filename": "file-240k.m3u8", | |
| "max_frame_rate": 15, | |
| "public": 1, | |
| "type": "segmented", | |
| "video_bitrate": 200, | |
| "width": 400, | |
| "format": "ts" | |
| }, | |
| { | |
| "audio_bitrate": 56, | |
| "audio_sample_rate": 22050, | |
| "base_url": base_url, | |
| "credentials": ZENCODER_CREDENTIALS, | |
| "decoder_bitrate_cap": 600, | |
| "decoder_buffer_size": 1600, | |
| "filename": "file-440k.m3u8", | |
| "public": 1, | |
| "type": "segmented", | |
| "video_bitrate": 400, | |
| "width": 400, | |
| "format": "ts" | |
| }, | |
| { | |
| "audio_bitrate": 56, | |
| "audio_sample_rate": 22050, | |
| "base_url": base_url, | |
| "credentials": ZENCODER_CREDENTIALS, | |
| "decoder_bitrate_cap": 900, | |
| "decoder_buffer_size": 2400, | |
| "filename": "file-640k.m3u8", | |
| "public": 1, | |
| "type": "segmented", | |
| "video_bitrate": 600, | |
| "width": 480, | |
| "format": "ts" | |
| }, | |
| { | |
| "audio_bitrate": 56, | |
| "audio_sample_rate": 22050, | |
| "base_url": base_url, | |
| "credentials": ZENCODER_CREDENTIALS, | |
| "decoder_bitrate_cap": 1500, | |
| "decoder_buffer_size": 4000, | |
| "filename": "file-1040k.m3u8", | |
| "public": 1, | |
| "type": "segmented", | |
| "video_bitrate": 1000, | |
| "width": 640, | |
| "format": "ts" | |
| }, | |
| { | |
| "audio_bitrate": 56, | |
| "audio_sample_rate": 22050, | |
| "base_url": base_url, | |
| "credentials": ZENCODER_CREDENTIALS, | |
| "decoder_bitrate_cap": 2250, | |
| "decoder_buffer_size": 6000, | |
| "filename": "file-1540k.m3u8", | |
| "public": 1, | |
| "type": "segmented", | |
| "video_bitrate": 1500, | |
| "width": 960, | |
| "format": "ts" | |
| }, | |
| { | |
| "audio_bitrate": 56, | |
| "audio_sample_rate": 22050, | |
| "base_url": base_url, | |
| "credentials": ZENCODER_CREDENTIALS, | |
| "decoder_bitrate_cap": 3000, | |
| "decoder_buffer_size": 8000, | |
| "filename": "file-2040k.m3u8", | |
| "public": 1, | |
| "type": "segmented", | |
| "video_bitrate": 2000, | |
| "width": 1024, | |
| "format": "ts" | |
| }, | |
| { | |
| "base_url": base_url, | |
| "credentials": ZENCODER_CREDENTIALS, | |
| "filename": "playlist.m3u8", | |
| "public": 1, | |
| "streams": [ | |
| { | |
| "bandwidth": 2040, | |
| "path": "file-2040k.m3u8" | |
| }, | |
| { | |
| "bandwidth": 1540, | |
| "path": "file-1540k.m3u8" | |
| }, | |
| { | |
| "bandwidth": 1040, | |
| "path": "file-1040k.m3u8" | |
| }, | |
| { | |
| "bandwidth": 640, | |
| "path": "file-640k.m3u8" | |
| }, | |
| { | |
| "bandwidth": 440, | |
| "path": "file-440k.m3u8" | |
| }, | |
| { | |
| "bandwidth": 240, | |
| "path": "file-240k.m3u8" | |
| }, | |
| { | |
| "bandwidth": 64, | |
| "path": "file-64k.m3u8" | |
| } | |
| ], | |
| "type": "playlist" | |
| } | |
| ] | |
| return outputs | |
| # What files have we seen already? | |
| try: | |
| encoded_files = open(ENCODED_DB).read().splitlines() | |
| except IOError: # create the database of seen files if it doesn't exist | |
| f = open(ENCODED_DB, 'w') | |
| f.write('') | |
| f.close() | |
| encoded_files = [] | |
| # Get a list of all available, un-encoded videos | |
| ftp = FTP(FTP_HOST, FTP_USER, FTP_PASS) | |
| ftp.cwd(FTP_DIR) | |
| video_files = [v for v in ftp.nlst() if v not in encoded_files] | |
| # Process the videos | |
| zen = Zencoder(ZENCODER_API_KEY) | |
| for file in video_files: | |
| if file.endswith('mp4'): | |
| print 'processing %s...' % file | |
| filename_stub = file.replace('.mp4', '') | |
| base_url = ZENCODER_DESTINATION_URL + filename_stub + '/' | |
| outputs = make_outputs(base_url) | |
| job = zen.job.create(FTP_SOURCE_URL + file, outputs=outputs) | |
| # mark this video as processed | |
| fo = open(ENCODED_DB, 'a+') | |
| fo.write('%s\n' % file) | |
| fo.close() | |
| else: | |
| print '%s is not a video file, ignoring' % file |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment