AAPLEAGLLayerCustom.m 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  1. //
  2. // AAPLEAGLLayerCustom.h
  3. // HSVideoUDP
  4. //
  5. // Created by ss on 2024/7/15.
  6. // Copyright © 2024年 ss. All rights reserved.
  7. //
  8. #import "AAPLEAGLLayerCustom.h"
  9. #import <AVFoundation/AVUtilities.h>
  10. #import <mach/mach_time.h>
  11. #include <AVFoundation/AVFoundation.h>
  12. #import <UIKit/UIScreen.h>
  13. #include <OpenGLES/EAGL.h>
  14. #include <OpenGLES/ES2/gl.h>
  15. #include <OpenGLES/ES2/glext.h>
  16. // Uniform index.
  17. enum
  18. {
  19. UNIFORM_Y,
  20. UNIFORM_UV,
  21. UNIFORM_ROTATION_ANGLE,
  22. UNIFORM_COLOR_CONVERSION_MATRIX,
  23. NUM_UNIFORMS
  24. };
  25. GLint uniformsTmp[NUM_UNIFORMS];
  26. // Attribute index.
  27. enum
  28. {
  29. ATTRIB_VERTEX,
  30. ATTRIB_TEXCOORD,
  31. NUM_ATTRIBUTES
  32. };
  33. // Color Conversion Constants (YUV to RGB) including adjustment from 16-235/16-240 (video range)
  34. // BT.601, which is the standard for SDTV.
  35. static const GLfloat kColorConversion601[] = {
  36. 1.164, 1.164, 1.164,
  37. 0.0, -0.392, 2.017,
  38. 1.596, -0.813, 0.0,
  39. };
  40. // BT.709, which is the standard for HDTV.
  41. static const GLfloat kColorConversion709[] = {
  42. 1.164, 1.164, 1.164,
  43. 0.0, -0.213, 2.112,
  44. 1.793, -0.533, 0.0,
  45. };
  46. @interface AAPLEAGLLayerCustom ()
  47. {
  48. // The pixel dimensions of the CAEAGLLayer.
  49. GLint _backingWidth;
  50. GLint _backingHeight;
  51. EAGLContext *_context;
  52. CVOpenGLESTextureRef _lumaTexture;
  53. CVOpenGLESTextureRef _chromaTexture;
  54. GLuint _frameBufferHandle;
  55. GLuint _colorBufferHandle;
  56. const GLfloat *_preferredConversion;
  57. }
  58. @property GLuint program;
  59. @end
  60. @implementation AAPLEAGLLayerCustom
  61. @synthesize pixelBuffer = _pixelBuffer;
  62. -(CVPixelBufferRef) pixelBuffer
  63. {
  64. return _pixelBuffer;
  65. }
  66. - (void)setPixelBuffer:(CVPixelBufferRef)pb
  67. {
  68. if(_pixelBuffer) {
  69. CVPixelBufferRelease(_pixelBuffer);
  70. }
  71. _pixelBuffer = CVPixelBufferRetain(pb);
  72. int frameWidth = (int)CVPixelBufferGetWidth(_pixelBuffer);
  73. int frameHeight = (int)CVPixelBufferGetHeight(_pixelBuffer);
  74. [self displayPixelBuffer:_pixelBuffer width:frameWidth height:frameHeight];
  75. }
  76. //-(void)paizhao
  77. //{
  78. // CAEAGLLayer *eaglLayer = (CAEAGLLayer *) self;
  79. // eaglLayer.drawableProperties = @{
  80. // kEAGLDrawablePropertyRetainedBacking: [NSNumber numberWithBool:YES],
  81. // kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8
  82. // };
  83. //}
  84. - (instancetype)initWithFrame:(CGRect)frame
  85. {
  86. self = [super init];
  87. if (self) {
  88. CGFloat scale = [[UIScreen mainScreen] scale];
  89. self.contentsScale = scale;
  90. self.opaque = TRUE;
  91. self.drawableProperties = @{kEAGLDrawablePropertyRetainedBacking :[NSNumber numberWithBool:YES]};
  92. [self setFrame:frame];
  93. // Set the context into which the frames will be drawn.
  94. _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
  95. if (!_context) {
  96. return nil;
  97. }
  98. // Set the default conversion to BT.709, which is the standard for HDTV.
  99. _preferredConversion = kColorConversion709;
  100. [self setupGL];
  101. }
  102. return self;
  103. }
  104. - (void)displayPixelBuffer:(CVPixelBufferRef)pixelBuffer width:(uint32_t)frameWidth height:(uint32_t)frameHeight
  105. {
  106. if (!_context || ![EAGLContext setCurrentContext:_context]) {
  107. return;
  108. }
  109. if(pixelBuffer == NULL) {
  110. NSLog(@"Pixel buffer is null");
  111. return;
  112. }
  113. CVReturn err;
  114. size_t planeCount = CVPixelBufferGetPlaneCount(pixelBuffer);
  115. /*
  116. Use the color attachment of the pixel buffer to determine the appropriate color conversion matrix.
  117. */
  118. CFTypeRef colorAttachments = CVBufferGetAttachment(pixelBuffer, kCVImageBufferYCbCrMatrixKey, NULL);
  119. if (CFStringCompare(colorAttachments, kCVImageBufferYCbCrMatrix_ITU_R_601_4, 0) == kCFCompareEqualTo) {
  120. _preferredConversion = kColorConversion601;
  121. }
  122. else {
  123. _preferredConversion = kColorConversion709;
  124. }
  125. /*
  126. CVOpenGLESTextureCacheCreateTextureFromImage will create GLES texture optimally from CVPixelBufferRef.
  127. */
  128. /*
  129. Create Y and UV textures from the pixel buffer. These textures will be drawn on the frame buffer Y-plane.
  130. */
  131. CVOpenGLESTextureCacheRef _videoTextureCache;
  132. // Create CVOpenGLESTextureCacheRef for optimal CVPixelBufferRef to GLES texture conversion.
  133. err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, _context, NULL, &_videoTextureCache);
  134. if (err != noErr) {
  135. NSLog(@"Error at CVOpenGLESTextureCacheCreate %d", err);
  136. return;
  137. }
  138. glActiveTexture(GL_TEXTURE0);
  139. err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
  140. _videoTextureCache,
  141. pixelBuffer,
  142. NULL,
  143. GL_TEXTURE_2D,
  144. GL_RED_EXT,
  145. frameWidth,
  146. frameHeight,
  147. GL_RED_EXT,
  148. GL_UNSIGNED_BYTE,
  149. 0,
  150. &_lumaTexture);
  151. if (err) {
  152. NSLog(@"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
  153. }
  154. glBindTexture(CVOpenGLESTextureGetTarget(_lumaTexture), CVOpenGLESTextureGetName(_lumaTexture));
  155. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  156. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  157. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  158. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  159. if(planeCount == 2) {
  160. // UV-plane.
  161. glActiveTexture(GL_TEXTURE1);
  162. err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
  163. _videoTextureCache,
  164. pixelBuffer,
  165. NULL,
  166. GL_TEXTURE_2D,
  167. GL_RG_EXT,
  168. frameWidth / 2,
  169. frameHeight / 2,
  170. GL_RG_EXT,
  171. GL_UNSIGNED_BYTE,
  172. 1,
  173. &_chromaTexture);
  174. if (err) {
  175. NSLog(@"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
  176. }
  177. glBindTexture(CVOpenGLESTextureGetTarget(_chromaTexture), CVOpenGLESTextureGetName(_chromaTexture));
  178. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  179. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  180. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  181. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  182. }
  183. glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferHandle);
  184. // Set the view port to the entire view.
  185. glViewport(0, 0, _backingWidth, _backingHeight);
  186. glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  187. glClear(GL_COLOR_BUFFER_BIT);
  188. // Use shader program.
  189. glUseProgram(self.program);
  190. // glUniform1f(uniformsTmp[UNIFORM_LUMA_THRESHOLD], 1);
  191. // glUniform1f(uniformsTmp[UNIFORM_CHROMA_THRESHOLD], 1);
  192. glUniform1f(uniformsTmp[UNIFORM_ROTATION_ANGLE], 0);
  193. glUniformMatrix3fv(uniformsTmp[UNIFORM_COLOR_CONVERSION_MATRIX], 1, GL_FALSE, _preferredConversion);
  194. // Set up the quad vertices with respect to the orientation and aspect ratio of the video.
  195. CGRect viewBounds = self.bounds;
  196. CGSize contentSize = CGSizeMake(frameWidth, frameHeight);
  197. CGRect vertexSamplingRect = AVMakeRectWithAspectRatioInsideRect(contentSize, viewBounds);
  198. // Compute normalized quad coordinates to draw the frame into.
  199. CGSize normalizedSamplingSize = CGSizeMake(0.0, 0.0);
  200. CGSize cropScaleAmount = CGSizeMake(vertexSamplingRect.size.width/viewBounds.size.width,
  201. vertexSamplingRect.size.height/viewBounds.size.height);
  202. // Normalize the quad vertices.
  203. if (cropScaleAmount.width > cropScaleAmount.height) {
  204. normalizedSamplingSize.width = 1.0;
  205. normalizedSamplingSize.height = cropScaleAmount.height/cropScaleAmount.width;
  206. }
  207. else {
  208. normalizedSamplingSize.width = cropScaleAmount.width/cropScaleAmount.height;
  209. normalizedSamplingSize.height = 1.0;;
  210. }
  211. /*
  212. The quad vertex data defines the region of 2D plane onto which we draw our pixel buffers.
  213. Vertex data formed using (-1,-1) and (1,1) as the bottom left and top right coordinates respectively, covers the entire screen.
  214. */
  215. GLfloat quadVertexData [] = {
  216. -1 * normalizedSamplingSize.width, -1 * normalizedSamplingSize.height,
  217. normalizedSamplingSize.width, -1 * normalizedSamplingSize.height,
  218. -1 * normalizedSamplingSize.width, normalizedSamplingSize.height,
  219. normalizedSamplingSize.width, normalizedSamplingSize.height,
  220. };
  221. // Update attribute values.
  222. glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, quadVertexData);
  223. glEnableVertexAttribArray(ATTRIB_VERTEX);
  224. /*
  225. The texture vertices are set up such that we flip the texture vertically. This is so that our top left origin buffers match OpenGL's bottom left texture coordinate system.
  226. */
  227. CGRect textureSamplingRect = CGRectMake(0, 0, 1, 1);
  228. GLfloat quadTextureData[] = {
  229. CGRectGetMinX(textureSamplingRect), CGRectGetMaxY(textureSamplingRect),
  230. CGRectGetMaxX(textureSamplingRect), CGRectGetMaxY(textureSamplingRect),
  231. CGRectGetMinX(textureSamplingRect), CGRectGetMinY(textureSamplingRect),
  232. CGRectGetMaxX(textureSamplingRect), CGRectGetMinY(textureSamplingRect)
  233. };
  234. glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, 0, 0, quadTextureData);
  235. glEnableVertexAttribArray(ATTRIB_TEXCOORD);
  236. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  237. glBindRenderbuffer(GL_RENDERBUFFER, _colorBufferHandle);
  238. [_context presentRenderbuffer:GL_RENDERBUFFER];
  239. [self cleanUpTextures];
  240. // Periodic texture cache flush every frame
  241. CVOpenGLESTextureCacheFlush(_videoTextureCache, 0);
  242. if(_videoTextureCache) {
  243. CFRelease(_videoTextureCache);
  244. }
  245. }
  246. # pragma mark - OpenGL setup
  247. - (void)setupGL
  248. {
  249. if (!_context || ![EAGLContext setCurrentContext:_context]) {
  250. return;
  251. }
  252. [self setupBuffers];
  253. [self loadShaders];
  254. glUseProgram(self.program);
  255. // 0 and 1 are the texture IDs of _lumaTexture and _chromaTexture respectively.
  256. glUniform1i(uniformsTmp[UNIFORM_Y], 0);
  257. glUniform1i(uniformsTmp[UNIFORM_UV], 1);
  258. glUniform1f(uniformsTmp[UNIFORM_ROTATION_ANGLE], 0);
  259. glUniformMatrix3fv(uniformsTmp[UNIFORM_COLOR_CONVERSION_MATRIX], 1, GL_FALSE, _preferredConversion);
  260. }
  261. #pragma mark - Utilities
  262. - (void)setupBuffers
  263. {
  264. glDisable(GL_DEPTH_TEST);
  265. glEnableVertexAttribArray(ATTRIB_VERTEX);
  266. glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
  267. glEnableVertexAttribArray(ATTRIB_TEXCOORD);
  268. glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
  269. [self createBuffers];
  270. }
  271. - (void) createBuffers
  272. {
  273. glGenFramebuffers(1, &_frameBufferHandle);
  274. glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferHandle);
  275. glGenRenderbuffers(1, &_colorBufferHandle);
  276. glBindRenderbuffer(GL_RENDERBUFFER, _colorBufferHandle);
  277. [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:self];
  278. glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth);
  279. glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);
  280. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorBufferHandle);
  281. if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
  282. NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
  283. }
  284. }
  285. - (void) releaseBuffers
  286. {
  287. if(_frameBufferHandle) {
  288. glDeleteFramebuffers(1, &_frameBufferHandle);
  289. _frameBufferHandle = 0;
  290. }
  291. if(_colorBufferHandle) {
  292. glDeleteRenderbuffers(1, &_colorBufferHandle);
  293. _colorBufferHandle = 0;
  294. }
  295. }
  296. - (void) resetRenderBuffer
  297. {
  298. if (!_context || ![EAGLContext setCurrentContext:_context]) {
  299. return;
  300. }
  301. [self releaseBuffers];
  302. [self createBuffers];
  303. }
  304. - (void) cleanUpTextures
  305. {
  306. if (_lumaTexture) {
  307. CFRelease(_lumaTexture);
  308. _lumaTexture = NULL;
  309. }
  310. if (_chromaTexture) {
  311. CFRelease(_chromaTexture);
  312. _chromaTexture = NULL;
  313. }
  314. }
  315. #pragma mark - OpenGL ES 2 shader compilation
  316. const GLchar *shader_fshTmp = (const GLchar*)"varying highp vec2 texCoordVarying;"
  317. "precision mediump float;"
  318. "uniform sampler2D SamplerY;"
  319. "uniform sampler2D SamplerUV;"
  320. "uniform mat3 colorConversionMatrix;"
  321. "void main()"
  322. "{"
  323. " mediump vec3 yuv;"
  324. " lowp vec3 rgb;"
  325. // Subtract constants to map the video range start at 0
  326. " yuv.x = (texture2D(SamplerY, texCoordVarying).r - (16.0/255.0));"
  327. " yuv.yz = (texture2D(SamplerUV, texCoordVarying).rg - vec2(0.5, 0.5));"
  328. " rgb = colorConversionMatrix * yuv;"
  329. " gl_FragColor = vec4(rgb, 1);"
  330. "}";
  331. const GLchar *shader_vshTmp = (const GLchar*)"attribute vec4 position;"
  332. "attribute vec2 texCoord;"
  333. "uniform float preferredRotation;"
  334. "varying vec2 texCoordVarying;"
  335. "void main()"
  336. "{"
  337. " mat4 rotationMatrix = mat4(cos(preferredRotation), -sin(preferredRotation), 0.0, 0.0,"
  338. " sin(preferredRotation), cos(preferredRotation), 0.0, 0.0,"
  339. " 0.0, 0.0, 1.0, 0.0,"
  340. " 0.0, 0.0, 0.0, 1.0);"
  341. " gl_Position = position * rotationMatrix;"
  342. " texCoordVarying = texCoord;"
  343. "}";
  344. - (BOOL)loadShaders
  345. {
  346. GLuint vertShader = 0, fragShader = 0;
  347. // Create the shader program.
  348. self.program = glCreateProgram();
  349. if(![self compileShaderString:&vertShader type:GL_VERTEX_SHADER shaderString:shader_vshTmp]) {
  350. NSLog(@"Failed to compile vertex shader");
  351. return NO;
  352. }
  353. if(![self compileShaderString:&fragShader type:GL_FRAGMENT_SHADER shaderString:shader_fshTmp]) {
  354. NSLog(@"Failed to compile fragment shader");
  355. return NO;
  356. }
  357. // Attach vertex shader to program.
  358. glAttachShader(self.program, vertShader);
  359. // Attach fragment shader to program.
  360. glAttachShader(self.program, fragShader);
  361. // Bind attribute locations. This needs to be done prior to linking.
  362. glBindAttribLocation(self.program, ATTRIB_VERTEX, "position");
  363. glBindAttribLocation(self.program, ATTRIB_TEXCOORD, "texCoord");
  364. // Link the program.
  365. if (![self linkProgram:self.program]) {
  366. NSLog(@"Failed to link program: %d", self.program);
  367. if (vertShader) {
  368. glDeleteShader(vertShader);
  369. vertShader = 0;
  370. }
  371. if (fragShader) {
  372. glDeleteShader(fragShader);
  373. fragShader = 0;
  374. }
  375. if (self.program) {
  376. glDeleteProgram(self.program);
  377. self.program = 0;
  378. }
  379. return NO;
  380. }
  381. // Get uniform locations.
  382. uniformsTmp[UNIFORM_Y] = glGetUniformLocation(self.program, "SamplerY");
  383. uniformsTmp[UNIFORM_UV] = glGetUniformLocation(self.program, "SamplerUV");
  384. // uniformsTmp[UNIFORM_LUMA_THRESHOLD] = glGetUniformLocation(self.program, "lumaThreshold");
  385. // uniformsTmp[UNIFORM_CHROMA_THRESHOLD] = glGetUniformLocation(self.program, "chromaThreshold");
  386. uniformsTmp[UNIFORM_ROTATION_ANGLE] = glGetUniformLocation(self.program, "preferredRotation");
  387. uniformsTmp[UNIFORM_COLOR_CONVERSION_MATRIX] = glGetUniformLocation(self.program, "colorConversionMatrix");
  388. // Release vertex and fragment shaders.
  389. if (vertShader) {
  390. glDetachShader(self.program, vertShader);
  391. glDeleteShader(vertShader);
  392. }
  393. if (fragShader) {
  394. glDetachShader(self.program, fragShader);
  395. glDeleteShader(fragShader);
  396. }
  397. return YES;
  398. }
  399. - (BOOL)compileShaderString:(GLuint *)shader type:(GLenum)type shaderString:(const GLchar*)shaderString
  400. {
  401. *shader = glCreateShader(type);
  402. glShaderSource(*shader, 1, &shaderString, NULL);
  403. glCompileShader(*shader);
  404. #if defined(DEBUG)
  405. GLint logLength;
  406. glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
  407. if (logLength > 0) {
  408. GLchar *log = (GLchar *)malloc(logLength);
  409. glGetShaderInfoLog(*shader, logLength, &logLength, log);
  410. NSLog(@"Shader compile log:\n%s", log);
  411. free(log);
  412. }
  413. #endif
  414. GLint status = 0;
  415. glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
  416. if (status == 0) {
  417. glDeleteShader(*shader);
  418. return NO;
  419. }
  420. return YES;
  421. }
  422. - (BOOL)compileShader:(GLuint *)shader type:(GLenum)type URL:(NSURL *)URL
  423. {
  424. NSError *error;
  425. NSString *sourceString = [[NSString alloc] initWithContentsOfURL:URL encoding:NSUTF8StringEncoding error:&error];
  426. if (sourceString == nil) {
  427. NSLog(@"Failed to load vertex shader: %@", [error localizedDescription]);
  428. return NO;
  429. }
  430. const GLchar *source = (GLchar *)[sourceString UTF8String];
  431. return [self compileShaderString:shader type:type shaderString:source];
  432. }
  433. - (BOOL)linkProgram:(GLuint)prog
  434. {
  435. GLint status;
  436. glLinkProgram(prog);
  437. #if defined(DEBUG)
  438. GLint logLength;
  439. glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
  440. if (logLength > 0) {
  441. GLchar *log = (GLchar *)malloc(logLength);
  442. glGetProgramInfoLog(prog, logLength, &logLength, log);
  443. NSLog(@"Program link log:\n%s", log);
  444. free(log);
  445. }
  446. #endif
  447. glGetProgramiv(prog, GL_LINK_STATUS, &status);
  448. if (status == 0) {
  449. return NO;
  450. }
  451. return YES;
  452. }
  453. - (BOOL)validateProgram:(GLuint)prog
  454. {
  455. GLint logLength, status;
  456. glValidateProgram(prog);
  457. glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
  458. if (logLength > 0) {
  459. GLchar *log = (GLchar *)malloc(logLength);
  460. glGetProgramInfoLog(prog, logLength, &logLength, log);
  461. NSLog(@"Program validate log:\n%s", log);
  462. free(log);
  463. }
  464. glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);
  465. if (status == 0) {
  466. return NO;
  467. }
  468. return YES;
  469. }
  470. - (void)dealloc
  471. {
  472. if (!_context || ![EAGLContext setCurrentContext:_context]) {
  473. return;
  474. }
  475. [self cleanUpTextures];
  476. if(_pixelBuffer) {
  477. CVPixelBufferRelease(_pixelBuffer);
  478. }
  479. if (self.program) {
  480. glDeleteProgram(self.program);
  481. self.program = 0;
  482. }
  483. if(_context) {
  484. //[_context release];
  485. _context = nil;
  486. }
  487. //[super dealloc];
  488. }
  489. @end