CMSampleBuffer 在 Swift 3 内从纵向旋转到横向

CMSampleBuffer rotate from portrait to landscape in Swift 3

我在 iOS 中处理 ReplayKit2,由于某些原因我需要将 CMSampleBuffer 从纵向旋转到横向,我发现结果不正确。

我想念什么?

这是原始样本缓冲区

这是实际的输出缓冲区

width & height are dimensions of sampleBuffer

func rotation(sampleBuffer: CMSampleBuffer, width: Int, height: Int) -> CMSampleBuffer {

        //create pixelbuffer from the delegate method samplebuffer
        let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!

        CVPixelBufferLockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))

        //create CI image from the buffer
        let image = CIImage(cvImageBuffer: pixelBuffer)

        let extent = CGRect(x: 0, y: 0, width: width, height: height)

        var tx = CGAffineTransform(translationX: extent.midX, y: extent.midY)

        tx = tx.rotated(by: CGFloat(Double.pi / 2))

        tx = tx.translatedBy(x: -extent.midX, y: -extent.midY)

        var transformImage = CIFilter(
            name: "CIAffineTransform",
            withInputParameters: [
                kCIInputImageKey: image,
                kCIInputTransformKey: NSValue.init(cgAffineTransform: tx)])!.outputImage!

        //create empty pixelbuffer
        var newPixelBuffer : CVPixelBuffer? = nil

        CVPixelBufferCreate(kCFAllocatorDefault,
                            width,
                            height,
                            kCVPixelFormatType_32BGRA,
                            nil,
                            &newPixelBuffer)
        //render the context to the new pixelbuffer, context is a global
        //CIContext variable. creating a new one each frame is too CPU intensive
        self.ciContext.render(transformImage, to: newPixelBuffer!)

        //finally, write this to the pixelbufferadaptor

        CVPixelBufferUnlockBaseAddress(pixelBuffer,CVPixelBufferLockFlags(rawValue: 0))

        var videoInfo: CMVideoFormatDescription?

        CMVideoFormatDescriptionCreateForImageBuffer(kCFAllocatorDefault, newPixelBuffer!, &videoInfo)

        var sampleTimingInfo = CMSampleTimingInfo(duration: CMSampleBufferGetDuration(sampleBuffer), presentationTimeStamp: CMSampleBufferGetPresentationTimeStamp(sampleBuffer), decodeTimeStamp: CMSampleBufferGetDecodeTimeStamp(sampleBuffer))

        var newSampleBuffer: CMSampleBuffer?

        CMSampleBufferCreateForImageBuffer(kCFAllocatorDefault, newPixelBuffer!, true, nil, nil, videoInfo!, &sampleTimingInfo, &newSampleBuffer)

        return newSampleBuffer!

    }

刚刚在 iOS11!

中发现了一个非常棒的方法
/* Returns a new image representing the original image transformeded for the given CGImagePropertyOrientation */
    @available(iOS 11.0, *)
    open func oriented(_ orientation: CGImagePropertyOrientation) -> CIImage

可能会有用

func rotate(_ sampleBuffer: CMSampleBuffer) -> CVPixelBuffer? {
        guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
            return nil
        }
        var newPixelBuffer: CVPixelBuffer?
        let error = CVPixelBufferCreate(kCFAllocatorDefault,
                                        CVPixelBufferGetHeight(pixelBuffer),
                                        CVPixelBufferGetWidth(pixelBuffer),
                                        kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,
                                        nil,
                                        &newPixelBuffer)
        guard error == kCVReturnSuccess else {
            return nil
        }
        let ciImage = CIImage(cvPixelBuffer: pixelBuffer).oriented(.right)
        let context = CIContext(options: nil)
        context.render(ciImage, to: newPixelBuffer!)
        return newPixelBuffer
    }