从视频中获取缩略图 - Objective C

5

我有一个应用程序,可以将视频上传到服务器,现在我想创建一个新闻源来显示这些视频帖子,但是要通过缩略图或视频帧。这样一旦用户点击缩略图,视频就会播放。

我有以下代码用于从服务器获取视频并播放:

- (void)openVideo {

    NSString *videoURLString = @"http://myite.com/dev/iphone/uploads/t69566.mov";
    NSURL *videoURL = [NSURL URLWithString:videoURLString];
    MPMoviePlayerViewController *moviePlayerView = [[[MPMoviePlayerViewController alloc] initWithContentURL:videoURL] autorelease];

    [self presentMoviePlayerViewControllerAnimated:moviePlayerView];

} 

现在,我想让openVideo随着视频发布的增加而变得更具动态性,但我卡在了如何将视频截取一帧或缩略图并显示出来的步骤上。
有什么建议或想法吗?
更新:
我想从服务器上拿到一个视频的缩略图。这也引发了我的一个问题。
当用户首次上传视频时,是否最好在那里创建一个缩略图并将其上传到我的服务器,然后只需在抓取它们以填充新闻源类型的视图时将其与视频相关联?

你想在服务器上获取缩略图吗?(这样你就可以下载缩略图和视频了) - Wain
我已经成功直接从视频中获取缩略图,但这种方式可能非常慢,因此我建议谨慎使用。 - Tony
最好是服务器从视频中提取缩略图。除非出于某种原因必须上传缩略图,否则没有必要这样做。 - Wain
@Wain 那就是我所假设的。那么,我应该如何从我的服务器上流式传输的视频中获取它呢?我的方法应该是什么? - David Biga
1个回答

5

您可以使用AVAssetImageGenerator来完成这个操作。以下是从一个工作项目中复制粘贴的草拟代码(但可能没有被很好地隔离):

  • _thumbnailView is an UIImageView to display the thumbnail.
  • _activityView is a UIActivityIndicatorView that gets hidden when the thumbnail finishes loading.

    AVPlayerItem *playerItem = [[AVPlayerItem playerItemWithURL:movieURL] retain];
    AVAssetImageGenerator *_generator;
    _generator = [[AVAssetImageGenerator assetImageGeneratorWithAsset:playerItem.asset] retain];
    [playerItem release];
    
    AVAssetImageGeneratorCompletionHandler handler = ^(CMTime requestedTime, CGImageRef image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error) {
        if (result == AVAssetImageGeneratorSucceeded) {
            UIImage *thumb = [UIImage imageWithCGImage:image];
            [_thumbnailView setImage:thumb forState:UIControlStateNormal];
        } else {
            DLog(@"%s - error: %@", __PRETTY_FUNCTION__, error);
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            _thumbnailView.hidden = NO;
            _playButton.hidden = NO;
            [_activityView stopAnimating];
        });
    };
    
    [_generator generateCGImagesAsynchronouslyForTimes:[NSArray arrayWithObject:[NSValue valueWithCMTime:CMTimeMakeWithSeconds(30,30)]] completionHandler:handler];
    
回到你的问题,我认为服务器端生成的缩略图通常更好,因为服务器有更强大的处理能力。此外,为了获取这个缩略图,您需要从服务器开始下载实际的视频。
最后,要注意传递包括对`CMTimeMakeWithSeconds()`调用的`CMTime`参数。这可能会导致问题,因为您很容易遇到空白帧。这就是为什么我们在我们的视频中使用30作为参数,以避免这种情况。

好的,非常感谢您的回复。关于我的openVideo方法,我有点困惑,什么时候应该调用您给我的代码?是在[self presentMoviePlayerViewControllerAnimated:moviePlayerView];之后吗?这也带来了一个问题。由于我只能在不从服务器下载视频的情况下完成此操作。我试图实现的是像Facebook一样,它首先显示视频框架,然后当您单击它时,它会打开流。如果没有将缩略图实际存储在我的服务器上,我是否无法做到这一点? - David Biga
你应该先使用缩略图生成器,然后使用该图像创建一个用户可以点击的按钮。一旦他点击了带有缩略图的按钮,你就可以调用你的 openVideo 方法,它将使用视频播放器接管用户屏幕。 - pgb
好的,那很有道理,所以在尝试使用您的代码时,我遇到了一些问题。首先,我正在使用 UIImageView *btn = [UIButton buttonWithType:UIButtonTypeCustom]; btn.frame = CGRectMake(0, 0, 30, 30); 定义一个测试按钮,然后从那里更改值以匹配我的代码。问题出在 cache 部分 -> [UIImagePNGRepresentation(thumb) writeToURL:[NSURL fileURLWithPath:cachedFilePath] atomically:NO]; 没有有效的标识符,更确切地说:cachedFilePath 不存在,我不确定那应该是什么? - David Biga
我认为你无法加速它。不过,尝试使用不同的CMTimeMakeWithSeconds值。也许使用0而不是30会从视频中下载更少的内容(文档在此)。在你的情况下,我还建议尝试使用服务器端缩略图。 - pgb
快问一下,我应该如何调用一个自定义的completionHandler在完成时[_generator generateCGImagesAsynchronouslyForTimes:[NSArray arrayWithObject:[NSValue valueWithCMTime:CMTimeMakeWithSeconds(30,30)]] completionHandler:handler];到一个方法中? - David Biga
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接