Video Capture OpenGL error after capture starts

kudanar
kudan

#1

Background

I’ve implemented the method for capturing video described in https://wiki.kudan.eu/Video_Recording_iOS

In the process I’ve ported this approach to Swift.

I’m testing with Swift 3.1 and on a device running iOS 10.3 and Kudan AR 1.5.1

Symptoms

Everything works up until after the completion of the setupFBO() and setupAssetWriter() calls. I have checked these calls in detail in the debugger and everything looks fine.

After this I get a succession of errors

OpenGL error 0x506: (null).

And further calls to glCheckFramebufferStatus return error 36055 which is apparently FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT

While my code is in Swift, I don’t think this is material to the problem I’m experiencing.

I have added additional calls to

glCheckFramebufferStatus(GLenum(GL_FRAMEBUFFER))

in order to check on the FBO. I get the correct GL_FRAMEBUFFER_COMPLETE response at the end of setupFBO()

Other things I’ve checked and found OK :

  • viewport sizes attached to my ARRenderTarget
  • correct size of my ARRenderTarget comparing it to the FBO obtained from ARRenderer.getInstance() and the default ARRenderTarget

My video file is rendered and written correctly but all the frames are (as expected from this error) black.


Key parts of code in my ARRenderTarget

enum CaptureState {
    case ready
    case writing
    case complete
    case failedAssetWriterInit
} 

// The following is inside my ARRenderTarget implementation
 
 func setupAssetWriter() {
        guard let url = setupFileSystem()  else { print ("output setup failure"); return }

do {
    try self.assetWriter = AVAssetWriter(url: url, fileType: AVFileTypeQuickTimeMovie)
    
}
catch {
    print("failed to setup asset writer")
    self.videoCaptureState = .failedAssetWriterInit
    return
}

let writerDict:[String : Any] = [ AVVideoCodecKey: AVVideoCodecH264,  AVVideoWidthKey: self.width,  AVVideoHeightKey: self.height]
let assetWriterInput = AVAssetWriterInput(mediaType: AVMediaTypeVideo, outputSettings: writerDict)

let sourcePixelBufferDict:[String:Any] = [ kCVPixelBufferPixelFormatTypeKey as String : kCVPixelFormatType_32BGRA  ,  kCVPixelBufferWidthKey as String : self.width, kCVPixelBufferHeightKey as String  : self.height]
assetWriterPixelBufferInput = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: assetWriterInput, sourcePixelBufferAttributes: sourcePixelBufferDict)

guard let writer = self.assetWriter else { return }

if writer.canAdd(assetWriterInput)   {
    writer.add(assetWriterInput)
}
else {
    print("error setting up the asset writer for videos")
    self.videoCaptureState = .failedAssetWriterInit
}

writer.startWriting()
writer.startSession(atSourceTime: kCMTimeZero)

startDate = Date()

if( writer.status == .failed) {
    print("failed to start asset writer for videos")
    self.videoCaptureState = .failedAssetWriterInit
}

self.videoCaptureState = .writing

}

func setupFBO() {

//Create renderer context for creating new OpenGL objects
ARRenderer.getInstance()!.useContext()
guard let renderer = ARRenderer.getInstance()  else { print("can't get renderer"); return }
renderer.useContext()

//Create and bind the FBO
glActiveTexture(GLenum(GL_TEXTURE))
glGenFramebuffers(1, &fbo)
glBindFramebuffer(GLenum(GL_FRAMEBUFFER),  fbo)
print("FBO BOUND = \(fbo)")

//Create the texture cache
var cvTextureCacheRef:CVOpenGLESTextureCache?

var err =  CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, nil, EAGLContext.current(),  nil,  &cvTextureCacheRef)
if err != kCVReturnSuccess {
    assert(false, "Error at CVOpenGLESTextureCacheCreate \(err)")
}

//Create the texture we will render into
guard let writerPixelBufferInput = assetWriterPixelBufferInput else { print("no assetWriterPixelBufferInput" ); return }
guard let pixelBufferPool = writerPixelBufferInput.pixelBufferPool else { print("no pixelBufferPool" ); return }
err = CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, pixelBufferPool, &self.pixeBuffer)
if err != kCVReturnSuccess {
    print ("error msg createing Pixelbuffer pool \(err)")
    return
}

var renderTexture:CVOpenGLESTexture?
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
                                             cvTextureCacheRef!,
                                             pixeBuffer!,
                                             nil,
                                             GLenum(GL_TEXTURE_2D),
                                             GL_RGBA,
                                             GLsizei(self.width),
                                             GLsizei(self.height),
                                             GLenum(GL_BGRA),
                                             GLenum(GL_UNSIGNED_BYTE),
                                             0,
                                             &renderTexture)
if err != kCVReturnSuccess {
    print ("error CVOpenGLESTextureCacheCreateTextureFromImage \(err)")
    return
}

//bind our render texture to framebuffer
glBindTexture(CVOpenGLESTextureGetTarget(renderTexture!), CVOpenGLESTextureGetName(renderTexture!))
glTexParameterf(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_S),   GLfloat(GL_CLAMP_TO_EDGE)  )
glTexParameterf(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_T),   GLfloat(GL_CLAMP_TO_EDGE)  )

glFramebufferTexture2D(GLenum(GL_FRAMEBUFFER), GLenum(GL_COLOR_ATTACHMENT0),   GLenum(GL_TEXTURE_2D),  CVOpenGLESTextureGetName(renderTexture!), 0)

var depthRenderBuffer:GLuint = 0
glGenRenderbuffers(1, &depthRenderBuffer)
print("depth render buffer =\(depthRenderBuffer)")

glBindRenderbuffer(GLenum(GL_RENDERBUFFER), depthRenderBuffer)
glRenderbufferStorage(GLenum(GL_RENDERBUFFER), GLenum(GL_DEPTH24_STENCIL8_OES),  GLsizei(self.width), GLsizei(self.height))
glFramebufferRenderbuffer(GLenum(GL_RENDERBUFFER), GLenum(GL_DEPTH_ATTACHMENT),  GLenum(GL_RENDERBUFFER),   depthRenderBuffer)


let fbostatus  = glCheckFramebufferStatus(GLenum(GL_FRAMEBUFFER))
if fbostatus == GLenum(GL_FRAMEBUFFER_COMPLETE) {
    print("FBO status COMPLETE  = \(fbostatus)")
}
else {
    print("FBO status 'ERROR' = \(fbostatus)")
}  
} 

override func bindBuffer() {
   glBindFramebuffer(GLenum(GL_FRAMEBUFFER),  fbo)
}

Calling method from hosting view controller, appears to complete correctly

 func startVideoCapture() {
        guard let captureTarget = ARCRenderTarget(width: Float(self.cameraView.frame.size.width), height: Float(self.cameraView.frame.size.height))  else { print("failed to start render target"); return }
        videoCaptureTarget = captureTarget
        captureTarget.addViewPort(self.cameraView.cameraViewPort)
        captureTarget.addViewPort(self.cameraView.contentViewPort)
        
        guard let renderer = ARRenderer.getInstance()  else { print("can't get renderer"); return }
        renderer.addRenderTarget(captureTarget)
        print("targets = \(renderer)")
    }

I have tried running with either or both viewPorts removed to make sure its not an incorrectly specified viewPort that is causing the issue, but the same thing happens in all cases.


#2

Hi paulfreeman,

I have also faced this error and not found the solution to fix yet.

Have you fixed this OpenGL error?

Best Regards,
Cristian