DKWechatHelper/dkhelper/dkhelperDylib/QGVAPlayer/class/Controllers/QGVAPConfigManager.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

257 lines
11 KiB
Objective-C

// QGVAPConfigManager.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 "QGVAPConfigManager.h"
#import "QGMP4Parser.h"
#import "QGVAPLogger.h"
#import "NSDictionary+VAPUtil.h"
#import "UIColor+VAPUtil.h"
#import "NSArray+VAPUtil.h"
#import "QGHWDMetalRenderer.h"
#import "QGVAPTextureLoader.h"
@interface QGVAPConfigManager () {
QGMP4HWDFileInfo *_fileInfo;
}
@end
@implementation QGVAPConfigManager
- (instancetype)initWith:(QGMP4HWDFileInfo *)fileInfo {
if (self = [super init]) {
_fileInfo = fileInfo;
[self setupConfig];
}
return self;
}
- (void)setupConfig {
QGMP4Box *vapc = [_fileInfo.mp4Parser.rootBox subBoxOfType:QGMP4BoxType_vapc];
if (!vapc) {
self.hasValidConfig = NO;
return ;
}
self.hasValidConfig = YES;
NSData *vapcData = [_fileInfo.mp4Parser readDataOfBox:vapc length:vapc.length-8 offset:8];
NSError *error = nil;
NSDictionary *configDictionary = [NSJSONSerialization JSONObjectWithData:vapcData options:kNilOptions error:&error];
if (error) {
VAP_Error(kQGVAPModuleCommon, @"fail to parse config as dictionary file %@", vapc);
}
[self parseConfigDictinary:configDictionary];
}
#pragma mark - resource loader
- (void)loadConfigResources {
if (self.model.resources.count == 0) {
if ([self.delegate respondsToSelector:@selector(onVAPConfigResourcesLoaded:error:)]) {
[self.delegate onVAPConfigResourcesLoaded:self.model error:nil];
}
return ;
}
//tags
if ([self.delegate respondsToSelector:@selector(vap_contentForTag:resource:)]) {
[self.model.resources enumerateObjectsUsingBlock:^(QGVAPSourceInfo * _Nonnull resource, NSUInteger idx, BOOL * _Nonnull stop) {
resource.contentTagValue = [self.delegate vap_contentForTag:resource.contentTag resource:resource];
}];
}
if (![self.delegate respondsToSelector:@selector(vap_loadImageWithURL:context:completion:)]) {
return ;
}
__block NSError *loadError = nil;
dispatch_group_t group = dispatch_group_create();
[self.model.resources enumerateObjectsUsingBlock:^(QGVAPSourceInfo * _Nonnull resource, NSUInteger idx, BOOL * _Nonnull stop) {
NSString *tagContent = resource.contentTagValue;
if ([resource.type isEqualToString:kQGAGAttachmentSourceTypeText] && [resource.loadType isEqualToString:QGAGAttachmentSourceLoadTypeLocal]) {
resource.sourceImage = [QGVAPTextureLoader drawingImageForText:tagContent color:resource.color size:resource.size bold:[resource.style isEqualToString:kQGAGAttachmentSourceStyleBoldText]];
}
if ([resource.type isEqualToString:kQGAGAttachmentSourceTypeImg] && [resource.loadType isEqualToString:QGAGAttachmentSourceLoadTypeNet]) {
NSString *imageURL = tagContent;
NSDictionary *context = @{@"resource":resource};
dispatch_group_enter(group);
[self.delegate vap_loadImageWithURL:imageURL context:context completion:^(UIImage *image, NSError *error, NSString *imageURL) {
if (!image || error) {
VAP_Error(kQGVAPModuleCommon, @"loadImageWithURL %@ error:%@", imageURL, error);
loadError = (loadError ?: (error ?: ([NSError errorWithDomain:[NSString stringWithFormat:@"loadImageError:%@", imageURL] code:-1 userInfo:nil])));
}
resource.sourceImage = image;
dispatch_group_leave(group);
}];
}
}];
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
if ([self.delegate respondsToSelector:@selector(onVAPConfigResourcesLoaded:error:)]) {
[self.delegate onVAPConfigResourcesLoaded:self.model error:loadError];
}
});
}
- (void)loadMTLTextures:(id<MTLDevice>)device {
[self.model.resources enumerateObjectsUsingBlock:^(QGVAPSourceInfo * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
id<MTLTexture> texture = [QGVAPTextureLoader loadTextureWithImage:obj.sourceImage device:device];
obj.sourceImage = nil;
obj.texture = texture;
}];
}
- (void)loadMTLBuffers:(id<MTLDevice>)device {
[self.model.resources enumerateObjectsUsingBlock:^(QGVAPSourceInfo * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
id<MTLBuffer> buffer = [QGVAPTextureLoader loadVapColorFillBufferWith:obj.color device:device];
obj.colorParamsBuffer = buffer;
}];
}
#pragma mark - parse json
- (void)parseConfigDictinary:(NSDictionary *)configDic {
NSDictionary *commonInfoDic = [configDic hwd_dicValue:@"info"];
NSArray *sourcesArr = [configDic hwd_arrValue:@"src"];
NSArray *framesArr = [configDic hwd_arrValue:@"frame"];
if (!commonInfoDic) {
VAP_Error(kQGVAPModuleCommon, @"has no commonInfoDic:%@", configDic);
return ;
}
QGVAPConfigModel *configModel = [QGVAPConfigModel new];
//parse
NSInteger version = [commonInfoDic hwd_integerValue:@"v"];
NSInteger frameCount = [commonInfoDic hwd_integerValue:@"f"];
CGFloat w = [commonInfoDic hwd_floatValue:@"w"];
CGFloat h = [commonInfoDic hwd_floatValue:@"h"];
CGFloat video_w = [commonInfoDic hwd_floatValue:@"videoW"];
CGFloat video_h = [commonInfoDic hwd_floatValue:@"videoH"];
CGFloat orientaion = [commonInfoDic hwd_integerValue:@"orien"];
NSInteger fps = [commonInfoDic hwd_integerValue:@"fps"];
BOOL isMerged = ([commonInfoDic hwd_integerValue:@"isVapx"] == 1);
NSArray *a_frame = [commonInfoDic hwd_arrValue:@"aFrame"];
NSArray *rgb_frame = [commonInfoDic hwd_arrValue:@"rgbFrame"];
self.model = configModel;
//整体信息
QGVAPCommonInfo *commonInfo = [QGVAPCommonInfo new];
commonInfo.version = version;
commonInfo.framesCount = frameCount;
commonInfo.size = CGSizeMake(w, h);
commonInfo.videoSize = CGSizeMake(video_w, video_h);
commonInfo.targetOrientaion = orientaion;
commonInfo.fps = fps;
commonInfo.isMerged = isMerged;
commonInfo.alphaAreaRect = a_frame ? [a_frame hwd_rectValue] : CGRectZero;
commonInfo.rgbAreaRect = rgb_frame ? [rgb_frame hwd_rectValue] : CGRectZero;
configModel.info = commonInfo;
if (!sourcesArr) {
VAP_Error(kQGVAPModuleCommon, @"has no sourcesArr:%@", configDic);
return ;
}
//源信息
NSMutableDictionary <NSString *, QGVAPSourceInfo *>*sources = [NSMutableDictionary new];
[sourcesArr enumerateObjectsUsingBlock:^(NSDictionary *sourceDic, NSUInteger idx, BOOL * _Nonnull stop) {
if (![sourceDic isKindOfClass:[NSDictionary class]]) {
VAP_Error(kQGVAPModuleCommon, @"sourceDic is not dic:%@", sourceDic);
return ;
}
NSString *sourceID = [sourceDic hwd_stringValue:@"srcId"];
if (!sourceID) {
VAP_Error(kQGVAPModuleCommon, @"has no sourceID:%@", sourceDic);
return ;
}
//parse
QGAGAttachmentSourceType sourceType = [sourceDic hwd_stringValue:@"srcType"];
QGAGAttachmentSourceLoadType loadType = [sourceDic hwd_stringValue:@"loadType"];
NSString *contentTag = [sourceDic hwd_stringValue:@"srcTag"];
UIColor *color = [UIColor hwd_colorWithHexString:[sourceDic hwd_stringValue:@"color"]];
QGAGAttachmentSourceStyle style = [sourceDic hwd_stringValue:@"style"];
CGFloat width = [sourceDic hwd_floatValue:@"w"];
CGFloat height = [sourceDic hwd_floatValue:@"h"];
QGAGAttachmentFitType fitType = [sourceDic hwd_stringValue:@"fitType"];
QGVAPSourceInfo *sourceInfo = [QGVAPSourceInfo new];
sourceInfo.type = sourceType;
sourceInfo.style = style;
sourceInfo.contentTag = contentTag;
sourceInfo.color = color;
sourceInfo.size = CGSizeMake(width, height);
sourceInfo.fitType = fitType;
sourceInfo.loadType = loadType;
sources[sourceID] = sourceInfo;
}];
configModel.resources = sources.allValues;
//融合信息
if (!framesArr) {
VAP_Error(kQGVAPModuleCommon, @"has no framesArr:%@", configDic);
return ;
}
NSMutableDictionary <NSNumber *, NSArray<QGVAPMergedInfo *>*> *mergedConfig = [NSMutableDictionary new];
[framesArr enumerateObjectsUsingBlock:^(NSDictionary *frameMergedDic, NSUInteger idx, BOOL * _Nonnull stop) {
if (![frameMergedDic isKindOfClass:[NSDictionary class]]) {
VAP_Error(kQGVAPModuleCommon, @"frameMergedDic is not dic:%@", frameMergedDic);
return ;
}
NSInteger frameIndex = [frameMergedDic hwd_integerValue:@"i"];
NSMutableArray <QGVAPMergedInfo *> *mergedInfos = [NSMutableArray new];
NSArray *mergedObjs = [frameMergedDic hwd_arrValue:@"obj"];
[mergedObjs enumerateObjectsUsingBlock:^(NSDictionary *mergeInfoDic, NSUInteger idx, BOOL * _Nonnull stop) {
if (![mergeInfoDic isKindOfClass:[NSDictionary class]]) {
VAP_Error(kQGVAPModuleCommon, @"mergeInfoDic is not dic:%@", mergeInfoDic);
return ;
}
NSString *sourceID = [mergeInfoDic hwd_stringValue:@"srcId"];
QGVAPSourceInfo *sourceInfo = sources[sourceID];
if (!sourceInfo) {
VAP_Error(kQGVAPModuleCommon, @"sourceInfo is nil:%@", mergeInfoDic);
return ;
}
//parse
NSArray *frame = [mergeInfoDic hwd_arrValue:@"frame"];
NSArray *m_frame = [mergeInfoDic hwd_arrValue:@"mFrame"];
NSInteger renderIndex = [mergeInfoDic hwd_integerValue:@"z"];
NSInteger rotationAngle = [mergeInfoDic hwd_integerValue:@"mt"];
QGVAPMergedInfo *mergeInfo = [QGVAPMergedInfo new];
mergeInfo.source = sourceInfo;
mergeInfo.renderIndex = renderIndex;
mergeInfo.needMask = (m_frame != nil);
mergeInfo.renderRect = frame ? [frame hwd_rectValue] : CGRectZero;
mergeInfo.maskRect = m_frame ? [m_frame hwd_rectValue] : CGRectZero;
mergeInfo.maskRotation = rotationAngle;
[mergedInfos addObject:mergeInfo];
}];
NSArray *sortedMergeInfos = [mergedInfos sortedArrayUsingComparator:^NSComparisonResult(QGVAPMergedInfo *info1, QGVAPMergedInfo *info2) {
return [@(info1.renderIndex) compare:@(info2.renderIndex)];
}];
mergedConfig[@(frameIndex)] = sortedMergeInfos;
}];
configModel.mergedConfig = mergedConfig;
}
@end