mirror of
https://github.com/DKJone/DKWechatHelper.git
synced 2025-05-25 20:36:08 +08:00
257 lines
11 KiB
Objective-C
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
|