Можно ли заставить AVURLAsset работать без расширения файла? - PullRequest
13 голосов
/ 15 февраля 2012

Я пытаюсь создать миниатюры для видеофайлов:

- (UIImage*) thumbnailForVideoAtURL: (NSURL*) videoURL
{
    AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoURL options:nil];
    AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
    CGImageRef imageHandle = [generator copyCGImageAtTime:kCMTimeZero actualTime:NULL error:NULL];
    if (imageHandle) {
        UIImage *frameImage = [UIImage imageWithCGImage:imageHandle];
        CFRelease(imageHandle);
        return frameImage;
    } else {
        return nil;
    }
}

Проблема в том, что видеофайлы хранятся в адресно-ориентированном хранилище и не имеют расширений.Похоже, это сбрасывает AVURLAsset, так как ресурс создается, но после прочтения изображения кадра я получаю следующую ошибку:

Error Domain=AVFoundationErrorDomain Code=-11828 "Cannot Open" UserInfo=0x167170 {NSLocalizedFailureReason=This media format is not supported., NSUnderlyingError=0x163a00 "The operation couldn’t be completed. (OSStatus error -12847.)", NSLocalizedDescription=Cannot Open}

Это задокументировано или где-то упоминалось?Я не могу поверить, что я действительно вынужден передавать информацию о формате файла через имя файла.Аргумент options инициализатора AVURLAsset выглядит как хорошее место для предоставления типа файла, но, согласно документации, поддержка этого, похоже, не поддерживается.

PS.Я проверил код, тот же файл с правильным расширением производит миниатюры очень хорошо.

Ответы [ 4 ]

12 голосов
/ 19 февраля 2012

В конце я временно создаю жесткую ссылку на файл и даю правильное расширение жесткой ссылке. Это взлом, хотя, я хотел бы увидеть лучшее решение. отправил отчет об ошибке против AVURLAsset, надеюсь, Apple может добавить функцию для чтения информации о формате файла из словаря options.

4 голосов
/ 01 ноября 2013

Я считаю, что нашел обходной путь в iOS7.Хитрость заключается в том, чтобы использовать AVAssetResourceLoader.Передайте в AVURLAsset фиктивный URL-адрес, который содержит созданную вами схему, в результате чего AVAssetResourceLoaderDelegate будет вызываться, например, «myscheme: //random.com/file.mp4». Как видно из созданного URL-адреса, он имеет.Расширение mp4, это позволит AVPlayer правильно открывать файл при условии, что вы правильно выполните следующий шаг.

Теперь реализуйте AVAssetResourceLoaderDelegate, чтобы использовать фактический URL, т. е. 'http://actual.com/file' Данные будуттеперь правильно передаваться в AVPlayer, не жалуясь на невозможность открыть файл такого формата.

3 голосов
/ 20 октября 2013

Быстрый ответ:

let filePath = ###YOU SET THIS###
let fileManager = NSFileManager.defaultManager()
let documentsURL = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .AllDomainsMask).last!
let tmpURL = documentsURL.URLByAppendingPathComponent("tmp.caf")
_ = try? fileManager.removeItemAtURL(tmpURL)
_ = try? fileManager.linkItemAtURL(fileURL, toURL: tmpURL)

Полный ответ Obj-C:

NSString *filePath = ###YOU SET THIS###
NSFileManager *dfm = [NSFileManager defaultManager];
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *tmpPath = [[documentPaths lastObject] stringByAppendingPathComponent:@"tmp.caf"];
[dfm removeItemAtPath:tmpPath error:nil];
[dfm linkItemAtPath:filePath toPath:tmpPath error:nil];

А теперь AVURLAsset будет работать с tmpPath.

1 голос
/ 08 января 2019
let mimeType = "video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\""
let asset = AVURLAsset(url: videoURL!, options:["AVURLAssetOutOfBandMIMETypeKey": mimeType])
let playerItem = AVPlayerItem(asset: asset)
avPlayer = AVPlayer(playerItem: playerItem)
self.avPlayerViewConroller?.player = avPlayer
playerItem.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions(), context: nil)
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
{
        if(avPlayer?.currentItem?.status == AVPlayerItemStatus.readyToPlay)
        {
            avPlayer?.play()
        }
}
...