我得到一个解码的avframe,其格式显示为160/Videotoolbox_vld。在搜索了一些文章(here)并查看了ffmpeg源代码(herehere)之后,CVBuffer句柄应该位于AVFrame.data[3]。但我得到的CVBuffer似乎无效,任何CVPixelBufferGetXXX()函数都返回0或零。
如果我像ffmpeg的example/hw_decode.c那样使用av_hwframe_transfer_data(),则可以将示例从hw下载到sw buffer。它的AVFrame.format将是nv12。通过sws_scale转换成bgra后,样品可以显示在视图上,内容正确。
我认为视频工具箱解码的帧是可以的。我将AVFrame.data[3]转换为CVBuffer的方式可能是错误的。刚学会用swift访问c指针,但我不确定如何正确读取指针中的资源句柄(cvbuffer)。
下面是我如何从avframe中提取cvbuffer

var pFrameOpt: UnsafeMutablePointer<AVFrame>? = av_frame_alloc()
avcodec_receive_frame(..., pFrameOpt)

let data3: UnsafeMutablePointer<UInt8>? = pFrameOpt?.pointee.data.3
data3?.withMemoryRebound(to: CVBuffer.self, capacity: 1) { pCvBuf in
    let fW = pFrameOpt!.pointee.width // print 3840
    let fH = pFrameOpt!.pointee.height // print 2160
    let fFmt = pFrameOpt!.pointee.format // print 160

    let cvBuf: CVBuffer = pCvBuf.pointee

    let a1 = CVPixelBufferGetDataSize(cvBuf)               // print 0
    let a2 = CVPixelBufferGetPixelFormatType(cvBuf)        // print 0
    let a3 = CVPixelBufferGetWidth(cvBuf)                  // print 0
    let a4 = CVPixelBufferGetHeight(cvBuf)                 // print 0
    let a5 = CVPixelBufferGetBytesPerRow(cvBuf)            // print 0
    let a6 = CVPixelBufferGetBytesPerRowOfPlane(cvBuf, 0)  // print 0
    let a7 = CVPixelBufferGetWidthOfPlane(cvBuf, 0)        // print 0
    let a8 = CVPixelBufferGetHeightOfPlane(cvBuf, 0)       // print 0
    let a9 = CVPixelBufferGetPlaneCount(cvBuf)             // print 0
    let a10 = CVPixelBufferIsPlanar(cvBuf)                 // print false
    let a11 = CVPixelBufferGetIOSurface(cvBuf)             // print nil
    let a12 = CVPixelBufferGetBaseAddress(cvBuf)           // print nil
    let a13 = CVPixelBufferGetBaseAddressOfPlane(cvBuf, 0) // print nil

    let b1 = CVImageBufferGetCleanRect(cvBuf)   // print 0, 0, 0, 0
    let b2 = CVImageBufferGetColorSpace(cvBuf)  // print nil
    let b3 = CVImageBufferGetDisplaySize(cvBuf) // print 0, 0, 0, 0
    let b4 = CVImageBufferGetEncodedSize(cvBuf) // print 0, 0, 0, 0
    let b5 = CVImageBufferIsFlipped(cvBuf)      // print false

    // bad exec
    var cvTextureOut: CVMetalTexture?
    CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, ..., cvBuf, nil, .bgra8Unorm, 3840, 2160, 0, ...)


}

最佳答案

似乎我把void*错误地投射到CVPixelBuffer*而不是直接投射到void*。我找不到从指针到数值的快速c样式转换方法。(使用CVPixelBuffer会导致崩溃)。
所以我在c代码中创建了一个函数,让as! CVPixelBuffervoid*来完成这样的转换工作。

// util.h
#include <CoreVideo/CVPixelBuffer.h>
CVPixelBufferRef CastToCVPixelBuffer(void* p);

// util.c
CVPixelBufferRef CastToCVPixelBuffer(void* p)
{
    return (CVPixelBufferRef)p;
}

// BridgeHeader.h
#include "util.h"

然后传入CVPixelBufferRef,取出cvpixelbuffer句柄。
let pFrameOpt: UnsafeMutablePointer<AVFrame>? = ...
let data3: UnsafeMutablePointer<UInt8>? = pFrameOpt?.pointee.data.3

let cvBuf: CVBuffer = CastToCVPixelBuffer(data3).takeUnretainedValue()

let width = CVPixelBufferGetWidth(cvBuf)   // print 3840
let height = CVPixelBufferGetHeight(cvBuf) // print 2160

关于swift - 如何从Swift中的UnsafeMutablePointer <UInt8>获取CVPixelBuffer句柄?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57464114/

10-10 16:34