文档

多源录制

更新时间:

短视频SDK在基础录制功能的基础上全新升级了录制模块,除了满足基础录制所有的录制能力,还新增支持了View录制(即录屏)。同时也可以把View录制、摄像头录制、本地视频等作为输入源进行实时合成录制,满足各种实时录制合成的场景。例如,摄像头录制+View录制可以实现白板教学场景;摄像头录制+本地视频可以实现合拍场景。

版本支持

版本

是否支持

专业版

支持

标准版

支持

基础版

不支持

概念介绍

在以下文档介绍中将提及一些特殊概念,为方便开发者理解,请预先对基础概念中的多源录制、轨道及轨道布局等概念做相关了解。

相关类功能

类名

功能

AliyunRecorder

多源录制核心类,包括录制、设置预览、设置特效、设置回调等多源录制的核心功能。

AliyunRecorderConfig

多源录制的配置类,设置录制的输出路径、添加采集源、添加水印、设置背景音乐等。

AliyunRecorderVideoConfig

输出视频配置类,输出视频的画面参数(分辨率、帧率、旋转角度、画面填充模式),压缩参数(编码、GOP、码率、视频质量,通常情况下不必设置,除非有相关要求)。

AliyunMicRecordController

麦克风控制器协议。

AliyunVideoRecordLayoutParam

输入源布局参数类,设置视频层级、自适应方式。

AliyunCameraRecordSource

摄像头录制输入源类。

AliyunCameraRecordController

摄像头录制控制器协议。

AliyunViewRecordSource

View录制输入源类。

AliyunViewRecordController

View录制控制器协议。

AliyunPlayerRecordSource

本地视频播放输入源配置类。

AliyunPlayerRecordController

本地视频播放控制器协议。

AliyunClipManager

录制片段管理器,获取片段信息,对视频片段进行删除操作等。

AliyunRecorderDelegate

录制代理回调。

多源录制流程

说明

多源录制功能需要获取摄像头和麦克风权限,否则无法录制。

多源录制的流程如下图所示:I多源录制.jpg

阶段

流程

说明

示例代码

基础

1

创建录制接口,并配置录制参数,添加录制源。

初始化

2

开启或结束预览。

预览控制

3

开始或停止录制。

开始录制

4

创建结束录制相关信息。

结束录制

进阶

5

配置输入源相关参数。

输入源控制-摄像头录制控制

输入源控制-View录制控制

输入源控制-本地视频控制

6

设置背景音乐、背景图片、变速、自定义渲染等。

其他功能

7

录制回调。

录制回调

初始化

初始化AliyunRecorder类,创建录制接口,并配置录制参数。

设置输出参数

通过AliyunRecorderVideoConfig设置输出视频的画面参数(分辨率、帧率、旋转角度、画面填充模式),压缩参数(编码、GOP、码率、视频质量,一般情况下不必设置,除非有相关要求)。

AliyunRecorderVideoConfig *videoConfig = [[AliyunRecorderVideoConfig alloc] init];
videoConfig.resolution = CGSizeMake(720, 1280); // 720P
videoConfig.fps = 30;
...

添加输入源

先通过输出参数对象与outputPath创建配置对象,然后添加输入源。

说明
  • 可根据业务场景组合多个采集源,可以添加一个或多个,但不建议超过3个。

  • 只能添加一个摄像头录制源,重复添加也无效。

//创建配置对象
AliyunRecorderConfig *config = [[AliyunRecorderConfig alloc] initWithVideoConfig:videoConfig outputPath:[taskPath stringByAppendingPathComponent:@"output.mp4"]];


//添加摄像头录制源
// 指定摄像头布局参数
AliyunVideoRecordLayoutParam *cameraLayout = [[AliyunVideoRecordLayoutParam alloc] initWithRenderMode:AliyunRenderMode_ResizeAspectFill];
cameraLayout.size = resolution;
cameraLayout.center = CGPointMake(resolution.width / 2.0, resolution.height / 2.0);
cameraLayout.zPosition = 1;
// 添加录制源,返回控制器
self.cameraRecorderController = [config addCamera:cameraLayout];
self.cameraRecorderController.preview = self.videoView;
self.cameraRecorderController.camera.resolution = AliyunRecordCameraResolution_3840x2160;
self.cameraRecorderController.camera.position = AVCaptureDevicePositionBack;


//添加View录制源
// 指定View录制布局参数
AliyunVideoRecordLayoutParam *viewRecordLayout = [[AliyunVideoRecordLayoutParam alloc] initWithRenderMode:AliyunRenderMode_ResizeAspect];
viewRecordLayout.size = CGSizeMake(0.5*videoConfig.resolution.width, 0.5*videoConfig.resolution.height);
viewRecordLayout.center = CGPointMake(0.5*videoConfig.resolution.width, 0.5*videoConfig.resolution.height);
viewRecordLayout.zPosition = 2;
// 指定View录制源参数
AliyunViewRecordSource *viewSource = [[AliyunViewRecordSource alloc] initWithTargetView:drawView fps:videoConfig.fps];
viewSource.captureInBackground = YES;
// 添加录制源,返回控制器
self.viewRecordController = [config addViewSource:viewSource layout:viewRecordLayout];


//添加本地播放源
// 指定View录制布局参数
AliyunVideoRecordLayoutParam *playerRecordLayout = [[AliyunVideoRecordLayoutParam alloc] initWithRenderMode:AliyunRenderMode_ResizeAspect];
playerRecordLayout.size = CGSizeMake(0.5*videoConfig.resolution.width, 0.5*videoConfig.resolution.height);
playerRecordLayout.center = CGPointMake(0.5*videoConfig.resolution.width, 0.5*videoConfig.resolution.height);
playerRecordLayout.zPosition = 2;
// 指定View录制源参数
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:videoPath] options:nil];
AliyunPlayerRecordSource *playerSource = [[AliyunPlayerRecordSource alloc] initWithAsset:asset fps:videoConfig.fps];
// 添加录制源,返回控制器
self.playerRecordController = [config addMVSource:playerSource layout:playerRecordLayout];
self.playerRecordController.preview = self.playerView;

创建实例

// 通过输入配置创建
AliyunRecorder *recorder = [[AliyunRecorder alloc] initWithConfig:config];
recorder.delegate = self;
recorder.clipManager.maxDuration = 5;
recorder.clipManager.minDuration = 1;
recorder.clipManager.deleteVideoClipsOnExit = YES;
self.aliyunRecorder = recorder;

预览控制

//开启预览
[self.aliyunRecorder startPreview];

//结束预览,通常在完成录制后,调用结束预览
[self.aliyunRecorder stopPreview];

开始录制

startRecording和stopRecording需要成对出现,可以调用一次或多次,对应SDK内部会生成一段或多段临时视频文件。

// 开始录制一段视频
[self.aliyunRecorder startRecord]; 

// 停止录制一段视频,并非立即停止状态,会出现录制状态的切换,注意通过onAliyunRecorder:stateDidChange:获取录制状态的回调
[self.aliyunRecorder stopRecord];

录制状态及说明如下:

状态

说明

AliyunRecorderState_Idle

空闲状态,等待录制。

AliyunRecorderState_LoadingForRecord

录制前加载,等待各个录制源首帧回调;收到全部回调后会自动变为Recording状态。

AliyunRecorderState_Recording

录制中。

AliyunRecorderState_Stopping

正在停止,等待内部缓冲处理完成会自动变为停止状态。

AliyunRecorderState_Stop

停止录制。

AliyunRecorderState_Error

发生错误,可以通过cancel来把状态重置为Idle。

结束录制

结束录制时可生成一个片段拼接的视频或只生成片段视频的配置信息。

// 结束录制,并且将录制片段视频拼接成一个完整的视频
[self.aliyunRecorder finishRecord:^(NSString *outputPath, NSError *error) {
 if (!error) {
 // 录制完成,可以把outputPath的视频进行预览、编辑、上传等
 }
}];

// 结束录制,不拼接视频片段,生成taskPath
[self.aliyunRecorder finishRecordForEdit:^(NSString *taskPath, NSError *error) {
 if (!error) {
 // 录制完成,后续通过taskPath初始化编辑器(AliyunEditor)进行视频编辑,详情参考编辑模块
 }
}];

输入源控制-摄像头录制控制

通过添加源返回基于AliyunCameraRecordController协议的控制器,可以执行参数调整、边框调整、基本美颜、人脸贴纸、静态贴纸、动图、静态滤镜、动效滤镜、拍照等操作。

常用参数调整

// 手电筒
self.cameraRecorderController.camera.torchMode = AVCaptureTorchModeOn;

// 摄像头位置
self.cameraRecorderController.camera.position = AVCaptureDevicePositionBack;

// 变焦倍数
self.cameraRecorderController.camera.videoZoomFactor = 2.0;

// 曝光度
self.cameraRecorderController.camera.exposureValue = 0.8;

// 方向
self.cameraRecorderController.camera.orientation = UIDeviceOrientationLandscapeLeft;

// 采集分辨率,一般情况下不建议修改,会根据输出大小自动适配合适采集分辨率
self.cameraRecorderController.camera.resolution = AliyunRecordCameraResolution_1280x720;

// 闪光灯,拍照时启用
self.cameraRecorderController.camera.flashMode = AVCaptureFlashModeOn;

边框调整

AliyunVideoRecordBorderInfo *cameraBorder = [AliyunVideoRecordBorderInfo new];
cameraBorder.color = UIColor.whiteColor;
cameraBorder.width = 3.0;
cameraBorder.cornerRadius = 10.0;
self.cameraRecorderController.borderInfo = cameraBorder;

基本美颜

// 开启
self.cameraRecorderController.beautifyStatus = YES;
self.cameraRecorderController.beautifyValue = 80;

// 关闭
self.cameraRecorderController.beautifyStatus = NO;
self.cameraRecorderController.beautifyValue = 0;

人脸贴纸

//添加人脸贴纸
[self.cameraRecorderController applyFaceSticker:[self.class resourcePath:@"Gif/hanfumei-800"]];

滤镜

支持自定义滤镜,滤镜的制作方法请参见滤镜及转场

//添加滤镜
AliyunEffectFilter *filter = [[AliyunEffectFilter alloc] initWithFile:path];
[self.cameraRecorderController applyFilter:filter];

动效滤镜

//添加动效滤镜
NSString *filterDir = [self.class resourcePath:@"AnimationEffect/split_screen_3"];
AliyunEffectFilter *animationFilter =[[AliyunEffectFilter alloc] initWithFile:filterDir];
[self.cameraRecorderController applyAnimationFilter:animationFilter];

静态贴纸

//添加静态贴纸
AliyunImageStickerController *imageController = [self.cameraRecorderController addImageSticker:imagePath];
[imageController beginEdit];
imageController.image.center = CGPointMake(150, 200);
[imageController endEdit];

动态贴纸

支持自定义动态贴纸,动态贴纸的制作方法请参见动图

//添加动态贴纸
AliyunGifStickerController * gifController = [self.cameraController addGifStickerWithConfig:[PathTool boundlePathWithPath:@"Resource/Gif/hanfumei-800"]];
[gifController beginEdit];
gifController.gif.center = CGPointMake(150, 200);
[gifController endEdit];

拍照

 // 拍摄一张图片 异步获取
 // image 采集的渲染后图片
 // rawImage 采集的原始图片
[self.cameraRecorderController takePhoto:^(UIImage *image, UIImage *rawImage) {
 
}];

输入源控制-View录制控制

通过添加源返回基于AliyunViewRecordController协议的控制器,仅可以进行边框调整。

边框

AliyunVideoRecordBorderInfo *border = [AliyunVideoRecordBorderInfo new];
border.color = UIColor.whiteColor;
border.width = 3.0;
border.cornerRadius = 10.0;
self.viewRecorderController.borderInfo = border;

输入源控制-本地视频控制

通过添加源返回基于AliyunPlayerRecordController协议的控制器,仅可以进行边框调整。

边框

AliyunVideoRecordBorderInfo *border = [AliyunVideoRecordBorderInfo new];
border.color = UIColor.whiteColor;
border.width = 3.0;
border.cornerRadius = 10.0;
self.playerRecordController.borderInfo = border;

其他功能

支持添加背景音乐、添加水印、设置背景等功能。

片段管理

通过startRecordstopRecord来录制多个片段,片段可通过clipManager管理,支持回删最后一个片段或删除所有片段等操作。接口参数请参考AliyunClipManager

// 删除最后一个视频片段
[self.aliyunRecorder.clipManager deletePart];
// 删除所有视频片段
[self.aliyunRecorder.clipManager deleteALLPart];

// 获取总的片段数量
[self.aliyunRecorder.clipManager partCount];

变速录制

//设置录制速度,建议为0.5到2之间。
[self.aliyunRecorder setRate:2];

背景音乐

// 添加背景音乐
AVURLAsset *audioAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:filePath] options:nil];
float audioDuration = CMTimeGetSeconds(audioAsset.duration);
[self.aliyunRecorder.config setBgMusicWithFile:filePath
 startTime:0.0 // 从0秒开始
 duration:MIN(self.aliyunRecorder.clipManager.maxDuration, audioDuration)];

// 移除背景音乐
[self.aliyunRecorder.config removeBgMusic];

水印

// 生成水印
- (AliyunRecorderImageSticker *) waterMark
{
 if (!_waterMark) {
 NSString *watermarkPath = [AlivcImage pathOfImageName:@"shortVideo_paster_gif"];
 _waterMark = [[AliyunRecorderImageSticker alloc] initWithImagePath:watermarkPath];
 _waterMark.size = CGSizeMake(42, 30);
 _waterMark.center = CGPointMake(_waterMark.size.width * 0.5 + 4, _waterMark.size.height * 0.5 + 4);
 _waterMark.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
 }
 return _waterMark;
}

// 应用水印
[self.aliyunRecorder.config addWaterMark:self.waterMark];

// 删除水印
[self.aliyunRecorder.config removeWaterMark:self.waterMark.stickerId];

设置背景

// 生成背景对象
- (AliyunRecorderBackgroundInfo *) bgInfo
{
 if (!_bgInfo) {
 _bgInfo = [AliyunRecorderBackgroundInfo new];
 // _bgInfo.color = UIColor.redColor;
 NSString *imgName = @"xxx.png";
 _bgInfo.image = [UIImage imageNamed:imgName];
 _bgInfo.renderMode = AliyunRenderMode_ResizeAspectFill;
 }
 return _bgInfo;
}

// 应用背景对象
self.aliyunRecorder.config.bgInfo = self.bgInfo;

自定义渲染

添加摄像头录制源后,会把采集的数据(CMSampleBufferRef)通过回调接口customRender传递给业务层,可以在业务层通过引入第三方SDK进行自定义渲染,最终把渲染的结果(CVPixelBufferRef)又交回给短视频SDK进行预览和合成。

// 第一步:设置自定义渲染,注意一定要有添加摄像头录制源
self.aliyunRecorder.customRender = self;
// 第二步:AliyunRecorderCustomRender协议
- (CVPixelBufferRef) onAliyunRecorderCustomRenderToPixelBuffer:(AliyunRecorder *)recorder withSampleBuffer:(CMSampleBufferRef)sampleBuffer {
 // 自定义渲染,此处可以接入美颜特效SDK,处理后返回CVPixelBufferRef示例
 // 不进行自定义渲染,可以返回CMSampleBufferGetImageBuffer(sampleBuffer)
 ...
}
说明

自定义渲染可以把摄像头采集回来的数据进行任何加工,应用场景包括美颜、美型、美妆、手势识别、AI抠像、绿幕抠图,美颜特效SDK已提供了这些能力,并能与短视频SDK很好的结合使用,详细使用请参见iOS短视频SDK Demo

录制回调

通过设置回调,及时获取音视频处理的进展和状态。

//常见的事件回调处理如下
#pragma mark - AliyunRecorderDelegate

- (void)onAliyunRecorderWillStopWithMaxDuration:(AliyunRecorder *)recorder {
 NSLog(@"Record2 Will Stop Recording With Max Duration");
 [self.aliyunRecorder stopPreview];
}

- (void)onAliyunRecorderDidStopWithMaxDuration:(AliyunRecorder *)recorder {
 NSLog(@"Record2 Did Recording With Max Duration");
 [self.aliyunRecorder finishRecord:^(NSString *outputPath, NSError *error) {
 if (!error) {

 }
 }];
}

- (void)onAliyunRecorder:(AliyunRecorder *)recorder progressWithDuration:(CGFloat)duration {
 NSLog(@"Record2 Video Duration: %f", duration);
}

- (void)onAliyunRecorder:(AliyunRecorder *)recorder occursError:(NSError *)error {
 NSLog(@"Record2 Occurs Error: %@", error);
}