美文网首页
iOS AVPlayer截取视频首帧缩略图,常规mp4与m3u8

iOS AVPlayer截取视频首帧缩略图,常规mp4与m3u8

作者: 假如兔子失了尾 | 来源:发表于2024-07-18 11:56 被阅读0次

    获取常规格式视频缩略图(适用于mp4、mov等)

    /**
     *  获取视频的缩略图方法
     *  @param videoUrl 视频链接  支持本地路径和网络路径
     *  @return 视频截图
     */
    + (UIImage *)getVideoImageFromPath:(NSURL *)videoUrl{
        UIImage *shotImage;
        AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoUrl 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];
        shotImage = [[UIImage alloc] initWithCGImage:image];
        CGImageRelease(image);
        return shotImage;
    }
    

    获取m3u8格式视频缩略图

    m3u8格式是适用于直播流的格式,加载时是以切片的模式分段加载,无法从视频流中直接获取某一帧图片
    这里是使用AVPlayerItemVideoOutput,采用截屏输出的方案来获取首帧图
    该方法一定要视频在可播放的状态下才能取到,如果该缩略图时做封面图使用,建议还是和服务端的同事沟通一下参数方案吧

    一、声明对象

    /// 播放器
    @property (nonatomic, strong) AVPlayer *player;
    /// 播放器item
    @property (nonatomic, strong) AVPlayerItem *playerItem;
    /// 播放器layer
    @property (nonatomic, strong) AVPlayerLayer *playerLayer;
    /// 视频截图输出
    @property (nonatomic, strong) AVPlayerItemVideoOutput *output;
    

    二、初始化播放器时,给播放器添加输出对象

    //包装到Asset,防止抓包泄露视频地址
    AVURLAsset *asset = [AVURLAsset assetWithURL:[NSURL URLWithString:@"视频链接"]];
    //创建播放源
    self.playerItem = [AVPlayerItem playerItemWithAsset:asset];
    //创建播放器
    self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
    //设置播放控件
    self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
    
    //已经创建过了,代表已经添加到playerItem中,这里先移除,防止重复
    if (self.output) {
        [self.playerItem removeOutput:self.output];
    }
    NSDictionary *settings = @{(id)kCVPixelBufferPixelFormatTypeKey:@(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange)};
    self.output = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:settings];
    [self.playerItem  addOutput:self.output];
    

    播放器销毁时要移除output对象并置为nil

    [self.playerItem removeOutput:self.output];
    self.output = nil;
    

    三、监听播放器缓存到可以播放的状态

    获取首帧缩略图时一定要监听该状态,否则在此之前去截取会失败

    //监听缓存足够播放的状态
    [self.playerItem addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];
    

    播放器销毁时移除

    [self.player.currentItem removeObserver:self forKeyPath:@"playbackLikelyToKeepUp"];
    

    四、去取首帧缩略图

    一定要先暂停,不然取到的图片不一定是首帧图,存在着播放中的误差

    //播放器状态监听
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
        if ([keyPath isEqualToString:@"playbackLikelyToKeepUp"]) {//缓冲到足够播放的状态
            [self.player pause];
            //这里等待0.5秒时为了等player绘制完成,否则取不到video缩略图
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                //取缩略图
                UIImage *thumImg = [self getThumbnailImageCompletion];
                [self.player play];
            });
        }
    }
    

    核心代码,如果播放器有截屏的功能也可以用该方法,获取当前播放帧的图片

    - (UIImage *)getThumbnailImageCompletion{
        UIImage *frameImg = nil;
        //确保当前时间的视频已经加载完成
        CVPixelBufferRef pixelBuffer = [self.output copyPixelBufferForItemTime:self.player.currentTime itemTimeForDisplay:nil];
        CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];
        CIContext *temporaryContext = [CIContext contextWithOptions:nil];
        CGImageRef videoImage = [temporaryContext createCGImage:ciImage
                                                       fromRect:CGRectMake(0, 0,
                                                     CVPixelBufferGetWidth(pixelBuffer),
                                                     CVPixelBufferGetHeight(pixelBuffer))];
        frameImg = [UIImage imageWithCGImage:videoImage];
        CGImageRelease(videoImage);
        CVBufferRelease(pixelBuffer);
        return frameImg;
    }
    

    相关文章

      网友评论

          本文标题:iOS AVPlayer截取视频首帧缩略图,常规mp4与m3u8

          本文链接:https://www.haomeiwen.com/subject/nvurhjtx.html