我得到一个解码的avframe,其格式显示为160/Videotoolbox_vld
。在搜索了一些文章(here)并查看了ffmpeg源代码(here和here)之后,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! CVPixelBuffer
到void*
来完成这样的转换工作。
// 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/