【问题标题】:Does anyone know how to implement the AVAssetResourceLoaderDelegate methods correctly?有谁知道如何正确实现 AVAssetResourceLoaderDelegate 方法?
【发布时间】:2017-08-02 17:57:40
【问题描述】:

我正在尝试哄骗 AVFoundation 从自定义 URL 中读取数据。自定义 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;
}

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

谢谢。

编辑:我要完整获取的电影是单帧电影。

【问题讨论】:

  • 现在看来 copyCGImageAtTime:actualTime:error: 调用不会等待委托方法完成(委托方法正在调度队列中运行)。所以问题就变成了如何确保在调用 copyCGImageAtTime:actualTime:error 之前已经加载了数据?
  • 参见developer.apple.com/library/mac/#documentation/AudioVideo/… 上的“准备使用资产” - 您的缩略图生成代码应该在完成处理程序块中。
  • 感谢您的评论,但是当我不需要更改 AVAssetResourceLoader 对象以及从 HTTP 或 FILE 类型的 URL 获取时,我的代码是正确的。我可以得到视频帧。我要解决的问题是如何从自定义 URL 获取它。有人告诉我 AVAssetResourceLoader 是关键,但我无法使用它。
  • loadingRequest.request.URL 是否等于@"memory://video"?如果 NSData 对象是您想要的,您可以通过使用 NSURLConnection 下载数据、将其写入磁盘然后使用 -[AVURLAsset initWithURL:options:]... 来规避整个问题,尽管这似乎是一个低于标准的解决方案。
  • 网址正确。问题似乎是 resourceLoader:shouldWaitForLoadingOfRequestedResource: 和 copyCGImageAtTime:actualTime:error: 之间的竞争条件。后者在前者完成之前完成。我希望委托方法在后者结束之前完全完成。所以我一定是用错了。

标签: ios objective-c avfoundation


【解决方案1】:

我已经实现了这个方法的一个工作版本。我花了一段时间才弄清楚。但生成的应用程序现在可以工作了。这表明代码没问题。

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

该方法必须同时响应内容请求(告诉播放器它正在加载什么) 以及数据请求(给玩家一些数据)。第一次调用该方法时,总是有一个内容请求。然后会有一系列的数据请求。

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

我将数据块交给媒体播放器。通常一次 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;
}

【讨论】:

  • 嗨,我有类似的实现,但有时在浏览视频时会遇到问题。当我们来回擦洗时,有时视频像素化或出现绿​​色。您是否遇到过类似的问题?
  • 我的应用程序稳定了。但该应用程序不需要擦洗。我有点不确定如何驱动 CCCrypto 代码。
【解决方案2】:

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

原来它只适用于设备,不适用于 iOS 模拟器!

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

【讨论】:

  • 我被代表困住了。我实现了它,但由于某种原因,我收到了“失败”状态。你有什么想法吗?
  • 我这样实现了我的委托: - (BOOL)resourceLoader:... { NSData* data = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"sample.m4v" withExtension:@" "]]; NSURLResponse* response = [[NSURLResponse alloc]initWithURL:self.url MIMEType:@"video/x-m4v" expectedContentLength:[data length] textEncodingName:nil]; [loadingRequest finishLoadingWithResponse:响应数据:数据重定向:无];返回是; }
【解决方案3】:

用户 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"))

【讨论】:

    【解决方案4】:

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

    【讨论】:

    • 我试过了 - 也没有用。也许它仍然是我需要的东西。但是发生的情况是,在委托方法完成之前,帧的获取以错误结束。委托方法的结果没有任何阻塞。要创建我使用的响应: [[NSURLResponse alloc] initWithURL:loadingRequest.request.URL MIMETYPE:@"video/mp4" expetedContentLength:data.length textEncodingName:nil]
    • 我认为问题不是委托方法(至少不是我必须解决的直接问题),因为它在 copyCGImageAtTime:actualTime:error: 调用返回之前没有完成。两个线程之间存在同步问题,我不知道如何解决。
    • ~Cthutu,你找到解决办法了吗。
    猜你喜欢
    • 2021-05-19
    • 1970-01-01
    • 2010-10-06
    • 2016-11-19
    • 1970-01-01
    • 2013-03-07
    • 2011-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多