diff --git a/MobileProject.xcodeproj/project.pbxproj b/MobileProject.xcodeproj/project.pbxproj index 2d7e2a1..45fb188 100644 --- a/MobileProject.xcodeproj/project.pbxproj +++ b/MobileProject.xcodeproj/project.pbxproj @@ -71,6 +71,8 @@ 340793851EA9A49400AF184A /* MPContextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 340793841EA9A49400AF184A /* MPContextView.m */; }; 340793861EA9A49400AF184A /* MPContextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 340793841EA9A49400AF184A /* MPContextView.m */; }; 3408A9FB1E00D7DF001A0EC8 /* XAspect-GeTuiAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3452EBAD1D1A919D0001732E /* XAspect-GeTuiAppDelegate.m */; }; + 340A46C11EC5AE0B00D578E7 /* MPWeakTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 340A46C01EC5AE0B00D578E7 /* MPWeakTimer.m */; }; + 340A46C21EC5AE0B00D578E7 /* MPWeakTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 340A46C01EC5AE0B00D578E7 /* MPWeakTimer.m */; }; 340AED351DF45A59007B5CEE /* MPKeyboardViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340AED341DF45A59007B5CEE /* MPKeyboardViewController.m */; }; 340AED361DF45A59007B5CEE /* MPKeyboardViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340AED341DF45A59007B5CEE /* MPKeyboardViewController.m */; }; 340B25B91EB82FE100A56792 /* MPAudioVideoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340B25B81EB82FE100A56792 /* MPAudioVideoViewController.m */; }; @@ -320,6 +322,10 @@ 348D001A1DA88A7600B890F4 /* test.html in Resources */ = {isa = PBXBuildFile; fileRef = 348D00181DA88A7600B890F4 /* test.html */; }; 348D001C1DA88D5000B890F4 /* test1.html in Resources */ = {isa = PBXBuildFile; fileRef = 348D001B1DA88D5000B890F4 /* test1.html */; }; 348D001D1DA88D5000B890F4 /* test1.html in Resources */ = {isa = PBXBuildFile; fileRef = 348D001B1DA88D5000B890F4 /* test1.html */; }; + 3497FEF41EC2DC950073CE26 /* MPClearCacheTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 3497FEF31EC2DC950073CE26 /* MPClearCacheTool.m */; }; + 3497FEF51EC2DC950073CE26 /* MPClearCacheTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 3497FEF31EC2DC950073CE26 /* MPClearCacheTool.m */; }; + 3497FEF81EC2DF9A0073CE26 /* MPvideoRecordingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3497FEF71EC2DF9A0073CE26 /* MPvideoRecordingViewController.m */; }; + 3497FEF91EC2DF9A0073CE26 /* MPvideoRecordingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3497FEF71EC2DF9A0073CE26 /* MPvideoRecordingViewController.m */; }; 349F81D01D45E571002104E3 /* MPUploadImageItemService.m in Sources */ = {isa = PBXBuildFile; fileRef = 349F81CF1D45E571002104E3 /* MPUploadImageItemService.m */; }; 349F81D11D45E571002104E3 /* MPUploadImageItemService.m in Sources */ = {isa = PBXBuildFile; fileRef = 349F81CF1D45E571002104E3 /* MPUploadImageItemService.m */; }; 34A14EE31D40974100ACCCCC /* MPUploadImageService.m in Sources */ = {isa = PBXBuildFile; fileRef = 34A14EE21D40974100ACCCCC /* MPUploadImageService.m */; }; @@ -1089,6 +1095,8 @@ 340793841EA9A49400AF184A /* MPContextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPContextView.m; sourceTree = ""; }; 3408A9F91E00D7A0001A0EC8 /* MobileProject_Local.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MobileProject_Local.entitlements; sourceTree = SOURCE_ROOT; }; 3408A9FA1E00D7A3001A0EC8 /* MobileProject.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MobileProject.entitlements; sourceTree = ""; }; + 340A46BF1EC5AE0B00D578E7 /* MPWeakTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPWeakTimer.h; sourceTree = ""; }; + 340A46C01EC5AE0B00D578E7 /* MPWeakTimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPWeakTimer.m; sourceTree = ""; }; 340AED331DF45A59007B5CEE /* MPKeyboardViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPKeyboardViewController.h; sourceTree = ""; }; 340AED341DF45A59007B5CEE /* MPKeyboardViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPKeyboardViewController.m; sourceTree = ""; }; 340B25B71EB82FE100A56792 /* MPAudioVideoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAudioVideoViewController.h; sourceTree = ""; }; @@ -1312,6 +1320,10 @@ 348D00151DA888D600B890F4 /* MPJavaScriptModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPJavaScriptModel.m; sourceTree = ""; }; 348D00181DA88A7600B890F4 /* test.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = test.html; sourceTree = ""; }; 348D001B1DA88D5000B890F4 /* test1.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = test1.html; sourceTree = ""; }; + 3497FEF21EC2DC950073CE26 /* MPClearCacheTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPClearCacheTool.h; sourceTree = ""; }; + 3497FEF31EC2DC950073CE26 /* MPClearCacheTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPClearCacheTool.m; sourceTree = ""; }; + 3497FEF61EC2DF9A0073CE26 /* MPvideoRecordingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPvideoRecordingViewController.h; sourceTree = ""; }; + 3497FEF71EC2DF9A0073CE26 /* MPvideoRecordingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPvideoRecordingViewController.m; sourceTree = ""; }; 349F81CE1D45E571002104E3 /* MPUploadImageItemService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUploadImageItemService.h; sourceTree = ""; }; 349F81CF1D45E571002104E3 /* MPUploadImageItemService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUploadImageItemService.m; sourceTree = ""; }; 34A14EE11D40974100ACCCCC /* MPUploadImageService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUploadImageService.h; sourceTree = ""; }; @@ -2210,6 +2222,8 @@ 34EA324D1EB9BF8D00FA120A /* MPZFPlayerViewController.m */, 34C089661EC1AAAF004A6B03 /* MPVideoClipViewController.h */, 34C089671EC1AAAF004A6B03 /* MPVideoClipViewController.m */, + 3497FEF61EC2DF9A0073CE26 /* MPvideoRecordingViewController.h */, + 3497FEF71EC2DF9A0073CE26 /* MPvideoRecordingViewController.m */, ); path = AudioVideoController; sourceTree = ""; @@ -2327,6 +2341,8 @@ 340D87AC1D3F7FC4003D9C88 /* cameraHelper.m */, 3412E3081EB07EEC00D8DFA1 /* MPMemoryHelper.h */, 3412E3091EB07EEC00D8DFA1 /* MPMemoryHelper.m */, + 340A46BF1EC5AE0B00D578E7 /* MPWeakTimer.h */, + 340A46C01EC5AE0B00D578E7 /* MPWeakTimer.m */, ); path = OtherHelper; sourceTree = ""; @@ -4345,6 +4361,8 @@ 342202441D62BB1D003F81B2 /* team_dictionary.plist */, 34FAEFC01E5AD83400CED341 /* MPEventCalendar.h */, 34FAEFC11E5AD83400CED341 /* MPEventCalendar.m */, + 3497FEF21EC2DC950073CE26 /* MPClearCacheTool.h */, + 3497FEF31EC2DC950073CE26 /* MPClearCacheTool.m */, ); path = Other; sourceTree = ""; @@ -5033,6 +5051,7 @@ 34E08A661C3BFB90005C6CA3 /* NSMutableURLRequest+Upload.m in Sources */, 34E08A671C3BFB90005C6CA3 /* JDStatusBarView.m in Sources */, 34153A561D76D5EA00D94F4A /* UIView+RoundedCorner.m in Sources */, + 340A46C21EC5AE0B00D578E7 /* MPWeakTimer.m in Sources */, 34E08A6A1C3BFB90005C6CA3 /* UIScrollView+Pages.m in Sources */, 34E08A6B1C3BFB90005C6CA3 /* UITableView+FDTemplateLayoutCellDebug.m in Sources */, 3411EF191D6FEC2300A6C7F3 /* CaptureManager.m in Sources */, @@ -5301,6 +5320,7 @@ 341C07D61D41A27E00FF905C /* BaseRequestService.m in Sources */, 34FFA1F31D49128100A7C342 /* NSString+Additions.m in Sources */, 34E08B2B1C3BFB90005C6CA3 /* UIWebView+Canvas.m in Sources */, + 3497FEF91EC2DF9A0073CE26 /* MPvideoRecordingViewController.m in Sources */, 34E08B2C1C3BFB90005C6CA3 /* LogInViewController.m in Sources */, 34E08B2D1C3BFB90005C6CA3 /* QBImagePickerController.m in Sources */, 34E08B2E1C3BFB90005C6CA3 /* QBAssetsCollectionVideoIndicatorView.m in Sources */, @@ -5355,6 +5375,7 @@ 3425826B1D379743003906BB /* introductoryPagesView.m in Sources */, 34E08B511C3BFB90005C6CA3 /* NSURLConnection+SelfSigned.m in Sources */, 34E08B521C3BFB90005C6CA3 /* UIView+Shake.m in Sources */, + 3497FEF51EC2DC950073CE26 /* MPClearCacheTool.m in Sources */, 342202431D62A8A1003F81B2 /* MPExpandHideViewController.m in Sources */, 34E08B531C3BFB90005C6CA3 /* UIApplication+KeyboardFrame.m in Sources */, 34E08B541C3BFB90005C6CA3 /* UIViewController+MJPopupViewController.m in Sources */, @@ -5503,6 +5524,7 @@ 34E891271C3B92AA001327C8 /* UIScrollView+MJExtension.m in Sources */, 34E893C71C3B9A03001327C8 /* UIApplication+NetworkActivityIndicator.m in Sources */, 34683B0F1D4EE93C0041F8A0 /* MPReduceTimeViewController.m in Sources */, + 3497FEF41EC2DC950073CE26 /* MPClearCacheTool.m in Sources */, 341C07E41D421F2800FF905C /* MPImageProgressCollectionCell.m in Sources */, 3400E4B31D35E1500056B673 /* JRSwizzle.m in Sources */, 34E893B21C3B9A03001327C8 /* NSTimer+Addition.m in Sources */, @@ -5823,6 +5845,7 @@ 34E8938A1C3B9A03001327C8 /* NSInvocation+Bb.m in Sources */, 341C07D51D41A27E00FF905C /* BaseRequestService.m in Sources */, 34E8941F1C3B9A03001327C8 /* UIView+Animation.m in Sources */, + 340A46C11EC5AE0B00D578E7 /* MPWeakTimer.m in Sources */, 34E9D8471C59C33B00E98C2A /* BaiDuMapViewController.mm in Sources */, 34E893B61C3B9A03001327C8 /* NSURLConnection+SelfSigned.m in Sources */, 34FFF4EF1E4BF8C200875ED9 /* MPTableSDWebImageViewController.m in Sources */, @@ -5837,6 +5860,7 @@ 342A8FA61D3F1D8B000C7B98 /* UINavigationController+KeyboardFix.m in Sources */, 340384801D47567900E4A496 /* MPAdaptationCell.m in Sources */, 34E893851C3B9A03001327C8 /* NSException+Trace.m in Sources */, + 3497FEF81EC2DF9A0073CE26 /* MPvideoRecordingViewController.m in Sources */, 3403B0BE1D367954007CD7EF /* UITextField+Extension.m in Sources */, 3411EF151D6FEC1A00A6C7F3 /* UIImage+Extensions.m in Sources */, 34EA325D1EB9C44800FA120A /* MPPlayerCell.m in Sources */, diff --git a/MobileProject.xcworkspace/xcuserdata/wujunyang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/MobileProject.xcworkspace/xcuserdata/wujunyang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index ed9a9b4..e2573a5 100644 --- a/MobileProject.xcworkspace/xcuserdata/wujunyang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/MobileProject.xcworkspace/xcuserdata/wujunyang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -2,4 +2,16 @@ + + + + + + diff --git a/MobileProject/Expand/Tool/OtherHelper/MPWeakTimer.h b/MobileProject/Expand/Tool/OtherHelper/MPWeakTimer.h new file mode 100644 index 0000000..30b98ef --- /dev/null +++ b/MobileProject/Expand/Tool/OtherHelper/MPWeakTimer.h @@ -0,0 +1,54 @@ +// +// MPWeakTimer.h 破坏nstimer内存泄露的问题 +// MobileProject +// +//使用说明:就可以在dealloc里面进行invalidate +//#import "HWWeakTimer.h" +// +//@interface DetailViewController () +//@property (nonatomic, weak) NSTimer *timer; +// +//@end +// +//@implementation DetailViewController +// +//- (IBAction)fireButtonPressed:(id)sender { +// _timer = [HWWeakTimer scheduledTimerWithTimeInterval:3.0f block:^(id userInfo) { +// NSLog(@"%@", userInfo); +// } userInfo:@"Fire" repeats:YES]; +// [_timer fire]; +//} +// +//- (IBAction)invalidateButtonPressed:(id)sender { +// [_timer invalidate]; +//} +// +//-(void)dealloc { +// [_timer invalidate]; +// NSLog(@"%@ dealloc", NSStringFromClass([self class])); +//} +// +//@end +// +// Created by wujunyang on 2017/5/12. +// Copyright © 2017年 wujunyang. All rights reserved. +// + +#import + +typedef void (^MPTimerHandler)(id userInfo); + +@interface MPWeakTimer : NSObject + ++ (NSTimer *) scheduledTimerWithTimeInterval:(NSTimeInterval)interval + target:(id)aTarget + selector:(SEL)aSelector + userInfo:(id)userInfo + repeats:(BOOL)repeats; + ++ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval + block:(MPTimerHandler)block + userInfo:(id)userInfo + repeats:(BOOL)repeats; + +@end diff --git a/MobileProject/Expand/Tool/OtherHelper/MPWeakTimer.m b/MobileProject/Expand/Tool/OtherHelper/MPWeakTimer.m new file mode 100644 index 0000000..ff53931 --- /dev/null +++ b/MobileProject/Expand/Tool/OtherHelper/MPWeakTimer.m @@ -0,0 +1,80 @@ +// +// MPWeakTimer.m +// MobileProject +// +// Created by wujunyang on 2017/5/12. +// Copyright © 2017年 wujunyang. All rights reserved. +// + +#import "MPWeakTimer.h" + +@interface MPWeakTimerTarget : NSObject + +@property (nonatomic, weak) id target; +@property (nonatomic, assign) SEL selector; +@property (nonatomic, weak) NSTimer* timer; + +@end + +@implementation MPWeakTimerTarget + +- (void) fire:(NSTimer *)timer { + if(self.target) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + [self.target performSelector:self.selector withObject:timer.userInfo afterDelay:0.0f]; +#pragma clang diagnostic pop + } else { + [self.timer invalidate]; + } +} + +@end + +@implementation MPWeakTimer + ++ (NSTimer *) scheduledTimerWithTimeInterval:(NSTimeInterval)interval + target:(id)aTarget + selector:(SEL)aSelector + userInfo:(id)userInfo + repeats:(BOOL)repeats { + MPWeakTimerTarget* timerTarget = [[MPWeakTimerTarget alloc] init]; + timerTarget.target = aTarget; + timerTarget.selector = aSelector; + timerTarget.timer = [NSTimer scheduledTimerWithTimeInterval:interval + target:timerTarget + selector:@selector(fire:) + userInfo:userInfo + repeats:repeats]; + return timerTarget.timer; +} + ++ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval + block:(MPTimerHandler)block + userInfo:(id)userInfo + repeats:(BOOL)repeats { + NSMutableArray *userInfoArray = [NSMutableArray arrayWithObject:[block copy]]; + if (userInfo != nil) { + [userInfoArray addObject:userInfo]; + } + return [self scheduledTimerWithTimeInterval:interval + target:self + selector:@selector(_timerBlockInvoke:) + userInfo:[userInfoArray copy] + repeats:repeats]; +} + ++ (void)_timerBlockInvoke:(NSArray*)userInfo { + MPTimerHandler block = userInfo[0]; + id info = nil; + if (userInfo.count == 2) { + info = userInfo[1]; + } + // or `!block ?: block();` @sunnyxx + if (block) { + block(info); + } +} + + +@end diff --git a/MobileProject/Main/Preview/Controller/AudioVideoController/MPAudioVideoViewController.m b/MobileProject/Main/Preview/Controller/AudioVideoController/MPAudioVideoViewController.m index 8dfafd8..477fd24 100644 --- a/MobileProject/Main/Preview/Controller/AudioVideoController/MPAudioVideoViewController.m +++ b/MobileProject/Main/Preview/Controller/AudioVideoController/MPAudioVideoViewController.m @@ -11,6 +11,7 @@ #import "MPAVFoundationViewController.h" #import "MPPlayerViewController.h" #import "MPVideoClipViewController.h" +#import "MPvideoRecordingViewController.h" @interface MPAudioVideoViewController () @property (nonatomic,strong) NSArray *dataArray; @@ -25,7 +26,7 @@ - (void)viewDidLoad { self.view.backgroundColor=[UIColor whiteColor]; if (!self.dataArray) { - self.dataArray=@[@"音效(AudioToolbox)运用",@"音乐AVFoundation运用",@"音乐库中的音乐MPMediaPickerController",@"视频剪编效果的实例"]; + self.dataArray=@[@"音效(AudioToolbox)运用",@"音乐AVFoundation运用",@"音乐库中的音乐MPMediaPickerController",@"视频剪编效果的实例",@"视频录制合成实例"]; } //初始化表格 @@ -99,6 +100,12 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath [self.navigationController pushViewController:vc animated:YES]; break; } + case 4: + { + MPvideoRecordingViewController *vc=[[MPvideoRecordingViewController alloc]init]; + [self.navigationController pushViewController:vc animated:YES]; + break; + } default: break; } diff --git a/MobileProject/Main/Preview/Controller/AudioVideoController/MPvideoRecordingViewController.h b/MobileProject/Main/Preview/Controller/AudioVideoController/MPvideoRecordingViewController.h new file mode 100644 index 0000000..888bffb --- /dev/null +++ b/MobileProject/Main/Preview/Controller/AudioVideoController/MPvideoRecordingViewController.h @@ -0,0 +1,14 @@ +// +// MPvideoRecordingViewController.h +// MobileProject +// +// Created by wujunyang on 2017/5/10. +// Copyright © 2017年 wujunyang. All rights reserved. +// + +#import +#import "BaseViewController.h" + +@interface MPvideoRecordingViewController : BaseViewController + +@end diff --git a/MobileProject/Main/Preview/Controller/AudioVideoController/MPvideoRecordingViewController.m b/MobileProject/Main/Preview/Controller/AudioVideoController/MPvideoRecordingViewController.m new file mode 100644 index 0000000..5dce447 --- /dev/null +++ b/MobileProject/Main/Preview/Controller/AudioVideoController/MPvideoRecordingViewController.m @@ -0,0 +1,446 @@ +// +// MPvideoRecordingViewController.m +// MobileProject +// +// Created by wujunyang on 2017/5/10. +// Copyright © 2017年 wujunyang. All rights reserved. +// + +#import "MPvideoRecordingViewController.h" +#import +#import "MPClearCacheTool.h" + + +@interface MPvideoRecordingViewController () + +@property (nonatomic,strong) AVCaptureMovieFileOutput *output; + +@property (nonatomic,strong)NSURL *firstVideoPath; + + +@property (nonatomic,strong)NSURL *secondVideoPath; + +@property (nonatomic,strong)NSMutableArray *videoPathArray; + + +@property (nonatomic,strong)NSString *videoName; + +@end + +@implementation MPvideoRecordingViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor=[UIColor whiteColor]; + + [self AVCaptureVideo]; + + [self setUpUI]; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +#pragma mark 重写BaseViewController设置内容 + +//设置导航栏背景色 +-(UIColor*)set_colorBackground +{ + return [UIColor whiteColor]; +} + +////设置标题 +-(NSMutableAttributedString*)setTitle +{ + return [self changeTitle:@"视频录制合成实例"]; +} + +//设置左边按键 +-(UIButton*)set_leftButton +{ + UIButton *left_button = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 22, 22)]; + [left_button setImage:[UIImage imageNamed:@"nav_back"] forState:UIControlStateNormal]; + [left_button setImage:[UIImage imageNamed:@"nav_back"] forState:UIControlStateHighlighted]; + return left_button; +} + +//设置左边事件 +-(void)left_button_event:(UIButton*)sender +{ + [self.navigationController popViewControllerAnimated:YES]; +} + +#pragma mark 自定义代码区 + +-(NSMutableAttributedString *)changeTitle:(NSString *)curTitle +{ + NSMutableAttributedString *title = [[NSMutableAttributedString alloc] initWithString:curTitle]; + [title addAttribute:NSForegroundColorAttributeName value:HEXCOLOR(0x333333) range:NSMakeRange(0, title.length)]; + [title addAttribute:NSFontAttributeName value:CHINESE_SYSTEM(18) range:NSMakeRange(0, title.length)]; + return title; +} + +-(NSMutableArray *)videoPathArray{ + if (!_videoPathArray) { + + _videoPathArray = [NSMutableArray array]; + + } + return _videoPathArray; +} + +-(void)setUpUI{ + + UIButton *playButton = [[UIButton alloc]init]; + + [playButton setTitle:@"录制" forState:(UIControlStateNormal)]; + + [playButton setTitleColor:[UIColor greenColor] forState:(UIControlStateNormal)]; + [playButton setBackgroundColor:[UIColor purpleColor]]; + + [self.view addSubview:playButton]; + + [playButton makeConstraints:^(MASConstraintMaker *make) { + + make.bottom.equalTo(self.view).offset(-50); + make.left.equalTo(self.view).offset(50); + make.width.offset(50); + make.height.offset(40); + + }]; + [playButton addTarget:self action:@selector(clickVideoBtn:) forControlEvents:(UIControlEventTouchUpInside)]; + + + UIButton *mergeButton = [[UIButton alloc]init]; + + [mergeButton setTitle:@"合并" forState:(UIControlStateNormal)]; + + [mergeButton setTitleColor:[UIColor purpleColor] forState:(UIControlStateNormal)]; + [mergeButton setBackgroundColor:[UIColor blueColor]]; + + [self.view addSubview:mergeButton]; + + [mergeButton makeConstraints:^(MASConstraintMaker *make) { + + make.bottom.offset(-50); + make.centerX.equalTo(self.view); + make.width.offset(50); + make.height.offset(40); + + }]; + + [mergeButton addTarget:self action:@selector(clickMergeButton) forControlEvents:(UIControlEventTouchUpInside)]; + + + UIButton *clear = [[UIButton alloc]init]; + + [clear setTitle:@"清除缓存" forState:(UIControlStateNormal)]; + [clear setTitleColor:[UIColor yellowColor] forState:(UIControlStateNormal)]; + [clear setBackgroundColor:[UIColor redColor]]; + + [self.view addSubview:clear]; + + [clear makeConstraints:^(MASConstraintMaker *make) { + + make.right.offset(-20); + make.bottom.offset(-50); + make.width.offset(80); + make.height.offset(40); + + }]; + [clear addTarget:self action:@selector(clickClearMemory) forControlEvents:(UIControlEventTouchUpInside)]; + +} + +-(void)AVCaptureVideo{ + + //创建视频设备(摄像头前,后) + NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + //初始化一个摄像头输入设备(first是后置摄像头,last是前置摄像头) + AVCaptureDeviceInput *inputVideo = [AVCaptureDeviceInput deviceInputWithDevice:[devices firstObject] error:NULL]; + //创建麦克风设备 + AVCaptureDevice *deviceAudio = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; + //初始化麦克风输入设备 + AVCaptureDeviceInput *inputAudio = [AVCaptureDeviceInput deviceInputWithDevice:deviceAudio error:NULL]; + + //初始化一个movie的文件输出 + AVCaptureMovieFileOutput *output = [[AVCaptureMovieFileOutput alloc] init]; + self.output = output; //保存output,方便下面操作 + + //初始化一个会话 + AVCaptureSession *session = [[AVCaptureSession alloc] init]; + + //将输入输出设备添加到会话中 + if ([session canAddInput:inputVideo]) { + [session addInput:inputVideo]; + } + if ([session canAddInput:inputAudio]) { + [session addInput:inputAudio]; + } + if ([session canAddOutput:output]) { + [session addOutput:output]; + } + + + //添加一个视频预览图层,设置大小,添加到控制器view的图层上 + //创建一个预览涂层 + AVCaptureVideoPreviewLayer *preLayer = [AVCaptureVideoPreviewLayer layerWithSession:session]; + //设置图层的大小 + preLayer.frame = self.view.bounds; + //添加到view上 + [self.view.layer addSublayer:preLayer]; + + //开始会话 + [session startRunning]; + +} + + +#pragma mark ============== +#pragma mark ===录制按钮====== +- (void)clickVideoBtn:(UIButton *)sender { + //判断是否在录制,如果在录制,就停止,并设置按钮title + if ([self.output isRecording]) { + [self.output stopRecording]; + + + [sender setTitle:@"录制" forState:UIControlStateNormal]; + return; + } + + //设置按钮的title + [sender setTitle:@"停止" forState:UIControlStateNormal]; + + //设置录制视频保存的路径 + NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, + NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.mov",[NSDate date]]]; + + + //转为视频保存的url + NSURL *url = [NSURL fileURLWithPath:path]; + + // UISaveVideoAtPathToSavedPhotosAlbum(path, nil, nil, nil); + + //开始录制,并设置控制器为录制的代理 + [self.output startRecordingToOutputFileURL:url recordingDelegate:self]; +} +//清楚缓存 +- (void)clickClearMemory{ + + NSString *path = [MPClearCacheTool getCacheSizeWithFilePath: [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]]; + + UIAlertController *alert=[UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"确定清除%@缓存吗?",path] message:nil preferredStyle:UIAlertControllerStyleActionSheet]; + //创建一个取消和一个确定按钮 + UIAlertAction *actionCancle=[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]; + //因为需要点击确定按钮后改变文字的值,所以需要在确定按钮这个block里面进行相应的操作 + UIAlertAction *actionOk=[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) { + + //清楚缓存 + BOOL isSuccess = [MPClearCacheTool clearCacheWithFilePath:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]]; + if (isSuccess) { + [MBProgressHUD showSuccess:@"清楚成功" ToView:self.view]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + + [MBProgressHUD hideAllHUDsForView:self.view animated:YES]; + }); + } + + + + } ]; + //将取消和确定按钮添加进弹框控制器 + [alert addAction:actionCancle]; + [alert addAction:actionOk]; + //添加一个文本框到弹框控制器 + + //显示弹框控制器 + [self presentViewController:alert animated:YES completion:nil]; + +} + +#pragma mark - AVCaptureFileOutputRecordingDelegate +//录制完成代理 +- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error +{ + [MBProgressHUD showSuccess:@"录制完成" ToView:self.view]; + + [self setAlertView:outputFileURL]; + +} + + +#pragma mark ============== +#pragma mark ===输入框====== +-(void)setAlertView:(NSURL *)inPutUrl{ + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"输入视频名称" message:@"" preferredStyle:(UIAlertControllerStyleAlert)]; + + [alert addTextFieldWithConfigurationHandler:^(UITextField*textField) { + + textField.text = [NSString stringWithFormat:@"%@",[NSDate date]]; + + [textField addTarget:self action:@selector(changValue:) forControlEvents:(UIControlEventEditingChanged)]; + + self.videoName = textField.text; + + }]; + + UIAlertAction *ok = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + + [self ZIPVideo:inPutUrl VideoName:self.videoName]; + }]; + + [alert addAction:ok]; + + [self presentViewController:alert animated:YES completion:nil]; + +} + + +#pragma mark ============== +#pragma mark ===视频压缩====== +- (void) lowQuailtyWithInputURL:(NSURL*)inputURL + outputURL:(NSURL*)outputURL + blockHandler:(void (^)(AVAssetExportSession*))handler +{ + AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil]; + AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetMediumQuality]; + session.outputURL = outputURL; + session.outputFileType = AVFileTypeQuickTimeMovie; + [session exportAsynchronouslyWithCompletionHandler:^(void) + { + handler(session); + }]; +} +-(void)ZIPVideo:(NSURL *)inputURl VideoName:(NSString *)videoName{ + + //设置录制视频保存的路径 + NSString *outpath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, + NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.mov",videoName]]; + + //转为视频保存的url + NSURL *outurl = [NSURL fileURLWithPath:outpath]; + + //把path添加到数组中(合并视频) + [self.videoPathArray addObject:outpath]; + + [self lowQuailtyWithInputURL:inputURl outputURL:outurl blockHandler:^(AVAssetExportSession *session) + { + if (session.status == AVAssetExportSessionStatusCompleted) + { + NSLog(@"压缩成功"); + + } + else + { + NSLog(@"压缩失败"); + + } + }]; +} + +#pragma mark ============== +#pragma mark ===监听textfield====== +-(void)changValue:(UITextField *)text{ + + self.videoName = text.text; + +} + +//视频合并按钮 +-(void)clickMergeButton{ + + [self mergeAndExportVideos:self.videoPathArray withOutPath:[self videoPath]]; +} +#pragma mark =====下面是合成视频的方法=========== +- (void)mergeAndExportVideos:(NSArray*)videosPathArray withOutPath:(NSString*)outpath{ + if (videosPathArray.count == 0) { + [MBProgressHUD showError:@"请录制视频" ToView:self.view]; + return; + } + + //合成中 + [MBProgressHUD showLoadToView:self.view]; + + AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init]; + + AVMutableCompositionTrack *audioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio + preferredTrackID:kCMPersistentTrackID_Invalid]; + AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo + preferredTrackID:kCMPersistentTrackID_Invalid]; + //视频旋转270(视频合并后默认旋转了-90度) + videoTrack.preferredTransform = CGAffineTransformMake(0, 1.0, -1.0, 0, 0, 0); + + CMTime totalDuration = kCMTimeZero; + for (int i = 0; i < videosPathArray.count; i++) { + AVURLAsset *asset = [AVURLAsset assetWithURL:[NSURL fileURLWithPath:videosPathArray[i]]]; + + NSError *erroraudio = nil; + //获取AVAsset中的音频 或者视频 + AVAssetTrack *assetAudioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] firstObject]; + + + + //向通道内加入音频或者视频 + [audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) + ofTrack:assetAudioTrack + atTime:totalDuration + error:&erroraudio]; + + // NSLog(@"erroraudio:%@",erroraudio); + NSError *errorVideo = nil; + AVAssetTrack *assetVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo]firstObject]; + [videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) + ofTrack:assetVideoTrack + atTime:totalDuration + error:&errorVideo]; + + // NSLog(@"errorVideo:%@",errorVideo); + totalDuration = CMTimeAdd(totalDuration, asset.duration); + } + + NSURL *mergeFileURL = [NSURL fileURLWithPath:outpath]; + AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition + presetName:AVAssetExportPresetMediumQuality]; + exporter.outputURL = mergeFileURL; + exporter.outputFileType = AVFileTypeQuickTimeMovie; + exporter.shouldOptimizeForNetworkUse = YES; + [exporter exportAsynchronouslyWithCompletionHandler:^{ + + if (exporter.error != nil) { + dispatch_async(dispatch_get_main_queue(), ^{ + [MBProgressHUD hideHUDForView:self.view]; + + [MBProgressHUD showSuccess:@"合并失败" ToView:self.view]; + }); + NSLog(@"合并失败"); + + }else{ + + dispatch_async(dispatch_get_main_queue(), ^{ + [MBProgressHUD hideHUDForView:self.view]; + + [MBProgressHUD showSuccess:@"合并成功" ToView:self.view]; + }); + + NSLog(@"合并成功"); + } + //保存到相册 + // UISaveVideoAtPathToSavedPhotosAlbum([mergeFileURL path], nil, nil, nil); + + }]; +} + +//路径 +- (NSString *)videoPath { + NSString *basePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; + NSString *moviePath = [basePath stringByAppendingPathComponent:[NSString stringWithFormat:@"qqq%@.mov",[NSDate date]]]; + return moviePath; +} + + +@end diff --git a/MobileProject/Main/Preview/Other/MPClearCacheTool.h b/MobileProject/Main/Preview/Other/MPClearCacheTool.h new file mode 100644 index 0000000..68ee7b1 --- /dev/null +++ b/MobileProject/Main/Preview/Other/MPClearCacheTool.h @@ -0,0 +1,33 @@ +// +// MPClearCacheTool.h +// MobileProject +// +// Created by wujunyang on 2017/5/10. +// Copyright © 2017年 wujunyang. All rights reserved. +// + +#import + +@interface MPClearCacheTool : NSObject + +/** + * + * 获取path路径文件夹的大小 + * + * @param path 要获取大小的文件夹全路径 + * + * @return 返回path路径文件夹的大小 + */ ++ (NSString *)getCacheSizeWithFilePath:(NSString *)path; + +/** + * + * 清除path路径文件夹的缓存 + * + * @param path 要清除缓存的文件夹全路径 + * + * @return 是否清除成功 + */ ++ (BOOL)clearCacheWithFilePath:(NSString *)path; + +@end diff --git a/MobileProject/Main/Preview/Other/MPClearCacheTool.m b/MobileProject/Main/Preview/Other/MPClearCacheTool.m new file mode 100644 index 0000000..bfed6c6 --- /dev/null +++ b/MobileProject/Main/Preview/Other/MPClearCacheTool.m @@ -0,0 +1,123 @@ +// +// MPClearCacheTool.m +// MobileProject +// +// Created by wujunyang on 2017/5/10. +// Copyright © 2017年 wujunyang. All rights reserved. +// + +#import "MPClearCacheTool.h" + +#define fileManager [NSFileManager defaultManager] + +@implementation MPClearCacheTool + +//获取path路径下文件夹大小 ++ (NSString *)getCacheSizeWithFilePath:(NSString *)path +{ + + //调试 +#ifdef DEBUG + //如果文件夹不存在或者不是一个文件夹那么就抛出一个异常 + //抛出异常会导致程序闪退,所以只在调试阶段抛出,发布阶段不要再抛了,不然极度影响用户体验 + BOOL isDirectory = NO; + BOOL isExist = [fileManager fileExistsAtPath:path isDirectory:&isDirectory]; + if (!isExist || !isDirectory) + { + NSException *exception = [NSException exceptionWithName:@"fileError" reason:@"please check your filePath!" userInfo:nil]; + [exception raise]; + + } + NSLog(@"debug"); + //发布 +#else + NSLog(@"post"); +#endif + + //获取“path”文件夹下面的所有文件 + NSArray *subpathArray= [fileManager subpathsAtPath:path]; + + NSString *filePath = nil; + NSInteger totleSize=0; + + for (NSString *subpath in subpathArray) + { + //拼接每一个文件的全路径 + filePath =[path stringByAppendingPathComponent:subpath]; + + //isDirectory,是否是文件夹,默认不是 + BOOL isDirectory = NO; + + //isExist,判断文件是否存在 + BOOL isExist = [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory]; + + //判断文件是否存在,不存在的话过滤 + //如果存在的话,那么是否是文件夹,是的话也过滤 + //如果文件既存在又不是文件夹,那么判断它是不是隐藏文件,是的话也过滤 + //过滤以上三个情况后,就是一个文件夹里面真实的文件的总大小 + //以上判断目的是忽略不需要计算的文件 + if (!isExist || isDirectory || [filePath containsString:@".DS"]) continue; + //NSLog(@"%@",filePath); + //指定路径,获取这个路径的属性 + //attributesOfItemAtPath:需要传文件夹路径 + //但是attributesOfItemAtPath 只可以获得文件属性,不可以获得文件夹属性,这个也就是需要for-in遍历文件夹里面每一个文件的原因 + NSDictionary *dict= [fileManager attributesOfItemAtPath:filePath error:nil]; + + NSInteger size=[dict[@"NSFileSize"] integerValue]; + totleSize+=size; + } + + //将文件夹大小转换为 M/KB/B + NSString *totleStr = nil; + + if (totleSize > 1000 * 1000) + { + totleStr = [NSString stringWithFormat:@"%.1fM",totleSize / 1000.0f /1000.0f]; + }else if (totleSize > 1000) + { + totleStr = [NSString stringWithFormat:@"%.1fKB",totleSize / 1000.0f ]; + + }else + { + totleStr = [NSString stringWithFormat:@"%.1fB",totleSize / 1.0f]; + } + + return totleStr; + + +} + + +//清除path文件夹下缓存大小 ++ (BOOL)clearCacheWithFilePath:(NSString *)path +{ + + //拿到path路径的下一级目录的子文件夹 + NSArray *subpathArray = [fileManager contentsOfDirectoryAtPath:path error:nil]; + + NSString *message = nil; + NSError *error = nil; + NSString *filePath = nil; + + for (NSString *subpath in subpathArray) + { + filePath =[path stringByAppendingPathComponent:subpath]; + //删除子文件夹 + [fileManager removeItemAtPath:filePath error:&error]; + if (error) { + message = [NSString stringWithFormat:@"%@这个路径的文件夹删除失败了,请检查后重新再试",filePath]; + return NO; + + }else { + message = @"成功了"; + } + + } + NSLog(@"%@",message); + + return YES; + +} + + +@end