Replaykit,startCaptureWithHandler()不在captureHandler中发送视频类型的CMSampleBufferRef

Tal*_*han 7 ios replaykit rpscreenrecorder

我已经实现了一个RPScreenRecorder记录屏幕和麦克风音频.多次录制完成后,我停止录制并使用视频合并Audios,AVMutableComposition然后将所有视频合并为单视频.

对于屏幕录制和获取视频和音频文件,我正在使用

- (void)startCaptureWithHandler:(nullable void(^)(CMSampleBufferRef sampleBuffer, RPSampleBufferType bufferType, NSError * _Nullable error))captureHandler completionHandler:
Run Code Online (Sandbox Code Playgroud)

用于停止录制.我叫这个功能:

- (void)stopCaptureWithHandler:(void (^)(NSError *error))handler;
Run Code Online (Sandbox Code Playgroud)

这些都很直接.

大部分时间它都很棒,我收到视频和音频CMSampleBuffers.但有时会发生这种情况,startCaptureWithHandler只发送音频缓冲区但不发送视频缓冲区. 一旦我遇到这个问题,它将不会发生,直到我重新启动我的设备并重新安装应用程序.这使我的应用程序对用户来说不可靠.我认为这是一个重播工具包问题,但无法与其他开发人员发现相关问题.如果你们中的任何一个遇到这个问题并得到解决方案,请告诉我.

我已多次检查但未在配置中看到任何问题.但无论如何它在这里.

NSError *videoWriterError;
videoWriter = [[AVAssetWriter alloc] initWithURL:fileString fileType:AVFileTypeQuickTimeMovie
                                           error:&videoWriterError];


NSError *audioWriterError;
audioWriter = [[AVAssetWriter alloc] initWithURL:audioFileString fileType:AVFileTypeAppleM4A
                                           error:&audioWriterError];

CGFloat width =UIScreen.mainScreen.bounds.size.width;
NSString *widthString = [NSString stringWithFormat:@"%f", width];
CGFloat height =UIScreen.mainScreen.boNSString *heightString = [NSString stringWithFormat:@"%f", height];unds.size.height;

NSDictionary  * videoOutputSettings= @{AVVideoCodecKey : AVVideoCodecTypeH264,
                                       AVVideoWidthKey: widthString,
                                       AVVideoHeightKey : heightString};
videoInput  = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:videoOutputSettings];

videoInput.expectsMediaDataInRealTime = true;

AudioChannelLayout acl;
bzero( &acl, sizeof(acl));
acl.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
NSDictionary * audioOutputSettings = [ NSDictionary dictionaryWithObjectsAndKeys:
                                      [ NSNumber numberWithInt: kAudioFormatAppleLossless ], AVFormatIDKey,
                                      [ NSNumber numberWithInt: 16 ], AVEncoderBitDepthHintKey,
                                      [ NSNumber numberWithFloat: 44100.0 ], AVSampleRateKey,
                                      [ NSNumber numberWithInt: 1 ], AVNumberOfChannelsKey,
                                      [ NSData dataWithBytes: &acl length: sizeof( acl ) ], AVChannelLayoutKey,
                                      nil ];

audioInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeAudio outputSettings:audioOutputSettings];

[audioInput setExpectsMediaDataInRealTime:YES];

[videoWriter addInput:videoInput];
    [audioWriter addInput:audioInput];

    [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:nil];

[RPScreenRecorder.sharedRecorder startCaptureWithHandler:^(CMSampleBufferRef  _Nonnull sampleBuffer, RPSampleBufferType bufferType, NSError * _Nullable myError) {

Block

}
Run Code Online (Sandbox Code Playgroud)

startCaptureWithHandler函数也具有非常直接的功能:

[RPScreenRecorder.sharedRecorder startCaptureWithHandler:^(CMSampleBufferRef  _Nonnull sampleBuffer, RPSampleBufferType bufferType, NSError * _Nullable myError) {

                    dispatch_sync(dispatch_get_main_queue(), ^{


                        if(CMSampleBufferDataIsReady(sampleBuffer))
                        {

                            if (self->videoWriter.status == AVAssetWriterStatusUnknown)
                            {
                                    self->writingStarted = true;
                                    [self->videoWriter startWriting];
                                    [self->videoWriter startSessionAtSourceTime:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)];

                                    [self->audioWriter startWriting];
                                    [self->audioWriter startSessionAtSourceTime:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)];
                            }
                            if (self->videoWriter.status == AVAssetWriterStatusFailed) {
                                return;
                            }

                            if (bufferType == RPSampleBufferTypeVideo)
                            {

                                if (self->videoInput.isReadyForMoreMediaData)
                                {
                                        [self->videoInput appendSampleBuffer:sampleBuffer];
                                }
                            }
                            else if (bufferType == RPSampleBufferTypeAudioMic)
                            {
                                //                                printf("\n+++ bufferAudio received %d \n",arc4random_uniform(100));
                                if (writingStarted){
                                    if (self->audioInput.isReadyForMoreMediaData)
                                    {
                                            [self->audioInput appendSampleBuffer:sampleBuffer];
                                    }
                                }
                            }

                        }
                    });

                }
Run Code Online (Sandbox Code Playgroud)

此外,当出现这种情况时,系统屏幕录像机也会损坏.在单击系统记录器时,此错误显示:

mediaservice错误

错误显示"屏幕录制已停止,原因是:由于Mediaservices错误导致录制失败".

必须有两个原因:

  1. iOS Replay工具包处于测试阶段,这就是为什么它在使用后会出现问题.
  2. 我已经实现了任何有问题的逻辑,这导致replaykit崩溃.

如果是问题没有.1,那没问题.如果这是问题没有.2然后我必须知道我可能在哪里错了?

意见和帮助将不胜感激.

Tal*_*han 3

因此,我遇到过一些情况,重播套件完全崩溃,系统记录器每次都会显示错误,除非您重新启动设备。

第一个场景

当您开始录制并在完成处理程序中停止它时

[RPScreenRecorder.sharedRecorder startCaptureWithHandler:^(CMSampleBufferRef  _Nonnull sampleBuffer, RPSampleBufferType bufferType, NSError * _Nullable error) {
    printf("recording");
} completionHandler:^(NSError * _Nullable error) {
    [RPScreenRecorder.sharedRecorder stopCaptureWithHandler:^(NSError * _Nullable error) {
        printf("Ended");
    }];
}];
Run Code Online (Sandbox Code Playgroud)

场景二

当您开始录制并直接在捕获处理程序中停止它时

__block BOOL stopDone = NO;
[RPScreenRecorder.sharedRecorder startCaptureWithHandler:^(CMSampleBufferRef  _Nonnull sampleBuffer, RPSampleBufferType bufferType, NSError * _Nullable error) {
    if (!stopDone){
        [RPScreenRecorder.sharedRecorder stopCaptureWithHandler:^(NSError * _Nullable error) {
            printf("Ended");
        }];
        stopDone = YES;
    }
    printf("recording");
} completionHandler:^(NSError * _Nullable error) {}];
Run Code Online (Sandbox Code Playgroud)

更多场景还有待发现,我会不断更新答案

更新1

确实,当我们在开始后立即停止录制时,系统录制的屏幕会出现错误,但是当我们再次调用startcapture后,它似乎工作正常。

我还遇到了一种情况,我仅在我的应用程序中没有获得视频缓冲区,并且系统屏幕录像机工作正常,将很快更新解决方案。

更新2

所以问题是,我的实际应用程序很旧,并且正在维护并及时更新。当重放套件出错时,我原来的应用程序无法接收视频缓冲区,我不知道是否有配置导致这种情况发生,或者什么?

但新的示例应用程序似乎工作正常,并且在重播工具包之后变得错误。当我下次调用 startCapture 时,重放套件就会变得正常。 诡异的

更新3

我观察到新问题。当权限警报出现时,应用程序将转到后台。由于我编写了代码,每当应用程序进入后台时,就会发生一些 UI 更改,并且录制将停止。这导致了错误

录制因多任务处理和内容大小调整而中断

我还不确定是哪个特定的 UI 更改导致了此故障,但只有当权限警报显示并且进行了 UI 更改时才会出现此故障。 如果有人注意到此问题的任何特殊情况,请告诉我们。