有谁知道如何正确实现AVAssetResourceLoaderDelegate方法?

时间:2013-02-21 15:03:07

标签: ios objective-c avfoundation

我试图哄骗AVFoundation从自定义URL读取。自定义网址的工作原理。下面的代码创建一个带有电影文件的NSData:

NSData* movieData = [NSData dataWithContentsOfURL:@"memory://video"];

我使用以下代码设置了AVAssetResourceLoader对象:

NSURL* url = [NSURL URLWithString:@"memory://video"];
AVURLAsset* asset = [[AVURLAsset alloc] initWithURL:url options:nil];
AVAssetResourceLoader* loader = [asset resourceLoader];
[loader setDelegate:self queue:mDispatchQueue];

调度队列是并发的。

然后我尝试从电影中提取第一帧:

AVAssetImageGenerator* imageGen = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset];
CMTime time = CMTimeMakeWithSeconds(0, 600);
NSError* error = nil;
CMTime actualTime;
CGImageRef image = [imageGen copyCGImageAtTime:time
                                    actualTime:&actualTime
                                         error:&error];
if (error) NSLog(@"%@", error);

但是当我运行此代码时,我得到了:

2013-02-21 10:02:22.197 VideoPlayer[501:907] Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo=0x1f863090 {NSLocalizedDescription=The operation could not be completed, NSUnderlyingError=0x1e575a90 "The operation couldn’t be completed. (OSStatus error 268451843.)", NSLocalizedFailureReason=An unknown error occurred (268451843)}

委托方法的实现是:

- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest
{
    NSData* data = [NSData dataWithContentsOfURL:loadingRequest.request.URL];
    [loadingRequest finishLoadingWithResponse:nil data:data redirect:nil];
    return YES;
}

现在,我的问题是,我是否正确实施了该方法?有谁知道我做的正确吗?

感谢。

编辑:我正在拍摄的电影是一部单帧电影。

4 个答案:

答案 0 :(得分:7)

我已经实现了此方法的工作版本。我花了一段时间才弄明白。但现在的应用程序正常运行。这表明代码没问题。

我的应用包含一个媒体文件,我不想在未加密的软件包中发送。我想动态解密文件。 (一次一块)。

该方法必须同时响应内容请求(告诉玩家它正在加载什么) 并向数据请求(给玩家一些数据)。第一次调用该方法时,始终存在内容请求。然后会有一系列数据请求。

玩家很贪心。它总是要求整个文件。您没有义务提供。它要求整个蛋糕。你可以给它一片。

我交出媒体播放器的数据块。通常一次1 MB。用特殊情况处理较小的最终块。通常会按顺序询问块。但是你也需要能够处理无序请求。

- (BOOL) resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest
{
    NSURLRequest* request = loadingRequest.request; 
    AVAssetResourceLoadingDataRequest* dataRequest = loadingRequest.dataRequest;
    AVAssetResourceLoadingContentInformationRequest* contentRequest = loadingRequest.contentInformationRequest;

    //handle content request
    if (contentRequest)
    {
        NSError* attributesError;
        NSString* path = request.URL.path;
        _fileURL = request.URL;
        if (_fileHandle == nil)
        {
            _fileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
        }

        // fire up the decryption here..
        // for example ... 
        if (_decryptedData == nil)
        {
            _cacheStart = 1000000000;
            _decryptedData = [NSMutableData dataWithLength:BUFFER_LENGTH+16];
            CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, [sharedKey cStringUsingEncoding:NSISOLatin1StringEncoding], kCCKeySizeAES256, NULL, &cryptoRef);
        }

        NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:&attributesError];

        NSNumber *fileSizeNumber = [fileAttributes objectForKey:NSFileSize];
        _fileSize = [fileSizeNumber longLongValue];

        //provide information about the content
        _mimeType = @"mp3";
        contentRequest.contentType = _mimeType;
        contentRequest.contentLength = _fileSize;
        contentRequest.byteRangeAccessSupported = YES;
    }

    //handle data request
    if (dataRequest)
    {
        //decrypt a block of data (can be any size you want) 
        //code omitted

        NSData* decodedData = [NSData dataWithBytes:outBuffer length:reducedLen];
       [dataRequest  respondWithData:decodedData];
    [loadingRequest finishLoading];
    }


    return YES;
}

答案 1 :(得分:1)

我浪费了2个小时试图做一些非常相似的事情。

原来它只能在设备上运行,并且在iOS模拟器上不起作用!

我猜模拟器中的AVFoundation以某种方式“桥接”到主机Mac的AVFoundation。不幸的是,这个API在OS X 10.8上不可用(根据WebCore上的一些提交,它将在OS X 10.9中提供),所以现在它在模拟器中不起作用。

答案 2 :(得分:0)

您需要create an NSURLResponse object才能传回来。你回来了nil。没有它,AVAssetResourceLoader不知道如何处理你提供的数据(也就是说,它不知道它是什么类型的数据 - 错误消息,jpeg等)。在假设成功之前,您还应该使用-[NSData dataWithContentsOfURL:options:error:]并检查错误。

答案 3 :(得分:0)

用户NSURLComponent以及scheme =“enc”以便调用AVAssetResourceLoaderDelegate方法。

let urlComponents = NSURLComponents(url: video_url, resolvingAgainstBaseURL: false)
    urlComponents?.scheme = "enc"
let avAsset = AVURLAsset(url: (urlComponents?.url)!, options: ["AVURLAssetHTTPHeaderFieldsKey": headers])
    avAsset.resourceLoader.setDelegate(self, queue: DispatchQueue(label: "AVARLDelegateDemo loader"))