Selaa lähdekoodia

feat: 添加QGVapWrapView,封装支持ContentMode

casscai 5 vuotta sitten
vanhempi
sitoutus
077baafb11

+ 14 - 4
iOS/QGVAPlayer/QGVAPlayer.xcodeproj/project.pbxproj

@@ -7,6 +7,8 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		43BAD32225F2153500D17934 /* QGVAPWrapView.h in Headers */ = {isa = PBXBuildFile; fileRef = 43BAD32025F2153500D17934 /* QGVAPWrapView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		43BAD32325F2153500D17934 /* QGVAPWrapView.m in Sources */ = {isa = PBXBuildFile; fileRef = 43BAD32125F2153500D17934 /* QGVAPWrapView.m */; };
 		630723B122F0409200B15629 /* QGVAPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 630723A722F0409200B15629 /* QGVAPlayer.framework */; };
 		630723B622F0409200B15629 /* QGVAPlayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 630723B522F0409200B15629 /* QGVAPlayerTests.m */; };
 		630723B822F0409200B15629 /* QGVAPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 630723AA22F0409200B15629 /* QGVAPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -100,6 +102,8 @@
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
+		43BAD32025F2153500D17934 /* QGVAPWrapView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QGVAPWrapView.h; sourceTree = "<group>"; };
+		43BAD32125F2153500D17934 /* QGVAPWrapView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QGVAPWrapView.m; sourceTree = "<group>"; };
 		630723A722F0409200B15629 /* QGVAPlayer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = QGVAPlayer.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		630723AA22F0409200B15629 /* QGVAPlayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QGVAPlayer.h; sourceTree = "<group>"; };
 		630723AB22F0409200B15629 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -249,6 +253,8 @@
 				6307240222F0410600B15629 /* VAPMacros.h */,
 				630723C722F0410600B15629 /* UIView+VAP.h */,
 				630723F522F0410600B15629 /* UIView+VAP.m */,
+				43BAD32025F2153500D17934 /* QGVAPWrapView.h */,
+				43BAD32125F2153500D17934 /* QGVAPWrapView.m */,
 				630723D722F0410600B15629 /* Models */,
 				630723F622F0410600B15629 /* Views */,
 				630723E522F0410600B15629 /* Controllers */,
@@ -430,6 +436,7 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				43BAD32225F2153500D17934 /* QGVAPWrapView.h in Headers */,
 				6307240B22F0410600B15629 /* UIView+VAP.h in Headers */,
 				630723B822F0409200B15629 /* QGVAPlayer.h in Headers */,
 				63AEB3A02316AF8A0069CEBB /* NSDictionary+VAPUtil.h in Headers */,
@@ -574,6 +581,7 @@
 				63AFC6B8231E3D4A00E127F9 /* QGVAPMetalShaderFunctionLoader.m in Sources */,
 				6307243A22F0410600B15629 /* QGHWDMP4OpenGLView.m in Sources */,
 				6307243322F0410600B15629 /* QGHWDMetalView.m in Sources */,
+				43BAD32325F2153500D17934 /* QGVAPWrapView.m in Sources */,
 				63AEB3A62317CD940069CEBB /* NSArray+VAPUtil.m in Sources */,
 				6307240C22F0410600B15629 /* QGVAPWeakProxy.m in Sources */,
 				6307240922F0410600B15629 /* QGMP4Parser.m in Sources */,
@@ -750,10 +758,11 @@
 		630723BC22F0409200B15629 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				CODE_SIGN_IDENTITY = "";
+				CODE_SIGN_IDENTITY = "Apple Development";
+				"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
 				DEFINES_MODULE = YES;
-				DEVELOPMENT_TEAM = 6W55574XBS;
+				DEVELOPMENT_TEAM = 579YKGP6HQ;
 				DYLIB_COMPATIBILITY_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 1;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
@@ -774,10 +783,11 @@
 		630723BD22F0409200B15629 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				CODE_SIGN_IDENTITY = "";
+				CODE_SIGN_IDENTITY = "Apple Development";
+				"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
 				DEFINES_MODULE = YES;
-				DEVELOPMENT_TEAM = 6W55574XBS;
+				DEVELOPMENT_TEAM = 579YKGP6HQ;
 				DYLIB_COMPATIBILITY_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 1;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";

+ 1 - 0
iOS/QGVAPlayer/QGVAPlayer/Classes/Controllers/QGVAPConfigManager.m

@@ -45,6 +45,7 @@
     QGMP4Box *vapc = [_fileInfo.mp4Parser.rootBox subBoxOfType:QGMP4BoxType_vapc];
     if (!vapc) {
         self.hasValidConfig = NO;
+        VAP_Error(kQGVAPModuleCommon, @"config can not find vapc box");
         return ;
     }
     self.hasValidConfig = YES;

+ 57 - 0
iOS/QGVAPlayer/QGVAPlayer/Classes/QGVAPWrapView.h

@@ -0,0 +1,57 @@
+// UIView+VAP.h
+// 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 <UIKit/UIKit.h>
+#import "UIView+VAP.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+typedef NS_ENUM(NSUInteger, QGVAPWrapViewContentMode) {
+    QGVAPWrapViewContentModeScaleToFill,
+    QGVAPWrapViewContentModeAspectFit,
+    QGVAPWrapViewContentModeAspectFill,
+};
+
+@protocol VAPWrapViewDelegate <NSObject>
+
+@optional
+//即将开始播放时询问,true马上开始播放,false放弃播放
+- (BOOL)vapWrap_viewshouldStartPlayMP4:(VAPView *)container config:(QGVAPConfigModel *)config;
+
+- (void)vapWrap_viewDidStartPlayMP4:(VAPView *)container;
+- (void)vapWrap_viewDidPlayMP4AtFrame:(QGMP4AnimatedImageFrame*)frame view:(VAPView *)container;
+- (void)vapWrap_viewDidStopPlayMP4:(NSInteger)lastFrameIndex view:(VAPView *)container;
+- (void)vapWrap_viewDidFinishPlayMP4:(NSInteger)totalFrameCount view:(VAPView *)container;
+- (void)vapWrap_viewDidFailPlayMP4:(NSError *)error;
+
+//vap APIs
+- (NSString *)vapWrapview_contentForVapTag:(NSString *)tag resource:(QGVAPSourceInfo *)info;        //替换配置中的资源占位符(不处理直接返回tag)
+- (void)vapWrapView_loadVapImageWithURL:(NSString *)urlStr context:(NSDictionary *)context completion:(VAPImageCompletionBlock)completionBlock; //由于组件内不包含网络图片加载的模块,因此需要外部支持图片加载。
+
+@end
+
+/// 封装渲染容器的View,提供ContentMode功能
+@interface QGVAPWrapView : UIView
+/// default is QGVAPWrapViewContentModeScaleToFill
+@property (nonatomic, assign) QGVAPWrapViewContentMode contentMode;
+
+- (void)vapWrapView_playHWDMP4:(NSString *)filePath
+                   repeatCount:(NSInteger)repeatCount
+                      delegate:(id<VAPWrapViewDelegate>)delegate;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 173 - 0
iOS/QGVAPlayer/QGVAPlayer/Classes/QGVAPWrapView.m

@@ -0,0 +1,173 @@
+// UIView+VAP.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 "QGVAPWrapView.h"
+#import "QGVAPConfigModel.h"
+
+@interface QGVAPWrapView()<VAPWrapViewDelegate, HWDMP4PlayDelegate>
+
+@property (nonatomic, weak) id<VAPWrapViewDelegate> delegate;
+
+@property (nonatomic, strong) VAPView *vapView;
+
+@end
+
+@implementation QGVAPWrapView
+
+- (instancetype)init {
+
+    if (self = [super init]) {
+        [self commonInit];
+    }
+    return self;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame {
+
+    if (self = [super initWithFrame:frame]) {
+        [self commonInit];
+    }
+    return self;
+}
+
+- (void)commonInit {
+    self.vapView = [[VAPView alloc] initWithFrame:self.bounds];
+    [self addSubview:self.vapView];
+}
+
+- (void)vapWrapView_playHWDMP4:(NSString *)filePath
+                   repeatCount:(NSInteger)repeatCount
+                      delegate:(id<VAPWrapViewDelegate>)delegate {
+    
+    self.delegate = delegate;
+    
+    [self.vapView playHWDMP4:filePath repeatCount:repeatCount delegate:self];
+}
+
+#pragma mark - Private
+
+- (void)p_setupContentModeWithConfig:(QGVAPConfigModel *)config {
+    CGFloat realWidth = 0.;
+    CGFloat realHeight = 0.;
+    
+    CGFloat layoutWidth = self.bounds.size.width;
+    CGFloat layoutHeight = self.bounds.size.height;
+    
+    CGFloat layoutRatio = self.bounds.size.width / self.bounds.size.height;
+    CGFloat videoRatio = config.info.size.width / config.info.size.height;
+    
+    switch (self.contentMode) {
+        case QGVAPWrapViewContentModeScaleToFill:
+        {
+
+        }
+            break;
+        case QGVAPWrapViewContentModeAspectFit:
+        {
+            if (layoutRatio < videoRatio) {
+                realWidth = layoutWidth;
+                realHeight = realWidth / videoRatio;
+            } else {
+                realHeight = layoutHeight;
+                realWidth = videoRatio * realHeight;
+            }
+            
+            self.vapView.frame = CGRectMake(0, 0, realWidth, realHeight);
+            self.vapView.center = self.center;
+        }
+            break;;
+        case QGVAPWrapViewContentModeAspectFill:
+        {
+            if (layoutRatio > videoRatio) {
+                realWidth = layoutWidth;
+                realHeight = realWidth / videoRatio;
+            } else {
+                realHeight = layoutHeight;
+                realWidth = videoRatio * realHeight;
+            }
+            
+            self.vapView.frame = CGRectMake(0, 0, realWidth, realHeight);
+            self.vapView.center = self.center;
+        }
+            break;;
+        default:
+            break;
+    }
+}
+
+#pragma mark -  mp4 hwd delegate
+
+#pragma mark -- 播放流程
+- (void)viewDidStartPlayMP4:(VAPView *)container {
+    if ([self.delegate respondsToSelector:@selector(vapWrap_viewDidStartPlayMP4:)]) {
+        [self.delegate vapWrap_viewDidStartPlayMP4:container];
+    }
+}
+
+- (void)viewDidFinishPlayMP4:(NSInteger)totalFrameCount view:(UIView *)container {
+    //note:在子线程被调用
+    if ([self.delegate respondsToSelector:@selector(vapWrap_viewDidFinishPlayMP4:view:)]) {
+        [self.delegate vapWrap_viewDidFinishPlayMP4:totalFrameCount view:container];
+    }
+}
+
+- (void)viewDidPlayMP4AtFrame:(QGMP4AnimatedImageFrame *)frame view:(UIView *)container {
+    //note:在子线程被调用
+    if ([self.delegate respondsToSelector:@selector(vapWrap_viewDidPlayMP4AtFrame:view:)]) {
+        [self.delegate vapWrap_viewDidPlayMP4AtFrame:frame view:container];
+    }
+}
+
+- (void)viewDidStopPlayMP4:(NSInteger)lastFrameIndex view:(UIView *)container {
+    //note:在子线程被调用
+    if ([self.delegate respondsToSelector:@selector(vapWrap_viewDidStopPlayMP4:view:)]) {
+        [self.delegate vapWrap_viewDidStopPlayMP4:lastFrameIndex view:container];
+    }
+}
+
+- (BOOL)shouldStartPlayMP4:(VAPView *)container config:(QGVAPConfigModel *)config {
+    [self p_setupContentModeWithConfig:config];
+    
+    if ([self.delegate respondsToSelector:@selector(vapWrap_viewshouldStartPlayMP4:config:)]) {
+        return [self.delegate vapWrap_viewshouldStartPlayMP4:container config:config];
+    }
+    return YES;
+}
+
+- (void)viewDidFailPlayMP4:(NSError *)error {
+    if ([self.delegate respondsToSelector:@selector(vapWrap_viewDidFailPlayMP4:)]) {
+        [self.delegate vapWrap_viewDidFailPlayMP4:error];
+    }
+}
+
+#pragma mark -- 融合特效的接口 vapx
+
+//provide the content for tags, maybe text or url string ...
+- (NSString *)contentForVapTag:(NSString *)tag resource:(QGVAPSourceInfo *)info {
+    if ([self.delegate respondsToSelector:@selector(vapWrapview_contentForVapTag:resource:)]) {
+        return [self.delegate vapWrapview_contentForVapTag:tag resource:info];
+    }
+    
+    return nil;
+}
+
+//provide image for url from tag content
+- (void)loadVapImageWithURL:(NSString *)urlStr context:(NSDictionary *)context completion:(VAPImageCompletionBlock)completionBlock {
+    if ([self.delegate respondsToSelector:@selector(vapWrapView_loadVapImageWithURL:context:completion:)]) {
+        [self.delegate vapWrapView_loadVapImageWithURL:urlStr context:context completion:completionBlock];
+    }
+}
+
+@end

+ 8 - 6
iOS/QGVAPlayerDemo/QGVAPlayerDemo.xcodeproj/project.pbxproj

@@ -543,9 +543,9 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
-				CODE_SIGN_STYLE = Automatic;
+				CODE_SIGN_STYLE = Manual;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-				DEVELOPMENT_TEAM = 6W55574XBS;
+				DEVELOPMENT_TEAM = N4S5894589;
 				ENABLE_BITCODE = NO;
 				FRAMEWORK_SEARCH_PATHS = "$(inherited)";
 				HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../QGVAPlayer/QGVAPlayer/**";
@@ -556,8 +556,9 @@
 					"@executable_path/Frameworks",
 				);
 				LIBRARY_SEARCH_PATHS = "$(inherited)";
-				PRODUCT_BUNDLE_IDENTIFIER = com.tencent.QGVAPlayerDemo;
+				PRODUCT_BUNDLE_IDENTIFIER = com.tencent.QGVAPlayerDemo111;
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = GeneralProfile;
 				TARGETED_DEVICE_FAMILY = "1,2";
 			};
 			name = Debug;
@@ -566,8 +567,8 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
-				CODE_SIGN_STYLE = Automatic;
-				DEVELOPMENT_TEAM = 6W55574XBS;
+				CODE_SIGN_STYLE = Manual;
+				DEVELOPMENT_TEAM = N4S5894589;
 				ENABLE_BITCODE = NO;
 				FRAMEWORK_SEARCH_PATHS = "$(inherited)";
 				HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../QGVAPlayer/QGVAPlayer/**";
@@ -578,8 +579,9 @@
 					"@executable_path/Frameworks",
 				);
 				LIBRARY_SEARCH_PATHS = "$(inherited)";
-				PRODUCT_BUNDLE_IDENTIFIER = com.tencent.QGVAPlayerDemo;
+				PRODUCT_BUNDLE_IDENTIFIER = com.tencent.QGVAPlayerDemo111;
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = GeneralProfile;
 				TARGETED_DEVICE_FAMILY = "1,2";
 			};
 			name = Release;

+ 37 - 3
iOS/QGVAPlayerDemo/QGVAPlayerDemo/ViewController.m

@@ -15,11 +15,15 @@
 
 #import "ViewController.h"
 #import "UIView+VAP.h"
+#import "QGVAPWrapView.h"
 
-@interface ViewController () <HWDMP4PlayDelegate>
+@interface ViewController () <HWDMP4PlayDelegate, VAPWrapViewDelegate>
 
 @property (nonatomic, strong) UIButton *vapButton;
 @property (nonatomic, strong) UIButton *vapxButton;
+@property (nonatomic, strong) UIButton *vapWrapViewButton;
+
+@property (nonatomic, strong) VAPView *vapView;
 
 @end
 
@@ -61,6 +65,13 @@ void qg_VAP_Logger_handler(VAPLogLevel level, const char* file, int line, const
     [_vapxButton setTitle:@"融合特效" forState:UIControlStateNormal];
     [_vapxButton addTarget:self action:@selector(playVapx) forControlEvents:UIControlEventTouchUpInside];
     [self.view addSubview:_vapxButton];
+    
+    //使用WrapView,支持ContentMode
+    _vapWrapViewButton = [[UIButton alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_vapxButton.frame)+60, CGRectGetWidth(self.view.frame), 90)];
+    _vapWrapViewButton.backgroundColor = [UIColor lightGrayColor];
+    [_vapWrapViewButton setTitle:@"WrapView-ContentMode" forState:UIControlStateNormal];
+    [_vapWrapViewButton addTarget:self action:@selector(playVapWithWrapView) forControlEvents:UIControlEventTouchUpInside];
+    [self.view addSubview:_vapWrapViewButton];
 }
 
 #pragma mark - 各种类型的播放
@@ -74,7 +85,7 @@ void qg_VAP_Logger_handler(VAPLogLevel level, const char* file, int line, const
     mp4View.userInteractionEnabled = YES;
     UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onImageviewTap:)];
     [mp4View addGestureRecognizer:tap];
-    NSString *resPath = [NSString stringWithFormat:@"%@/Resource/test.mp4", [[NSBundle mainBundle] resourcePath]];
+    NSString *resPath = [NSString stringWithFormat:@"%@/Resource/demo.mp4", [[NSBundle mainBundle] resourcePath]];
     //单纯播放的接口
     //[mp4View playHWDMp4:resPath];
     //指定素材混合模式,重复播放次数,delegate的接口
@@ -83,7 +94,7 @@ void qg_VAP_Logger_handler(VAPLogLevel level, const char* file, int line, const
 
 //vap动画
 - (void)playVapx {
-    NSString *mp4Path = [NSString stringWithFormat:@"%@/Resource/vap1.mp4", [[NSBundle mainBundle] resourcePath]];
+    NSString *mp4Path = [NSString stringWithFormat:@"%@/Resource/vap.mp4", [[NSBundle mainBundle] resourcePath]];
     VAPView *mp4View = [[VAPView alloc] initWithFrame:self.view.bounds];
     [self.view addSubview:mp4View];
     mp4View.center = self.view.center;
@@ -93,6 +104,18 @@ void qg_VAP_Logger_handler(VAPLogLevel level, const char* file, int line, const
     [mp4View playHWDMP4:mp4Path repeatCount:-1 delegate:self];
 }
 
+/// 使用WrapView,支持ContentMode
+- (void)playVapWithWrapView {
+    QGVAPWrapView *wrapView = [[QGVAPWrapView alloc] initWithFrame:self.view.bounds];
+    wrapView.center = self.view.center;
+    wrapView.contentMode = QGVAPWrapViewContentModeAspectFit;
+    [self.view addSubview:wrapView];
+    NSString *resPath = [NSString stringWithFormat:@"%@/Resource/demo.mp4", [[NSBundle mainBundle] resourcePath]];
+    [wrapView vapWrapView_playHWDMP4:resPath repeatCount:-1 delegate:self];
+    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onImageviewTap:)];
+    [wrapView addGestureRecognizer:tap];
+}
+
 #pragma mark -  mp4 hwd delegate
 
 #pragma mark -- 播放流程
@@ -153,4 +176,15 @@ void qg_VAP_Logger_handler(VAPLogLevel level, const char* file, int line, const
     [ges.view removeFromSuperview];
 }
 
+#pragma mark - WrapViewDelegate
+
+//provide the content for tags, maybe text or url string ...
+- (NSString *)vapWrapview_contentForVapTag:(NSString *)tag resource:(QGVAPSourceInfo *)info {
+    return nil;
+}
+
+//provide image for url from tag content
+- (void)vapWrapView_loadVapImageWithURL:(NSString *)urlStr context:(NSDictionary *)context completion:(VAPImageCompletionBlock)completionBlock {
+}
+
 @end

BIN
iOS/QGVAPlayerDemo/Resource/b_frame.mp4


BIN
iOS/QGVAPlayerDemo/Resource/demo.mp4


BIN
iOS/QGVAPlayerDemo/Resource/destroy.mp4


BIN
iOS/QGVAPlayerDemo/Resource/test.mp4


BIN
iOS/QGVAPlayerDemo/Resource/vap.mp4


BIN
iOS/QGVAPlayerDemo/Resource/vap1.mp4


BIN
iOS/QGVAPlayerDemo/Resource/vap_264_classical.mp4


BIN
iOS/QGVAPlayerDemo/Resource/vap_265.mp4


BIN
iOS/QGVAPlayerDemo/Resource/vap_265_classical.mp4


BIN
iOS/QGVAPlayerDemo/Resource/vap_265_hvc1.mp4