5

我正在尝试从视频中获取第一个缩略图。

我尝试了以下方法:

AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:[NSURL fileURLWithPath:_moviePath] options:nil];
AVAssetImageGenerator *gen = [[AVAssetImageGenerator alloc] initWithAsset:asset];
gen.appliesPreferredTrackTransform = YES;
CMTime time = CMTimeMakeWithSeconds(0.0, 600);
NSError *error = nil;
CMTime actualTime;

CGImageRef image = [gen copyCGImageAtTime:time actualTime:&actualTime error:&error];
UIImage *thumb = [[UIImage alloc] initWithCGImage:image];
CGImageRelease(image);
NSLog(@"the error is %@: image is %@: url is %@: ",error,_mainThumbnail,[NSURL fileURLWithPath:_moviePath] );

但是,我的日志是:

the error is (null): image is (null): 
url is file:///private/var/mobile/Applications/D1293BDC-EA7E-4AC7-AD3C-1BA3548F37D6/tmp/trim.6F0C4631-E5E8-43CD-BF32-9B8F09D4ACF1.MOV: 

AVURLAsset *asset=[[AVURLAsset alloc] initWithURL:[NSURL fileURLWithPath:_moviePath] options:nil];
    AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
    generator.appliesPreferredTrackTransform=TRUE;

    CMTime thumbTime = CMTimeMakeWithSeconds(0,30);

    AVAssetImageGeneratorCompletionHandler handler = ^(CMTime requestedTime, CGImageRef im, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error){
        if (result != AVAssetImageGeneratorSucceeded) {
            NSLog(@"couldn't generate thumbnail, error:%@", error);
        }
        _mainThumbnail.image = [UIImage imageWithCGImage:im];
        NSLog(@"thumbnails %@ ",_mainThumbnail.image);
    };

    CGSize maxSize = CGSizeMake(320, 180);
    generator.maximumSize = maxSize;
    [generator generateCGImagesAsynchronouslyForTimes:[NSArray arrayWithObject:[NSValue valueWithCMTime:thumbTime]] completionHandler:handler];

日志缩略图为空。

为什么图像为空?我查看了其他论坛,他们建议使用我已经在使用的 fileURLWithPath。

我正在使用ios7

4

5 回答 5

19

你可以试试这个方法。它获取给定 URL 处视频的第一帧并将其返回为UIImage.

- (UIImage *)thumbnailFromVideoAtURL:(NSURL *)url
{
    AVAsset *asset = [AVAsset assetWithURL:url];

    //  Get thumbnail at the very start of the video
    CMTime thumbnailTime = [asset duration];
    thumbnailTime.value = 0;

    //  Get image from the video at the given time
    AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];

    CGImageRef imageRef = [imageGenerator copyCGImageAtTime:thumbnailTime actualTime:NULL error:NULL];
    UIImage *thumbnail = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);

    return thumbnail;
}

该方法不会检查错误,因为我的代码使用它是可以的,nil如果有任何失败就返回。


编辑:澄清CMTime价值观

CMTime

  • timescale- 将此视为视频的 FPS(每秒帧数)(25 FPS -> 1s 的视频有 25 个视频帧)
  • value- 混凝土框架的识别。在上面的代码中,这表示您要获取哪个帧的缩略图。

要在确切时间计算帧,您必须进行以下计算:

value = timescale * seconds_to_skip

这相当于

"Frame of the video to take" = "FPS" * "Number of seconds to skip"

例如,如果您想拍摄视频的第 2 秒的第 1 帧,您实际上希望跳过视频的第 1 秒。所以你会使用:

CMTime thumbnailTime = [asset duration];
thumbnailTime.value = thumbnailTime.timescale * 1;

再看一眼:您想跳过视频的前 1 秒而不是缩略图。即在 25 FPS 上,您想要跳过 25 帧。所以CMTime.value = 25(跳过 25 帧)。

于 2013-10-09T13:03:16.887 回答
2

以防万一有人犯了和我一样的错误:

检查是否URL使用适当的方法生成。您不应该URL对文件的 local 和 web 感到困惑。

如果是本地视频文件,请使用以下代码:

NSURL *movieURL = [NSURL fileURLWithPath:_moviePath];
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:movieURL options:nil];

如果是来自互联网的视频文件,请使用以下代码:

NSURL *movieURL = [NSURL URLWithString:_moviePath];
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:movieURL options:nil];
于 2016-03-18T17:58:37.703 回答
0

我成功地使用了这个片段,从视频中获取截图:

- (UIImage *)currentItemScreenShot
{
    AVURLAsset *asset = (AVURLAsset *)playerItem_.asset;

    AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];

    imageGenerator.appliesPreferredTrackTransform = YES;

    CGImageRef thumb = [imageGenerator 
    copyCGImageAtTime:CMTimeMakeWithSeconds(0, 1.0)
    actualTime:NULL
    error:NULL];

    UIImage *image = [UIImage imageWithCGImage:thumb];

    CGImageRelease(thumb);

    [imageGenerator release];

    return image;
}

就我而言 - 我是在视频成功导入应用程序后两秒钟做的。(它有图片方向的问题,如果我在导入视频后这样做,有时会不返回图像或半图像)。

于 2013-10-09T12:58:06.517 回答
0

已接受答案的Swift版本@Lukas Kukacka 答案:

func thumbnailFromVideoAtURL(url: URL) -> UIImage?{

        let asset = AVAsset(url: url)

        //  Get thumbnail at the very start of the video
        var thumbnailTime: CMTime = asset.duration
        thumbnailTime.value = 0

        //  Get image from the video at the given time
        let imageGenerator = AVAssetImageGenerator(asset: asset)
        imageGenerator.appliesPreferredTrackTransform = true // this rotates the image to the correct position the camera took it in

        do{
            let imageRef = try imageGenerator.copyCGImage(at: thumbnailTime, actualTime: nil)
            return UIImage(cgImage: imageRef)

        }catch let err as NSError{
            print(err.localizedDescription)
        }

        return nil
}

奖金

let imageGenerator = AVAssetImageGenerator(asset: asset)下我补充说:

imageGenerator.appliesPreferredTrackTransform = true

我遇到了一个问题,我会以纵向记录,获取缩略图,然后以横向返回。这个答案解决了这个问题。

于 2018-03-16T03:50:15.893 回答
0

斯威夫特 5.2 版本:

您可以在此处找到我的原始帖子,我从rozochkin 的回答中获得灵感。

func getCurrentFrame() -> UIImage? {
    guard let player = self.player, let avPlayerAsset = player.currentItem?.asset else {return nil}
    let assetImageGenerator = AVAssetImageGenerator(asset: avPlayerAsset)
    assetImageGenerator.requestedTimeToleranceAfter = .zero
    assetImageGenerator.requestedTimeToleranceBefore = .zero
    assetImageGenerator.appliesPreferredTrackTransform = true
    let imageRef = try! assetImageGenerator.copyCGImage(at: player.currentTime(), actualTime: nil)
    let image = UIImage(cgImage: imageRef)
    return image
}

重要笔记:

requestedTimeToleranceAfterrequestedTimeToleranceBefore应设置为 .zero,因为根据源代码,“生成图像的实际时间 [...] 可能与请求的时间不同以提高效率”。

applyPreferredTrackTransform必须设置为TRUE(默认为 FALSE),否则你会得到一个糟糕的旋转帧。将此属性设置为 TRUE,您将获得您在播放器中真正看到的内容。

于 2020-05-11T17:37:16.420 回答