【问题标题】:Render dynamic text onto CVPixelBufferRef while recording video录制视频时将动态文本渲染到 CVPixelBufferRef
【发布时间】:2015-08-17 00:32:17
【问题描述】:

我正在使用AVCaptureVideoDataOutput 和AVCaptureAudioDataOutput 录制视频和音频,在captureOutput:didOutputSampleBuffer:fromConnection: 委托方法中,我想将文本绘制到我从视频连接接收到的每个单独的样本缓冲区上。文本几乎每帧都会发生变化(它是秒表标签),我希望将其记录在捕获的视频数据之上。

以下是我目前所能想到的:

//1.
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);

//2.   
UIImage *textImage = [self createTextImage];
CIImage *maskImage = [CIImage imageWithCGImage:textImage.CGImage];

//3.
CVPixelBufferLockBaseAddress(pixelBuffer, 0); 
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
NSDictionary *options = [NSDictionary dictionaryWithObject:(__bridge id)colorSpace forKey:kCIImageColorSpace];
CIImage *inputImage = [CIImage imageWithCVPixelBuffer:pixelBuffer options:options];

//4.
CIFilter *filter = [CIFilter filterWithName:@"CIBlendWithMask"];
[filter setValue:inputImage forKey:@"inputImage"];
[filter setValue:maskImage forKey:@"inputMaskImage"];
CIImage *outputImage = [filter outputImage];
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);

//5.   
[self.renderContext render:outputImage toCVPixelBuffer:pixelBuffer bounds:[outputImage extent] colorSpace:CGColorSpaceCreateDeviceRGB()];

//6.
[self.pixelBufferAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:timestamp];
  1. 我在这里抓取像素缓冲区,非常简单。
  2. 我使用核心图形将文本写入空白 UIImage(createTextImage 就是这样做的。我能够验证此步骤是否有效;我将带有文本的图像保存到我的照片中。
  3. 我从像素缓冲区创建了一个 CGImage。
  4. 我为CIBlendWithMask 制作了一个CIFilter,将输入图像设置为从原始像素缓冲区创建的图像,并将输入掩码设置为CIImage,该图像由带有文本的图像制成。
  5. 最后,我将过滤器输出图像渲染到像素缓冲区。 CIContext 是使用 [CIContext contextWithOptions:nil]; 预先创建的。
  6. 毕竟,我将像素缓冲区附加到我的 pixelBufferAdaptor 并带有适当的时间戳。

在录制结束时保存的视频没有可见的变化,即没有将蒙版图像绘制到像素缓冲区。

有人知道我在哪里出错了吗?我已经坚持了好几天了,任何帮助将不胜感激。

编辑:

- (UIImage *)createTextImage {
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.view.bounds.size.width, self.view.bounds.size.height), NO, 1.0);
    NSMutableAttributedString *timeStamp = [[NSMutableAttributedString alloc]initWithString:self.timeLabel.text attributes:@{NSForegroundColorAttributeName:self.timeLabel.textColor, NSFontAttributeName: self.timeLabel.font}];
    NSMutableAttributedString *countDownString = [[NSMutableAttributedString alloc]initWithString:self.cDownLabel.text attributes:@{NSForegroundColorAttributeName:self.cDownLabel.textColor, NSFontAttributeName:self.cDownLabel.font}];
    [timeStamp drawAtPoint:self.timeLabel.center];
    [countDownString drawAtPoint:self.view.center];
    UIImage *blank = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return blank;
}

【问题讨论】:

  • 嗨!你的问题是对我问题的回答。但是 self.renderContext 是什么?
  • 这是一个CIContext 对象
  • 你最后是怎么做到的?
  • 我最终使用 GPUImage 录制实时视频,然后对结果应用了过滤器。
  • 你能分享那个示例代码吗? @barndog 我正在使用 GPUImage,但无法达到同样的效果。

标签: ios objective-c avfoundation core-image core-video


【解决方案1】:

班宁斯答案的 Swift 版本。

        let combinedFilter = CIFilter(name: "CISourceOverCompositing")!
        combinedFilter.setValue(maskImage.oriented(.left), forKey: "inputImage")
        combinedFilter.setValue(inputImage, forKey: "inputBackgroundImage")

        let outputImage = combinedFilter.outputImage!

        let tmpcontext = CIContext(options: nil)
        tmpcontext.render(outputImage, to: pixelBuffer, bounds: outputImage.extent, colorSpace: CGColorSpaceCreateDeviceRGB())

【讨论】:

    【解决方案2】:

    我向 Apple DTS 询问了同样的问题,因为我使用的所有方法运行速度都很慢或做奇怪的事情,他们给我发了这个:

    https://developer.apple.com/documentation/avfoundation/avasynchronousciimagefilteringrequest?language=objc

    这让我很快找到了一个可行的解决方案!您可以使用 CIFilters 完全绕过 CVPixelBuffer,恕我直言,它更容易使用。因此,如果您实际上不需要使用 CVPixelBuffer,那么这种方法将很快成为您的新朋友。

    结合使用 CIFilter(s) 来合成源图像和图像以及我为每一帧生成的文本就可以了。

    我希望这对其他人有帮助!

    【讨论】:

    • 任何示例如何使用 CIFilters 向 CVPixelBuffer 添加文本?​​
    【解决方案3】:

    您还可以使用CoreGraphics 和CoreText 直接在现有CVPixelBufferRef 的顶部(如果它是RGBA 的话)(或者如果它是YUV 的话在副本上)。我在这个答案中有一些示例代码:https://stackoverflow.com/a/46524831/48125

    【讨论】:

      【解决方案4】:

      你想像下面这样吗?

      你应该使用CISourceOverCompositing,而不是CIBlendWithMask,试试这个:

      //4.
      CIFilter *filter = [CIFilter filterWithName:@"CISourceOverCompositing"];
      [filter setValue:maskImage forKey:kCIInputImageKey];
      [filter setValue:inputImage forKey:kCIInputBackgroundImageKey];
      CIImage *outputImage = [filter outputImage];
      

      【讨论】:

      • 这正是我想要的!我试过了,但还是没有运气。
      • 您是否将maskImage 设置为kCIInputImageKey 而不是kCIInputBackgroundImageKey?
      • 是的,刚刚检查以确保。
      • 你能发布你的createTextImage吗?
      • 没问题,刚刚做了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-15
      • 2020-08-17
      • 2011-04-16
      • 2014-10-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多