Play encrypted videos with AVPlayer on iOS
So, I am trying to play an encrypted video using AVplayer and nothing appears in the player.
So my progress on this project looks like this:
1. Added AVPlayer which will have UIView which will play AV content (this works great for playing unencrypted files.)
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:fileURL options:nil]; //local file url with custom scheme
AVAssetResourceLoader *loader = [asset resourceLoader];
[loader setDelegate:self queue:dispatch_get_main_queue()];
self.playerItem = [AVPlayerItem playerItemWithAsset:asset];
self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
[self.playerView setPlayer:self.player];
From the above code, I know my following resource loader method is being called:
2.Implemented AVAssetResourceLoaderDelegate protocol and I have implemented the resource loading method as follows.
- (BOOL) resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest
{
NSURLRequest* request = loadingRequest.request;
AVAssetResourceLoadingDataRequest* dataRequest = loadingRequest.dataRequest;
AVAssetResourceLoadingContentInformationRequest* contentRequest = loadingRequest.contentInformationRequest;
NSMutableData *data;
//handle content request
if (contentRequest)
{
contentRequest.contentType = @"mov";
contentRequest.contentLength = movieFileLengthInBytes
contentRequest.byteRangeAccessSupported = YES;
}
if (dataRequest)
{
DecryptedStream* readStream = [FS getReadStream:filename error:nil];
if (readStream)
{
while ([readStream hasBytesAvailable])
{
NSInteger nRead;
uint8_t buffer[kBufferReadSize];
nRead = [readStream read:buffer maxLength:kBufferReadSize];
NSMutableData *data = [NSMutableData data];
[data appendBytes:buffer length:nRead];
[dataRequest respondWithData:data];
}
}
[loadingRequest finishLoading];
}
return YES;
}
Based on the above code and other reading in the apple docs for resourceloader: "During loading, the resource loader object may ask for help in loading the resource. For example, a resource that needs decryption may result in the resource loader being asked to provide the appropriate decryption keys. You you can assign a delegate object to a resource loader object and use the delegate to intercept those requests and provide an appropriate response "is basically what I'm doing. However, I cannot get my video to play. I made sure that the data I decoded is correct (i.e. I can write it to a tmp file and play the mov).
source to share
I am also stuck with this task for a few days. It is not difficult, but there is not enough information (or clear information) on how to use AVAssetResourceLoader
and AVAssetResourceLoaderDelegate
. This is what I get when doing this task:
-
If you are uploading a local video file, you must provide a custom scheme for
fileURL
that to be able to useAVAssetResourceLoaderDelegate
.let urlComponents = NSURLComponents(URL: fileURL, resolvingAgainstBaseURL: false) urlComponents?.scheme = "enc" let asset = AVURLAsset(URL: urlComponents!.URL!, options: nil)
Simple use
let asset = AVURLAsset(URL: fileURL, options: nil)
will not cause any ofAVAssetResourceLoaderDelegate
- When using,
resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest
you must specifycontentInformationRequest
forloadingRequest
. You can find a list of video formats Link to AV Foundation constant . And one more thingcontentLength
. It should be set to the size of the decrypted file, not the file you are using to decrypt. -
loadingRequest
may request overlap data or request the same data many times. So that you can't just decode and insert data intodataRequest
. You will need another buffer to decode the data. And inresourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest
, check if you have enough data to return or need to decrypt more. When you decode more data, you can flush the previous buffer to keep memory low, but remember to copy any unused data in the previous buffer.
And I suggest to try the encrypted file first. Make sure your method of loading data to loadingRequest
work correctly before moving to an encrypted file. In the end, you will find that it is very interesting and interesting to do such a task. Happy coding :)
source to share