【问题标题】:Decoding ProresRAW format to native bayer representation将 ProresRAW 格式解码为原生拜耳表示
【发布时间】:2021-12-27 01:05:30
【问题描述】:

我正在尝试解码 Prores 视频文件,但它不起作用。我总是得到

Optional(Error Domain=AVFoundationErrorDomain Code=-11821 "Cannot Decode" UserInfo={NSLocalizedFailureReason=媒体数据无法解码。可能已损坏。, NSLocalizedDescription=无法解码, NSUnderlyingError=0x600002a982a0 {Error Domain=NSOSStatusErrorDomain Code =-12137 "(null)"}})

这里有一个完整的解码器:

class Decoder {

private let assetReader: AVAssetReader?
private let output: AVAssetReaderTrackOutput

init() throws {
    
    VTRegisterProfessionalVideoWorkflowVideoDecoders()
    VTRegisterProfessionalVideoWorkflowVideoEncoders()
    
        let assetReader = try AVAssetReader(asset: movieAsset)
        let tracks = movieAsset.tracks(withMediaType: .video)
        
        guard let firstTrack = tracks.first else {
            print("No video tracks found")
            throw NSError()
        }
    
        let out = AVAssetReaderTrackOutput(track: firstTrack, outputSettings: outputSettings)
        out.alwaysCopiesSampleData = true
        
        assetReader.add(out)
        
        self.assetReader = assetReader
        self.output = out

   
}

func run(){
    
    guard let assetReader = assetReader, assetReader.startReading() else {
        print("Failed to stard asset reader")
        return
    }
    

    while(assetReader.status == .reading) {
        guard let sampleBuffer = output.copyNextSampleBuffer() else {
            print(assetReader.status.rawValue)
            print(assetReader.error)
            continue
        }
          
        print("Decoding success!")
    }
}

}

【问题讨论】:

    标签: avfoundation video-processing avkit video-toolbox


    【解决方案1】:

    不清楚你为什么想要拜耳,我不确定你所说的“本地”是什么意思,但我猜你可能希望你的数据是

    1. 尽可能高的定义,或
    2. 以其最自然/高效/最少处理的格式
    3. 拜耳别再问我问题了

    所以我认为有两种可能。

    如果您喜欢高清数据,请尝试将您的AVAssetReaderTrackOutput 像素格式设置为kCVPixelFormatType_444YpCbCr16VideoRange_16A_TriPlanarkCVPixelFormatType_4444AYpCbCr16kCVPixelFormatType_64RGBALEAVAssetReaderTrackOutput 中提到的其他格式之一。我认为AVAssetReader 不会无缘无故截断数据的可能性很大。

    在使用 ProRes RAW 时,我不知道自然或高效的表示,但如果你真的想要 Bayer 输出,你可以将你的 outputSettings 设置为 nil 并使用 VTDecompressionSession 将原始样本缓冲区转换为kCVPixelFormatType_16VersatileBayer(或kCVPixelFormatType_64RGBAHalfkCVPixelFormatType_128RGBAFloat,如果您仍然使用AVAssetReader 出于某种原因不喜欢的高范围格式),但不是 kCVPixelFormatType_64RGBA_DownscaledProResRAW 因为那似乎不是工作。

    无论如何,您可以稍微修改您的代码以解码为kCVPixelFormatType_16VersatileBayer,如下所示:

    import AVFoundation
    import VideoToolbox
    
    class Decoder {
        private let assetReader: AVAssetReader?
        private let output: AVAssetReaderTrackOutput
        private var decompressionSession: VTDecompressionSession!
            
        init() throws {
            let movieUrl = URL(fileURLWithPath: "/Users/xxxx/ProresRAW_Video.MOV")
            let movieAsset = AVAsset(url: movieUrl)
            
            do {
                let assetReader = try AVAssetReader(asset: movieAsset)
                let tracks = movieAsset.tracks(withMediaType: .video)
                
                guard let firstTrack = tracks.first else {
                    print("No video tracks found")
                    throw NSError()
                }
                
                let out = AVAssetReaderTrackOutput(track: firstTrack, outputSettings: nil)
                out.alwaysCopiesSampleData = true
                
                assetReader.add(out)
                
                self.assetReader = assetReader
                self.output = out
                
            } catch {
                print(error)
                throw error
            }
            
        }
        
        func run(){
            guard let assetReader = assetReader, assetReader.startReading() else {
                print("Failed to stard asset reader")
                return
            }
            
            while(assetReader.status == .reading) {
                guard let sampleBuffer = output.copyNextSampleBuffer() else {
                    print(assetReader.status.rawValue)
                    print(assetReader.error)
                    continue
                }
                
                print("Decoding success! \(sampleBuffer)")
                
                if let formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer) {
                    if decompressionSession == nil {
                        let imageBufferAttributes: [CFString: Any] = [
                            kCVPixelBufferPixelFormatTypeKey: kCVPixelFormatType_16VersatileBayer
                        ]
                        var outputCallback = VTDecompressionOutputCallbackRecord(decompressionOutputCallback: { _, _, status, infoFlags, imageBuffer, presentationTimeStamp, presentationDuration in
                            assert(noErr == status)
                            print("decode callback status: \(status), bayer imageBuffer \(String(describing: imageBuffer)), flags: \(infoFlags), pts: \(presentationDuration), ptsd: \(presentationDuration)")
                        }, decompressionOutputRefCon: nil)
                        let status = VTDecompressionSessionCreate(allocator: nil, formatDescription: formatDescription, decoderSpecification: nil, imageBufferAttributes: imageBufferAttributes as CFDictionary, outputCallback: &outputCallback, decompressionSessionOut: &decompressionSession)
                        assert(noErr == status)
                    }
    
                    let status = VTDecompressionSessionDecodeFrame(decompressionSession, sampleBuffer: sampleBuffer, flags: [], frameRefcon: nil, infoFlagsOut: nil)
                    assert(noErr == status)
                }
            }
        }
    }
    

    我不明白为什么AVAssetReader(它可能在后台使用VTDecompressionSession)并不能简单地让您首先请求kCVPixelFormatType_16VersatileBayer。也许这是血腥的思想,或者也许没有意义? p.s.你想做什么?

    【讨论】:

    • 我说的是 Prores RAW 不是 Prores 422/4444 格式。我想写 Prores RAW 到 cDNG 转换器。
    • 我试过你的示例代码,第一次断言总是失败。 ibb.co/ckyYzmY
    • I want to write Prores RAW to cDNG converter. 你想要kCVPixelFormatType中的哪一个? I have tried your sample code, and first assert always fail.你在什么操作系统上&你能分享一个文件吗?您的文件格式与我的不同(我的是“aprh”而不是“aprn”)。
    • 我需要 kCVPixelFormatType_16VersatileBayer。这是一个完整的测试项目:github.com/jasin755/prrdecoder 和我的代码作为 macOS 通用应用程序运行。这是一些测试 Prores RAW 视频:pognerebko.me:5001/sharing/vHx59T6rp
    • 奇怪,您链接的代码与您在运行 macOS 12.0.1 的 m1 上为我链接的视频一起工作(创建 kCVPixelFormatType_16VersatileBayerCVPixelBuffers)