[ios] CoreVideo 프레임워크를 활용한 화면 캡쳐 및 녹화 기능

iOS 앱에서 화면을 캡쳐하거나 녹화하는 기능을 구현하려면 CoreVideo 프레임워크를 사용할 수 있습니다. CoreVideo는 iOS 기기의 비디오 프레임 데이터에 접근하고 다루는 데 사용되며, CoreVideo를 사용하면 화면 상태를 실시간으로 캡쳐하고 녹화할 수 있습니다.

1. 화면 캡쳐

CoreVideo를 사용하여 iOS 앱에서 현재 화면을 캡쳐하는 방법은 다음과 같습니다.

import UIKit
import AVFoundation
import CoreVideo

func captureScreen() -> CVPixelBuffer? {
    guard let window = UIApplication.shared.windows.first(where: { $0.isKeyWindow }),
        let layer = window.layer as? CAEAGLLayer else {
            return nil
    }
    
    let scale = UIScreen.main.scale
    layer.contentsScale = scale
    layer.render(in: UIGraphicsRenderer(bounds: window.bounds).cgContext)
    
    var pixelBuffer: CVPixelBuffer?
    CVPixelBufferCreate(nil, Int(window.bounds.width * scale), Int(window.bounds.height * scale),
                        kCVPixelFormatType_32BGRA, nil, &pixelBuffer)
    
    guard let buffer = pixelBuffer else { return nil }
    
    CVPixelBufferLockBaseAddress(buffer, [])
    defer { CVPixelBufferUnlockBaseAddress(buffer, []) }
    guard let context = CGContext(data: CVPixelBufferGetBaseAddress(buffer),
                                  width: CVPixelBufferGetWidth(buffer),
                                  height: CVPixelBufferGetHeight(buffer),
                                  bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(buffer),
                                  space: CGColorSpaceCreateDeviceRGB(),
                                  bitmapInfo: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue) else {
                                    return nil
    }
    
    UIGraphicsPushContext(context)
    window.layer.render(in: context)
    UIGraphicsPopContext()
    
    return buffer
}

위의 코드는 captureScreen() 함수를 사용하여 현재 화면을 캡쳐하고 결과를 CVPixelBuffer로 반환합니다.

2. 화면 녹화

CoreVideo를 사용하여 iOS 앱에서 화면을 실시간으로 녹화하는 방법은 아래와 같습니다.

import UIKit
import AVFoundation
import CoreVideo

var writer: AVAssetWriter?
var writerInput: AVAssetWriterInput?
var pixelAdaptor: AVAssetWriterInputPixelBufferAdaptor?

func startRecording() {
    let fileUrl = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("video.mp4")
    
    do {
        writer = try AVAssetWriter(outputURL: fileUrl, fileType: .mp4)
    } catch {
        print("Error creating AVAssetWriter: \(error.localizedDescription)")
        return
    }
    
    let screenSize = UIScreen.main.bounds.size
    let videoSettings: [String: Any] = [
        AVVideoCodecKey: AVVideoCodecType.h264,
        AVVideoWidthKey: screenSize.width,
        AVVideoHeightKey: screenSize.height
    ]
    
    writerInput = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings)
    writerInput?.expectsMediaDataInRealTime = true

    let sourcePixelBufferAttributes: [String: Any] = [
        kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32ARGB,
        kCVPixelBufferWidthKey as String: screenSize.width,
        kCVPixelBufferHeightKey as String: screenSize.height
    ]
    
    pixelAdaptor = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: writerInput!,
                                                        sourcePixelBufferAttributes: sourcePixelBufferAttributes)
    
    if let writer = writer, writer.canAdd(writerInput!) {
        writer.add(writerInput!)
    } else {
        print("Error adding writer input")
        return
    }
    
    writer.startWriting()
    writer.startSession(atSourceTime: .zero)
}

func recordFrameAtTime(_ presentationTime: CMTime) {
    guard let pixelBuffer = captureScreen() else { return }
    pixelAdaptor?.append(pixelBuffer, withPresentationTime: presentationTime)
}

func stopRecording() {
    writerInput?.markAsFinished()
    writer.finishWriting {
        if let error = writer.error {
            print("Error writing video: \(error.localizedDescription)")
        } else {
            print("Video recording complete")
        }
    }
}

startRecording() 함수를 사용하여 녹화를 시작하고, recordFrameAtTime() 함수는 각 프레임을 녹화하는 데 사용됩니다. 마지막으로 stopRecording() 함수를 호출하여 녹화를 중지합니다.

이제 CoreVideo 프레임워크를 사용하여 iOS 앱에서 화면을 캡쳐하고 녹화하는 방법에 대해 알아보았습니다.

참고 자료