在录制视频时将动态文本渲染到CVPixelBufferRef上

时间:2015-06-03 01:16:17

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

我正在使用AVCaptureVideoDataOutputAVCaptureAudioDataOutput录制视频和音频,并且在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. 最后,我将滤镜输出图像渲染到pixelBuffer。 CIContext预先使用[CIContext contextWithOptions:nil];创建。{/ li>
  6. 毕竟,我使用适当的时间戳将像素缓冲区附加到pixelBufferAdaptor
  7. 在录制结束时保存的视频没有可见的变化,即没有在像素缓冲区上绘制蒙版图像。

    任何人都知道我在哪里错了?我已经坚持了几天,任何帮助都会如此受到赞赏。

    编辑:

    - (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;
    }
    

4 个答案:

答案 0 :(得分:4)

你想要如下吗? enter image description here

您应该使用CIBlendWithMask,而不是CISourceOverCompositing,请尝试:

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

答案 1 :(得分:1)

您还可以使用CoreGraphicsCoreText直接在现有CVPixelBufferRef上绘制(如果它是RGBA)(如果是YUV则在副本上)。我在这个答案中有一些示例代码:https://stackoverflow.com/a/46524831/48125

答案 2 :(得分:1)

我向Apple DTS询问了同样的问题,因为我的所有方法都运行得非常慢或做得很奇怪,他们发给我了这个:

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

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

将源图像和图像与我为每个帧生成的文本合成的CIFilter的组合起到了作用。

我希望这有助于其他人!

答案 3 :(得分:0)

Bannings答案的快速版本。

        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())