繁体   English   中英

iOS:AVPlayer - 获取视频当前帧的快照

[英]iOS: AVPlayer - getting a snapshot of the current frame of a video

我花了一整天时间,经历了很多SO答案,Apple参考文献,文档等,但都没有成功。

我想要一个简单的事情: 我正在使用AVPlayer播放视频,我想暂停它并将当前帧作为UIImage 而已。

我的视频是位于互联网上的m3u8文件,它在AVPlayerLayer中正常播放没有任何问题。

我试过了什么:

  1. AVAssetImageGenerator 它不起作用,方法copyCGImageAtTime:actualTime: error:返回null image ref。 根据答案 AVAssetImageGenerator不适用于流式传输视频。
  2. 拍摄玩家视图的快照。 我在AVPlayerLayer上尝试了第一个renderInContext:但后来我意识到它没有呈现这种“特殊”层。 然后我发现在iOS 7中引入了一个新方法 - drawViewHierarchyInRect:afterScreenUpdates:它应该能够渲染特殊图层,但没有运气,仍然得到了带有空白黑色区域的UI快照,其中显示了视频。
  3. AVPlayerItemVideoOutput 我为我的AVPlayerItem添加了一个视频输出,但每当我调用hasNewPixelBufferForItemTime:它返回NO 我想问题是再次流式传输视频, 我并不孤单
  4. AVAssetReader 我正在考虑尝试,但决定在这里找到相关问题后不要浪费时间。

所以,有没有办法得到我现在在屏幕上看到的东西的快照? 我简直不敢相信。

从m3u8开始, AVPlayerItemVideoOutput对我来说很好。 也许是因为我不咨询hasNewPixelBufferForItemTime而只是调用copyPixelBufferForItemTime 此代码生成CVPixelBuffer而不是UIImage ,但有些答案描述了如何执行此操作

这个答案大多来自这里

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>

@interface ViewController ()

@property (nonatomic) AVPlayer *player;
@property (nonatomic) AVPlayerItem *playerItem;
@property (nonatomic) AVPlayerItemVideoOutput *playerOutput;

@end

@implementation ViewController
- (void)setupPlayerWithLoadedAsset:(AVAsset *)asset {
    NSDictionary* settings = @{ (id)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA) };
    self.playerOutput = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:settings];
    self.playerItem = [AVPlayerItem playerItemWithAsset:asset];
    [self.playerItem addOutput:self.playerOutput];
    self.player = [AVPlayer playerWithPlayerItem:self.playerItem];

    AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
    playerLayer.frame = self.view.frame;
    [self.view.layer addSublayer:playerLayer];

    [self.player play];
}

- (IBAction)grabFrame {
    CVPixelBufferRef buffer = [self.playerOutput copyPixelBufferForItemTime:[self.playerItem currentTime] itemTimeForDisplay:nil];
    NSLog(@"The image: %@", buffer);
}

- (void)viewDidLoad {
    [super viewDidLoad];


    NSURL *someUrl = [NSURL URLWithString:@"http://qthttp.apple.com.edgesuite.net/1010qwoeiuryfg/sl.m3u8"];
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:someUrl options:nil];

    [asset loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:@"tracks"] completionHandler:^{

        NSError* error = nil;
        AVKeyValueStatus status = [asset statusOfValueForKey:@"tracks" error:&error];
        if (status == AVKeyValueStatusLoaded)
        {
            dispatch_async(dispatch_get_main_queue(), ^{
                [self setupPlayerWithLoadedAsset:asset];
            });
        }
        else
        {
            NSLog(@"%@ Failed to load the tracks.", self);
        }
    }];
}

@end

AVAssetImageGenerator是对视频进行快照的最佳方式,此方法异步返回UIImage

import AVFoundation

// ...

var player:AVPlayer? = // ...

func screenshot(handler:@escaping ((UIImage)->Void)) {
    guard let player = player ,
        let asset = player.currentItem?.asset else {
            return
    }

    let imageGenerator = AVAssetImageGenerator(asset: asset)
    imageGenerator.appliesPreferredTrackTransform = true
    let times = [NSValue(time:player.currentTime())]

    imageGenerator.generateCGImagesAsynchronously(forTimes: times) { _, image, _, _, _ in
        if image != nil {
            handler(UIImage(cgImage: image!))
        }
    }
}

(这是Swift 4.2)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM