diff --git a/APIDiffs/api-diffs-1.13.0.md b/APIDiffs/api-diffs-1.13.0.md new file mode 100644 index 00000000..f077a48a --- /dev/null +++ b/APIDiffs/api-diffs-1.13.0.md @@ -0,0 +1,39 @@ +# PLShortVideoKit 1.11.1 to 1.13.0 API Differences + +## General Headers + + +``` +PLShortVideoTranscoder +``` + +- *Added* @property (assign, nonatomic) CGRect videoSelectedRect; + +- *Added* @property (assign, nonatomic) CGSize destVideoSize; + +- *Added* @property (assign, nonatomic) float videoFrameRate; + +- *Added* + (CGRect)videoDisplay:(AVAsset *)asset bounds:(CGRect)bounds rotate:(PLSPreviewOrientation)previewOrientation; + +``` +PLSVideoMixRecorder.h +``` + +- *Added* - (void)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder microphoneSourceDidGetAudioBufferList:(AudioBufferList *__nonnull)audioBufferList; + +- *Added* - (void)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder sampleSourceDidGetAudioBufferList:(AudioBufferList *__nonnull)audioBufferList; + +- *Added* - (void)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder didGetMergeAudioBufferList:(AudioBufferList * __nonnull)audioBufferList; + +- *Deprecated* - (CMSampleBufferRef __nonnull)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder microphoneSourceDidGetSampleBuffer:(CMSampleBufferRef __nonnull)sampleBuffer; + +- *Deprecated* - (CMSampleBufferRef __nonnull)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder sampleSourceDidGetSampleBuffer:(CMSampleBufferRef __nonnull)sampleBuffer; + +- *Deprecated* - (CMSampleBufferRef __nonnull)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder didGetMergeAudioSampleBuffer:(CMSampleBufferRef __nonnull)sampleBuffer; + + + + + + + diff --git a/Example/PLShortVideoKitDemo.xcodeproj/project.pbxproj b/Example/PLShortVideoKitDemo.xcodeproj/project.pbxproj index 8eba3e7d..8f110550 100644 --- a/Example/PLShortVideoKitDemo.xcodeproj/project.pbxproj +++ b/Example/PLShortVideoKitDemo.xcodeproj/project.pbxproj @@ -173,6 +173,7 @@ 760F7706202AF92A0052F513 /* BaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 760F76FA202AF92A0052F513 /* BaseViewController.m */; }; 760F7707202AF92A0052F513 /* PLSPlayerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 760F76FB202AF92A0052F513 /* PLSPlayerView.m */; }; 760F7709202AF92A0052F513 /* PLSClipMulitMediaView.m in Sources */ = {isa = PBXBuildFile; fileRef = 760F76FF202AF92A0052F513 /* PLSClipMulitMediaView.m */; }; + 76181FD721186ADE005F4F8B /* scope_image.png in Resources */ = {isa = PBXBuildFile; fileRef = 76181FD621186ADE005F4F8B /* scope_image.png */; }; 7623E9E020B5414600847998 /* ImageRotateViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7623E9DF20B5414600847998 /* ImageRotateViewController.m */; }; 7635E3E120CE494900E36027 /* 3video_template@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 7635E3DB20CE494800E36027 /* 3video_template@3x.png */; }; 7635E3E220CE494900E36027 /* 2video_template@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 7635E3DC20CE494800E36027 /* 2video_template@2x.png */; }; @@ -442,6 +443,7 @@ 760F7700202AF92A0052F513 /* MulitPhotoAlbumViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MulitPhotoAlbumViewController.h; sourceTree = ""; }; 760F7701202AF92A0052F513 /* BaseViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BaseViewController.h; sourceTree = ""; }; 760F7702202AF92A0052F513 /* PLSPlayerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PLSPlayerView.h; sourceTree = ""; }; + 76181FD621186ADE005F4F8B /* scope_image.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = scope_image.png; sourceTree = ""; }; 7623E9DE20B5414600847998 /* ImageRotateViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImageRotateViewController.h; sourceTree = ""; }; 7623E9DF20B5414600847998 /* ImageRotateViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ImageRotateViewController.m; sourceTree = ""; }; 7635E3DB20CE494800E36027 /* 3video_template@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "3video_template@3x.png"; path = "images/3video_template@3x.png"; sourceTree = ""; }; @@ -637,6 +639,7 @@ 0A1DDC7E20BBE0CA00DF53B6 /* rotate_background.png */, 0A1DDC8020BBE0CA00DF53B6 /* rotate_image.png */, 0ADCCC5D209BFAA300BC114A /* gif1.gif */, + 76181FD621186ADE005F4F8B /* scope_image.png */, 0ADCCC5C209BFAA300BC114A /* gif2.gif */, 0ADCCC5E209BFAA300BC114A /* gif3.gif */, 0ADCCC5B209BFAA200BC114A /* gif4.gif */, @@ -963,7 +966,7 @@ 0A9435791E6CA2E2008845A3 /* Frameworks */, 0A94357A1E6CA2E2008845A3 /* Resources */, B051BAB51EADFEF900385FF0 /* ShellScript */, - E97B874681F4942673BDAA0F /* [CP] Embed Pods Frameworks */, + F12800A47717371B5B955FDD /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -985,7 +988,7 @@ TargetAttributes = { 0A94357B1E6CA2E2008845A3 = { CreatedOnToolsVersion = 8.2.1; - DevelopmentTeam = W2TP34G2MM; + DevelopmentTeam = GDFHW66V92; ProvisioningStyle = Automatic; }; }; @@ -1140,6 +1143,7 @@ 0A398F761ED62A1500996229 /* btn_banner_a@3x.png in Resources */, 0A24C5ED1EE951B900B2314E /* movie.png in Resources */, 0A1DDC8120BBE0CB00DF53B6 /* rotate_background.png in Resources */, + 76181FD721186ADE005F4F8B /* scope_image.png in Resources */, 0AECA4F41E884CD200AF2931 /* btn_back.png in Resources */, 7635E40820CE8F5900E36027 /* select_meterial@2x.png in Resources */, 0AE8ACA01F065DCD006166E2 /* Greenery.m4a in Resources */, @@ -1206,7 +1210,7 @@ shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Fabric/run\" 356922ded861e8764b53656f328bf3e7610fb59b 4e8f96a6c525321b1833e0fdb19f396702d2cb0b6e581fdf80efde45b2a3bfc1\n\n\nshortVersion=$(/usr/libexec/PlistBuddy -c \"Print :CFBundleShortVersionString\" \"${PROJECT_DIR}/${INFOPLIST_FILE}\")\nbuildNumber=$(/usr/libexec/PlistBuddy -c \"Print :CFBundleVersion\" \"${PROJECT_DIR}/${INFOPLIST_FILE}\")\n\ngitVersion=$(git log -1 --pretty=format:\"git-%cd-%h\" --date=short 2> /dev/null)\nbuildNumber=\"$shortVersion.$gitVersion\"\n\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $buildNumber\" \"${PROJECT_DIR}/${INFOPLIST_FILE}\"\n\n"; }; - E97B874681F4942673BDAA0F /* [CP] Embed Pods Frameworks */ = { + F12800A47717371B5B955FDD /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -1403,7 +1407,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = W2TP34G2MM; + DEVELOPMENT_TEAM = GDFHW66V92; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -1434,7 +1438,7 @@ baseConfigurationReference = 85B60FAE619932ED649E6840 /* Pods-PLShortVideoKitDemo.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = W2TP34G2MM; + DEVELOPMENT_TEAM = GDFHW66V92; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", diff --git a/Example/PLShortVideoKitDemo/Info.plist b/Example/PLShortVideoKitDemo/Info.plist index d2fcb0e2..de375bd8 100644 --- a/Example/PLShortVideoKitDemo/Info.plist +++ b/Example/PLShortVideoKitDemo/Info.plist @@ -15,9 +15,9 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.11.1 + 1.13.0 CFBundleVersion - 1.11.1.git-2018-07-27-0236195 + 1.13.0.git-2018-08-06-5d9d340 Fabric APIKey diff --git a/Example/PLShortVideoKitDemo/MixRecordViewController.m b/Example/PLShortVideoKitDemo/MixRecordViewController.m index 145001d4..d1074d3d 100644 --- a/Example/PLShortVideoKitDemo/MixRecordViewController.m +++ b/Example/PLShortVideoKitDemo/MixRecordViewController.m @@ -144,7 +144,7 @@ - (void)setupvideoMixRecorder { self.videoConfiguration.position = AVCaptureDevicePositionFront; self.videoConfiguration.sessionPreset = AVCaptureSessionPresetiFrame1280x720; self.videoConfiguration.videoFrameRate = 25; - self.videoConfiguration.averageVideoBitRate = 1024*1500;//1.5M + self.videoConfiguration.averageVideoBitRate = 1024*2000;//2.0M self.videoConfiguration.videoSize = CGSizeMake(720, 640); self.videoConfiguration.cameraVideoFrame = CGRectMake(0, 0, 360, 640); self.videoConfiguration.sampleVideoFrame = CGRectMake(360, 0, 360, 640); @@ -657,26 +657,25 @@ - (void)videoMixRecorder:(PLSVideoMixRecorder *)recorder didFinishSampleMediaDec self.fileEndDecoding = YES; } -// Microphone 采集数据回调 -- (CMSampleBufferRef __nonnull)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder microphoneSourceDidGetSampleBuffer:(CMSampleBufferRef __nonnull)sampleBuffer{ - return sampleBuffer; +// Microphone 采集数据回调, 如果想替换 Microphone 采集的音频数据,可以直接将用于替换的音频数据放在 audioBufferList 中 +- (void)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder microphoneSourceDidGetAudioBufferList:(AudioBufferList *__nonnull)audioBufferList { } -// 素材视频音频数据回调 -- (CMSampleBufferRef __nonnull)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder sampleSourceDidGetSampleBuffer:(CMSampleBufferRef __nonnull)sampleBuffer{ - return sampleBuffer; +// 素材视频音频数据回调,如果想替换素材的音频数据,可以直接将用于替换的音频数据放在 audioBufferList 中 +- (void)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder sampleSourceDidGetAudioBufferList:(AudioBufferList *__nonnull)audioBufferList { } + // 素材视频数据回调 - (CVPixelBufferRef __nonnull)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder sampleSourceDidGetPixelBuffer:(CVPixelBufferRef __nonnull)pixelBuffer{ return pixelBuffer; } -// 混音数据回调 -- (CMSampleBufferRef __nonnull)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder didGetMergeAudioSampleBuffer:(CMSampleBufferRef __nonnull)sampleBuffer{ - return sampleBuffer; +// 混音数据回调, 如果想替换混合后的音频数据,可以直接将用于替换的音频数据放在 audioBufferList 中 +- (void)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder didGetMergeAudioBufferList:(AudioBufferList * __nonnull)audioBufferList { } + // 合并之后的视频数据回调 - (CVPixelBufferRef __nonnull)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder didGetMergePixelBuffer:(CVPixelBufferRef __nonnull)pixelBuffer{ return pixelBuffer; diff --git a/Example/PLShortVideoKitDemo/MovieTransCodeViewController.m b/Example/PLShortVideoKitDemo/MovieTransCodeViewController.m index a70f8a6b..7353bced 100644 --- a/Example/PLShortVideoKitDemo/MovieTransCodeViewController.m +++ b/Example/PLShortVideoKitDemo/MovieTransCodeViewController.m @@ -21,6 +21,14 @@ #define PLS_SCREEN_HEIGHT CGRectGetHeight([UIScreen mainScreen].bounds) +typedef enum : NSUInteger { + enumPanPositionTopLeft, + enumPanPositionTopRight, + enumPanPositionBottomLeft, + enumPanPositionBottomRight, + enumPanPositionCenter, +} EnumPanPosition; + @interface MovieTransCodeViewController () < PLSClipMovieViewDelegate, @@ -52,6 +60,12 @@ @interface MovieTransCodeViewController () @property (assign, nonatomic) float bitrate; @property (strong, nonatomic) PLShortVideoTranscoder *shortVideoTranscoder; +@property (strong, nonatomic) UIView *maxScopeView; +@property (strong, nonatomic) UIImageView *scopeView; + +@property (strong, nonatomic) AVAsset *asset; +@property (assign, nonatomic) EnumPanPosition enumTapPosition; + @end @implementation MovieTransCodeViewController @@ -74,6 +88,8 @@ - (void)viewDidLoad { [self setupSelectionView]; [self setupClipMovieView]; + + [self setupScopeCutView]; } - (void)viewWillAppear:(BOOL)animated { @@ -103,6 +119,9 @@ - (void)setupShortVideoEditor { self.movieSettings[PLSDurationKey] = [NSNumber numberWithFloat:CMTimeGetSeconds(asset.duration)]; self.movieSettings[PLSVolumeKey] = [NSNumber numberWithFloat:1.0f]; + // 剪裁使用到 + self.asset = asset; + // 视频编辑类 self.shortVideoEditor = [[PLShortVideoEditor alloc] initWithAsset:asset videoSize:CGSizeZero]; self.shortVideoEditor.delegate = self; @@ -183,12 +202,13 @@ - (void)setupBaseToolboxView { - (void)setupSelectionView { CGFloat rotateViewTopSpace; if (PLS_SCREEN_HEIGHT > 568) { - rotateViewTopSpace = PLS_BaseToolboxView_HEIGHT + PLS_SCREEN_WIDTH + 32; + rotateViewTopSpace = PLS_BaseToolboxView_HEIGHT + PLS_SCREEN_WIDTH + 5; } else{ rotateViewTopSpace = PLS_BaseToolboxView_HEIGHT + PLS_SCREEN_WIDTH; } self.selectionView = [[PLSSelectionView alloc] initWithFrame:CGRectMake(0, rotateViewTopSpace, PLS_SCREEN_WIDTH, 35) lineWidth:1 lineColor:[UIColor blackColor]]; + self.selectionView.backgroundColor = [UIColor redColor]; [self.selectionView setItemsWithTitle:[NSArray arrayWithObjects:@"Medium", @"Highest", @"480P", @"540P", @"720P", @"1080P", nil] normalItemColor:[UIColor whiteColor] selectItemColor:[UIColor blackColor] normalTitleColor:[UIColor blackColor] selectTitleColor:[UIColor whiteColor] titleTextSize:15 selectItemNumber:3]; self.selectionView.delegate = self; self.selectionView.layer.cornerRadius = 5.0; @@ -207,8 +227,17 @@ - (void)setupSelectionView { rotateVideoButton.layer.borderWidth = 1; rotateVideoButton.layer.borderColor = [UIColor whiteColor].CGColor; + UILabel *cutLabel = [[UILabel alloc] init]; + cutLabel.font = [UIFont systemFontOfSize:14]; + cutLabel.text = @"移动红色线框选择剪裁区域"; + cutLabel.textColor = [UIColor colorWithWhite:1 alpha:.5]; + [cutLabel sizeToFit]; + cutLabel.frame = CGRectMake(5, rotateVideoButton.frame.origin.y + 10, cutLabel.bounds.size.width, cutLabel.bounds.size.height); + [self.view addSubview:cutLabel]; + [rotateVideoButton addTarget:self action:@selector(rotateVideoButtonEvent:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:rotateVideoButton]; + } - (void)setupClipMovieView { @@ -218,10 +247,26 @@ - (void)setupClipMovieView { [self.view addSubview:self.clipMovieView]; [self.clipMovieView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.bottom.mas_equalTo(0); - make.height.mas_equalTo(150); + make.height.mas_equalTo(145); }]; } +- (void)setupScopeCutView { + self.maxScopeView = [[UIView alloc] init]; + [self.shortVideoEditor.previewView addSubview:self.maxScopeView]; + self.maxScopeView.frame = [PLShortVideoTranscoder videoDisplay:self.asset bounds:self.shortVideoEditor.previewView.bounds rotate:self.rotateOrientation]; + + self.scopeView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"scope_image"]]; + self.scopeView.userInteractionEnabled = YES; + self.scopeView.layer.borderWidth = 1; + self.scopeView.layer.borderColor = [UIColor redColor].CGColor; + self.scopeView.frame = self.maxScopeView.bounds; + [self.maxScopeView addSubview:self.scopeView]; + + UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureHandle:)]; + [self.scopeView addGestureRecognizer:panGesture]; +} + // 加载视频转码的动画 - (void)loadActivityIndicatorView { if ([self.activityIndicatorView isAnimating]) { @@ -239,6 +284,103 @@ - (void)removeActivityIndicatorView { [self.activityIndicatorView stopAnimating]; } +- (void)panGestureHandle:(UIPanGestureRecognizer *)gestureRecognizer { + CGPoint transPoint = [gestureRecognizer translationInView:gestureRecognizer.view]; + [gestureRecognizer setTranslation:CGPointMake(0, 0) inView:gestureRecognizer.view]; + + switch (gestureRecognizer.state) { + + case UIGestureRecognizerStateBegan: { + + CGPoint point = [gestureRecognizer locationInView:gestureRecognizer.view]; + CGFloat edgeWidth = self.scopeView.bounds.size.width / 3; + CGFloat edgeHeight = self.scopeView.bounds.size.height / 3; + if (point.x <= edgeWidth && point.y <= edgeHeight) { + self.enumTapPosition = enumPanPositionTopLeft; + } else if (point.x <= edgeWidth && point.y >= self.scopeView.bounds.size.height - edgeHeight) { + self.enumTapPosition = enumPanPositionBottomLeft; + } else if (point.x >= self.scopeView.bounds.size.width - edgeWidth && point.y <= edgeHeight) { + self.enumTapPosition = enumPanPositionTopRight; + } else if (point.x >= self.scopeView.bounds.size.width - edgeWidth && point.y >= self.scopeView.bounds.size.height - edgeHeight) { + self.enumTapPosition = enumPanPositionBottomRight; + } else { + self.enumTapPosition = enumPanPositionCenter; + } + break; + + } + case UIGestureRecognizerStateChanged: { + + CGRect rect = self.scopeView.frame; + CGRect maxRect = self.maxScopeView.bounds; + + switch (self.enumTapPosition) { + case enumPanPositionTopLeft: { + transPoint.x = MIN(transPoint.x, rect.size.width); + transPoint.y = MIN(transPoint.y, rect.size.height); + if (rect.origin.x + transPoint.x < 0) { + transPoint.x = - rect.origin.x; + } + if (rect.origin.y + transPoint.y < 0) { + transPoint.y = - rect.origin.y; + } + rect = CGRectMake(rect.origin.x + transPoint.x, rect.origin.y + transPoint.y, rect.size.width - transPoint.x, rect.size.height - transPoint.y); + } + break; + + case enumPanPositionTopRight: { + transPoint.x = MIN(maxRect.size.width - rect.size.width - rect.origin.x, transPoint.x); + transPoint.x = MAX(-rect.size.width, transPoint.x); + transPoint.y = MIN(transPoint.y, rect.size.height); + if (rect.origin.y + transPoint.y < 0) { + transPoint.y = -rect.origin.y; + } + rect = CGRectMake(rect.origin.x, rect.origin.y + transPoint.y, rect.size.width + transPoint.x, rect.size.height - transPoint.y); + } + break; + case enumPanPositionBottomLeft: { + transPoint.x = MIN(transPoint.x, rect.size.width); + if (rect.origin.x + transPoint.x < 0) { + transPoint.x = - rect.origin.x; + } + transPoint.y = MAX(-rect.size.height, transPoint.y); + transPoint.y = MIN(maxRect.size.height - rect.size.height - rect.origin.y, transPoint.y); + + rect = CGRectMake(rect.origin.x + transPoint.x, rect.origin.y, rect.size.width - transPoint.x, rect.size.height + transPoint.y); + } + break; + case enumPanPositionBottomRight: { + transPoint.x = MIN(maxRect.size.width - rect.origin.x - rect.size.width, transPoint.x); + transPoint.y = MIN(maxRect.size.height - rect.origin.y - rect.size.height, transPoint.y); + transPoint.x = MAX(-rect.size.width, transPoint.x); + transPoint.y = MAX(-rect.size.height, transPoint.y); + + rect = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width + transPoint.x, rect.size.height + transPoint.y); + } + break; + case enumPanPositionCenter: { + rect = CGRectMake(rect.origin.x + transPoint.x, rect.origin.y + transPoint.y, rect.size.width, rect.size.height); + rect.origin.x = MAX(rect.origin.x, 0); + rect.origin.x = MIN(maxRect.size.width - rect.size.width, rect.origin.x); + rect.origin.y = MAX(rect.origin.y, 0); + rect.origin.y = MIN(maxRect.size.height - rect.size.height, rect.origin.y); + } + break; + } + self.scopeView.frame = rect; + + break; + } + case UIGestureRecognizerStateEnded: + case UIGestureRecognizerStateCancelled: { + + break; + } + default: + break; + } +} + #pragma mark - PLSClipMovieView delegate - (void)didStartDragView { @@ -326,6 +468,11 @@ - (void)rotateVideoButtonEvent:(UIButton *)button { self.rotateOrientation = [self.shortVideoEditor rotateVideoLayer]; NSLog(@"videoLayerOrientation: %ld", (long)self.rotateOrientation); + + + self.maxScopeView.frame = [PLShortVideoTranscoder videoDisplay:self.asset bounds:self.shortVideoEditor.previewView.bounds rotate:self.rotateOrientation]; + self.scopeView.frame = self.maxScopeView.bounds; + self.shortVideoTranscoder.videoSelectedRect = CGRectZero; } // 检查视频文件中是否含有视频轨道 @@ -374,6 +521,31 @@ - (void)movieTransCodeAction { self.shortVideoTranscoder.rotateOrientation = self.rotateOrientation; // self.shortVideoTranscoder.outputURL = [self getFileURL:@"videoTranscoder-outputURL"]; // 自定义视频的存放地址 + CGRect maxRect = self.maxScopeView.bounds; + if (CGRectEqualToRect(maxRect, self.scopeView.frame)) { + self.shortVideoTranscoder.videoSelectedRect = CGRectZero; + } else { + CGSize videoSize = [self.asset pls_videoSize]; + if (PLSPreviewOrientationLandscapeLeft == self.rotateOrientation || + PLSPreviewOrientationLandscapeRight == self.rotateOrientation) { + videoSize = CGSizeMake(videoSize.height, videoSize.width); + } + CGFloat scale = videoSize.width / maxRect.size.width; + + CGRect cutPixelFrame = CGRectMake( + (self.scopeView.frame.origin.x - maxRect.origin.x) * scale, + (self.scopeView.frame.origin.y - maxRect.origin.y) * scale, + self.scopeView.frame.size.width * scale, + self.scopeView.frame.size.height * scale + ); + self.shortVideoTranscoder.videoSelectedRect = cutPixelFrame; + self.shortVideoTranscoder.destVideoSize = CGSizeMake(cutPixelFrame.size.width / 1.5, cutPixelFrame.size.height / 1.5); + self.shortVideoTranscoder.videoFrameRate = 25; + + NSLog(@"设置剪裁区域:%@", NSStringFromCGRect(cutPixelFrame)); + NSLog(@"设置导出宽高:%@", NSStringFromCGSize(self.shortVideoTranscoder.destVideoSize)); + } + __weak typeof(self) weakSelf = self; [self.shortVideoTranscoder setCompletionBlock:^(NSURL *url){ diff --git a/Example/PLShortVideoKitDemo/PhotoAlbumViewController.m b/Example/PLShortVideoKitDemo/PhotoAlbumViewController.m index 2133722e..65f61775 100644 --- a/Example/PLShortVideoKitDemo/PhotoAlbumViewController.m +++ b/Example/PLShortVideoKitDemo/PhotoAlbumViewController.m @@ -13,6 +13,7 @@ #import "ViewRecordViewController.h" #import "EditViewController.h" +#define AlertViewShow(msg) [[[UIAlertView alloc] initWithTitle:@"warning" message:[NSString stringWithFormat:@"%@", msg] delegate:nil cancelButtonTitle:@"ok" otherButtonTitles:nil] show] #define iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO) #define PLS_RGBCOLOR(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1] #define PLS_SCREEN_WIDTH CGRectGetWidth([UIScreen mainScreen].bounds) @@ -289,6 +290,7 @@ @interface PhotoAlbumViewController () 7.1) - - PLShortVideoKit/ex-libMuseProcessor (1.11.1): + - PLShortVideoKit/ex-libMuseProcessor (1.13.0): - Qiniu (~> 7.1) - - PLShortVideoKit/libMuseProcessor (1.11.1): + - PLShortVideoKit/libMuseProcessor (1.13.0): - Qiniu (~> 7.1) - Qiniu (7.1.7): - AFNetworking (~> 3) @@ -67,7 +67,7 @@ SPEC CHECKSUMS: HappyDNS: dc6a164ee81979093123c241c6353bcf0218add6 Masonry: 7c429b56da9d4ee0bbb3ed77a5ea710d6a5df39e PLPlayerKit: 63a9c6a7661f497591c84121e854e8e6ac003256 - PLShortVideoKit: 2989b14d5df393ccecb73c3cd96291d5829a0af0 + PLShortVideoKit: 922cfb53e1a067fdaa3f27b46450f97d777c7b3e Qiniu: 56ea8b9d785326e45e3a6fdd45bdbc84f78d0eff PODFILE CHECKSUM: 52b7da48e404d168c557854032f9219299df1326 diff --git a/Example/Pods/Local Podspecs/PLShortVideoKit.podspec.json b/Example/Pods/Local Podspecs/PLShortVideoKit.podspec.json index 37457caa..7213da2e 100644 --- a/Example/Pods/Local Podspecs/PLShortVideoKit.podspec.json +++ b/Example/Pods/Local Podspecs/PLShortVideoKit.podspec.json @@ -1,6 +1,6 @@ { "name": "PLShortVideoKit", - "version": "1.11.1", + "version": "1.13.0", "summary": "PILI iOS short video record SDK", "homepage": "https://github.com/pili-engineering/PLShortVideoKit", "license": "Apache License 2.0", @@ -8,8 +8,7 @@ "pili": "pili@qiniu.com" }, "source": { - "git": "https://github.com/pili-engineering/PLShortVideoKit.git", - "tag": "v1.11.1" + "http": "http://sdk-release.qnsdk.com/PLShortVideoKit-v1.13.0.zip" }, "platforms": { "ios": "8.0" diff --git a/Example/Pods/Manifest.lock b/Example/Pods/Manifest.lock index 41717242..7237ebf3 100644 --- a/Example/Pods/Manifest.lock +++ b/Example/Pods/Manifest.lock @@ -23,13 +23,13 @@ PODS: - PLPlayerKit (3.3.1): - PLPlayerKit/iphoneos (= 3.3.1) - PLPlayerKit/iphoneos (3.3.1) - - PLShortVideoKit (1.11.1): - - PLShortVideoKit/ex-libMuseProcessor (= 1.11.1) - - PLShortVideoKit/libMuseProcessor (= 1.11.1) + - PLShortVideoKit (1.13.0): + - PLShortVideoKit/ex-libMuseProcessor (= 1.13.0) + - PLShortVideoKit/libMuseProcessor (= 1.13.0) - Qiniu (~> 7.1) - - PLShortVideoKit/ex-libMuseProcessor (1.11.1): + - PLShortVideoKit/ex-libMuseProcessor (1.13.0): - Qiniu (~> 7.1) - - PLShortVideoKit/libMuseProcessor (1.11.1): + - PLShortVideoKit/libMuseProcessor (1.13.0): - Qiniu (~> 7.1) - Qiniu (7.1.7): - AFNetworking (~> 3) @@ -67,7 +67,7 @@ SPEC CHECKSUMS: HappyDNS: dc6a164ee81979093123c241c6353bcf0218add6 Masonry: 7c429b56da9d4ee0bbb3ed77a5ea710d6a5df39e PLPlayerKit: 63a9c6a7661f497591c84121e854e8e6ac003256 - PLShortVideoKit: 2989b14d5df393ccecb73c3cd96291d5829a0af0 + PLShortVideoKit: 922cfb53e1a067fdaa3f27b46450f97d777c7b3e Qiniu: 56ea8b9d785326e45e3a6fdd45bdbc84f78d0eff PODFILE CHECKSUM: 52b7da48e404d168c557854032f9219299df1326 diff --git a/PLShortVideoKit.podspec b/PLShortVideoKit.podspec index 7d2eb5d5..4cd11bb0 100644 --- a/PLShortVideoKit.podspec +++ b/PLShortVideoKit.podspec @@ -9,12 +9,12 @@ Pod::Spec.new do |s| s.name = "PLShortVideoKit" - s.version = "1.11.1" + s.version = "1.13.0" s.summary = "PILI iOS short video record SDK" s.homepage = "https://github.com/pili-engineering/PLShortVideoKit" s.license = "Apache License 2.0" s.author = { "pili" => "pili@qiniu.com" } - s.source = { :git => "https://github.com/pili-engineering/PLShortVideoKit.git", :tag => "v#{s.version}" } + s.source = { :http => "http://sdk-release.qnsdk.com/PLShortVideoKit-v1.13.0.zip"} s.platform = :ios s.requires_arc = true diff --git a/Pod/Library/PLShortVideoKit.framework/Headers/PLSVideoMixRecorder.h b/Pod/Library/PLShortVideoKit.framework/Headers/PLSVideoMixRecorder.h index 1ec0a13c..b170c71c 100644 --- a/Pod/Library/PLShortVideoKit.framework/Headers/PLSVideoMixRecorder.h +++ b/Pod/Library/PLShortVideoKit.framework/Headers/PLSVideoMixRecorder.h @@ -58,12 +58,20 @@ */ - (CVPixelBufferRef __nonnull)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder cameraSourceDidGetPixelBuffer:(CVPixelBufferRef __nonnull)pixelBuffer; +/** + @abstract 获取到麦克风原数据时的回调,需要注意的是这个回调在 microphone 数据的输出线程,请不要做过于耗时的操作,否则可能阻塞该线程影响音频输出或其他未知问题 + 如果需要修改音频数据,可以直接对 audioBufferList 进行修改 + + @since v1.13.0 + */ +- (void)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder microphoneSourceDidGetAudioBufferList:(AudioBufferList *__nonnull)audioBufferList; + /** @abstract 获取到麦克风原数据时的回调,需要注意的是这个回调在 microphone 数据的输出线程,请不要做过于耗时的操作,否则可能阻塞该线程影响音频输出或其他未知问题 @since v1.11.0 */ -- (CMSampleBufferRef __nonnull)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder microphoneSourceDidGetSampleBuffer:(CMSampleBufferRef __nonnull)sampleBuffer; +- (CMSampleBufferRef __nonnull)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder microphoneSourceDidGetSampleBuffer:(CMSampleBufferRef __nonnull)sampleBuffer __deprecated_msg("Method deprecated in v1.13.0. Use `videoMixRecorder: microphoneSourceDidGetAudioBufferList:`"); #pragma mark -- 素材视频/音频数据的回调 /** @@ -74,12 +82,19 @@ - (CVPixelBufferRef __nonnull)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder sampleSourceDidGetPixelBuffer:(CVPixelBufferRef __nonnull)pixelBuffer; /** - @abstract 获取到素材数据时的回调,需要注意的是这个回调在 素材解码 数据的输出线程,请不要做过于耗时的操作,否则可能阻塞该线程影响音频输出或其他未知问题 + @abstract 获取到素材音频数据时的回调,需要注意的是这个回调在 素材解码 数据的输出线程,请不要做过于耗时的操作,否则可能阻塞该线程影响音频输出或其他未知问题 + 如果需要修改音频数据,可以直接对 audioBufferList 进行修改 - @since v1.11.1 + @since v1.13.0 */ -- (CMSampleBufferRef __nonnull)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder sampleSourceDidGetSampleBuffer:(CMSampleBufferRef __nonnull)sampleBuffer; +- (void)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder sampleSourceDidGetAudioBufferList:(AudioBufferList *__nonnull)audioBufferList; +/** + @abstract 获取到素材音频数据时的回调,需要注意的是这个回调在 素材解码 数据的输出线程,请不要做过于耗时的操作,否则可能阻塞该线程影响音频输出或其他未知问题 + + @since v1.11.0 + */ +- (CMSampleBufferRef __nonnull)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder sampleSourceDidGetSampleBuffer:(CMSampleBufferRef __nonnull)sampleBuffer __deprecated_msg("Method deprecated in v1.13.0. Use `videoMixRecorder: sampleSourceDidGetAudioBufferList:`"); #pragma mark -- 合并之后的视频/音频数据的回调 /** @@ -89,12 +104,20 @@ */ - (CVPixelBufferRef __nonnull)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder didGetMergePixelBuffer:(CVPixelBufferRef __nonnull)pixelBuffer; +/** + @abstract 合并之后数据的回调, 便于开发者对音频数据做处理,需要注意的是这个回调在 合并 的输出线程,请不要做过于耗时的操作,否则可能会导致帧率下降 + 如果需要修改音频数据,可以直接对 audioBufferList 进行修改 + + @since v1.13.0 + */ +- (void)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder didGetMergeAudioBufferList:(AudioBufferList * __nonnull)audioBufferList; + /** @abstract 合并之后数据的回调, 便于开发者对音频数据做处理,需要注意的是这个回调在 合并 的输出线程,请不要做过于耗时的操作,否则可能会导致帧率下降 @since v1.11.1 */ -- (CMSampleBufferRef __nonnull)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder didGetMergeAudioSampleBuffer:(CMSampleBufferRef __nonnull)sampleBuffer; +- (CMSampleBufferRef __nonnull)videoMixRecorder:(PLSVideoMixRecorder *__nonnull)recorder didGetMergeAudioSampleBuffer:(CMSampleBufferRef __nonnull)sampleBuffer __deprecated_msg("Method deprecated in v1.13.0. Use `videoMixRecorder: didGetMergeAudioBufferList:`"); #pragma mark -- 视频录制动作的回调 diff --git a/Pod/Library/PLShortVideoKit.framework/Headers/PLShortVideoTranscoder.h b/Pod/Library/PLShortVideoKit.framework/Headers/PLShortVideoTranscoder.h index a830da6d..76c22fa4 100644 --- a/Pod/Library/PLShortVideoKit.framework/Headers/PLShortVideoTranscoder.h +++ b/Pod/Library/PLShortVideoKit.framework/Headers/PLShortVideoTranscoder.h @@ -97,6 +97,31 @@ */ @property (assign, nonatomic) PLSPreviewOrientation rotateOrientation; +/** + @abstract 视频剪裁区域,默认为 CGRectZero,不剪裁. 如果不为 emptyRect,会覆盖 @property outputFilePreset, + 有效范围 [CGRectZero ~ {0, 0, videoOriginWidth, videoOriginHeight}] + + @since v1.13.0 + */ +@property (assign, nonatomic) CGRect videoSelectedRect; + +/** + @abstract 导出视频的宽高,仅当 videoSelectedRect 不是 emptyRect 时,destVideoSize 才有效。默认为 CGSizeZero, 此时导出 + 视频的宽高为 videoSelectedRect.size. 每次设置 destVideoSize 的值的时候,bitrate 都会自动调整到合适的值。如果想 + 自定义输出码率,设置 destVideoSize 之后,需要再次设置 bitrate 的值 + + @since v1.13.0 + */ +@property (assign, nonatomic) CGSize destVideoSize; + +/** + @abstract 导出视频的帧率,默认 0,有效范围 [0 ~ 原视频帧率],当为 0 的时候,导出视频帧率等于原视频帧率, + 当设置的帧率大于原视频帧率时,会被自动调整为原视频帧率 + + @since v1.13.0 + */ +@property (assign, nonatomic) float videoFrameRate; + /** @abstract 视频转码完成的 block @@ -152,6 +177,14 @@ */ - (void)cancelTranscoding; +/** + * 返回 AVAsset 在 bounds 大小的 view 中播放,有视频部分的 frame + * + + @since v1.13.0 + */ ++ (CGRect)videoDisplay:(AVAsset *)asset bounds:(CGRect)bounds rotate:(PLSPreviewOrientation)previewOrientation; + @end diff --git a/Pod/Library/PLShortVideoKit.framework/Info.plist b/Pod/Library/PLShortVideoKit.framework/Info.plist index f39959f6..4afe0f64 100644 Binary files a/Pod/Library/PLShortVideoKit.framework/Info.plist and b/Pod/Library/PLShortVideoKit.framework/Info.plist differ diff --git a/Pod/Library/PLShortVideoKit.framework/PLShortVideoKit b/Pod/Library/PLShortVideoKit.framework/PLShortVideoKit index dc94fda0..5c4f08dc 100644 Binary files a/Pod/Library/PLShortVideoKit.framework/PLShortVideoKit and b/Pod/Library/PLShortVideoKit.framework/PLShortVideoKit differ diff --git a/ReleaseNotes/release-notes-1.13.0.md b/ReleaseNotes/release-notes-1.13.0.md new file mode 100644 index 00000000..5d59b492 --- /dev/null +++ b/ReleaseNotes/release-notes-1.13.0.md @@ -0,0 +1,24 @@ +# PLShortVideoKit Release Notes for 1.13.0 + +### 简介 +PLShortVideoKit 是七牛推出的一款适用于 iOS 平台的短视频 SDK,提供了包括美颜、滤镜、水印、断点录制、分段回删、视频编辑、混音特效、MV 特效、本地/云端存储在内的多种功能,支持高度定制以及二次开发。 + +### 版本 +- 发布 PLShortVideoKit.framework + +### 功能 +- 支持设置视频转码帧率 +- 支持视频转码时裁剪视频像素区域 +- 优化素材视频合拍音频数据回调格式,由 CMSampleBufferRef 修改为 AudioBufferlist +- 优化图片转视频模块生成的视频时长不精准的问题 +- 优化 pod install 或 update PLShortVideoKit 时进度缓慢的问题 +- 修复 PLSEditPlayer 在 iOS 9.0 以下无法播放的问题 +- 修复 PLSMovieComposer 拼接 16 个以上视频失败的问题 +- 修复 SDK 无法处理 5.1 声道的视频的问题 +- 修复素材合拍,素材视频没有音频轨道时合拍失败的问题 + + +### 注意事项 +- 若需要使用 PLShortVideoKit.framework 中的内置滤镜,则必须将 PLShortVideoKit.bundle 导入项目中。若需要增删、替换滤镜资源可操作 PLShortVideoKit.bundle 中的 colorFilter 文件夹。 +- 抖音特效,需要联系七牛商务获取 appkey 和资源文件。具体使用可参看 PLShortVideoKitDemo。 +