录制
录制的相关接口是在BDCloudAVStreamContext类里,包括采集预览(startPreview),录制(startRecording:),添加视频美颜(applyBeautyBaseVideoFx)等。
注意:百度云拍摄器SDK所有的类都是以“BDCloud”开头。
BDCloudAVStreamContext类
BDCloudAVStreamContext是拍摄器SDK的流媒体上下文类,是接入拍摄器SDK产品的入口。开始使用前,需要先初始化BDCloudAVStreamContext类,注意BDCloudAVStreamContext是单例类。
BDCloudAVStreamContext初始化代码如下
_avStreamContext = [BDCloudAVStreamContext sharedInstance];
BDCloudAVStreamContext销毁代码如下
[_avStreamContext destroyInstance];
_avStreamContext = nil;
注意:BDCloudAVStreamContext初始化后,需要调用verifySDKLicense: completionHandler:验证客户的合法性,其中appid即用户申请的licenseID,若未申请授权,请参考快速接入
BDCloudAVStreamSettings类配置
BDCloudAVStreamSettings是拍摄器SDK配置项,支持客户调整摄像头位置、摄像头类型、视频维度(分辨率)、视频帧速率、视频帧码率及手电筒、对焦、曝光补光、预览放大缩小、预览模式。
考虑到配置项较多且偏专业,拍摄器SDK提供默认配置项,代码如下:
BDCloudAVStreamSettings *settings = [BDCloudAVStreamSettings defaultSettings];
预览前设置
完成流媒体上下文初始化及配置项后,下面就要创建预览前配置,创建拍摄器及预览画面,代码如下:
// 使用配置项创建拍摄器
_avStreamContext = [_avStreamContext initWithCaptureConfig:settings];
// 获取拍摄器预览界面
UIView *preview = _avStreamContext.view;
// 设置预览界面展示区域
preview.frame = self.view.bounds;
// 设置拍摄器回调代理
_avStreamContext.delegate = self;
// 将预览界面添加到用户控制器上
[self.view insertSubview:preview atIndex:0];
启动预览
启动预览对应startPreview接口,此接口发检查用户照相机和麦克风系统权限。
录制与停止录制
录制
- 调用录制接口前startRecording: recordCallBack:,需要先创建录制文件的路径,建议用户使用.MOV和.mp4文件
- 录制接口在写入文件的同时,会不断回调给使用方,用户需要关心回调状态BDCloudAVStreamFileOutputState。
- 代码示例如下:
[[BDCloudAVStreamContext sharedInstance] startRecording:recordVideoPath recordCallBack:^(BDCloudAVStreamFileOutputState state, double recordSecond, NSError *error) {
switch (state) {
case BDCloudAVStreamFileOutputStateStarting:
break;
case BDCloudAVStreamFileOutputStateStarted:
break;
case BDCloudAVStreamFileOutputStateCancel:
break;
case BDCloudAVStreamFileOutputStateError:
//错误信息
break;
case BDCloudAVStreamFileOutputStateEnding:
//录制结束
break;
case BDCloudAVStreamFileOutputStateEnded:
break;
default:
break;
}
}];
停止录制
- 代码示例如下:
[[BDCloudAVStreamContext sharedInstance] stopRecording];
录制设置
- 设置闪光灯是否开启,代码示例如下:
AVCaptureFlashMode _flashMode;
_flashMode = _flashMode == AVCaptureFlashModeOff ? AVCaptureFlashModeOn : AVCaptureFlashModeOff;
[[BDCloudAVStreamContext sharedInstance] toggleFlash:_flashMode];
if (_flashMode == AVCaptureFlashModeOff) {
[[BDCloudAVStreamContext sharedInstance] toggleTorch:NO];
}else {
[[BDCloudAVStreamContext sharedInstance] toggleTorch:YES];
}
- 设置自动对焦
[[BDCloudAVStreamContext sharedInstance] setCameraContinuousAutofocus:YES];
[[BDCloudAVStreamContext sharedInstance] setCameraFocusPointOfInterest:[BDCloudAVStreamContext sharedInstance].view.center];
- 设置曝光点
[[BDCloudAVStreamContext sharedInstance] setCameraExposurePointOfInterest:[BDCloudAVStreamContext sharedInstance].view.center];
- 设置缩放
[[BDCloudAVStreamContext sharedInstance] setCameraZoomFactor:1.3];
开启美颜
- 添加美颜(applyBeautyBaseVideoFx)特效后,在预览窗口就可以看到美颜效果。录制视频时,用户需要根据手机性能任意选择带美颜录制或者不带美颜录制。 美颜特效分为基础美颜(美白、磨皮)和高级美颜(大眼、瘦脸)。
- 开启美颜,代码示例如下:
//开启美颜
[_avStreamContext applyBeautyBaseVideoFx];
//调整美白
[[BDCloudAVStreamContext sharedInstance] adjustBeautyWhiteLevel:newValue];
//调整磨皮
[[BDCloudAVStreamContext sharedInstance] adjustBeautyBlurLevel:newValue];
//调整大眼
[[BDCloudAVStreamContext sharedInstance] adjustBeautyEnlargingLevel:newValue];
//调整瘦脸
[[BDCloudAVStreamContext sharedInstance] adjustBeautyThinningLevel:newValue];
- 注意,开启美颜需要在初始化拍摄器后。
- 注意:使用高级美颜时,需要申请对应权限,免费版本不支持此功能
开启滤镜
- 开启滤镜(applyEffect:)特效后,在预览窗口就可以看到滤镜效果。
- 代码示例如下:
[[BDCloudAVStreamContext sharedInstance] applyEffect:filterID];
- 注意:当前filterID仅支持内置滤镜使用,用户在申请授权成功后,会得到滤镜资源包,具体使用可以参考短视频SDK DemoD拍摄模块
开启贴纸
- 开启滤镜(applyLocalStickerVideoFx: stickerModelPath: stickerType: stickerIdentify:)特效后,在预览窗口就可以看到贴纸效果。注:【v3.0.0】版本后,贴纸不在支持内置使用,详见下方下载贴纸
- 代码示例如下:
- (void)setLocalSticker:(NSString *)stickerID andSubtype:(NSString *)subType withModel:(NSString *)model gestureSupport:(BOOL)isSupport {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
if (stickerID == nil || stickerID.length == 0) {
[[BDCloudAVStreamContext sharedInstance] disabledStickerVideoFx];
} else {
[[BDCloudAVStreamContext sharedInstance] disabledStickerVideoFx];
NSString *path = [BDSSVFileUtils getDocumentPath]; //大文件放在沙盒下的Library/Caches
NSString *finishPath = [NSString stringWithFormat:@"%@/Stickers", path]; //保存解压后文件的文件夹的路径
NSString *resultpath = [NSString stringWithFormat:@"%@/%@.zip", finishPath, stickerID]; //下载的zip包存放路径
//模型地址
NSString *modelpath = [NSString stringWithFormat:@"%@/%@.zip", finishPath, model]
BOOL isExist = [[NSFileManager defaultManager] fileExistsAtPath:resultpath];
BOOL isModelExist = [[NSFileManager defaultManager] fileExistsAtPath:modelpath];
//解压
if (isExist) {
NSString *localPath = [self localPath];
//资源地址
NSString *resultDestPath = [localPath stringByAppendingPathComponent:stickerID];
BOOL bSucess = [self unzipStickerPackage:resultpath destPath:resultDestPath];
NSString *modelDestPath = [localPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@-model", stickerID]];
BOOL bModelSucess = NO;
if (isModelExist) {
bModelSucess = [self unzipStickerPackage:modelpath destPath:modelDestPath];
}
if (!bModelSucess) {
modelDestPath = @"";
}
if (bSucess) {
if (isSupport) {
[[BDCloudAVStreamContext sharedInstance] applyLocalStickerVideoFx:resultDestPath stickerModelPath:modelDestPath stickerType:subType stickerIdentify:@"10273" upportGesture:YES];
} else {
[[BDCloudAVStreamContext sharedInstance] applyLocalStickerVideoFx:resultDestPath stickerModelPath:modelDestPath stickerType:subType stickerIdentify:@"10273" upportGesture:NO];
}
}
} else {
[[BDCloudAVStreamContext sharedInstance] disabledStickerVideoFx];
}
}
});
}
- 注意:当前仅支持贴纸内置使用,用户在申请授权成功后,会得到贴纸资源包,具体使用可以参考短视频SDK DemoD拍摄模块
下载贴纸
【v3.0】版本后,/贴纸采用后下载方式使用/,开通license的同时可以在Console购买或选择贴纸信息
下载贴纸涉及两个接口,贴纸列表信息和贴纸下载使用。
- 贴纸列表信息,即用于产品展示,建议开发者提前获取贴纸列表,可缓存,减少用户等待。
下方获取贴纸列表数据实例代码:
- (NSMutableArray<BDMVComposeStickerItem *> *)stickerItems {
if (!_stickerItems) {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
_stickerItems = [[NSMutableArray<BDMVComposeStickerItem *> alloc] init];
/**在线获取贴纸信息**/
//建议提前获取贴纸列表&&缓存本地
[[BDCloudAVStreamContext sharedInstance] downloadStickerList:^(NSArray * _Nonnull stickerList,
NSError * _Nonnull error)
{
if (stickerList) {
for (NSDictionary *dict in stickerList) {
BDMVComposeStickerItem *item = [[BDMVComposeStickerItem alloc] initWitStickerDict:dict type:YES];
[self->_stickerItems addObject:item];
}
}
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return _stickerItems;
}
return _stickerItems;
}
贴纸下载使用,即用户选择某个贴纸后,下载贴纸并且加载使用。注:部分贴纸还会涉及模型下载,见下方示例代码
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
BDMVComposeStickerItem *item = self.stickers[indexPath.row];
if (item.state == BDMVComposeStickerItemState_Downloading || indexPath == self.selectedIndexPath) {
return;
}
// 移除当前贴纸
if (self.selectedIndexPath && self.selectedIndexPath.row < self.stickers.count) {
BDMVComposeStickerItem *item = self.stickers[self.selectedIndexPath.row];
item.state = BDMVComposeStickerItemState_Inexistence;
[collectionView reloadItemsAtIndexPaths:@[self.selectedIndexPath]];
}
//选择新贴纸
if (indexPath.row < self.stickers.count) {
if (![self isExistWithStickerItem:item]) {
//本地无缓存当前贴纸
item.state = BDMVComposeStickerItemState_Downloading;
[collectionView reloadItemsAtIndexPaths:@[indexPath]];
// 首先创建缓存文件夹
// 再下载贴纸列表
if (![self isExistWithStickerDir]) {
NSLog(@"缓存贴纸文件夹创建失败~~");
}
[[BDCloudAVStreamContext sharedInstance] downloadStickerVideoFx:item.identifier
downloadCallBack:^(NSDictionary * _Nonnull stickerDic,
NSError * _Nonnull error) {
if (stickerDic) {
BDMVComposeStickerItem *remoteItem = [[BDMVComposeStickerItem alloc] initWitStickerDict:stickerDic type:YES];
[self downloadStickerZip:remoteItem.decryptFile md5:remoteItem.fileMd5 completionHandler:^(NSString *md5){
// fix 用户快速切换贴纸
if ([md5 containsString:item.fileMd5]) {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// 部分贴纸还依赖模型文件
if (remoteItem.modelRemotePath) {
[self asynDownloadDecalsWithURL:[NSURL URLWithString:remoteItem.modelRemotePath] destination:remoteItem.model_sk completion:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
if (!error) {
[self setLocalSticker:item.fileMd5 andSubtype:item.sub_type withModel:remoteItem.model_sk gestureSupport:item.gestureSupport];
}else {
NSLog(@"AR模型下载失败");
}
}];
}else {
[self setLocalSticker:item.fileMd5 andSubtype:item.sub_type withModel:remoteItem.model_sk gestureSupport:item.gestureSupport];
}
dispatch_async(dispatch_get_main_queue(), ^{
if (self.selectedIndexPath) {
BDMVComposeStickerItem *selectedItem = self.stickers[self.selectedIndexPath.row];
selectedItem.state = BDMVComposeStickerItemState_Inexistence;
[collectionView reloadItemsAtIndexPaths:@[self.selectedIndexPath]];
}
item.state = BDMVComposeStickerItemState_OK;
self.selectedIndexPath = indexPath;
[collectionView reloadItemsAtIndexPaths:@[indexPath]];
});
});
} else {
remoteItem.state = BDMVComposeStickerItemState_Inexistence;
[collectionView reloadItemsAtIndexPaths:@[indexPath]];
}
}];
}
}];
} else {
//本地有缓存
NSLog(@"贴纸已缓存");
[self setLocalSticker:item.fileMd5 andSubtype:item.sub_type withModel:item.model_sk gestureSupport:item.gestureSupport];
dispatch_async(dispatch_get_main_queue(), ^{
if (self.selectedIndexPath) {
BDMVComposeStickerItem *selectedItem = self.stickers[self.selectedIndexPath.row];
selectedItem.state = BDMVComposeStickerItemState_Inexistence;
[collectionView reloadItemsAtIndexPaths:@[self.selectedIndexPath]];
}
item.state = BDMVComposeStickerItemState_OK;
self.selectedIndexPath = indexPath;
[collectionView reloadItemsAtIndexPaths:@[indexPath]];
});
}
}
}