【问题标题】:Taking thumbnail image from video always returns null从视频中获取缩略图总是返回 null
【发布时间】:2013-10-06 18:33:17
【问题描述】:

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

我尝试了以下方法:

一个

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

【问题讨论】:

  • 什么是_mainThumbnail?你确定那不是nil(因为看起来是这样)?您为什么不尝试直接登录thumb(在第一个示例中)?
  • 第一个在我看来 _mainThumbnail 从未设置过。

标签: iphone ios objective-c cocoa-touch ios6


【解决方案1】:

你可以试试这个方法。它获取给定 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 -> 1 秒的视频有 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 秒而不是缩略图。 IE。在 25 FPS 上,您想跳过 25 帧。所以CMTime.value = 25(跳过25帧)。

【讨论】:

  • 如果我想要第二个怎么办?我应该试试 thumbnailTime.value = 1 吗?
  • 您需要视频的第 2 秒或第 2 帧的缩略图吗?为什么需要第二帧?第一个和第二个之间的差异约为 0.04s @ 25FPS :-) 但是:CMTime 定义了应该拍摄缩略图的视频时间,而不是确切的帧数。而且我的代码使用简单的前提,即第一帧在时间 0 ;-) 所以为了得到特定的帧,你可能必须计算视频的 FPS 等,但这是一个不同的讨论
  • 我的意思是第二秒。我怎样才能得到它?
  • 请看一下这个 SO 问题:stackoverflow.com/questions/4001755/… 它涵盖的这个主题比我在 cmets 中给你的更详细。基本上,CMTime docs 说“值/时间刻度 = 秒”......所以如果你设置 thumbnailTime.value = thumbnailTime.timescale * 1(其中 1 是你想要拍摄缩略图的视频的秒数),你应该有大约第一帧的时间视频的第 2 秒(时间 00h00m01s)
  • 我在这里找到了解决方案stackoverflow.com/questions/5347800/…
【解决方案2】:

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

检查URL 是否使用适当的方法生成。您不应该对文件的本地和网络URLs 感到困惑。

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

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

【讨论】:

    【解决方案3】:

    我成功使用这个sn-p,从视频中获取截图:

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

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

    【讨论】:

    • 成功导入是什么意思?
    • 嗯 - 在我的情况下,我拍摄视频或从库中选择,然后此视频正在导入应用程序(并保存在应用程序缓存目录中) - 如果成功保存 - 则成功导入.可能出现问题 - 视频损坏、内存已满或任何其他问题。
    【解决方案4】:

    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
    

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

    【讨论】:

      【解决方案5】:

      SWIFT 5.2 版本:

      您可以找到我的原帖 here,我的灵感来自 rozochkin's answer

      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,因为根据源代码,“生成图像的实际时间 [...] 可能与效率所需的时间”。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-06-26
        • 2013-08-31
        • 2017-10-21
        • 2011-05-25
        • 1970-01-01
        • 2018-11-06
        • 1970-01-01
        • 2013-06-05
        相关资源
        最近更新 更多