最近在做直播内录制视频分享的功能,便尝试使用了ReplayKit,期间遇到一些问题,在这里记录下来。
在尝试过程中,遇到两种场景:
场景1
- 开启 AVAssetWriter (包含 Audio / Video Writer Input)
- 使用RPScreenRecorder开始录制(不启动Microphone)
- 录制成功并成功获得视频
场景2
- 开启 AVAssetWriter (包含 Audio / Video Writer Input)
- 使用RPScreenRecorder开始录制(启动Microphone)
- 录制失败
针对第二种情况,网上相应的解决方案很少(不知道是不是只有我遇到了)。所以在经过n次google(stackoverflow上的解决方案)和自己尝试之后,终于成功解决。下面是我的代码
if (openMic) {
[RPScreenRecorder sharedRecorder].microphoneEnabled = YES;
} else {
[RPScreenRecorder sharedRecorder].microphoneEnabled = NO;
}
[self.videoWriter startWriting];
__weak typeof(self) weakSelf = self;
[[RPScreenRecorder sharedRecorder] startCaptureWithHandler:^(CMSampleBufferRef _Nonnull sampleBuffer,RPSampleBufferType bufferType, NSError *_Nullable error) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!CMSampleBufferDataIsReady(sampleBuffer)) {
return;
}
if (strongSelf.videoWriter.status == AVAssetWriterStatusFailed) {
NSLog(@"[录屏]AVAssetWriterStatusFailed");
return;
}
if (strongSelf.videoWriter.status == AVAssetWriterStatusWriting) {
if (bufferType == RPSampleBufferTypeVideo) {
if (!strongSelf.startedSession) {
[strongSelf.videoWriter startSessionAtSourceTime:CMSampleBufferGetPresentationTimeStam(sampleBuffer)];
strongSelf.startedSession = YES;
NSLog(@"[录屏]开启session 视频处");
}
if (CMTimeCompare(kCMTimeInvalid, strongSelf.firstVideoFramTime) == 0) {
strongSelf.firstVideoFramTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
}
if ([strongSelf.videoWriterInput isReadyForMoreMediaData]) {
@try {
[strongSelf.videoWriterInput appendSampleBuffer:sampleBuffer];
NSLog(@"[录屏]写入视频数据");
} @catch (NSException *exception) {
NSLog(@"[录屏]写入视频数据失败");
}
}
}
if (bufferType == RPSampleBufferTypeAudioApp || bufferType == RPSampleBufferTypeAudioMic) {
// 可以在这里做一些过滤操作
// if (onlyMicAudio && bufferType == RPSampleBufferTypeAudioApp) {
// return;
// }
if (CMTimeCompare(kCMTimeInvalid, strongSelf.firstVideoFramTime) == 0 || CMTimeCompar(strongSelf.firstVideoFramTime, CMSampleBufferGetPresentationTimeStamp(sampleBuffer)) == 1) {
return;
}
if (!strongSelf.startedSession) {
[strongSelf.videoWriter startSessionAtSourceTime:CMSampleBufferGetPresentationTimeStam(sampleBuffer)];
strongSelf.startedSession = YES;
NSLog(@"[录屏]开启session 音频处");
}
if ([strongSelf.audioWriterInput isReadyForMoreMediaData]) {
@try {
[strongSelf.audioWriterInput appendSampleBuffer:sampleBuffer];
NSLog(@"[录屏]写入音频数据");
} @catch (NSException *exception) {
NSLog(@"[录屏]写入音频数据失败");
}
}
}
}
} completionHandler:^(NSError *_Nullable error) {
}];
下面是 AVAssetWriter 和 AVAssetWriterInput 的配置(因为不是专业的多媒体工程师,所以很多参数配置不一定合理,仅供大家参考)
- (void)setupVideoWriter
{
if (!_videoWriter) {
NSURL *outputURL = [NSURL fileURLWithPath:self.videoOutputPath];
NSError *error = nil;
_videoWriter = [AVAssetWriter assetWriterWithURL:outputURL fileType:AVFileTypeQuickTimeMovie error:&error];
if (error) {
NSLog(@"创建Video Writer失败:%@", [error localizedDescription]);
}
}
}
- (void)setupVideoWriterInput
{
if (!_videoWriterInput) {
CGFloat scale = [UIScreen mainScreen].scale;
CGSize size = CGSizeMake(CGRectGetWidth([UIScreen mainScreen].bounds) * scale, CGRectGetHeight([UIScreen mainScreen].bounds) * scale);
NSDictionary *copressionProperties = @{ AVVideoAverageBitRateKey : @(1200 * 1024) };
_videoWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo
outputSettings:@{
AVVideoCodecKey : AVVideoCodecH264,
AVVideoWidthKey : @(size.width),
AVVideoHeightKey : @(size.height),
AVVideoCompressionPropertiesKey : copressionProperties
}];
_videoWriterInput.expectsMediaDataInRealTime = YES;
if ([self.videoWriter canAddInput:_videoWriterInput]) {
[self.videoWriter addInput:_videoWriterInput];
} else {
NSLog(@"无法添加Video Writer Input");
}
}
}
- (void)setupAudioWriterInput
{
if (!_audioWriterInput) {
AudioChannelLayout acl;
bzero(&acl, sizeof(acl));
acl.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
_audioWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio
outputSettings:@{
AVSampleRateKey : @(44100),
AVFormatIDKey : @(kAudioFormatAppleLossless),
AVEncoderBitDepthHintKey : @(16),
AVNumberOfChannelsKey : @(1),
AVChannelLayoutKey : [NSData dataWithBytes:&acl length:sizeof(acl)],
}];
_audioWriterInput.expectsMediaDataInRealTime = YES;
if ([self.videoWriter canAddInput:_audioWriterInput]) {
[self.videoWriter addInput:_audioWriterInput];
} else {
NSLog(@"无法添加Video Writer Input");
}
}
}