AVSampleBufferDisplayLayer中的视频流不会显示在屏幕截图中

时间:2015-02-27 21:19:09

标签: ios ios8 uiimage screenshot cmsamplebufferref

我一直在使用新的视频工具箱方法拍摄H.264视频流,并使用AVSampleBufferDisplayLayer将其显示在视图控制器中。这一切都按预期工作,流看起来很棒。 但是,当我尝试截取整个视图的屏幕截图时,AVSampleBufferDisplayLayer(即解压缩的视频流)的内容不会显示在快照中。快照显示所有其他内容UI按钮/标签/等。但屏幕截图仅显示AVSampleBufferDisplayLayer(我设置为亮蓝色)的背景颜色,而不是实时视频输入。

在下面的方法中(受this post启发)我从我的流中取出SampleBuffer并将其排队以显示在AVSampleBufferDisplayLayer上。然后我调用我的方法 imageFromLayer:将快照作为UIImage获取。 (然后我在 UIImageView imageDisplay 中显示UIImage,或者将其保存到设备的本地相机胶卷以验证UIImage的外观。两种方法都产生相同的效果结果。)

-(void) h264VideoFrame:(CMSampleBufferRef)sample
{
    [self.AVSampleDisplayLayer enqueueSampleBuffer:sample];

    dispatch_sync(dispatch_get_main_queue(), ^(void) {
        UIImage* snapshot = [self imageFromLayer:self.AVSampleDisplayLayer];
        [self.imageDisplay setImage:snapshot];
    });
}

在这里,我只需获取AVSampleBufferDisplayLayer的内容,然后尝试将其转换为UIImage。如果我将整个屏幕作为图层传递给此方法,则除了AVDisplayLayer之外,所有其他UI元素(如标签/按钮/图像)都会显示。如果我只传入AVDisplayLayer,我会得到一个稳定的蓝色图像(因为背景颜色为蓝色)。

- (UIImage *)imageFromLayer:(CALayer *)layer
{
    UIGraphicsBeginImageContextWithOptions([layer frame].size, YES, 1.0);

    [layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();

    //UIImageWriteToSavedPhotosAlbum(outputImage, self, nil, nil);

    UIGraphicsEndImageContext();

    return outputImage;
}

我已尝试使用UIImage snapshot = [self imageFromLayer: self.AVSampleDisplayLayer.presentationLayer];.modelLayer,但这并没有帮助。我已经尝试排队采样缓冲并在拍摄快照之前等待,我已经尝试弄乱AVDisplayLayer的不透明度和xPosition ...我甚至尝试为其设置不同的值CMTimebase的{​​{1}}。任何提示都表示赞赏!

同样根据this postthis post其他人在iOS 8中遇到类似的快照问题。

1 个答案:

答案 0 :(得分:0)

我通过从AVSampleDisplayLayer切换到VTDecompressionSession来解决此问题。在VTDecompression didDecompress回调方法中,我将解压缩的图片(CVImageBufferRef)发送到以下方法,以获取视频流的屏幕截图并将其转换为UIImage

-(void) screenshotOfVideoStream:(CVImageBufferRef)imageBuffer
{
    CIImage *ciImage = [CIImage imageWithCVPixelBuffer:imageBuffer];
    CIContext *temporaryContext = [CIContext contextWithOptions:nil];
    CGImageRef videoImage = [temporaryContext
                             createCGImage:ciImage
                             fromRect:CGRectMake(0, 0, 
                             CVPixelBufferGetWidth(imageBuffer), 
                             CVPixelBufferGetHeight(imageBuffer))];

    UIImage *image = [[UIImage alloc] initWithCGImage:videoImage];
    [self doSomethingWithOurUIImage:image];
    CGImageRelease(videoImage);
}