【iOS】控制元件截圖、MP4格式視訊流和m3u8格式視訊流擷取某一幀功能的實現

淺淺青丘發表於2018-01-19

最近開發遇到一個點選按鈕實現直播視訊流截圖的功能,去網上查了一下資料,總結了一下iOS中截圖相關的知識,然後自己做了個demo。
demo主要實現了3種截圖方法,分別對應三種不同的應用場景。
1、imageView截圖,這個截圖方法可以用來實現擷取專案中的控制元件,可擷取的控制元件可包括UIImageView、UIView等。截圖方法如下:

-(UIImage *)screenshotsWithView:(UIView *)view{
    
    UIGraphicsBeginImageContextWithOptions(view.frame.size, NO, 0.0);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

2、MP4格式的視訊流截圖,即獲取MP4格式視訊流中的某一幀。擷取方法如下:

-(UIImage *)screenshotsMP4WithCurrentTime:(CMTime)currentTime videoUrl:(NSString *)url{
    
    AVURLAsset * asset = [[AVURLAsset alloc] initWithURL:[NSURL URLWithString:url] options:nil];
    AVAssetImageGenerator * gen = [[AVAssetImageGenerator alloc] initWithAsset:asset];
    gen.appliesPreferredTrackTransform = YES;
    gen.requestedTimeToleranceAfter = kCMTimeZero;
    gen.requestedTimeToleranceBefore = kCMTimeZero;
    CMTime time = CMTimeMakeWithSeconds(CMTimeGetSeconds(currentTime), 600);
    NSError * error = nil;
    CMTime actualTime;
    CGImageRef imageRef = [gen copyCGImageAtTime:time actualTime:&actualTime error:&error];
    UIImage * image = [[UIImage alloc] initWithCGImage:imageRef];
    return image;
}

這個方法是不是僅限於MP4格式的視訊我不是很清楚,但是可以確定的是,MP4擷取某一幀的方法不適用於m3u8格式的視訊流。
3、m3u8格式視訊流截圖。方法如下:

-(UIImage *)screenshotsm3u8WithCurrentTime:(CMTime)currentTime playerItemVideoOutput:(AVPlayerItemVideoOutput *)output{
    
    CVPixelBufferRef pixelBuffer = [output copyPixelBufferForItemTime: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))];
    UIImage *frameImg = [UIImage imageWithCGImage:videoImage];
    CGImageRelease(videoImage);
    CVBufferRelease(pixelBuffer);
    return frameImg;
}

需要特別指出來的那兩個release方法,不呼叫的話會造成記憶體洩漏(可用Instruments除錯)。
另外還有一點需要注意,m3u8格式的視訊流在擷取時需要傳入一個AVPlayerItemVideoOutput物件,這個物件一定要在AVPlayerItem初始化的時候設定好,如果以臨時變數的形式傳入或導致擷取失敗。
在截圖事件裡直接呼叫以上方法即可獲取到擷取的image。demo連結地址:https://github.com/zhanqin/screenshots


相關文章