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).

+3


source to share


2 answers


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 use AVAssetResourceLoaderDelegate

    .

    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 specify contentInformationRequest

    for loadingRequest

    . You can find a list of video formats Link to AV Foundation constant . And one more thing contentLength

    . 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 into dataRequest

    . You will need another buffer to decode the data. And in resourceLoader:(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 :)

+3


source


in line

contentRequest.contentType = @"mov";

      



you need to set a valid UTI of the decrypted content like

contentRequest.contentType = @"public.mpeg-4";

      

0


source







All Articles