在iOS中使用AVPlayer播放加密视频

4

我正在尝试使用AVPlayer播放加密视频,但是在播放器中没有显示任何内容。

目前,我的进展如下:

1.实现了一个AVPlayer,其中包含一个UIView,用于播放AV内容(播放非加密文件时工作正常)。

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];

从上面的代码中,我知道我的资源加载器方法正在被调用:

2.实现了AVAssetResourceLoaderDelegate协议,并将资源加载器方法实现如下。

- (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;
}

基于上述代码以及苹果文档中对资源加载器的进一步阅读:

在加载过程中,资源加载器对象可能被要求协助加载资源。例如,需要解密的资源可能导致资源加载器被要求提供适当的解密密钥。您可以将委托对象分配给资源加载器对象,并使用您的委托拦截这些请求并提供适当的响应。

这基本上就是我正在做的事情。但是,我无法播放我的视频。我确保我解密的数据是正确的(即,我可以将它写入临时文件并播放我的mov)。


你是否在资源加载器方法中设置了断点并逐步执行,以查看设置了哪些值,特别是 data 的值? - Phillip Mills
是的,通过将数据写入临时文件并播放文件,我已经验证了它是正确的数据。 - Ahmed Ebaid
1
您可能想要查看示例应用程序AVARLDelegateDemo - A-Live
我之前参加过这个,我相信操作的顺序基本相同,他们正在使用一堆调度队列,而我没有。 - Ahmed Ebaid
你有搞清楚这个问题吗? - user3344977
不好意思,我还没有机会回头看它。 - Ahmed Ebaid
2个回答

3

我也在这个任务上卡了好几天。虽然不难,但是关于如何使用AVAssetResourceLoaderAVAssetResourceLoaderDelegate的信息不够充足(或者说不够清晰)。以下是我在完成这个任务时获得的一些内容:

  1. If you are loading a local video file, you must provide a custom scheme for your fileURL in order 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) won't trigger any of AVAssetResourceLoaderDelegate

  2. In use of resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest you must provide the contentInformationRequest for loadingRequest. You can find the list of video format AV Foundation Constants Reference. And another thing is contentLength. It must be set to the size of the decrypted file, not the file you are using to decrypt.
  3. The loadingRequest can request overlap data or request same data many times. So that you can't simply decode and paste data to the dataRequest. You will need to have another buffer for decoding data. And in resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest, check if you have enough data to return or you need to decode more. When you decode for more data, you can clean up previous buffer to keep memory low but remember to copy any unused data in the previous buffer.

另外,我建议您先尝试播放一个非加密文件。在尝试加密文件之前,请确保loadingRequest的数据加载方法正常运行。最终,您会发现像这样完成任务非常有趣和有意义。祝编程愉快:)


嗨Sahara,感谢您的评论。您有代码存储库的链接吗? - James Rao
我也需要那个 :) - Devanshu Saini
@sahara108,我已经尝试了您建议的内容,除了第三点,因为我首先要尝试使用小型非加密文件。但是我仍然无法播放视频。我的代码与问题中的代码相同,并添加了您的前两个建议。您能帮助我解决它吗? - prabhu
@prabhu,你能分享一下你的代码吗?我会看一下,看看我能否帮忙。 - sahara108

1
在编程中的一行。
contentRequest.contentType = @"mov";

你需要设置有效的解密内容UTI,例如:
contentRequest.contentType = @"public.mpeg-4";

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接