iOS直播与点播iOS开发实践直播/短视频技术

iOS 直播屏幕Replaykit

2018-08-01  本文已影响2546人  pokeey

相关文章
iOS 解决LFLiveKit 自带GPUImage
iOS ReplayKit RPRecordingErrorFailedToStart

Github地址

Replaykit是iOS对屏幕进行直播推出的框架

流程图

本文涉及三方:

LFLiveKit-ReplayKit

准备工作

使用Replaykit需要建立两个扩展

Broadcast Upload Extension  接受和上传视频帧和音频帧(记录:[RPScreenRecorder sharedRecorder]不开启enableMic就没mic声音)
Broadcast Setup UI Extension 用户交互界面,比如输入直播地址
这两个可以简单理解为一个是拉皮条的,一个是干活的,缺一不可

选择Broadcast Upload Extension


建立扩展

勾选上Include UI Extension选项,就会自动添加Broadcast Setup UI Extension扩展


勾选上UI这个选项就会自动建立UI的扩展了

建立这两个扩展之后,项目里就会多出两个新的target


扩展

先简单介绍一下这两个扩展里的那点勾当

BroadcastSetupViewController,用来布局直播配置界面
这个Controller就像平常VC那样用
其实扩展就可以理解为一个新的app,平时怎么用,在这就怎么用

BroadcastSetupViewController里用户输入完信息之后,在控制器里调用

[self.extensionContext completeRequestWithBroadcastURL:broadcastURL setupInfo:setupInfo]; 
//该方法是iOS11后的的新方法

用来将用户配置信息传递给刚建立的另一个扩展Broadcast Upload Extension
其中的setupInfo是NSDictionary类型,用来存储自定义信息

比如:@{ 
  @"broadcastName" : @"example",
  @"MyName":@"Pokkey"
 };

这个会传进Broadcast Upload Extension里的

 - (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {}

其中的setupInfo就是传进来的setupInfo

起手

调起Replaykit进行屏幕直播

咱们建立的 Broadcast Upload Extension 和 Broadcast Setup UI Extension 都是依附于主app的扩展app,但是这个扩展不是只有咱们的主App能吊起来,其他在主app里添加了调起直播扩展的都能调起咱们写的这个直播扩展,当然别人写的直播扩展你的app也能调起来。

在app里引入Replaykit

#import <ReplayKit/ReplayKit.h>

调起扩展,调下面这个就能看到present了一个控制器,里面装满了你手机的直播扩展,包括我们自己的那个。

[RPBroadcastActivityViewController loadBroadcastActivityViewControllerWithHandler:^(RPBroadcastActivityViewController * _Nullable broadcastActivityViewController, NSError * _Nullable error) {
            if (error) {
                NSLog(@"RPBroadcast err %@", [error localizedDescription]);
            } else {
                broadcastActivityViewController.delegate = self;
                broadcastActivityViewController.modalPresentationStyle = UIModalPresentationPopover;
                [self presentViewController:broadcastActivityViewController animated:YES completion:nil];
            }
            
        }];

加上代理

@interface ViewController ()<RPBroadcastActivityViewControllerDelegate, RPBroadcastControllerDelegate>{

实现代理方法

这个方法是用户选了扩展之后回调的方法,我们在这方法里正式调起UI扩展,

- (void)broadcastActivityViewController:(RPBroadcastActivityViewController *) broadcastActivityViewController
       didFinishWithBroadcastController:(RPBroadcastController *)broadcastController
                                  error:(NSError *)error {
    [broadcastActivityViewController dismissViewControllerAnimated:YES
                                                        completion:nil];
    NSLog(@"BundleID %@", broadcastController.broadcastExtensionBundleID);
    self.broadcastController = broadcastController;
    if (error) {
        NSLog(@"BAC: %@ didFinishWBC: %@, err: %@",
              broadcastActivityViewController,
              broadcastController,
              error);
        return;
    }
    [broadcastController startBroadcastWithHandler:^(NSError * _Nullable error) {
        if (!error) {
            NSLog(@"--fshfka----success");
        }
        else {
            NSLog(@"startBroadcast %@",error.localizedDescription);
        }
    }];
}

这个方法用来接收直播传回来的NSDictionary

// Watch for service info from broadcast service
- (void)broadcastController:(RPBroadcastController *)broadcastController
       didUpdateServiceInfo:(NSDictionary <NSString *, NSObject <NSCoding> *> *)serviceInfo {
    NSLog(@"didUpdateServiceInfo: %@", serviceInfo);
}

直播关闭

// Broadcast service encountered an error
- (void)broadcastController:(RPBroadcastController *)broadcastController
         didFinishWithError:(NSError *)error {
    NSLog(@"didFinishWithError: %@", error);
}
>>> 特别提示!!!
>>> 特别提示!!!
>>> 特别提示!!!
>>> 如果开始直播后画面没有变化,就没有视频帧
如果需要接入麦克风
[[RPScreenRecorder sharedRecorder] setMicrophoneEnabled:YES];

接下来我们就要进入Replaykit的关键部分了

开干

进入核心部分UploadExtension,建立UploadExtension扩展会根据模版自动建立SampleHandle.h和.m两个文件

UI调起这个方法,传入自定义信息

- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {
    
    // User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional. 
}

这三个方法覆盖父类,接受停止,继续,和停止事件

- (void)broadcastPaused {
    // User has requested to pause the broadcast. Samples will stop being delivered.
}

- (void)broadcastResumed {
    // User has requested to resume the broadcast. Samples delivery will resume.
}

- (void)broadcastFinished {
    // User has requested to finish the broadcast.
}

这个接收传过来的
<视频帧 RPSampleBufferTypeVideo>
< app音效 RPSampleBufferTypeAudioApp >
< 话筒 RPSampleBufferTypeAudioMic >

- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
    
    switch (sampleBufferType) {
        case RPSampleBufferTypeVideo:
            // Handle video sample buffer
            break;
        case RPSampleBufferTypeAudioApp:
            // Handle audio sample buffer for app audio
            break;
        case RPSampleBufferTypeAudioMic:
            // Handle audio sample buffer for mic audio
            break;
            
        default:
            break;
    }
}

这个方法才是核心方法,在这个里拿到了视频帧和音频帧就可以推给直播平台了

不过后来又出了个方法,在这个里也是直接拿到视频帧和音频帧,而且不需要掉Extension,不过这两种方法见仁见智,看哪种更适合你的需求

[RPScreenRecorder sharedRecorder]
- (void)startCaptureWithHandler:(nullable void(^)(CMSampleBufferRef sampleBuffer, RPSampleBufferType bufferType, NSError * _Nullable error))captureHandler completionHandler:(nullable void(^)(NSError * _Nullable error))completionHandler API_AVAILABLE(ios(11.0), tvos(11.0));

数据传输

在扩展里最好建立一个单例来进行IO,防止扩展多次调用造成重复创建。
在demo中使用ZFUploadTool负责进行数据的传输

- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
    switch (sampleBufferType) {
        case RPSampleBufferTypeVideo:
// 将视频帧交给ZFUploadTool
            [self.tool sendVideoBuffer:sampleBuffer];
            break;
        case RPSampleBufferTypeAudioApp:
            //            [self.tool sendAudioBuffer:sampleBuffer];
            break;
        case RPSampleBufferTypeAudioMic:
// 将音频帧交给ZFUploadTool 此项需要打开 [[RPScreenRecorder sharedRecorder] setMicrophoneEnabled:YES];
            [self.tool sendAudioBuffer:sampleBuffer];
            break;
            
        default:
            break;
    }
}

在ZFUploadTool只需要

[self.session pushAudioBuffer:sampleBuffer];
[self.session pushVideoBuffer:sampleBuffer];
这两个方法限于LFLiveKit-ReplayKit 版本

更多详细查看Demo
有问题或者指正意见请不吝赐教和评论!

上一篇下一篇

猜你喜欢

热点阅读