视频截图-AVKit - (Obj-C)

视频图与视频是否在播放没有关系的,这里演示截图只是为了演示,截取当前正在播放的那一个点(当前界面内容)

示例代码:

#import "ViewController.h"
#import 
#import 

@interface ViewController ()
// 截取正在播放的视频后,用来显示截取的图片
@property (weak, nonatomic) IBOutlet UIImageView *showSnipImageView;
// 因为在封装的截图方法内需要使用播放控制器,所以声明一个全局属性
@property (nonatomic,strong) AVPlayerViewController *playerViewController;
@end

@implementation ViewController


// 开始播放
- (IBAction)ClickStartButton:(id)sender {
    
    // 创建播放控制器
    self.playerViewController = [[AVPlayerViewController alloc]init];
    
    // 获取本地视频资源路径
    NSString *filePath = [[NSBundle mainBundle]pathForResource:@"minion_01.mp4" ofType:nil];
    
    // 设置播放器
    self.playerViewController.player = [AVPlayer playerWithURL:[NSURL fileURLWithPath:filePath]];
    
    // 自定义视图
    self.playerViewController.view.frame = CGRectMake(50, 200, 320, 300);
    [self.view addSubview:self.playerViewController.view];
    
    // 开始播放
    [self.playerViewController.player play];
    
    
}
// 截图
- (IBAction)clickSnipButton:(id)sender {
    
    // 上面为了简单,没有通过资源图片的方式加载视频,使用了URL路径的方式
    // 获取本地视频资源路径
    NSString *filePath = [[NSBundle mainBundle]pathForResource:@"minion_01.mp4" ofType:nil];
    
    // 获取资源文件
    AVAsset *imageAsset = [AVAsset assetWithURL:[NSURL fileURLWithPath:filePath]];
    
    // 创建资源图片生成器
    AVAssetImageGenerator *generator = [AVAssetImageGenerator assetImageGeneratorWithAsset:imageAsset];
    
    // 获取截图的时间 当前播放的时间
    NSValue *currentTimeValue = [NSValue valueWithCMTime:self.playerViewController.player.currentTime];
    
    /*
     生成图片 (异步处理)
     参数1: 时间(需要一个存放NSValue类型的数组)
     参数2:完成回调
     */
    [generator generateCGImagesAsynchronouslyForTimes:@[currentTimeValue] completionHandler:^(CMTime requestedTime, CGImageRef  _Nullable image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError * _Nullable error) {
        // 回到主线程刷新UI
        dispatch_sync(dispatch_get_main_queue(), ^{
            self.showSnipImageView.image = [UIImage imageWithCGImage:image];
        });
        /*
         
         注意点: 刷新UI需要回归主线程,并且在回调block内,刷新UI需要使用内部的image参数
                如果异步处理,当线程执行到这行代码会开启新线程,跳过执行后面的代码,而不会等待该代码块执行完毕
                等到新线程访问image的时候,有可能image已经被释放了,就会出现野指针访问,所以需要同步
              (当回调block代码块执行完毕,image就会被释放,image是一个内部参数,外部并没有进行强引用)

        并非所有的情况下主队列同步都会造成死锁,此方法block内部代码默认在子线程执行
        刷新UI需要放在主线程,所以使用了主队列同步处理任务,保证了在内部参数image释放前,block代码块结束前完成UI刷新操作

         dispatch_async(dispatch_get_main_queue(), ^{
            self.showSnipImageView.image = [UIImage imageWithCGImage:image];
         });
         [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            self.showSnipImageView.image = [UIImage imageWithCGImage:image];
         }];
         */

    }];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}


@end
注意点:

刷新UI需要回归主线程,并且在回调block内,刷新UI需要使用内部的image参数 如果异步处理,当线程执行到这行代码会开启新线程,跳过执行后面的代码,而不会等待该代码块执行完毕 等到新线程访问image的时候,有可能image已经被释放了,就会出现野指针访问,所以需要同步 (当回调block代码块执行完毕,image就会被释放,image是一个内部参数,外部并没有进行强引用)

并非所有的情况下主队列同步都会造成死锁,此方法block内部代码默认在子线程执行 刷新UI需要放在主线程,所以使用了主队列同步处理任务,保证了在内部参数image释放前,block代码块结束前完成UI刷新操作

效果图:

视频截图-AVKit - (Obj-C)_第1张图片
视频截图.png

你可能感兴趣的:(视频截图-AVKit - (Obj-C))