1// Copyright 2016-present 650 Industries. All rights reserved. 2 3#import <AVKit/AVKit.h> 4 5#include <OpenGLES/ES3/gl.h> 6#include <OpenGLES/ES3/glext.h> 7 8#import <ExpoModulesCore/EXCameraInterface.h> 9 10#import <ExpoGL/EXGLCameraObject.h> 11#import <ExpoGL/EXGLContext.h> 12 13@interface EXGLCameraObject () <AVCaptureVideoDataOutputSampleBufferDelegate> 14 15@property (nonatomic, strong) id<EXCameraInterface> camera; 16@property (nonatomic, strong) EAGLContext *eaglCtx; 17@property (nonatomic, strong) AVCaptureVideoDataOutput *cameraOutput; 18@property (nonatomic, assign) CVOpenGLESTextureCacheRef cameraTextureCache; 19 20@end 21 22@implementation EXGLCameraObject 23 24- (instancetype)initWithContext:(EXGLContext *)glContext andCamera:(id<EXCameraInterface>)camera 25{ 26 EXGLContextId exglCtxId = [glContext contextId]; 27 28 if (self = [super initWithConfig:@{ @"exglCtxId": @(exglCtxId) }]) { 29 _eaglCtx = [glContext createSharedEAGLContext]; 30 _camera = camera; 31 32 dispatch_async(camera.sessionQueue, ^{ 33 AVCaptureVideoDataOutput *videoOutput = [[AVCaptureVideoDataOutput alloc] init]; 34 35 if ([camera.session canAddOutput:videoOutput]) { 36 videoOutput.videoSettings = @{ (id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA) }; 37 [videoOutput setSampleBufferDelegate:self queue:camera.sessionQueue]; 38 [videoOutput setAlwaysDiscardsLateVideoFrames:YES]; 39 [camera.session addOutput:videoOutput]; 40 self->_cameraOutput = videoOutput; 41 } 42 }); 43 } 44 return self; 45} 46 47- (void)dealloc 48{ 49 if (_cameraOutput) { 50 [_camera.session removeOutput:_cameraOutput]; 51 [_cameraOutput setSampleBufferDelegate:nil queue:nil]; 52 } 53} 54 55- (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection 56{ 57 [connection setVideoOrientation:AVCaptureVideoOrientationPortrait]; 58 [connection setVideoMirrored:YES]; 59 60 CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 61 GLsizei bufferWidth = (GLsizei)CVPixelBufferGetWidth(pixelBuffer); 62 GLsizei bufferHeight = (GLsizei)CVPixelBufferGetHeight(pixelBuffer); 63 64 CVPixelBufferRetain(pixelBuffer); 65 CVPixelBufferLockBaseAddress(pixelBuffer, 0); 66 67 [EAGLContext setCurrentContext:_eaglCtx]; 68 69 if (!_cameraTextureCache) { 70 CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, _eaglCtx, NULL, &_cameraTextureCache); 71 } 72 73 CVOpenGLESTextureRef textureRef = NULL; 74 75 CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, 76 _cameraTextureCache, 77 pixelBuffer, 78 NULL, 79 GL_TEXTURE_2D, 80 GL_RGBA, 81 bufferWidth, 82 bufferHeight, 83 GL_BGRA, 84 GL_UNSIGNED_BYTE, 85 0, 86 &textureRef); 87 88 if (textureRef) { 89 GLuint textureName = CVOpenGLESTextureGetName(textureRef); 90 EXGLContextMapObject([self exglCtxId], [self exglObjId], textureName); 91 } 92 93 CVOpenGLESTextureCacheFlush(_cameraTextureCache, 0); 94 CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); 95 CVPixelBufferRelease(pixelBuffer); 96 CFRelease(textureRef); 97 98 [EAGLContext setCurrentContext:nil]; 99} 100 101@end 102