Note that there are some explanatory texts on larger screens.

plurals
  1. POOpenGL Texture from CALayer (AVPlayerLayer)
    primarykey
    data
    text
    <p>I have an AVPlayerLayer which I would like to create an OpenGL Texture out of. I'm comfortable with opengl textures, and even comfortable with converting a CGImageRef into an opengl texture. It seems to me the code below should work, but I get just plain black. What am I doing wrong? Do I need to set any properties on the CALayer / AVPlayerLayer first?</p> <pre><code>CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); int width = (int)[layer bounds].size.width; int height = (int)[layer bounds].size.height; CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast); CGColorSpaceRelease(colorSpace); if (context== NULL) { ofLog(OF_LOG_ERROR, "getTextureFromLayer: failed to create context 1"); return; } [[layer presentationLayer] renderInContext:context]; CGImageRef cgImage = CGBitmapContextCreateImage(context); int bytesPerPixel = CGImageGetBitsPerPixel(cgImage)/8; if(bytesPerPixel == 3) bytesPerPixel = 4; GLubyte *pixels = (GLubyte *) malloc(width * height * bytesPerPixel); CGContextRelease(context); context = CGBitmapContextCreate(pixels, width, height, CGImageGetBitsPerComponent(cgImage), width * bytesPerPixel, CGImageGetColorSpace(cgImage), kCGImageAlphaPremultipliedLast); if(context == NULL) { ofLog(OF_LOG_ERROR, "getTextureFromLayer: failed to create context 2"); free(pixels); return; } CGContextDrawImage(context, CGRectMake(0.0, 0.0, width, height), cgImage); int glMode; switch(bytesPerPixel) { case 1: glMode = GL_LUMINANCE; break; case 3: glMode = GL_RGB; break; case 4: default: glMode = GL_RGBA; break; } if(texture.bAllocated() == false || texture.getWidth() != width || texture.getHeight() != height) { NSLog(@"getTextureFromLayer: allocating texture %i, %i\n", width, height); texture.allocate(width, height, glMode, true); } // test texture // for(int i=0; i&lt;width*height*4; i++) pixels[i] = ofRandomuf() * 255; texture.loadData(pixels, width, height, glMode); CGContextRelease(context); CFRelease(cgImage); free(pixels); </code></pre> <p>P.S. The variable 'texture' is a C++ opengl (-es compatible) texture object which I know works. If I uncomment the 'test texture' for-loop filling the texture with random noise, I can see that, so problem is definitely before.</p> <h2>UPDATE</h2> <p>In response to Nick Weaver's reply I tried a different approach, and now I'm always getting NULL back from copyNextSampleBuffer with status == 3 (AVAssetReaderStatusFailed). Am I missing something?</p> <h3>variables</h3> <pre><code>AVPlayer *videoPlayer; AVPlayerLayer *videoLayer; AVAssetReader *videoReader; AVAssetReaderTrackOutput*videoOutput; </code></pre> <h3>init</h3> <pre><code> videoPlayer = [[AVPlayer alloc] initWithURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:videoPath.c_str()]]]; if(videoPlayer == nil) { NSLog(@"videoPlayer == nil ERROR LOADING %s\n", videoPath.c_str()); } else { NSLog(@"videoPlayer: %@", videoPlayer); videoLayer = [[AVPlayerLayer playerLayerWithPlayer:videoPlayer] retain]; videoLayer.frame = [ThreeDView instance].bounds; // [[ThreeDView instance].layer addSublayer:videoLayer]; // test to see if it's loading and running AVAsset *asset = videoPlayer.currentItem.asset; NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo]; NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA], (NSString*)kCVPixelBufferPixelFormatTypeKey, nil]; videoReader = [[AVAssetReader alloc] initWithAsset:asset error:nil]; videoOutput = [[AVAssetReaderTrackOutput alloc] initWithTrack:[tracks objectAtIndex:0] outputSettings:settings]; [videoReader addOutput:videoOutput]; [videoReader startReading]; } </code></pre> <h3>draw loop</h3> <pre><code> if(videoPlayer == 0) { ofLog(OF_LOG_WARNING, "Shot::drawVideo: videoPlayer == 0"); return; } if(videoOutput == 0) { ofLog(OF_LOG_WARNING, "Shot::drawVideo: videoOutput == 0"); return; } CMSampleBufferRef sampleBuffer = [videoOutput copyNextSampleBuffer]; if(sampleBuffer == 0) { ofLog(OF_LOG_ERROR, "Shot::drawVideo: sampleBuffer == 0, status: %i", videoReader.status); return; } CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); CFRelease(sampleBuffer); CVPixelBufferLockBaseAddress(imageBuffer,0); unsigned char *pixels = ( unsigned char *)CVPixelBufferGetBaseAddress(imageBuffer); int width = CVPixelBufferGetWidth(imageBuffer); int height = CVPixelBufferGetHeight(imageBuffer); if(videoTexture.bAllocated() == false || videoTexture.getWidth() != width || videoTexture.getHeight() != height) { NSLog(@"Shot::drawVideo() allocating texture %i, %i\n", width, height); videoTexture.allocate(width, height, GL_RGBA, true); } videoTexture.loadData(pixels, width, height, GL_BGRA); CVPixelBufferUnlockBaseAddress(imageBuffer,0); </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload