DKWechatHelper/dkhelper/dkhelperDylib/QGVAPlayer/class/Views/OpenGL/QGHWDMP4OpenGLView.m
DKJone 888af8954e [v1.0.7](https://github.com/DKWechatHelper/DKWechatHelper/releases/tag/1.0.7) / 2021-01-29
what's new
* 动态启动图
* 动态聊天背景
* 支持8.0.1
* 更新越狱包8.0.1
* 更新已注入助手的8.0.1未签名包
* 更新越狱源安装包
2021-01-29 16:35:34 +08:00

646 lines
21 KiB
Objective-C

// QGHWDMP4OpenGLView.m
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions and
// limitations under the License.
#import "QGHWDMP4OpenGLView.h"
#import <QuartzCore/QuartzCore.h>
#import <AVFoundation/AVUtilities.h>
#import <mach/mach_time.h>
#import <GLKit/GLKit.h>
#import "VAPMacros.h"
// Uniform index.
enum {
HWD_UNIFORM_Y,
HWD_UNIFORM_UV,
HWD_UNIFORM_COLOR_CONVERSION_MATRIX,
HWD_NUM_UNIFORMS
};
GLint hwd_uniforms[HWD_NUM_UNIFORMS];
// Attribute index.
enum {
ATTRIB_VERTEX,
ATTRIB_TEXCOORD_RGB,
ATTRIB_TEXCOORD_ALPHA,
NUM_ATTRIBUTES
};
// BT.709-HDTV.
static const GLfloat kColorConversion709[] = {
1.164, 1.164, 1.164,
0.0, -0.213, 2.112,
1.793, -0.533, 0.0,
};
// BT.601 full range-http://www.equasys.de/colorconversion.html
const GLfloat kColorConversion601FullRange[] = {
1.0, 1.0, 1.0,
0.0, -0.343, 1.765,
1.4, -0.711, 0.0,
};
// texture coords for blend
const GLfloat textureCoordLeft[] = { // 左侧
0.5, 0.0,
0.0, 0.0,
0.5, 1.0,
0.0, 1.0
};
const GLfloat textureCoordRight[] = { // 右侧
1.0, 0.0,
0.5, 0.0,
1.0, 1.0,
0.5, 1.0
};
const GLfloat textureCoordTop[] = { // 上侧
1.0, 0.0,
0.0, 0.0,
1.0, 0.5,
0.0, 0.5
};
const GLfloat textureCoordBottom[] = { // 下侧
1.0, 0.5,
0.0, 0.5,
1.0, 1.0,
0.0, 1.0
};
#undef cos
#undef sin
NSString *const kVertexShaderSource = SHADER_STRING
(
attribute vec4 position;
attribute vec2 RGBTexCoord;
attribute vec2 alphaTexCoord;
varying vec2 RGBTexCoordVarying;
varying vec2 alphaTexCoordVarying;
void main()
{
float preferredRotation = 3.14;
mat4 rotationMatrix = mat4(cos(preferredRotation), -sin(preferredRotation), 0.0, 0.0,sin(preferredRotation),cos(preferredRotation), 0.0, 0.0,0.0,0.0,1.0,0.0,0.0,0.0, 0.0,1.0);
gl_Position = rotationMatrix * position;
RGBTexCoordVarying = RGBTexCoord;
alphaTexCoordVarying = alphaTexCoord;
}
);
NSString *const kFragmentShaderSource = SHADER_STRING
(
varying highp vec2 RGBTexCoordVarying;
varying highp vec2 alphaTexCoordVarying;
precision mediump float;
uniform sampler2D SamplerY;
uniform sampler2D SamplerUV;
uniform mat3 colorConversionMatrix;
void main()
{
mediump vec3 yuv_rgb;
lowp vec3 rgb_rgb;
mediump vec3 yuv_alpha;
lowp vec3 rgb_alpha;
// Subtract constants to map the video range start at 0
yuv_rgb.x = (texture2D(SamplerY, RGBTexCoordVarying).r);// - (16.0/255.0));
yuv_rgb.yz = (texture2D(SamplerUV, RGBTexCoordVarying).ra - vec2(0.5, 0.5));
rgb_rgb = colorConversionMatrix * yuv_rgb;
yuv_alpha.x = (texture2D(SamplerY, alphaTexCoordVarying).r);// - (16.0/255.0));
yuv_alpha.yz = (texture2D(SamplerUV, alphaTexCoordVarying).ra - vec2(0.5, 0.5));
rgb_alpha = colorConversionMatrix * yuv_alpha;
gl_FragColor = vec4(rgb_rgb,rgb_alpha.r);
// gl_FragColor = vec4(1, 0, 0, 1);
}
);
@interface QGHWDMP4OpenGLView() {
GLint _backingWidth;
GLint _backingHeight;
CVOpenGLESTextureRef _lumaTexture;
CVOpenGLESTextureRef _chromaTexture;
CVOpenGLESTextureCacheRef _textureCache;
GLuint _frameBufferHandle;
GLuint _colorBufferHandle;
const GLfloat *_preferredConversion;
}
@property GLuint program;
- (void)setupBuffers;
- (void)cleanupTextures;
- (BOOL)isValidateProgram:(GLuint)prog;
- (BOOL)loadShaders;
- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type URL:(NSURL *)URL;
- (BOOL)linkProgram:(GLuint)prog;
@end
@implementation QGHWDMP4OpenGLView
+ (Class)layerClass {
return [CAEAGLLayer class];
}
- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
if (![self commonInit]) {
return nil;
}
}
return self;
}
- (instancetype)init {
if (self = [super init]) {
if (![self commonInit]) {
return nil;
}
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
if (![self commonInit]) {
return nil;
}
}
return self;
}
- (BOOL)commonInit {
self.contentScaleFactor = [[UIScreen mainScreen] scale];
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
eaglLayer.opaque = NO;
eaglLayer.drawableProperties = @{ kEAGLDrawablePropertyRetainedBacking :[NSNumber numberWithBool:NO],
kEAGLDrawablePropertyColorFormat : kEAGLColorFormatRGBA8};
_glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!_glContext || ![EAGLContext setCurrentContext:_glContext] || ![self loadShaders]) {
return NO;
}
_preferredConversion = kColorConversion709;
return YES;
}
- (void)dealloc {
[self cleanupTextures];
if(_textureCache) {
CFRelease(_textureCache);
}
if ([self.displayDelegate respondsToSelector:@selector(onViewUnavailableStatus)]) {
[self.displayDelegate onViewUnavailableStatus];
}
}
# pragma mark - OpenGL setup
/**
初始化opengl环境
*/
- (void)setupGL {
VAP_Info(kQGVAPModuleCommon, @"setupGL");
[EAGLContext setCurrentContext:_glContext];
[self setupBuffers];
[self loadShaders];
glUseProgram(self.program);
glUniform1i(hwd_uniforms[HWD_UNIFORM_Y], 0);
glUniform1i(hwd_uniforms[HWD_UNIFORM_UV], 1);
glUniformMatrix3fv(hwd_uniforms[HWD_UNIFORM_COLOR_CONVERSION_MATRIX], 1, GL_FALSE, _preferredConversion);
// Create CVOpenGLESTextureCacheRef for optimal CVPixelBufferRef to GLES texture conversion.
if (!_textureCache) {
CVReturn err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, _glContext, NULL, &_textureCache);
if (err != noErr) {
VAP_Event(kQGVAPModuleCommon, @"Error at CVOpenGLESTextureCacheCreate %d", err);
return;
}
}
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}
#pragma mark - Utilities
- (void)setupBuffers {
glDisable(GL_DEPTH_TEST);
glEnableVertexAttribArray(ATTRIB_VERTEX);
glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
glEnableVertexAttribArray(ATTRIB_TEXCOORD_RGB);
glVertexAttribPointer(ATTRIB_TEXCOORD_RGB, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
glEnableVertexAttribArray(ATTRIB_TEXCOORD_ALPHA);
glVertexAttribPointer(ATTRIB_TEXCOORD_ALPHA, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
glGenFramebuffers(1, &_frameBufferHandle);
glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferHandle);
glGenRenderbuffers(1, &_colorBufferHandle);
glBindRenderbuffer(GL_RENDERBUFFER, _colorBufferHandle);
[_glContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorBufferHandle);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
VAP_Event(kQGVAPModuleCommon, @"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
}
}
- (void)layoutSubviews {
[super layoutSubviews];
[self updateBackingSize];
}
/**
根据容器大小更新渲染尺寸
*/
- (void)updateBackingSize {
if ([EAGLContext currentContext] != _glContext) {
[EAGLContext setCurrentContext:_glContext];
}
[_glContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);
}
- (void)cleanupTextures {
if (_lumaTexture) {
CFRelease(_lumaTexture);
_lumaTexture = NULL;
}
if (_chromaTexture) {
CFRelease(_chromaTexture);
_chromaTexture = NULL;
}
CVOpenGLESTextureCacheFlush(_textureCache, 0);
}
#pragma mark - OpenGLES drawing
/**
上屏
@param pixelBuffer 硬解出来的samplebuffer数据
*/
- (void)displayPixelBuffer:(CVPixelBufferRef)pixelBuffer {
if (!self.window && [self.displayDelegate respondsToSelector:@selector(onViewUnavailableStatus)]) {
[self.displayDelegate onViewUnavailableStatus];
return ;
}
if ([EAGLContext currentContext] != _glContext) {
[EAGLContext setCurrentContext:_glContext];
}
CVReturn err;
if (pixelBuffer != NULL) {
int frameWidth = (int)CVPixelBufferGetWidth(pixelBuffer);
int frameHeight = (int)CVPixelBufferGetHeight(pixelBuffer);
if (!_textureCache) {
VAP_Event(kQGVAPModuleCommon, @"No video texture cache");
return;
}
[self cleanupTextures];
_preferredConversion = kColorConversion601FullRange;
//y
glActiveTexture(GL_TEXTURE0);
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
_textureCache,
pixelBuffer,
NULL,
GL_TEXTURE_2D,
GL_LUMINANCE,
frameWidth,
frameHeight,
GL_LUMINANCE,
GL_UNSIGNED_BYTE,
0,
&_lumaTexture);
if (err) {
VAP_Event(kQGVAPModuleCommon, @"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
}
glBindTexture(CVOpenGLESTextureGetTarget(_lumaTexture), CVOpenGLESTextureGetName(_lumaTexture));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// uv
glActiveTexture(GL_TEXTURE1);
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
_textureCache,
pixelBuffer,
NULL,
GL_TEXTURE_2D,
GL_LUMINANCE_ALPHA,
frameWidth / 2.0,
frameHeight / 2.0,
GL_LUMINANCE_ALPHA,
GL_UNSIGNED_BYTE,
1,
&_chromaTexture);
if (err) {
VAP_Error(kQGVAPModuleCommon, @"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
}
glBindTexture(CVOpenGLESTextureGetTarget(_chromaTexture), CVOpenGLESTextureGetName(_chromaTexture));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferHandle);
// Set the view port to the entire view.
glViewport(0, 0, _backingWidth, _backingHeight);
}
// glClearColor(0.1f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(self.program);
glUniformMatrix3fv(hwd_uniforms[HWD_UNIFORM_COLOR_CONVERSION_MATRIX], 1, GL_FALSE, _preferredConversion);
// 根据视频的方向和高宽比设置四个顶点。
CGRect vertexRect = AVMakeRectWithAspectRatioInsideRect(CGSizeMake(_backingWidth, _backingHeight), self.layer.bounds);
// 计算归一化四坐标来绘制坐标系。
CGSize normalizedSamplingSize = CGSizeMake(0.0, 0.0);
CGSize cropScaleAmount = CGSizeMake(vertexRect.size.width/self.layer.bounds.size.width, vertexRect.size.height/self.layer.bounds.size.height);
if (cropScaleAmount.width > cropScaleAmount.height) {
normalizedSamplingSize.width = 1.0;
normalizedSamplingSize.height = cropScaleAmount.height/cropScaleAmount.width;
} else {
normalizedSamplingSize.width = 1.0;
normalizedSamplingSize.height = cropScaleAmount.width/cropScaleAmount.height;
}
GLfloat quadVertexData [] = {
-1 * normalizedSamplingSize.width, -1 * normalizedSamplingSize.height,
normalizedSamplingSize.width, -1 * normalizedSamplingSize.height,
-1 * normalizedSamplingSize.width, normalizedSamplingSize.height,
normalizedSamplingSize.width, normalizedSamplingSize.height,
};
// 更新顶点数据
glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, quadVertexData);
glEnableVertexAttribArray(ATTRIB_VERTEX);
glVertexAttribPointer(ATTRIB_TEXCOORD_RGB, 2, GL_FLOAT, 0, 0, [self quadTextureRGBData]);
glEnableVertexAttribArray(ATTRIB_TEXCOORD_RGB);
glVertexAttribPointer(ATTRIB_TEXCOORD_ALPHA, 2, GL_FLOAT, 0, 0, [self quedTextureAlphaData]);
glEnableVertexAttribArray(ATTRIB_TEXCOORD_ALPHA);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindRenderbuffer(GL_RENDERBUFFER, _colorBufferHandle);
if ([EAGLContext currentContext] == _glContext && !self.pause && self.window && [UIApplication sharedApplication].applicationState != UIApplicationStateBackground) {
[_glContext presentRenderbuffer:GL_RENDERBUFFER];
}
}
- (const void *)quedTextureAlphaData {
switch (self.blendMode) {
case QGHWDTextureBlendMode_AlphaLeft:
return textureCoordLeft;
case QGHWDTextureBlendMode_AlphaRight:
return textureCoordRight;
case QGHWDTextureBlendMode_AlphaTop:
return textureCoordTop;
case QGHWDTextureBlendMode_AlphaBottom:
return textureCoordBottom;
default:
return textureCoordLeft;
}
}
- (const void *)quadTextureRGBData {
switch (self.blendMode) {
case QGHWDTextureBlendMode_AlphaLeft:
return textureCoordRight;
case QGHWDTextureBlendMode_AlphaRight:
return textureCoordLeft;
case QGHWDTextureBlendMode_AlphaTop:
return textureCoordBottom;
case QGHWDTextureBlendMode_AlphaBottom:
return textureCoordTop;
default:
return textureCoordRight;
}
}
#pragma mark - OpenGL ES 2 shader compilation
- (BOOL)loadShaders {
GLuint vShader, fShader;
self.program = glCreateProgram();
// Create and compile the vertex shader.
if (![self compileShader:&vShader type:GL_VERTEX_SHADER source:kVertexShaderSource]) {
VAP_Error(kQGVAPModuleCommon, @"Failed to compile vertex shader");
return NO;
}
// Create and compile fragment shader.
if (![self compileShader:&fShader type:GL_FRAGMENT_SHADER source:kFragmentShaderSource]) {
VAP_Error(kQGVAPModuleCommon, @"Failed to compile fragment shader");
return NO;
}
// Attach vertex shader to program.
glAttachShader(self.program, vShader);
// Attach fragment shader to program.
glAttachShader(self.program, fShader);
// Bind attribute locations. This needs to be done prior to linking.
glBindAttribLocation(self.program, ATTRIB_VERTEX, "position");
glBindAttribLocation(self.program, ATTRIB_TEXCOORD_RGB, "RGBTexCoord");
glBindAttribLocation(self.program, ATTRIB_TEXCOORD_ALPHA, "alphaTexCoord");
// Link the program.
if (![self linkProgram:self.program]) {
VAP_Event(kQGVAPModuleCommon, @"Failed to link program: %d", self.program);
if (vShader) {
glDeleteShader(vShader);
vShader = 0;
}
if (fShader) {
glDeleteShader(fShader);
fShader = 0;
}
if (self.program) {
glDeleteProgram(self.program);
self.program = 0;
}
return NO;
}
// Get uniforms' location.
hwd_uniforms[HWD_UNIFORM_Y] = glGetUniformLocation(self.program, "SamplerY");
hwd_uniforms[HWD_UNIFORM_UV] = glGetUniformLocation(self.program, "SamplerUV");
hwd_uniforms[HWD_UNIFORM_COLOR_CONVERSION_MATRIX] = glGetUniformLocation(self.program, "colorConversionMatrix");
// Release vertex and fragment shaders.
if (vShader) {
glDetachShader(self.program, vShader);
glDeleteShader(vShader);
}
if (fShader) {
glDetachShader(self.program, fShader);
glDeleteShader(fShader);
}
return YES;
}
- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type source:(const NSString *)sourceString {
GLint status;
const GLchar *source;
source = (GLchar *)[sourceString UTF8String];
*shader = glCreateShader(type);
glShaderSource(*shader, 1, &source, NULL);
glCompileShader(*shader);
#if defined(DEBUG)
GLint lengthOfLog;
glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &lengthOfLog);
if (lengthOfLog > 0) {
GLchar *log = (GLchar *)malloc(lengthOfLog);
glGetShaderInfoLog(*shader, lengthOfLog, &lengthOfLog, log);
VAP_Info(kQGVAPModuleCommon, @"MODULE_DECODE Shader compile log:\n%s", log)
free(log);
}
#endif
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
if (status == 0) {
glDeleteShader(*shader);
return NO;
}
return YES;
}
- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type URL:(NSURL *)URL {
VAP_Info(kQGVAPModuleCommon, @"compileShader");
NSError *error;
NSString *sourceString = [[NSString alloc] initWithContentsOfURL:URL encoding:NSUTF8StringEncoding error:&error];
if (sourceString == nil) {
VAP_Event(kQGVAPModuleCommon, @"Failed to load vertex shader: %@", [error localizedDescription]);
return NO;
}
const GLchar *source;
source = (GLchar *)[sourceString UTF8String];
*shader = glCreateShader(type);
glShaderSource(*shader, 1, &source, NULL);
glCompileShader(*shader);
#if defined(DEBUG)
GLint lengthOfLog;
glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &lengthOfLog);
if (lengthOfLog > 0) {
GLchar *log = (GLchar *)malloc(lengthOfLog);
glGetShaderInfoLog(*shader, lengthOfLog, &lengthOfLog, log);
VAP_Info(kQGVAPModuleCommon, @"Shader compile log:\n%s", log);
free(log);
}
#endif
GLint status;
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
if (status == 0) {
glDeleteShader(*shader);
return NO;
}
return YES;
}
- (BOOL)linkProgram:(GLuint)prog {
GLint status;
glLinkProgram(prog);
#if defined(DEBUG)
GLint lengthOfLog;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &lengthOfLog);
if (lengthOfLog > 0) {
GLchar *log = (GLchar *)malloc(lengthOfLog);
glGetProgramInfoLog(prog, lengthOfLog, &lengthOfLog, log);
VAP_Info(kQGVAPModuleCommon, @"Program link log:\n%s", log);
free(log);
}
#endif
glGetProgramiv(prog, GL_LINK_STATUS, &status);
if (status == 0) {
return NO;
}
return YES;
}
- (BOOL)isValidateProgram:(GLuint)prog {
GLint logLength, status;
glValidateProgram(prog);
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(prog, logLength, &logLength, log);
VAP_Info(kQGVAPModuleCommon, @"Program validate log:\n%s", log);
free(log);
}
glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);
if (status == 0) {
VAP_Event(kQGVAPModuleCommon, @"program is not valid:%@",@(status));
return NO;
}
VAP_Info(kQGVAPModuleCommon, @"programe is valid");
return YES;
}
- (void)dispose {
glDisableVertexAttribArray(ATTRIB_VERTEX);
glDisableVertexAttribArray(ATTRIB_TEXCOORD_RGB);
glDisableVertexAttribArray(ATTRIB_TEXCOORD_ALPHA);
}
@end