Ios MTLTexture.getbytes()返回EXC\u BAD\u访问-可能的原因?
我正在使用ARKit3身体跟踪功能,将3D模型覆盖在摄影机提要上,并允许用户将提要捕获为带有音频的MP4。我已经能够成功地将相机预览绘制到MTL视图。但是,我收到一个EXC_BAD_访问错误,在尝试写入我的资产编写器时,我似乎无法调试该错误。我的应用程序有一个render类,负责渲染提要中的金属纹理,还有一个MetalVideoRecorder类,用于将帧写入mp4文件。我在下面突出显示了生成错误的行: 我的MetalVideoWriter类的相关代码:Ios MTLTexture.getbytes()返回EXC\u BAD\u访问-可能的原因?,ios,swift,arkit,metal,Ios,Swift,Arkit,Metal,我正在使用ARKit3身体跟踪功能,将3D模型覆盖在摄影机提要上,并允许用户将提要捕获为带有音频的MP4。我已经能够成功地将相机预览绘制到MTL视图。但是,我收到一个EXC_BAD_访问错误,在尝试写入我的资产编写器时,我似乎无法调试该错误。我的应用程序有一个render类,负责渲染提要中的金属纹理,还有一个MetalVideoRecorder类,用于将帧写入mp4文件。我在下面突出显示了生成错误的行: 我的MetalVideoWriter类的相关代码: func writeFrame(forT
func writeFrame(forTexture texture: MTLTexture) {
//Only if recording and our asset writer has been initialized
if (assetWriter == nil) { return; }
if !isRecording { return; }
while !assetWriterVideoInput!.isReadyForMoreMediaData {}
//Get pixer buffer pool from the asset writer (to write to)
guard let pixelBufferPool = assetWriterPixelBufferInput!.pixelBufferPool else { return; }
var maybePixelBuffer: CVPixelBuffer? = nil
let status = CVPixelBufferPoolCreatePixelBuffer(nil, pixelBufferPool, &maybePixelBuffer)
if status != kCVReturnSuccess { return; }
guard let pixelBuffer = maybePixelBuffer else { return }
CVPixelBufferLockBaseAddress(pixelBuffer, [])
let pixelBufferBytes = CVPixelBufferGetBaseAddress(pixelBuffer)!
let bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer)
let region = MTLRegionMake2D(0, 0, texture.width, texture.height)
//########################################
//#### This line returns the error... ####
//########################################
texture.getBytes(pixelBufferBytes, bytesPerRow: bytesPerRow, from: region, mipmapLevel: 0)
//Timestamp of the frame
let frameTime = CACurrentMediaTime() - recordingStartTime
let presentationTime = CMTimeMakeWithSeconds(frameTime, 240)
assetWriterPixelBufferInput!.append(pixelBuffer, withPresentationTime: presentationTime)
CVPixelBufferUnlockBaseAddress(pixelBuffer, [])
firstFrameWritten = true;
}
这就是我的渲染器类处理帧的方式:
func update() {
if (self.metalVideoRecorder == nil) {
print("Failed - Metal video recorder is nil")
return;
}
// Wait to ensure only kMaxBuffersInFlight are getting proccessed by any stage in the Metal
// pipeline (App, Metal, Drivers, GPU, etc)
let _ = inFlightSemaphore.wait(timeout: DispatchTime.distantFuture)
// Create a new command buffer for each renderpass to the current drawable
if let commandBuffer = commandQueue.makeCommandBuffer() {
commandBuffer.label = "MyCommand"
// Retain our CVMetalTextures for the duration of the rendering cycle. The MTLTextures
// we use from the CVMetalTextures are not valid unless their parent CVMetalTextures
// are retained. Since we may release our CVMetalTexture ivars during the rendering
// cycle, we must retain them separately here.
var textures = [capturedImageTextureY, capturedImageTextureCbCr]
updateBufferStates()
updateGameState()
guard let renderDescriptor = renderDestination.currentRenderPassDescriptor else {return}
renderDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0, 0, 0, 1) //Black background
guard let currentDrawable = renderDestination.currentDrawable else {return}
guard let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderDescriptor) else {return}
renderEncoder.label = "MyRenderEncoder"
let texture = currentDrawable.texture
// Add completion hander which signal _inFlightSemaphore when Metal and the GPU has fully
// finished proccssing the commands we're encoding this frame. This indicates when the
// dynamic buffers, that we're writing to this frame, will no longer be needed by Metal
// and the GPU.
commandBuffer.addCompletedHandler{ [weak self] commandBuffer in
if let strongSelf = self {
strongSelf.inFlightSemaphore.signal()
if (strongSelf.metalVideoRecorder!.isRecording == true)
{
strongSelf.metalVideoRecorder!.writeFrame(forTexture: texture)
}
}
textures.removeAll()
}
//Draw camera image
drawCapturedImage(renderEncoder: renderEncoder)
//Draw additional items on top (cube etc.)
drawAnchorGeometry(renderEncoder: renderEncoder)
// We're done encoding commands
renderEncoder.endEncoding()
// Schedule a present once the framebuffer is complete using the current drawable
commandBuffer.present(currentDrawable)
// Finalize rendering here & push the command buffer to the GPU
commandBuffer.commit()
}
}
这一错误的一些潜在原因是什么?调试错误的最佳方法是什么
请注意,我录制帧的方法受到以下答案的启发:
更新
上述方法假设您的纹理和输出视频大小相同。在我的例子中,我试图生成一个1280x720视频,但我试图录制的MTLView大小不同(它是一个全屏视图,所以不管手机的显示大小如何)。我的选择是以非标准纵横比(恶心)记录或确定裁剪方式。我会继续寻找裁剪框架的方法