S3ZencoderVideoManager contains 2 independent modules:
-
S3ZUploadManager
-
S3ZDownloadManager
The role of S3ZencoderVideoManager Uploader is a video upload queue to S3 and start encoding for HLS which is must for long/big video files on App Store apps. The encoding is done with Zencoder which is the best service because of API, uptime and compression. See the example for more info.
The role of S3ZencoderVideoManager Downloader is to be able to download big files with cache and progress support.
The downloader is not a queue and each time you start a new download the old download will be cancelled.
Video uploading queue to S3 bucket and Zencoder encoding for [HLS] (https://developer.apple.com/library/ios/documentation/networkinginternet/conceptual/streamingmediaguide/UsingHTTPLiveStreaming/UsingHTTPLiveStreaming.html).
When the encoding is done Zencoder will send Push Notification using Parse.
Important features:
- All jobs should try to run in the background.
- When app becomes active, resume all jobs.
- On startup/active, reload encoding state from Zencoder and update stage if needed.
One file cached download task with done block and progress block.
Starting new task will cancel the active task.
To run the example project; clone the repo, and run pod install from the Example directory first.
-
[AWS Account] (http://aws.amazon.com)
-
[Zencoder Account] (http://www.zencoder.com)
-
[Parse Account] (http://www.parse.com)
S3ZencoderVideoManager is available through CocoaPods, to install it simply add the following line to your Podfile:
pod "S3ZencoderVideoManager"
Run the following configuration code before first use:
S3ZConfiguration *configuration = [[S3ZConfiguration alloc] init];
configuration.awsAccessKeyID = @""; // AWS Access Key ID
configuration.awsSecretKey = @""; // AWS Secret Key
configuration.awsBucket = @""; // AWS Bucket
configuration.awsCDN = @""; // AWS CloudFront (Full https)
configuration.zencoderAPI = @"https://app.zencoder.com/api/v2/jobs"; // Zencoder API
configuration.zencoderAPIKey = @""; // Zencoder API Key
configuration.zencoderTimeout = 30.0; // Polling time in seconds to check Zencoder status if Push wasn't received
configuration.zencoderRetries = 3; // Number of Zencoder encoding retries before giving up
configuration.parseAPI = @""; // Parse API - http://YOUR_USERNAME:YOUR_PASSWORD@APP_NAME.parseapp.com/notify
configuration.cacheCapacity = 100*1024*1024; // Download Cache size in bytes
configuration.cachePath = @"cache.db"; // Download Cache file name
configuration.uploadRetries = 3; // Number of uploading retries before giving up
[S3ZUploadManager setupWithConfiguration:configuration];
[S3ZDownloadManager setupWithConfiguration:configuration];Parse configuration for push: (https://parse.com/tutorials/ios-push-notifications)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[Parse setApplicationId:@"" clientKey:@""];
[application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeSound];
return YES;
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)newDeviceToken {
PFInstallation *currentInstallation = [PFInstallation currentInstallation];
[currentInstallation setDeviceTokenFromData:newDeviceToken];
[currentInstallation saveInBackground];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[[S3ZUploadManager sharedInstance] notifyJobEncodingCompleted:userInfo];
}Parse Cloud Code for sending the notifications using Zencoder: (https://parse.com/docs/cloud_code_guide#webhooks)
var express = require('express');
var app = express();
app.use(express.bodyParser());
app.post('/notify',
express.basicAuth('YOUR_USERNAME', 'YOUR_PASSWORD'),
function(req, res) {
var job = req.body.job;
var query = new Parse.Query(Parse.Installation);
query.containedIn('deviceToken', [job.pass_through]);
Parse.Push.send({
where: query,
data: {
alert: "Job Done!",
state: job.state,
id: job.id
}
});
res.send('Success');
}, function(error) {
res.status(500);
res.send('Error');
});
app.listen();Each upload queue job can be found in one of the following states:
S3ZUploadJobQueued
S3ZUploadJobUploading
S3ZUploadJobUploadFailed // After uploadRetries
S3ZUploadJobEncoding
S3ZUploadJobEncodingFailed // After zencoderRetries
S3ZUploadJobDone
When starting a job the final play url can be used before the job done @property (nonatomic) NSURL *playURL.
Each job has it's own @property (nonatomic) NSString *jobID.
Each stage change will generate S3ZUploadJobDidChange notification with the S3ZUploadJobStageDidChange object.
Array with all S3ZUploadJob jobs:
@property (readonly, nonatomic) NSMutableArray *jobs;Number of jobs in the array:
@property (readonly, nonatomic) NSInteger jobsCount;Setup function before first use:
+ (void)setupWithConfiguration:(S3ZConfiguration *)configuration;Accessing the shared instance:
+ (instancetype)sharedInstance;Starting a new upload job:
- (S3ZUploadJob *)enqueueVideo:(NSURL *)url forUserID:(NSString *)userID withContext:(id<NSCoding>)context;Example:
S3ZUploadJob *uploadJob = [[S3ZUploadManager sharedInstance] enqueueVideo:url forUserID:@"uploader" withContext:nil];Cancelling an upload job:
- (void)cancelJob:(NSString *)jobID;Cancelling all upload jobs:
- (void)cancelAllJobs;Encoding again on UploadEncodingFailed state:
- (void)reEncodeJob:(NSString *)jobID;Encoding again on UploadUploadingFailed state:
- (void)reUploadJob:(NSString *)jobID;Run this function to read all upload jobs from disk:
- (void)notifyAppBecomesActive;Run this function to write all upload jobs to disk:
- (void)notifyAppBecomesInactive;Push notification when Zencoder job done:
- (void)notifyJobEncodingCompleted:(NSDictionary *)userInfo;Setup function before first use:
+ (void)setupWithConfiguration:(S3ZConfiguration *)configuration;Accessing the shared instance:
+ (instancetype)sharedInstance;Starting downloading task:
- (void)downloadURL:(NSURL *)url
withBlock:(void (^)(BOOL succeeded, NSURL *location, NSError *error))block
progressBlock:(void (^)(float downloadProgress))progressBlock;Genady Okrain, genady@okrain.com
S3ZencoderVideoManager is available under the MIT license. See the LICENSE file for more info.
