-
Notifications
You must be signed in to change notification settings - Fork 145
playerRecord
短视频录制功能也可以理解为录屏功能,可以将当前正在播放的视频(可以包含有UI界面)录制为mp4或flv格式的文件保存到本地。
如果不需要录制UI,可以直接获取播放器返回的原始音视频数据写入文件,这种方法比较简单,此处不再赘述。本文则重点介绍如何完成含有UI的播放录制功能。
因为视频录制功能需要音视频的编码和复用功能,而这些功能对于独立的播放SDK并不存在也不需要,所以要使用短视频录制功能,需要集成的SDK为融合版SDK,使用其中的KSYGPUPicMixer、KSYAudioMixer、KSYGPUPicOutput等模块
v1.9.5及以上版本支持
播放时通过播放器中的textureBlock获取渲染的TextureId,与UIElement叠加后得到视频数据送入KSYStreamerBase模块;原始音频数据则从播放器的audioDataBlock中获取,经过KSYAudioMixer后送入KSYStreamerBase模块,示意图如下:
- 支持自定义录制UI层级
- 能够按照视频帧率录制
- 在某些设备上及资源占用严重
v2.1.1及以上版本支持
音频数据的获取与处理方式同方案一,不同之处是视频和UI数据的获取,方案二通过直接截取UIView上内容来获取当前的显示内容,转换为CVPixerBuffer后直接送入KSYStreamerBase模块,示意图如下:
- 支持自定义录制UI层级
- 可自定义录制帧率
- 资源占用相对较少
- 无法按照视频播放的帧率进行录制
KSYLive_iOS的Demo中提供了KSYUIRecorderKit类实现录屏功能,KSYRecordVC类中演示了如何使用KSYUIRecorderKit进行短视频录制 录制功能的具体实现请参见KSYUIRecorderKit.m文件源码,此处简单介绍直接使用该类的方法
-
引入所需头文件
#import "KSYUIRecorderKit.h" #import <GPUImage/GPUImage.h> #import <libksygpulive/libksygpulive.h>
-
声明KSYMoviePlayerController对象和KSYUIRecorderKit对象
@property (strong, nonatomic) KSYMoviePlayerController *player; @property (strong, nonatomic) KSYUIRecorderKit* kit;
-
初始化KSYUIRecorderKit对象
-(void)setupUIKit{ _kit = [[KSYUIRecorderKit alloc]init]; [self addUIToKit]; } //addUIToKit将需要录制的界面元素添加到_kit.contentView,未添加的元素将不能被录制下来 -(void)addUIToKit{ [_kit.contentView addSubview:labelVolume]; [_kit.contentView addSubview:sliderVolume]; [_kit.contentView addSubview:lableHWCodec]; [_kit.contentView addSubview:switchHwCodec]; [_kit.contentView addSubview:btnPlay]; [_kit.contentView addSubview:btnPause]; [_kit.contentView addSubview:btnResume]; [_kit.contentView addSubview:btnStop]; [_kit.contentView addSubview:btnQuit]; [_kit.contentView addSubview:btnStartRecord]; [_kit.contentView addSubview:btnStopRecord]; [_kit.contentView addSubview:stat]; [_kit.contentView addSubview:_player.view]; [self.view addSubview:_kit.contentView]; [_kit.contentView sendSubviewToBack:videoView]; }
-
初始化KSYMoviePlayerController对象并设置音视频数据的回调
此处对播放器的初始化使用initWithContentURL:sharegroup:进行初始化操作self.player = [[KSYMoviePlayerController alloc] initWithContentURL:_url sharegroup:[[[GPUImageContext sharedImageProcessingContext] context] sharegroup]]; [self setupObservers]; //player视频数据输入 __weak KSYUIRecorderKit* weakKit = _kit; _player.textureBlock = ^(GLuint textureId, int width, int height, double pts){ CGSize size = CGSizeMake(width, height); CMTime _pts = CMTimeMake((int64_t)(pts * 1000), 1000); [weakKit processWithTextureId:textureId TextureSize:size Time:_pts]; }; //player音频数据输入 _player.audioDataBlock = ^(CMSampleBufferRef buf){ CMTime pts = CMSampleBufferGetPresentationTimeStamp(buf); if(pts.value < 0) { return; } [weakKit processAudioSampleBuffer:buf]; };
-
开始录制
path为录制文件的保存路径,目前支持mp4和flv格式,依靠后缀名区分NSString* recordFilePath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/RecordAv.mp4"]; NSURL * path =[[NSURL alloc] initWithString:recordFilePath]; [_kit startRecord:path];
-
停止录制
[_kit stopRecord];
因为stopRecord操作为异步操作,所以stopRecord调用结束后并不表示文件已经写完,需要用以下方式处理
-
启动录制前注册KSYStreamStateDidChangeNotification消息
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onStreamStateChange:) name:(KSYStreamStateDidChangeNotification) object:nil];
-
当收到KSYStreamStateDidChangeNotification消息,且_kit.writer.streamState的值为KSYStreamStateIdle时才表示文件已经写完,此时可以进一步处理文件,否则有可能因为文件被占用导致操作失败
- (void) onStreamStateChange :(NSNotification *)notification{ if (_kit.writer.streamState == KSYStreamStateIdle && _kit.bPlayRecord == NO){ [self saveVideoToAlbum: recordFilePath]; } }