|
日期:2018-07-10
|
|
日期:2019-11-14
|
|
|
|
|
|
# 1.概述
|
|
# 1.概述
|
|
iOS短视频SDK是适用于iOS平台的短视频SDK。使用此SDK可以实现短视频相关功能。
|
|
iOS短视频SDK是适用于iOS平台的短视频SDK。使用此SDK可以实现短视频相关功能。
|
... | @@ -11,8 +11,14 @@ iOS短视频SDK是适用于iOS平台的短视频SDK。使用此SDK可以实现 |
... | @@ -11,8 +11,14 @@ iOS短视频SDK是适用于iOS平台的短视频SDK。使用此SDK可以实现 |
|
| 美颜滤镜 | 支持拍摄加入美颜滤镜 |
|
|
| 美颜滤镜 | 支持拍摄加入美颜滤镜 |
|
|
| 视频时长剪辑 | 支持选取视频时长剪辑 |
|
|
| 视频时长剪辑 | 支持选取视频时长剪辑 |
|
|
| 视频区域剪辑 | 支持选取视频区域剪辑 |
|
|
| 视频区域剪辑 | 支持选取视频区域剪辑 |
|
|
|
|
| 视频倍速调整 | 支持选取视频倍速调整 |
|
|
## 1.2阅读对象
|
|
| 多视频合成 | 支持多视频合成 |
|
|
|
|
| 视频水印 | 支持根据时段,位置添加视频水印 |
|
|
|
|
| 气泡文字 | 支持根据时段,位置添加气泡文字 |
|
|
|
|
| 音频插入 | 支持对视频插入背景音乐 |
|
|
|
|
| 视频大小修改 | 支持修改视频分辨率 |
|
|
|
|
|
|
|
|
## 1.2 阅读对象
|
|
本文档为技术文档,需要阅读者:
|
|
本文档为技术文档,需要阅读者:
|
|
|
|
|
|
* 具备基本的iOS开发能力
|
|
* 具备基本的iOS开发能力
|
... | @@ -21,13 +27,13 @@ iOS短视频SDK是适用于iOS平台的短视频SDK。使用此SDK可以实现 |
... | @@ -21,13 +27,13 @@ iOS短视频SDK是适用于iOS平台的短视频SDK。使用此SDK可以实现 |
|
|
|
|
|
# 2.开发准备
|
|
# 2.开发准备
|
|
|
|
|
|
## 2.1开发环境
|
|
## 2.1 开发环境
|
|
|
|
|
|
* Xcode:苹果官方IDE
|
|
* Xcode:苹果官方IDE
|
|
|
|
|
|
* iOS8+
|
|
* iOS8+
|
|
|
|
|
|
## 2.2SDK使用说明
|
|
## 2.2 SDK使用说明
|
|
|
|
|
|
首先,需要下载最新版本的SDK,下载地址为:[VOD_iOS_ShortVideo_SDK](https://github.com/CCVideo/VOD_iOS_ShortVideo_SDK),然后导入SDK包到工程,在相应地方引入头文件`#import "DWShortSDK"`
|
|
首先,需要下载最新版本的SDK,下载地址为:[VOD_iOS_ShortVideo_SDK](https://github.com/CCVideo/VOD_iOS_ShortVideo_SDK),然后导入SDK包到工程,在相应地方引入头文件`#import "DWShortSDK"`
|
|
|
|
|
... | @@ -39,9 +45,9 @@ iOS短视频SDK是适用于iOS平台的短视频SDK。使用此SDK可以实现 |
... | @@ -39,9 +45,9 @@ iOS短视频SDK是适用于iOS平台的短视频SDK。使用此SDK可以实现 |
|
|
|
|
|
# 3.快速集成
|
|
# 3.快速集成
|
|
注:快速集成主要提供的是拍摄功能
|
|
注:快速集成主要提供的是拍摄功能
|
|
## 3.1拍摄快速集成
|
|
## 3.1 拍摄快速集成
|
|
|
|
|
|
### 3.1.1SDK添加到项目后,在info.plist文件设置麦克风 相机 相册 图片权限
|
|
### 3.1.1 SDK添加到项目后,在info.plist文件设置麦克风 相机 相册 图片权限
|
|
```
|
|
```
|
|
<!-- 相册 -->
|
|
<!-- 相册 -->
|
|
<key>NSPhotoLibraryUsageDescription</key>
|
|
<key>NSPhotoLibraryUsageDescription</key>
|
... | @@ -57,8 +63,8 @@ iOS短视频SDK是适用于iOS平台的短视频SDK。使用此SDK可以实现 |
... | @@ -57,8 +63,8 @@ iOS短视频SDK是适用于iOS平台的短视频SDK。使用此SDK可以实现 |
|
<string>App需要您的同意,才能保存图片到您的相册</string>
|
|
<string>App需要您的同意,才能保存图片到您的相册</string>
|
|
```
|
|
```
|
|
|
|
|
|
### 3.1.2基于GPUImage 建议用cocoapods导入 也可手动导入 确保工程中只导入一次GPUImage
|
|
### 3.1.2 基于GPUImage 建议用cocoapods导入 也可手动导入 确保工程中只导入一次GPUImage
|
|
### 3.1.3GPUImage引入后 修改以下部分:
|
|
### 3.1.3 GPUImage引入后 修改以下部分:
|
|
```
|
|
```
|
|
1.GPUImageMovieWriter.h文件中添加isNeedBreakAudioWhiter属性
|
|
1.GPUImageMovieWriter.h文件中添加isNeedBreakAudioWhiter属性
|
|
|
|
|
... | @@ -89,272 +95,823 @@ iOS短视频SDK是适用于iOS平台的短视频SDK。使用此SDK可以实现 |
... | @@ -89,272 +95,823 @@ iOS短视频SDK是适用于iOS平台的短视频SDK。使用此SDK可以实现 |
|
3.GPUImageMovieWriter初始化时设置 isNeedBreakAudioWhiter =YES;
|
|
3.GPUImageMovieWriter初始化时设置 isNeedBreakAudioWhiter =YES;
|
|
具体详情参见demo
|
|
具体详情参见demo
|
|
```
|
|
```
|
|
|
|
|
|
### 3.1.3初始化相机及filterView
|
|
### 3.1.3 初始化相机
|
|
```
|
|
```
|
|
//录制相关
|
|
//录制相关
|
|
videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPreset1280x720
|
|
self.videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPreset1280x720
|
|
cameraPosition:AVCaptureDevicePositionBack];
|
|
cameraPosition:AVCaptureDevicePositionBack];
|
|
|
|
|
|
if ([videoCamera.inputCamera lockForConfiguration:nil]) {
|
|
|
|
|
|
if ([self.videoCamera.inputCamera lockForConfiguration:nil]) {
|
|
//自动对焦
|
|
//自动对焦
|
|
if ([videoCamera.inputCamera isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) {
|
|
if ([self.videoCamera.inputCamera isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) {
|
|
[videoCamera.inputCamera setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
|
|
[self.videoCamera.inputCamera setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
|
|
}
|
|
}
|
|
//自动曝光
|
|
//自动曝光
|
|
if ([videoCamera.inputCamera isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) {
|
|
if ([self.videoCamera.inputCamera isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) {
|
|
[videoCamera.inputCamera setExposureMode:AVCaptureExposureModeContinuousAutoExposure];
|
|
[self.videoCamera.inputCamera setExposureMode:AVCaptureExposureModeContinuousAutoExposure];
|
|
}
|
|
}
|
|
//自动白平衡
|
|
//自动白平衡
|
|
if ([videoCamera.inputCamera isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance]) {
|
|
if ([self.videoCamera.inputCamera isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance]) {
|
|
[videoCamera.inputCamera setWhiteBalanceMode:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance];
|
|
[self.videoCamera.inputCamera setWhiteBalanceMode:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance];
|
|
}
|
|
}
|
|
|
|
|
|
[videoCamera.inputCamera unlockForConfiguration];
|
|
[self.videoCamera.inputCamera unlockForConfiguration];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//输出方向为竖屏
|
|
//输出方向为竖屏
|
|
videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
|
|
self.videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
|
|
//防止允许声音通过的情况下,避免录制第一帧黑屏闪屏
|
|
//防止允许声音通过的情况下,避免录制第一帧黑屏闪屏
|
|
[videoCamera addAudioInputsAndOutputs];
|
|
[self.videoCamera addAudioInputsAndOutputs];
|
|
videoCamera.horizontallyMirrorFrontFacingCamera = YES;
|
|
self.videoCamera.horizontallyMirrorFrontFacingCamera = YES;
|
|
videoCamera.horizontallyMirrorRearFacingCamera = NO;
|
|
self.videoCamera.horizontallyMirrorRearFacingCamera = NO;
|
|
|
|
|
|
|
|
//相机开始运行
|
|
//显示view
|
|
[self.videoCamera startCameraCapture];
|
|
filterView =[[GPUImageView alloc]initWithFrame:[UIScreen mainScreen].bounds];
|
|
|
|
[self.view addSubview:filterView];
|
|
|
|
//组合
|
|
|
|
// filter = [[GPUImageBilateralFilter alloc] init];
|
|
|
|
// [videoCamera addTarget:filter];
|
|
|
|
// [filter addTarget:filterView];
|
|
|
|
|
|
|
|
|
|
|
|
[videoCamera addTarget:filterView];
|
|
|
|
//相机开始运行
|
|
|
|
[videoCamera startCameraCapture];
|
|
|
|
|
|
|
|
```
|
|
```
|
|
|
|
|
|
### 3.1.4初始化moviewriter
|
|
### 3.1.4 初始化moviewriter
|
|
```
|
|
```
|
|
|
|
//苹果默认是MOV格式
|
|
|
|
NSString *path =[self getVideoSaveFilePathString:@".MOV" addPathArray:YES];
|
|
|
|
unlink([path UTF8String]);
|
|
|
|
self.videoURL = [NSURL fileURLWithPath:path];
|
|
|
|
|
|
//写入
|
|
//写入
|
|
movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:videoURL size:CGSizeMake(720.0, 1280.0)];
|
|
CGSize size = CGSizeZero;
|
|
|
|
if (self.scale == 0) {
|
|
|
|
//9:16
|
|
|
|
size = CGSizeMake(720.0, 1280.0);
|
|
|
|
}else if (self.scale == 1){
|
|
|
|
//3:4
|
|
|
|
size = CGSizeMake(720.0, 960.0);
|
|
|
|
}else{
|
|
|
|
//1:1
|
|
|
|
size = CGSizeMake(720.0, 720.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:self.videoURL size:size];
|
|
|
|
|
|
//设置为liveVideo
|
|
//设置为liveVideo
|
|
movieWriter.isNeedBreakAudioWhiter =YES;
|
|
self.movieWriter.isNeedBreakAudioWhiter =YES;
|
|
movieWriter.encodingLiveVideo = YES;
|
|
self.movieWriter.encodingLiveVideo = YES;
|
|
movieWriter.shouldPassthroughAudio =YES;
|
|
self.movieWriter.shouldPassthroughAudio =YES;
|
|
|
|
|
|
|
|
//根据实际需求,添加滤镜链
|
|
|
|
if (self.filter) {
|
|
|
|
if (self.isBeautyFilter) {
|
|
|
|
if (self.isBilateralExist) {
|
|
|
|
[self.bilateralFilter addTarget:self.movieWriter];
|
|
|
|
}else{
|
|
|
|
[self.brightnessFilter addTarget:self.movieWriter];
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
[self.filter addTarget:self.movieWriter];
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
if (self.isBeautyFilter) {
|
|
|
|
if (self.isBilateralExist) {
|
|
|
|
[self.bilateralFilter addTarget:self.movieWriter];
|
|
|
|
}else{
|
|
|
|
[self.brightnessFilter addTarget:self.movieWriter];
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
[self.videoCamera addTarget:self.movieWriter];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// [filter addTarget:movieWriter];
|
|
|
|
[videoCamera addTarget:movieWriter];
|
|
|
|
|
|
|
|
//设置声音
|
|
//设置声音
|
|
videoCamera.audioEncodingTarget = movieWriter;
|
|
self.videoCamera.audioEncodingTarget = self.movieWriter;
|
|
|
|
|
|
```
|
|
```
|
|
|
|
|
|
# 4.功能使用
|
|
# 4.功能使用
|
|
|
|
|
|
## 4.1删除功能具体使用
|
|
## 4.1 删除功能具体使用
|
|
```
|
|
```
|
|
//删除前要停止录制
|
|
BOOL isSuccess = [DWShortTool dw_deleteFileWithFilePath:filePath];
|
|
if (isRecording) {
|
|
|
|
|
|
if (self.pathArray.count == 0) {
|
|
[self stopWrite];
|
|
return YES;
|
|
}
|
|
}
|
|
//读取文件 做个比对
|
|
|
|
[self readShortVideoFiles];
|
|
|
|
|
|
|
|
NSString *filePath =[self.pathArray lastObject];
|
|
|
|
BOOL isSuccess = [DWShortTool dw_deleteFileWithFilePath:filePath];
|
|
|
|
if (isSuccess) {
|
|
if (isSuccess) {
|
|
|
|
|
|
|
|
|
|
self.videoArray =[[[NSUserDefaults standardUserDefaults] objectForKey:@"videoArray"] mutableCopy];
|
|
|
|
[self.videoArray removeLastObject];
|
|
|
|
[[NSUserDefaults standardUserDefaults] setObject:self.videoArray forKey:@"videoArray"];
|
|
|
|
[[NSUserDefaults standardUserDefaults] synchronize];
|
|
|
|
|
|
|
|
[self.pathArray removeLastObject];
|
|
[self.pathArray removeLastObject];
|
|
deleteBtn.hidden =self.pathArray.count>0?NO:YES;
|
|
|
|
|
|
|
|
UIView *view =[self.viewArray lastObject];
|
|
UIView * view = [self.viewArray lastObject];
|
|
[view removeFromSuperview];
|
|
[view removeFromSuperview];
|
|
[self.viewArray removeLastObject];
|
|
[self.viewArray removeLastObject];
|
|
|
|
|
|
logdebug(@"数组__%@__%@",self.pathArray,self.viewArray);
|
|
//要减去相应的录制时间
|
|
//注意要减去相应的录制时间
|
|
|
|
double recordTime =[[self.secondsArray lastObject] doubleValue];
|
|
double recordTime =[[self.secondsArray lastObject] doubleValue];
|
|
totalTime -=recordTime;
|
|
self.totalTime -= recordTime;
|
|
[self.secondsArray removeLastObject];
|
|
[self.secondsArray removeLastObject];
|
|
|
|
[self.bottomView setRecordTime:self.totalTime];
|
|
|
|
|
|
|
|
NSLog(@"余下录制时间%f__%f",self.totalTime,recordTime);
|
|
|
|
}
|
|
```
|
|
```
|
|
|
|
|
|
## 4.2切换功能具体使用
|
|
## 4.2 相机功能具体使用
|
|
|
|
|
|
```
|
|
```
|
|
//前置摄像头不打开闪光灯
|
|
//闪光灯的使用
|
|
if (videoCamera.inputCamera.position == AVCaptureDevicePositionFront) {
|
|
//前置摄像头不打开闪光灯
|
|
return;
|
|
if (self.videoCamera.inputCamera.position == AVCaptureDevicePositionFront) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
button.selected = !button.selected;
|
|
|
|
if (self.videoCamera.inputCamera.position == AVCaptureDevicePositionBack) {
|
|
|
|
if (self.videoCamera.inputCamera.torchMode ==AVCaptureTorchModeOn) {
|
|
|
|
[self.videoCamera.inputCamera lockForConfiguration:nil];
|
|
|
|
[self.videoCamera.inputCamera setTorchMode:AVCaptureTorchModeOff];
|
|
|
|
[self.videoCamera.inputCamera setFlashMode:AVCaptureFlashModeOff];
|
|
|
|
[self.videoCamera.inputCamera unlockForConfiguration];
|
|
|
|
}else{
|
|
|
|
[self.videoCamera.inputCamera lockForConfiguration:nil];
|
|
|
|
[self.videoCamera.inputCamera setTorchMode:AVCaptureTorchModeOn];
|
|
|
|
[self.videoCamera.inputCamera setFlashMode:AVCaptureFlashModeOn];
|
|
|
|
[self.videoCamera.inputCamera unlockForConfiguration];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//前后摄像头切换
|
|
|
|
[self.videoCamera rotateCamera];
|
|
|
|
```
|
|
|
|
|
|
|
|
## 4.3 美颜滤镜功能具体使用
|
|
|
|
```
|
|
|
|
//再添加新的滤镜效果前,首先移除响应链上的滤镜
|
|
|
|
[self removeAllTarget];
|
|
|
|
|
|
|
|
if (type == 0) {
|
|
|
|
self.filter = nil;
|
|
}
|
|
}
|
|
|
|
|
|
if (videoCamera.inputCamera.position == AVCaptureDevicePositionBack) {
|
|
//根据滤镜效果,添加合适的滤镜。
|
|
|
|
//这里的滤镜效果仅供参考,更多效果请详见GPUImage功能介绍。
|
|
if (videoCamera.inputCamera.torchMode ==AVCaptureTorchModeOn) {
|
|
if (type == 1) {
|
|
|
|
GPUImageSaturationFilter * saturationFilter = [[GPUImageSaturationFilter alloc]init];
|
|
[videoCamera.inputCamera lockForConfiguration:nil];
|
|
saturationFilter.saturation = 2;
|
|
[videoCamera.inputCamera setTorchMode:AVCaptureTorchModeOff];
|
|
self.filter = saturationFilter;
|
|
[videoCamera.inputCamera setFlashMode:AVCaptureFlashModeOff];
|
|
}
|
|
[videoCamera.inputCamera unlockForConfiguration];
|
|
|
|
//改变按钮状态
|
|
if (type == 2) {
|
|
lightBtn.selected =NO;
|
|
GPUImageSaturationFilter * saturationFilter = [[GPUImageSaturationFilter alloc]init];
|
|
|
|
saturationFilter.saturation = 0.7;
|
|
}else{
|
|
self.filter = saturationFilter;
|
|
|
|
}
|
|
[videoCamera.inputCamera lockForConfiguration:nil];
|
|
|
|
[videoCamera.inputCamera setTorchMode:AVCaptureTorchModeOn];
|
|
if (type == 3) {
|
|
[videoCamera.inputCamera setFlashMode:AVCaptureFlashModeOn];
|
|
GPUImageWhiteBalanceFilter * whiteBalanceFilter = [[GPUImageWhiteBalanceFilter alloc]init];
|
|
[videoCamera.inputCamera unlockForConfiguration];
|
|
whiteBalanceFilter.temperature = 4500;
|
|
//改变按钮状态
|
|
self.filter = whiteBalanceFilter;
|
|
lightBtn.selected =YES;
|
|
}
|
|
|
|
|
|
}
|
|
if (type == 4) {
|
|
|
|
GPUImageSepiaFilter * sepiaFilter = [[GPUImageSepiaFilter alloc]init];
|
|
|
|
self.filter = sepiaFilter;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type == 5) {
|
|
|
|
GPUImageExposureFilter * exposureFilter = [[GPUImageExposureFilter alloc]init];
|
|
|
|
exposureFilter.exposure = 0.3;
|
|
|
|
self.filter = exposureFilter;
|
|
|
|
}
|
|
|
|
|
|
|
|
//添加新的滤镜响应链
|
|
|
|
if (self.filter) {
|
|
|
|
if (self.isBeautyFilter) {
|
|
|
|
if (self.isBilateralExist) {
|
|
|
|
[self.videoCamera addTarget:self.filter];
|
|
|
|
[self.filter addTarget:self.brightnessFilter];
|
|
|
|
[self.brightnessFilter addTarget:self.bilateralFilter];
|
|
|
|
[self.bilateralFilter addTarget:self.filterView];
|
|
|
|
}else{
|
|
|
|
[self.videoCamera addTarget:self.filter];
|
|
|
|
[self.filter addTarget:self.brightnessFilter];
|
|
|
|
[self.brightnessFilter addTarget:self.filterView];
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
[self.videoCamera addTarget:self.filter];
|
|
|
|
[self.filter addTarget:self.filterView];
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
if (self.isBeautyFilter) {
|
|
|
|
if (self.isBilateralExist) {
|
|
|
|
[self.videoCamera addTarget:self.brightnessFilter];
|
|
|
|
[self.brightnessFilter addTarget:self.bilateralFilter];
|
|
|
|
[self.bilateralFilter addTarget:self.filterView];
|
|
|
|
}else{
|
|
|
|
[self.videoCamera addTarget:self.brightnessFilter];
|
|
|
|
[self.brightnessFilter addTarget:self.filterView];
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
[self.videoCamera addTarget:self.filterView];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
## 4.4 暂停or开始录制
|
|
|
|
```
|
|
|
|
//开始录制
|
|
|
|
//UI修改
|
|
|
|
[self hiddenAllView:YES];
|
|
|
|
[self.bottomView setStyle:2];
|
|
|
|
|
|
|
|
if (self.isDelay) {
|
|
|
|
//__weak typeof(self) weakSelf = self;
|
|
|
|
//开始延迟计时
|
|
|
|
DWDelayView * delayView = [[DWDelayView alloc]init];
|
|
|
|
[delayView beginAnimation];
|
|
|
|
|
|
|
|
delayView.finish = ^{
|
|
|
|
//进度条
|
|
|
|
[self initProgressView];
|
|
|
|
self.seconds = 0;
|
|
|
|
|
|
|
|
[self gcdTimer];
|
|
|
|
|
|
|
|
//开始录制
|
|
|
|
[self initMovieWriter];
|
|
|
|
|
|
|
|
[self.movieWriter startRecording];
|
|
|
|
};
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//进度条
|
|
|
|
[self initProgressView];
|
|
|
|
self.seconds = 0;
|
|
|
|
|
|
|
|
//启动计时器
|
|
|
|
[self gcdTimer];
|
|
|
|
|
|
|
|
//开始录制
|
|
|
|
[self initMovieWriter];
|
|
|
|
[self.movieWriter startRecording];
|
|
|
|
|
|
|
|
//暂停录制
|
|
|
|
//UI修改
|
|
|
|
[self hiddenAllView:NO];
|
|
|
|
|
|
|
|
[self.bottomView setStyle:3];
|
|
|
|
|
|
|
|
//移除定时器
|
|
|
|
[self removeTimer];
|
|
|
|
//暂停写入
|
|
|
|
[self.movieWriter finishRecording];
|
|
|
|
self.videoCamera.audioEncodingTarget = nil;
|
|
|
|
|
|
|
|
[self.secondsArray addObject:[NSString stringWithFormat:@"%f",self.seconds]];
|
|
|
|
|
|
|
|
//保存视频到本地
|
|
|
|
[self savePhotosAlbum:self.videoURL];
|
|
|
|
|
|
```
|
|
```
|
|
## 4.3美颜滤镜功能具体使用
|
|
## 4.5 断点拍摄功能具体使用
|
|
|
|
断点拍摄后的几个小视频可以合成为一个视频,DWShortTool提供了接口(4.10.4)用于此功能。
|
|
```
|
|
```
|
|
beautyBtn.selected =!beautyBtn.selected;
|
|
//延迟执行,等待视频写入完成。
|
|
if (beautyBtn.selected) {
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
|
|
|
// 移除之前所有的处理链
|
|
//合成视频输出路径
|
|
[videoCamera removeAllTargets];
|
|
NSString * path = [self getVideoSaveFilePathString:@".MOV" addPathArray:NO];
|
|
|
|
|
|
|
|
self.hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
|
|
|
|
self.hud.removeFromSuperViewOnHide = YES;
|
|
|
|
self.hud.label.text = @"视频生成中";
|
|
|
|
|
|
|
|
[DWShortTool dw_compositeAndExportVideos:self.pathArray withVideoSize:CGSizeZero outPath:path outputFileType:AVFileTypeQuickTimeMovie presetName:AVAssetExportPresetHighestQuality didComplete:^(NSError *error, NSURL *compressionFileURL) {
|
|
|
|
|
|
|
|
[self.hud hideAnimated:YES];
|
|
|
|
|
|
|
|
if (!error) {
|
|
|
|
|
|
|
|
DWShortVideoEditViewController * shortVideoEditVC = [[DWShortVideoEditViewController alloc]init];
|
|
|
|
shortVideoEditVC.videoURL = [NSURL fileURLWithPath:path];
|
|
|
|
[self presentViewController:shortVideoEditVC animated:YES completion:nil];
|
|
|
|
}else{
|
|
|
|
[@"合成失败,请重试" showAlert];
|
|
|
|
}
|
|
|
|
}];
|
|
|
|
});
|
|
|
|
```
|
|
|
|
## 4.6 视频剪辑功能的使用
|
|
|
|
通过设置裁剪时间,裁剪范围,裁剪倍速来对视频进行剪辑处理。DWShortTool提供了接口(4.10.2)用于此功能。
|
|
|
|
```
|
|
|
|
NSString *videoPath = [self createFilePath];
|
|
|
|
|
|
|
|
MBProgressHUD * hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
|
|
|
|
hud.removeFromSuperViewOnHide = YES;
|
|
|
|
|
|
|
|
[DWShortTool dw_videoSizeAndTimeCropAndExportVideo:self.videoURL.absoluteString
|
|
|
|
size:self.cropView.scaleFrame.size
|
|
|
|
point:self.cropView.scaleFrame.origin
|
|
|
|
range:CMTimeRangeMake(self.cropView.start, self.cropView.duration)
|
|
|
|
videoRate:self.cropView.speed
|
|
|
|
withOutPath:videoPath
|
|
|
|
outputFileType:AVFileTypeQuickTimeMovie
|
|
|
|
presetName:AVAssetExportPresetHighestQuality
|
|
|
|
didComplete:^(NSError *error, NSURL *compressionFileURL) {
|
|
|
|
|
|
|
|
[hud hideAnimated:YES];
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
[error.localizedDescription showAlert];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
// 创建美颜滤镜
|
|
//剪辑完成,跳转编辑页面
|
|
filter = [[GPUImageBilateralFilter alloc] init];
|
|
DWShortVideoEditViewController * shortVideoEditVC = [[DWShortVideoEditViewController alloc]init];
|
|
|
|
shortVideoEditVC.videoURL = compressionFileURL;
|
|
|
|
[self presentViewController:shortVideoEditVC animated:YES completion:nil];
|
|
|
|
}];
|
|
|
|
```
|
|
|
|
## 4.7 插入背景音乐功能的使用
|
|
|
|
可以设置新的背景音乐插入到原视频中。DWShortTool提供了接口(4.10.5)用于此功能。
|
|
|
|
```
|
|
|
|
//判断是否选择了音频
|
|
|
|
BOOL select = NO;
|
|
|
|
for (NSDictionary * dict in self.musicListArray) {
|
|
|
|
if ([[dict objectForKey:@"isSelect"] boolValue]) {
|
|
|
|
select = YES;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!select) {
|
|
|
|
self.musicDict = nil;
|
|
|
|
[self addStickerWithVideoUrl:videoUrl];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//插入音频
|
|
|
|
NSString * outPath = [self createFilePath];
|
|
|
|
// NSURL * outPathUrl = [NSURL fileURLWithPath:outPath];
|
|
|
|
|
|
|
|
[DWShortTool dw_insertAudioAndExportVideo:videoUrl.absoluteString
|
|
|
|
withAudioPath:[self.musicDict objectForKey:@"audioPath"]
|
|
|
|
originalVolume:[[self.musicDict objectForKey:@"originalVolume"] floatValue]
|
|
|
|
insertVolume:[[self.musicDict objectForKey:@"insertVolume"] floatValue]
|
|
|
|
timeRange:CMTimeRangeMake([[self.musicDict objectForKey:@"start"] CMTimeValue], [[self.musicDict objectForKey:@"duration"] CMTimeValue])
|
|
|
|
outPath:outPath
|
|
|
|
outputFileType:OUTPUTFILETYPE
|
|
|
|
presetName:PRESETNAME
|
|
|
|
didComplete:^(NSError *error, NSURL *compressionFileURL) {
|
|
|
|
|
|
// 设置GPUImage处理链,从数据->滤镜->界面展示
|
|
|
|
[videoCamera addTarget:filter];
|
|
|
|
[filter addTarget:filterView];
|
|
|
|
|
|
|
|
}else{
|
|
if (error) {
|
|
|
|
|
|
|
|
[self.editAndUploadVC endEditWithSuccess:NO];
|
|
|
|
|
|
|
|
[error.localizedDescription showAlert];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
// 移除之前所有的处理链
|
|
}];
|
|
[videoCamera removeAllTargets];
|
|
```
|
|
[videoCamera addTarget:filterView];
|
|
## 4.8 贴纸功能的使用
|
|
|
|
通过设置贴纸图片,贴纸位置(注意,贴纸point,size的参数为百分比),以及贴纸出现的时间范围为原视频增加视频贴纸。DWShortTool提供了接口(4.10.3)用于此功能。
|
|
|
|
```
|
|
|
|
if (!self.canEdit) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
//判断是否添加贴纸
|
|
|
|
if (self.stickerArray.count == 0) {
|
|
|
|
[self addBubbleVideoUrl:videoUrl];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSString * outPath = [self createFilePath];
|
|
|
|
|
|
|
|
NSArray * images = @[@"icon_sticker_1.png",@"icon_sticker_2.png",@"icon_sticker_3.png",@"icon_sticker_4.png",@"icon_sticker_5.png"];
|
|
|
|
NSMutableArray * stickerImages = [NSMutableArray array];
|
|
|
|
NSMutableArray * stickerImagePoints = [NSMutableArray array];
|
|
|
|
NSMutableArray * stickerImageSizes = [NSMutableArray array];
|
|
|
|
NSMutableArray * rotateAngles = [NSMutableArray array];
|
|
|
|
NSMutableArray * timeRanges = [NSMutableArray array];
|
|
|
|
|
|
|
|
for (NSDictionary * dict in self.stickerArray) {
|
|
|
|
UIImage * stickerImage = [UIImage imageNamed:[images objectAtIndex:[[dict objectForKey:@"index"] integerValue]]];
|
|
|
|
LINConversionView * conversionView = [dict objectForKey:@"object"];
|
|
|
|
CGRect frame = conversionView.frame;
|
|
|
|
CGAffineTransform transform = conversionView.transform;
|
|
|
|
|
|
|
|
CGFloat rotate = [self getAngleFromAffineTransform:transform];
|
|
|
|
CGFloat sizeLength = [self getStickerSideLengthWithView:conversionView];
|
|
|
|
//计算偏移量
|
|
|
|
CGFloat offset = (conversionView.frame.size.width - sizeLength) / 2.0;
|
|
|
|
CGPoint offsetPoint = CGPointMake(frame.origin.x + offset, frame.origin.y + offset);
|
|
|
|
//百分比
|
|
|
|
CGPoint stickerImagePoint = CGPointMake((offsetPoint.x - self.videoBackground.origin.x) / self.videoBackground.size.width, (offsetPoint.y - self.videoBackground.origin.y) / self.videoBackground.size.height);
|
|
|
|
CGSize stickerImageSize = CGSizeMake(sizeLength / self.videoBackground.size.width, sizeLength / self.videoBackground.size.height);
|
|
|
|
|
|
|
|
CMTime start = [[dict objectForKey:@"start"] CMTimeValue];
|
|
|
|
CMTime duration = [[dict objectForKey:@"duration"] CMTimeValue];
|
|
|
|
//如果需要整个视频都添加贴纸,传kCMTimeZero即可。
|
|
|
|
if (CMTimeCompare(duration, self.videoDuration) == 0) {
|
|
|
|
duration = kCMTimeZero;
|
|
|
|
}
|
|
|
|
CMTimeRange timeRange = CMTimeRangeMake(start, duration);
|
|
|
|
|
|
|
|
[stickerImages addObject:stickerImage];
|
|
|
|
[stickerImagePoints addObject:[NSValue valueWithCGPoint:stickerImagePoint]];
|
|
|
|
[stickerImageSizes addObject:[NSValue valueWithCGSize:stickerImageSize]];
|
|
|
|
[rotateAngles addObject:[NSNumber numberWithFloat:rotate]];
|
|
|
|
[timeRanges addObject:[NSValue valueWithCMTimeRange:timeRange]];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
[DWShortTool dw_addStickerAndExportVideo:videoUrl.absoluteString
|
|
|
|
withStickerImages:stickerImages
|
|
|
|
stickerImagePoints:stickerImagePoints
|
|
|
|
stickerImageSizes:stickerImageSizes
|
|
|
|
rotateAngles:rotateAngles
|
|
|
|
timeRanges:timeRanges
|
|
|
|
outPath:outPath
|
|
|
|
outputFileType:OUTPUTFILETYPE
|
|
|
|
presetName:PRESETNAME
|
|
|
|
didComplete:^(NSError *error, NSURL *compressionFileURL) {
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
[self.editAndUploadVC endEditWithSuccess:NO];
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
|
[self addBubbleVideoUrl:compressionFileURL];
|
|
|
|
});
|
|
|
|
|
|
|
|
}];
|
|
```
|
|
```
|
|
## 4.4暂停功能具体使用
|
|
|
|
|
|
## 4.9 气泡文字功能的使用
|
|
|
|
添加逻辑同4.8,贴纸图片需要通过背景图与文字生成。
|
|
```
|
|
```
|
|
//因为GCDtimer较为精准 务必先调用移除定时器的方法 再调用停止录制的方法
|
|
if (!self.canEdit) {
|
|
[self removeTimer];
|
|
return;
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
}
|
|
//注意顺序
|
|
|
|
[movieWriter finishRecording];
|
|
if (self.bubbleArray.count == 0) {
|
|
[filter removeTarget:movieWriter];
|
|
[self.editAndUploadVC endEditWithSuccess:YES];
|
|
videoCamera.audioEncodingTarget = nil;
|
|
|
|
|
|
|
|
});
|
|
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
|
|
|
|
[library writeVideoAtPathToSavedPhotosAlbum:videoUrl completionBlock:^(NSURL *assetURL, NSError *error)
|
|
|
|
{
|
|
|
|
|
|
|
|
}];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
beautyBtn.hidden =NO;
|
|
NSString * outPath = [self createFilePath];
|
|
[self.secondsArray addObject:[NSString stringWithFormat:@"%f",seconds]];
|
|
|
|
// [self saveModelToVideoArray];
|
|
NSMutableArray * bubbleImages = [NSMutableArray array];
|
|
|
|
NSMutableArray * bubbleImagePoints = [NSMutableArray array];
|
|
|
|
NSMutableArray * bubbleImageSizes = [NSMutableArray array];
|
|
|
|
NSMutableArray * rotateAngles = [NSMutableArray array];
|
|
|
|
NSMutableArray * timeRanges = [NSMutableArray array];
|
|
|
|
for (NSDictionary * dict in self.bubbleArray) {
|
|
|
|
LINConversionView * conversionView = [dict objectForKey:@"object"];
|
|
|
|
CGRect frame = conversionView.frame;
|
|
|
|
CGAffineTransform transform = conversionView.transform;
|
|
|
|
|
|
|
|
CGFloat rotate = [self getAngleFromAffineTransform:transform];
|
|
|
|
CGFloat sizeLength = [self getStickerSideLengthWithView:conversionView];
|
|
|
|
|
|
|
|
//计算偏移量
|
|
|
|
CGFloat offset = (conversionView.frame.size.width - sizeLength) / 2.0;
|
|
|
|
CGPoint offsetPoint = CGPointMake(frame.origin.x + offset, frame.origin.y + offset);
|
|
|
|
|
|
|
|
//获取贴纸所占视频区域的百分比
|
|
|
|
CGPoint bubbleImagePoint = CGPointMake((offsetPoint.x - self.videoBackground.origin.x) / self.videoBackground.size.width, (offsetPoint.y - self.videoBackground.origin.y) / self.videoBackground.size.height);
|
|
|
|
|
|
|
|
CGSize bubbleImageSize = CGSizeMake(sizeLength / self.videoBackground.size.width, sizeLength / self.videoBackground.size.height);
|
|
|
|
|
|
|
|
CMTime start = [[dict objectForKey:@"start"] CMTimeValue];
|
|
|
|
CMTime duration = [[dict objectForKey:@"duration"] CMTimeValue];
|
|
|
|
//如果需要整个视频都添加贴纸,传kCMTimeZero即可。
|
|
|
|
if (CMTimeCompare(duration, self.videoDuration) == 0) {
|
|
|
|
duration = kCMTimeZero;
|
|
|
|
}
|
|
|
|
CMTimeRange timeRange = CMTimeRangeMake(start, duration);
|
|
|
|
|
|
|
|
//生成贴纸图片
|
|
|
|
[bubbleImages addObject:[self bubbleImageWithBubbleDict:dict]];
|
|
|
|
[bubbleImagePoints addObject:[NSValue valueWithCGPoint:bubbleImagePoint]];
|
|
|
|
[bubbleImageSizes addObject:[NSValue valueWithCGSize:bubbleImageSize]];
|
|
|
|
[rotateAngles addObject:[NSNumber numberWithFloat:rotate]];
|
|
|
|
[timeRanges addObject:[NSValue valueWithCMTimeRange:timeRange]];
|
|
|
|
}
|
|
|
|
|
|
|
|
[DWShortTool dw_addStickerAndExportVideo:videoUrl.absoluteString
|
|
|
|
withStickerImages:bubbleImages
|
|
|
|
stickerImagePoints:bubbleImagePoints
|
|
|
|
stickerImageSizes:bubbleImageSizes
|
|
|
|
rotateAngles:rotateAngles
|
|
|
|
|
|
|
|
timeRanges:timeRanges
|
|
|
|
outPath:outPath
|
|
|
|
outputFileType:OUTPUTFILETYPE
|
|
|
|
presetName:PRESETNAME
|
|
|
|
didComplete:^(NSError *error, NSURL *compressionFileURL) {
|
|
|
|
if (error) {
|
|
|
|
[self.editAndUploadVC endEditWithSuccess:NO];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
[self.editAndUploadVC endEditWithSuccess:YES];
|
|
|
|
|
|
|
|
//保存视频到本地相册
|
|
|
|
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
|
|
|
|
[library writeVideoAtPathToSavedPhotosAlbum:compressionFileURL completionBlock:^(NSURL *assetURL, NSError *error)
|
|
|
|
{
|
|
|
|
|
|
|
|
}];
|
|
|
|
}];
|
|
|
|
|
|
|
|
//生成气泡文字图片
|
|
|
|
-(UIImage *)bubbleImageWithBubbleDict:(NSDictionary *)dict
|
|
|
|
{
|
|
|
|
NSArray * images = @[@"icon_bubble_1.png",@"icon_bubble_2.png",@"icon_bubble_3.png",@"icon_bubble_4.png",@"icon_bubble_5.png"];
|
|
|
|
//总体生成图片
|
|
|
|
UIImage * bubbleImage = [UIImage imageNamed:[images objectAtIndex:[[dict objectForKey:@"index"] integerValue]]];
|
|
|
|
LINConversionView * conversionView = [dict objectForKey:@"object"];
|
|
|
|
DWBubbleInputView * inputView = (DWBubbleInputView *)conversionView.contentView;
|
|
|
|
|
|
|
|
UIImageView * bubbleImageView = [[UIImageView alloc]init];
|
|
|
|
|
|
|
|
CGFloat sizeLength = [self getStickerSideLengthWithView:conversionView];
|
|
|
|
bubbleImageView.frame = CGRectMake(0, 0, sizeLength, sizeLength);
|
|
|
|
bubbleImageView.image = bubbleImage;
|
|
|
|
|
|
|
|
UILabel * label = [[UILabel alloc]initWithFrame:CGRectMake(bubbleImageView.frame.size.width * 32 / BUBBLEWIDTH, bubbleImageView.frame.size.height * 102 / BUBBLEWIDTH, bubbleImageView.frame.size.width - (bubbleImageView.frame.size.width * 32 / BUBBLEWIDTH) * 2, bubbleImageView.frame.size.height * 49 / BUBBLEWIDTH)];
|
|
|
|
label.text = inputView.placeholderLabel.text;
|
|
|
|
label.font = inputView.placeholderLabel.font;
|
|
|
|
label.textColor = inputView.placeholderLabel.textColor;
|
|
|
|
label.textAlignment = inputView.placeholderLabel.textAlignment;
|
|
|
|
label.numberOfLines = 2;
|
|
|
|
label.adjustsFontSizeToFitWidth = YES;
|
|
|
|
[bubbleImageView addSubview:label];
|
|
|
|
|
|
|
|
UIGraphicsBeginImageContextWithOptions(bubbleImageView.bounds.size, NO, 0);
|
|
|
|
|
|
|
|
if ([bubbleImageView respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) {
|
|
|
|
|
|
|
|
[bubbleImageView drawViewHierarchyInRect:bubbleImageView.bounds afterScreenUpdates:YES];
|
|
|
|
}else{
|
|
|
|
[bubbleImageView.layer renderInContext:UIGraphicsGetCurrentContext()];
|
|
|
|
}
|
|
|
|
|
|
recordBtn.selected =NO;
|
|
UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
|
|
isRecording =NO;
|
|
UIGraphicsEndImageContext();
|
|
[self savePhotosAlbum:videoURL];
|
|
return image;
|
|
logdebug(@"录制时间为%f 当前时间为%f",seconds,totalTime);
|
|
}
|
|
```
|
|
```
|
|
## 4.5断点拍摄功能具体使用
|
|
|
|
断点拍摄后的几个小视频可以合成为一个视频, DWShortTool提供了如下接口用于合成视频:
|
|
## 4.10 工具类DWShortTool接口功能
|
|
|
|
### 4.10.1 视频压缩
|
|
|
|
```
|
|
|
|
/// 压缩视频
|
|
|
|
/// @param videoPath 视频路径
|
|
|
|
/// @param outPath 输出路径
|
|
|
|
/// @param outputFileType 视频格式
|
|
|
|
/// @param presetName 视频导出质量
|
|
|
|
/// @param completeBlock 完成后回调
|
|
|
|
+ (void)dw_compressionAndExportVideo:(NSString *)videoPath
|
|
|
|
withOutPath:(NSString *)outPath
|
|
|
|
outputFileType:(NSString *)outputFileType
|
|
|
|
presetName:(NSString *)presetName
|
|
|
|
didComplete:(void(^)(NSError *error,NSURL *compressionFileURL) )completeBlock;
|
|
```
|
|
```
|
|
/* 合成视频|转换视频格式
|
|
### 4.10.2 视频剪辑
|
|
@param videosPathArray:合成视频的路径数组
|
|
|
|
@param outpath:输出路径
|
|
|
|
@param outputFileType:视频格式 如:AVFileTypeQuickTimeMovie AVFileTypeMPEG4等
|
|
|
|
@param presetName:分辨率 如:AVAssetExportPresetMediumQuality AVAssetExportPreset640x480等
|
|
|
|
@param completeBlock mergeFileURL:合成后新的视频URL
|
|
|
|
*/
|
|
|
|
+ (void)dw_mergeAndExportVideos:(NSArray *)videosPathArray withOutPath:(NSString *)outpath outputFileType:(NSString *)outputFileType presetName:(NSString *)presetName didComplete:(void(^)(NSError *error,NSURL *mergeFileURL) )completeBlock;
|
|
|
|
|
|
|
|
使用详情参见demo。
|
|
#### 4.10.2.1 视频时长剪辑 视频区域不变
|
|
```
|
|
```
|
|
## 4.6工具类DWShortTool开放的其它接口
|
|
/// 视频时长剪辑 视频区域不变
|
|
### 4.6.1视频压缩
|
|
/// @param videoPath 视频路径
|
|
|
|
/// @param outPath 视频输出路径
|
|
|
|
/// @param outputFileType 视频格式
|
|
|
|
/// @param presetName 视频导出质量
|
|
|
|
/// @param timeRange 截取视频的时间范围
|
|
|
|
/// @param completeBlock 完成后回调
|
|
|
|
+ (void)dw_videoTimeCropAndExportVideo:(NSString *)videoPath
|
|
|
|
withOutPath:(NSString *)outPath
|
|
|
|
outputFileType:(NSString *)outputFileType
|
|
|
|
presetName:(NSString *)presetName
|
|
|
|
range:(CMTimeRange)timeRange
|
|
|
|
didComplete:(void(^)(NSError *error,NSURL *compressionFileURL))completeBlock;
|
|
```
|
|
```
|
|
/**
|
|
|
|
压缩视频
|
|
|
|
|
|
|
|
@param videoPath 视频路径
|
|
#### 4.10.2.2 视频区域剪裁 视频时长不变
|
|
@param outPath 输出路径
|
|
|
|
@param outputFileType 视频格式
|
|
|
|
@param presetName 分辨率
|
|
|
|
@param completeBlock 回调的block compressionFileURL:压缩后的视频URL
|
|
|
|
*/
|
|
|
|
+ (void)dw_compressionAndExportVideo:(NSString *)videoPath withOutPath:(NSString *)outPath outputFileType:(NSString *)outputFileType presetName:(NSString *)presetName didComplete:(void(^)(NSError *error,NSURL *compressionFileURL) )completeBlock
|
|
|
|
```
|
|
```
|
|
### 4.6.2选取视频时长剪辑
|
|
/// 视频区域剪裁 视频时长不变
|
|
|
|
/// @param videoPath 视频路径
|
|
|
|
/// @param outPath 视频输出路径
|
|
|
|
/// @param outputFileType 视频格式
|
|
|
|
/// @param presetName 视频导出质量
|
|
|
|
/// @param videoSize 剪裁区域
|
|
|
|
/// @param videoPoint 剪裁起点
|
|
|
|
/// @param shouldScale 是否拉伸 YES拉伸 NO不拉伸 剪裁黑背景
|
|
|
|
/// @param completeBlock 剪裁完成后的回调
|
|
|
|
+ (void)dw_videoSizeCropAndExportVideo:(NSString *)videoPath
|
|
|
|
withOutPath:(NSString *)outPath
|
|
|
|
outputFileType:(NSString *)outputFileType
|
|
|
|
presetName:(NSString *)presetName
|
|
|
|
size:(CGSize)videoSize
|
|
|
|
point:(CGPoint)videoPoint
|
|
|
|
shouldScale:(BOOL)shouldScale
|
|
|
|
didComplete:(void(^)(NSError *error,NSURL *compressionFileURL))completeBlock;
|
|
```
|
|
```
|
|
/**
|
|
|
|
视频时长剪辑 视频区域不变
|
|
|
|
|
|
|
|
@param videoPath 视频路径
|
|
#### 4.10.2.3 视频区域兼时长剪裁
|
|
@param outPath 视频输出路径
|
|
```
|
|
@param outputFileType 视频格式
|
|
/// 视频区域兼时长剪裁
|
|
@param presetName 分辨率
|
|
/// @param videoPath 视频路径
|
|
@param timeRange 截取视频的时间范围
|
|
/// @param outPath 视频输出路径
|
|
@param completeBlock 回调的block compressionFileURL:剪辑后的视频URL
|
|
/// @param outputFileType 视频格式
|
|
*/
|
|
/// @param presetName 视频导出质量
|
|
+ (void)dw_videoTimeCropAndExportVideo:(NSString *)videoPath withOutPath:(NSString *)outPath outputFileType:(NSString *)outputFileType presetName:(NSString *)presetName range:(CMTimeRange )timeRange didComplete:(void(^)(NSError *error,NSURL *compressionFileURL) )completeBlock;
|
|
/// @param videoSize 剪裁区域
|
|
|
|
/// @param videoPoint 剪裁起点
|
|
|
|
/// @param shouldScale 是否拉伸 YES拉伸 NO不拉伸 剪裁黑背景
|
|
|
|
/// @param timeRange 截取视频的时间范围
|
|
|
|
/// @param completeBlock 剪裁完成后的回调
|
|
|
|
+ (void)dw_videoSizeAndTimeCropAndExportVideo:(NSString *)videoPath
|
|
|
|
withOutPath:(NSString *)outPath
|
|
|
|
outputFileType:(NSString *)outputFileType
|
|
|
|
presetName:(NSString *)presetName
|
|
|
|
size:(CGSize)videoSize
|
|
|
|
point:(CGPoint)videoPoint
|
|
|
|
shouldScale:(BOOL)shouldScale
|
|
|
|
range:(CMTimeRange)timeRange
|
|
|
|
didComplete:(void(^)(NSError *error,NSURL *compressionFileURL))completeBlock;
|
|
|
|
```
|
|
|
|
|
|
|
|
#### 4.10.2.4 视频区域,时长,倍速剪裁
|
|
```
|
|
```
|
|
### 4.6.3视频区域裁剪
|
|
/// 视频区域,时长,倍速剪裁
|
|
|
|
/// @param videoPath 视频路径
|
|
|
|
/// @param videoSize 剪裁区域,CGSizeZero不裁剪
|
|
|
|
/// @param videoPoint 剪裁起点
|
|
|
|
/// @param timeRange 截取视频的时间范围,kCMTimeRangeZero,不裁剪时长
|
|
|
|
/// @param videoRate 截取视频倍速
|
|
|
|
/// @param outPath 视频输出路径
|
|
|
|
/// @param outputFileType 视频格式
|
|
|
|
/// @param presetName 视频导出质量
|
|
|
|
/// @param completeBlock 完成后的回调
|
|
|
|
+ (void)dw_videoSizeAndTimeCropAndExportVideo:(NSString *)videoPath
|
|
|
|
size:(CGSize)videoSize
|
|
|
|
point:(CGPoint)videoPoint
|
|
|
|
range:(CMTimeRange)timeRange
|
|
|
|
videoRate:(CGFloat)videoRate
|
|
|
|
withOutPath:(NSString *)outPath
|
|
|
|
outputFileType:(NSString *)outputFileType
|
|
|
|
presetName:(NSString *)presetName
|
|
|
|
didComplete:(void(^)(NSError *error,NSURL *compressionFileURL))completeBlock;
|
|
```
|
|
```
|
|
/**
|
|
|
|
视频区域剪裁 视频时长不变
|
|
|
|
|
|
|
|
@param videoPath 视频路径
|
|
### 4.10.3 新增视频水印
|
|
@param outPath 视频输出路径
|
|
|
|
@param outputFileType 视频格式
|
|
|
|
@param presetName 分辨率
|
|
|
|
@param videoSize 剪裁区域
|
|
|
|
@param videoPoint 剪裁起点
|
|
|
|
@param shouldScale 是否拉伸 YES拉伸 NO不拉伸 剪裁黑背景
|
|
|
|
@param completeBlock 剪裁完成后的回调
|
|
|
|
*/
|
|
|
|
+ (void)dw_videoSizeCropAndExportVideo:(NSString *)videoPath withOutPath:(NSString *)outPath outputFileType:(NSString *)outputFileType presetName:(NSString *)presetName size:(CGSize )videoSize point:(CGPoint )videoPoint shouldScale:(BOOL )shouldScale didComplete:(void(^)(NSError *error,NSURL *compressionFileURL) )completeBlock;
|
|
|
|
|
|
|
|
|
|
#### 4.10.3.1 添加单个视频水印
|
|
```
|
|
```
|
|
### 4.6.4视频区域兼时长剪裁
|
|
/// 添加单个视频水印
|
|
|
|
/// @param videoPath 视频路径
|
|
|
|
/// @param stickerImage 水印图片
|
|
|
|
/// @param stickerImagePoint 水印位置,point为水印所占视频位置的百分比。eg:CGPointMake(0.1, 0.1)
|
|
|
|
/// @param stickerImageSize 水印大小,为水印所占视频大小的百分比。eg:CGSizeMake(0.4, 0.4)
|
|
|
|
/// @param rotateAngle 水印旋转弧度。eg:M_PI_2
|
|
|
|
/// @param timeRange 添加水印的时间范围,kCMTimeRangeZero时,全部时长都添加水印
|
|
|
|
/// @param outPath 视频输出路径
|
|
|
|
/// @param outputFileType 视频格式
|
|
|
|
/// @param presetName 视频导出质量
|
|
|
|
/// @param completeBlock 完成后的回调
|
|
|
|
+ (void)dw_addStickerAndExportVideo:(NSString *)videoPath
|
|
|
|
withStickerImage:(UIImage *)stickerImage
|
|
|
|
stickerImagePoint:(CGPoint)stickerImagePoint
|
|
|
|
stickerImageSize:(CGSize)stickerImageSize
|
|
|
|
rotateAngle:(CGFloat)rotateAngle
|
|
|
|
timeRange:(CMTimeRange)timeRange
|
|
|
|
outPath:(NSString *)outPath
|
|
|
|
outputFileType:(NSString *)outputFileType
|
|
|
|
presetName:(NSString *)presetName
|
|
|
|
didComplete:(void(^)(NSError *error,NSURL *compressionFileURL))completeBlock;
|
|
|
|
|
|
```
|
|
```
|
|
/**
|
|
|
|
视频区域兼时长剪裁
|
|
|
|
|
|
|
|
@param videoPath 视频路径
|
|
|
|
@param outPath 视频输出路径
|
|
|
|
@param outputFileType 视频格式
|
|
|
|
@param presetName 分辨率
|
|
|
|
@param videoSize 剪裁区域
|
|
|
|
@param videoPoint 剪裁起点
|
|
|
|
@param shouldScale 是否拉伸 YES拉伸 NO不拉伸 剪裁黑背景
|
|
|
|
@param timeRange 截取视频的时间范围
|
|
|
|
@param completeBlock 剪裁完成后的回调
|
|
|
|
*/
|
|
|
|
+ (void)dw_videoSizeAndTimeCropAndExportVideo:(NSString *)videoPath withOutPath:(NSString *)outPath outputFileType:(NSString *)outputFileType presetName:(NSString *)presetName size:(CGSize )videoSize point:(CGPoint )videoPoint shouldScale:(BOOL )shouldScale range:(CMTimeRange)timeRange didComplete:(void(^)(NSError *error,NSURL *compressionFileURL) )completeBlock;
|
|
|
|
|
|
|
|
|
|
#### 4.10.3.2 批量添加视频水印
|
|
|
|
```
|
|
|
|
/// 批量添加视频水印
|
|
|
|
/// @param videoPath 视频路径
|
|
|
|
/// @param stickerImages 水印图片数组
|
|
|
|
/// @param stickerImagePoints 水印位置数组,points为水印所占视频位置的百分比数组。eg:@[[NSValue valueWithCGPoint:CGPointMake(0.1, 0.1)]]
|
|
|
|
/// @param stickerImageSizes 水印大小数组,sizes为水印所占视频大小的百分比数组。eg:@[[NSValue valueWithCGPoint:CGSizeMake(0.4, 0.4)]]
|
|
|
|
/// @param rotateAngles 水印旋转弧度数据。eg:[NSNumber numberWithFloat:M_PI_2]
|
|
|
|
/// @param timeRanges 添加水印的时间范围数组,kCMTimeRangeZero时,全部时长都添加水印
|
|
|
|
/// @param outPath 视频输出路径
|
|
|
|
/// @param outputFileType 视频格式
|
|
|
|
/// @param presetName 视频导出质量
|
|
|
|
/// @param completeBlock 完成后的回调
|
|
|
|
+ (void)dw_addStickerAndExportVideo:(NSString *)videoPath
|
|
|
|
withStickerImages:(NSArray <UIImage *>*)stickerImages
|
|
|
|
stickerImagePoints:(NSArray <NSValue *> *)stickerImagePoints
|
|
|
|
stickerImageSizes:(NSArray <NSValue *> *)stickerImageSizes
|
|
|
|
rotateAngles:(NSArray <NSNumber *> *)rotateAngles
|
|
|
|
timeRanges:(NSArray <NSValue *> *)timeRanges
|
|
|
|
outPath:(NSString *)outPath
|
|
|
|
outputFileType:(NSString *)outputFileType
|
|
|
|
presetName:(NSString *)presetName
|
|
|
|
didComplete:(void(^)(NSError *error,NSURL *compressionFileURL))completeBlock;
|
|
```
|
|
```
|
|
|
|
|
|
|
|
### 4.10.4 多视频合成
|
|
|
|
```
|
|
|
|
/// 多视频合成
|
|
|
|
/// @param videosPath 视频路径数组
|
|
|
|
/// @param videoSize 合成视频尺寸,不设置(CGRectZero)默认取第一个视频大小为基准
|
|
|
|
/// @param outPath 输出路径
|
|
|
|
/// @param outputFileType 视频格式
|
|
|
|
/// @param presetName 视频导出质量
|
|
|
|
/// @param completeBlock 完成后的回调
|
|
|
|
+(void)dw_compositeAndExportVideos:(NSArray <NSString *>*)videosPath
|
|
|
|
withVideoSize:(CGSize)videoSize
|
|
|
|
outPath:(NSString *)outPath
|
|
|
|
outputFileType:(NSString *)outputFileType
|
|
|
|
presetName:(NSString *)presetName
|
|
|
|
didComplete:(void(^)(NSError *error,NSURL *compressionFileURL))completeBlock;
|
|
|
|
```
|
|
|
|
### 4.10.5 插入音频
|
|
|
|
```
|
|
|
|
/// 插入音频
|
|
|
|
/// @param videoPath 视频路径
|
|
|
|
/// @param audioPath 待插入音频路径
|
|
|
|
/// @param originalVolume 原音频音量
|
|
|
|
/// @param insertVolume 插入音频音量
|
|
|
|
/// @param timeRange 插入音频范围,kCMTimeRangeZero时,从0开始添加
|
|
|
|
/// @param outPath 视频输出路径
|
|
|
|
/// @param outputFileType 视频格式
|
|
|
|
/// @param presetName 视频导出质量
|
|
|
|
/// @param completeBlock 完成后的回调
|
|
|
|
+(void)dw_insertAudioAndExportVideo:(NSString *)videoPath
|
|
|
|
withAudioPath:(NSString *)audioPath
|
|
|
|
originalVolume:(CGFloat)originalVolume
|
|
|
|
insertVolume:(CGFloat)insertVolume
|
|
|
|
timeRange:(CMTimeRange)timeRange
|
|
|
|
outPath:(NSString *)outPath
|
|
|
|
outputFileType:(NSString *)outputFileType
|
|
|
|
presetName:(NSString *)presetName
|
|
|
|
didComplete:(void(^)(NSError *error,NSURL *compressionFileURL))completeBlock;
|
|
|
|
```
|
|
|
|
### 4.10.6 修改视频分辨率
|
|
|
|
```
|
|
|
|
/// 修改视频分辨率
|
|
|
|
/// @param videoPath 视频路径
|
|
|
|
/// @param videoSize 要输出的视频分辨率
|
|
|
|
/// @param outPath 视频输出路径
|
|
|
|
/// @param outputFileType 视频格式
|
|
|
|
/// @param presetName 视频导出质量
|
|
|
|
/// @param completeBlock 完成后的回调
|
|
|
|
+ (void)dw_videoSizeChangeRenderAndExportVideo:(NSString *)videoPath
|
|
|
|
videoSize:(CGSize)videoSize
|
|
|
|
withOutPath:(NSString *)outPath
|
|
|
|
outputFileType:(NSString *)outputFileType
|
|
|
|
presetName:(NSString *)presetName
|
|
|
|
didComplete:(void(^)(NSError *error,NSURL *compressionFileURL))completeBlock;
|
|
|
|
```
|
|
|
|
|
|
## 4.7Demo具体使用
|
|
### 4.10.7 其他开放接口
|
|
|
|
```
|
|
|
|
/// 取得缩略图
|
|
|
|
/// @param videoPath 文件路径
|
|
|
|
/// @param time 第几秒的缩略图
|
|
|
|
+(UIImage *)dw_getThumbnailImage:(NSString *)videoPath time:(NSTimeInterval)time;
|
|
|
|
|
|
|
|
/// 十六进制色彩
|
|
|
|
/// @param string 色值
|
|
|
|
+(UIColor *)dw_colorWithHexString:(NSString *)string;
|
|
|
|
|
|
|
|
/// 删除文件
|
|
|
|
/// @param filePath 文件路径 并返回是否成功
|
|
|
|
+(BOOL)dw_deleteFileWithFilePath:(NSString *)filePath;
|
|
|
|
|
|
|
|
/// 获取文件大小
|
|
|
|
/// @param filePath 文件路径
|
|
|
|
+(CGFloat)dw_fileSizeAtPath:(NSString*)filePath;
|
|
|
|
```
|
|
|
|
|
|
|
|
## 4.11 Demo具体使用
|
|
Demo是示例源码,可直接用Xcode运行。Demo的设计旨在展示SDK各项功能的使用方法,如果希望应用获得更好的使用体验,要根据需求自行更改。
|
|
Demo是示例源码,可直接用Xcode运行。Demo的设计旨在展示SDK各项功能的使用方法,如果希望应用获得更好的使用体验,要根据需求自行更改。
|
|
如果在使用SDK过程中遇到其他问题请联系CC客服进行反馈。
|
|
如果在使用SDK过程中遇到其他问题请联系CC客服进行反馈。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 5.API查询
|
|
# 5.API 查询
|
|
[https://github.com/CCVideo/VOD_iOS_ShortVideo_SDK/tree/master/doc/api](https://github.com/CCVideo/VOD_iOS_ShortVideo_SDK/blob/master/doc/api)
|
|
[https://github.com/CCVideo/VOD_iOS_ShortVideo_SDK/tree/master/doc/api](https://github.com/CCVideo/VOD_iOS_ShortVideo_SDK/blob/master/doc/api)
|
|
|
|
|
|
# 6.Q&A
|
|
# 6.Q&A
|
|
|
|
|