转码 (Transcoding)

CI

一个简单的 Swift 包,用于视频编码和解码,带有 Annex-B 适配器,专为通过网络传输视频而优化。

Transcoding 用于 Castaway 中的视频编码和解码,Castaway 是一款将 HDMI 采集设备从 iPad 或 Mac 流式传输到附近的 Vision Pro 的应用程序。

Example data flow

用法 (Usage)

VideoEncoder

VideoEncoder 是一个对象,它接收包含 CVPixelBufferCMSampleBuffer,并输出包含压缩后的 H264/HEVC 数据的 CMBlockBufferCMSampleBuffer 流。 VideoEncoder 使用 Config 初始化,其中包含用于实时采集、主动转码、后台转码和超低延迟的预设,遵循 Apple 的建议。

用法 (Usage)

let videoEncoder = VideoEncoder(config: .ultraLowLatency)
encoderStreamTask = Task {
    for await encodedSampleBuffer in videoEncoder.encodedSampleBuffers {
        // encodedSampleBuffer: CMSampleBuffer > CMBlockBuffer
    }
}
videoEncoder.encode(sampleBuffer)

VideoDecoder

VideoDecoder 是一个对象,它接收包含压缩后的 H264/HEVC 数据的 CMBlockBuffersCMSampleBuffer,并输出包含 CVPixelBufferCMSampleBuffer 流。 VideoDecoder 使用包含各种可选解压缩设置的 Config 初始化。

用法 (Usage)

let videoDecoder = VideoDecoder(config: .init(realTime: true))
decoderStreamTask = Task {
    for await decodedSampleBuffer in videoDecoder.decodedSampleBuffers {
        // decodedSampleBuffer: CMSampleBuffer > CVPixelBuffer
    }
}
videoDecoder.decode(sampleBuffer)

Annex B

VideoEncoderAnnexBAdaptorVideoDecoderAnnexBAdaptor 可用于将压缩后的 CMSampleBuffer 转换为 Annex B (ITU-T-REC-H.265) 字节流,以及从 Annex B 字节流转换为压缩后的 CMSampleBuffer。 这非常适合通过网络发送压缩视频数据。

示例流程 (Example Pipeline)

在此示例中,来自采集设备的视频帧被编码和解码为 Annex-B 数据流,该数据流针对低延迟进行了优化。

let videoEncoder = VideoEncoder(config: .ultraLowLatency)
let videoEncoderAnnexBAdaptor = VideoEncoderAnnexBAdaptor(
    videoEncoder: videoEncoder
)
let videoDecoder = VideoDecoder(config: .init(realTime: true))
let videoDecoderAnnexBAdaptor = VideoDecoderAnnexBAdaptor(
    videoDecoder: videoDecoder,
    codec: .hevc
)

videoEncoderTask = Task {
    for await data in videoEncoderAnnexBAdaptor.annexBData {
        // send data over network or whatever
    }
}

videoDecoderTask = Task {
    for await decodedSampleBuffer in videoDecoder.decodedSampleBuffers {
        // here you have a received decoded sample buffer with image buffer
    }
}

receivedMessageTask = Task {
    // Replace `realtimeStreaming.receivedMessages` with however you receive encoded data packets 
    for await (data, _) in realtimeStreaming.receivedMessages {
        videoDecoderAnnexBAdaptor.decode(data)
    }
}

captureSessionTask = Task {
    // Replace `captureSession.pixelBuffers` with your video data source
    for await pixelBuffer in captureSession.pixelBuffers {
        videoEncoder.encode(pixelBuffer)
    }
}

重要提示 (Important Notes)