From 4efede279e991b118f68945bcf0a0b9992e177ab Mon Sep 17 00:00:00 2001 From: Brook Date: Sun, 15 Sep 2019 16:11:10 +0800 Subject: [PATCH] Add CropCommand class --- WAVideoBox.xcodeproj/project.pbxproj | 6 ++ .../WAAVSeCommand/WAAVSECropCommand.h | 21 +++++ .../WAAVSeCommand/WAAVSECropCommand.m | 84 +++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 WAVideoBox/WAVideoBox/WAAVSeCommand/WAAVSECropCommand.h create mode 100644 WAVideoBox/WAVideoBox/WAAVSeCommand/WAAVSECropCommand.m diff --git a/WAVideoBox.xcodeproj/project.pbxproj b/WAVideoBox.xcodeproj/project.pbxproj index 72218e5..ca734f2 100644 --- a/WAVideoBox.xcodeproj/project.pbxproj +++ b/WAVideoBox.xcodeproj/project.pbxproj @@ -34,6 +34,7 @@ 3B90283821E1FF22001B1497 /* nature.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = 3B90283321E1FF22001B1497 /* nature.mp4 */; }; 3BCAF55621E72B8000663097 /* test2.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = 3BCAF55521E72B8000663097 /* test2.mp4 */; }; 3BD923AA21E44D8F007D85B8 /* test1.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = 3BD923A921E44D8F007D85B8 /* test1.mp4 */; }; + E43E6F47232E27BB0025C062 /* WAAVSECropCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = E43E6F46232E27BA0025C062 /* WAAVSECropCommand.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -103,6 +104,8 @@ 3B90283321E1FF22001B1497 /* nature.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = nature.mp4; sourceTree = ""; }; 3BCAF55521E72B8000663097 /* test2.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = test2.mp4; sourceTree = ""; }; 3BD923A921E44D8F007D85B8 /* test1.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = test1.mp4; sourceTree = ""; }; + E43E6F45232E27BA0025C062 /* WAAVSECropCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WAAVSECropCommand.h; sourceTree = ""; }; + E43E6F46232E27BA0025C062 /* WAAVSECropCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WAAVSECropCommand.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -201,6 +204,8 @@ 3B9027FF21E1F2F3001B1497 /* WAAVSeCommand */ = { isa = PBXGroup; children = ( + E43E6F45232E27BA0025C062 /* WAAVSECropCommand.h */, + E43E6F46232E27BA0025C062 /* WAAVSECropCommand.m */, 3B90280A21E1F2F3001B1497 /* WAAVSEComposition.h */, 3B90281521E1F2F3001B1497 /* WAAVSEComposition.m */, 3B90280221E1F2F3001B1497 /* WAAVSECommand.h */, @@ -387,6 +392,7 @@ 3B222FF921E863DC0056CE83 /* WAAVSEExtractSoundCommand.m in Sources */, 3B90282121E1F2F3001B1497 /* WAAVSEReplaceSoundCommand.m in Sources */, 3B9027DB21E1F2E9001B1497 /* main.m in Sources */, + E43E6F47232E27BB0025C062 /* WAAVSECropCommand.m in Sources */, 3B90281B21E1F2F3001B1497 /* WAAVSEGearboxCommand.m in Sources */, 3B90281D21E1F2F3001B1497 /* WAAVSERotateCommand.m in Sources */, 3B9027CD21E1F2E7001B1497 /* AppDelegate.m in Sources */, diff --git a/WAVideoBox/WAVideoBox/WAAVSeCommand/WAAVSECropCommand.h b/WAVideoBox/WAVideoBox/WAAVSeCommand/WAAVSECropCommand.h new file mode 100644 index 0000000..ca73699 --- /dev/null +++ b/WAVideoBox/WAVideoBox/WAAVSeCommand/WAAVSECropCommand.h @@ -0,0 +1,21 @@ +// +// WAAVSECropCommand.h +// WAVideoBox +// +// Created by Hallfry on 2019/4/17 +// Modified by Hallfry +// Copyright © 2019年 XPLO. All rights reserved. +// 区域裁剪 + + +#import "WAAVSECommand.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface WAAVSECropCommand : WAAVSECommand + +- (void)performWithAsset:(AVAsset *)asset cropRect:(CGRect)cropRect; + +@end + +NS_ASSUME_NONNULL_END diff --git a/WAVideoBox/WAVideoBox/WAAVSeCommand/WAAVSECropCommand.m b/WAVideoBox/WAVideoBox/WAAVSeCommand/WAAVSECropCommand.m new file mode 100644 index 0000000..f5ad06c --- /dev/null +++ b/WAVideoBox/WAVideoBox/WAAVSeCommand/WAAVSECropCommand.m @@ -0,0 +1,84 @@ +// +// WAAVSECropCommand.m +// WAVideoBox +// +// Created by Hallfry on 2019/4/17 +// Modified by Hallfry +// Copyright © 2019年 XPLO. All rights reserved. +// + + +#import "WAAVSECropCommand.h" + + +@interface AVAssetTrack(XPAssetTrack) + +- (CGAffineTransform)getTransformWithCropRect:(CGRect)cropRect; + +@end + +@implementation AVAssetTrack(XPAssetTrack) +- (CGAffineTransform)getTransformWithCropRect:(CGRect)cropRect { + + CGSize renderSize = cropRect.size; + CGFloat renderScale = renderSize.width / cropRect.size.width; + CGPoint offset = CGPointMake(-cropRect.origin.x, -cropRect.origin.y); + double rotation = atan2(self.preferredTransform.b, self.preferredTransform.a); + + CGPoint rotationOffset = CGPointMake(0, 0); + if (self.preferredTransform.b == -1.0) { // 倒着拍 -M_PI_2 + rotationOffset.y = self.naturalSize.width; + } else if (self.preferredTransform.c == -1.0) { // 正着拍 M_PI_2 + // 奇怪的偏移 + rotationOffset.x = self.naturalSize.height; + } else if (self.preferredTransform.a == -1.0) { // 两侧拍 M_PI + rotationOffset.x = self.naturalSize.width; + rotationOffset.y = self.naturalSize.height; + } + + CGAffineTransform transform = CGAffineTransformIdentity; + transform = CGAffineTransformScale(transform, renderScale, renderScale); + transform = CGAffineTransformTranslate(transform, offset.x + rotationOffset.x, offset.y + rotationOffset.y); + transform = CGAffineTransformRotate(transform, rotation); + + return transform; +} + +@end + + +@implementation WAAVSECropCommand + +- (void)performWithAsset:(AVAsset *)asset cropRect:(CGRect)cropRect { + [super performWithAsset:asset]; + + if ([[self.composition.mutableComposition tracksWithMediaType:AVMediaTypeVideo] count] != 0) { + + [super performVideoCompopsition]; + + // 绿边问题,是因为宽或高不是偶数 + int64_t renderWidth = round(cropRect.size.width); + int64_t renderHeight = round(cropRect.size.height); + if (renderWidth % 2 != 0) { + renderWidth -= 1; + } + if (renderHeight % 2 != 0) { + renderHeight -= 1; + } + + AVMutableVideoCompositionInstruction *instruction = [self.composition.instructions lastObject]; + AVMutableVideoCompositionLayerInstruction *layerInstruction = (AVMutableVideoCompositionLayerInstruction *)instruction.layerInstructions[0]; + + // 获取父类的属性进行方向矫正 + // 更安全的话,可以考虑让父类暴露属性 + AVAssetTrack *videoTrack = [self valueForKey:@"assetVideoTrack"]; + + [layerInstruction setTransform:[videoTrack getTransformWithCropRect:cropRect] atTime:kCMTimeZero]; + [layerInstruction setOpacity:1.0 atTime:kCMTimeZero]; + + + self.composition.mutableVideoComposition.renderSize = CGSizeMake(renderWidth, renderHeight); + } +} + +@end