下载地址:https://github.com/pili-engineering/PLCameraStreamingKit
使用CocoaPods导入 pod'PLCameraStreamingKit'
非Cocoapods集成 http://blog.csdn.net/kivenhehaoyu/article/details/51051279
在项目AppDelegate.m中进行 SDK 初始化,否则会报错。
#import
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions{
[PLStreamingEnv initEnv];
}
在使用的地方#import
@property (nonatomic, strong) PLCameraStreamingSession *session;
网络请求必备
PLCameraStreamingSession是核心类,可以完成通过摄像头推流、预览的工作。如果你只需要做纯音频推流,那么你可以使用PLAudioStreamingSession
推流前要先对摄像头&麦克风的授权,否则会导致程序崩溃,并记得设置预览界面,StreamingSession的创建需要 Stream 对象。
// streamJSON 是从服务端拿回的
//
// 从服务端拿回的 streamJSON 结构如下:
// @{@"id": @"stream_id",
// @"title": @"stream_title",
// @"hub": @"hub_name",
// @"publishKey": @"publish_key",
// @"publishSecurity": @"dynamic", // or static// @"disabled": @(NO),
// @"profiles": @[@"480p", @"720p"], // or empty Array []
// @"hosts": @{
// ...
// }
//服务器拿回来的streamJSON是NSString型的json对象,此地需要的是NSDictionary类型的,可以用一下方法转类型
//+ (NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString {
// if (jsonString == nil) {
// return nil;
// }
//
// NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
// NSError *err;
// NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData
// options:NSJSONReadingMutableContainers
// error:&err];
// if(err) {
// NSLog(@"json解析失败:%@",err);
// return nil;
// }
// return dic;
//}
NSDictionary*streamJSON;
PLStream *stream = [PLStream streamWithJSON:streamJSON];
// 授权后执行
void(^permissionBlock)(void) = ^{
PLVideoCaptureConfiguration *videoCaptureConfiguration = [self.videoCaptureConfigurations defaultConfiguration];
PLAudioCaptureConfiguration *audioCaptureConfiguration = [PLAudioCaptureConfiguration defaultConfiguration];
PLVideoStreamingConfiguration *videoStreamingConfiguration = [self.videoStreamingConfigurations defaultConfiguration];
PLAudioStreamingConfiguration *audioStreamingConfiguration = [PLAudioStreamingConfiguration defaultConfiguration];
//创建推流 session 对象
self.session = [[PLCameraStreamingSession alloc]initWithVideoCaptureConfiguration:videoCaptureConfiguration audioCaptureConfiguration:audioCaptureConfiguration videoStreamingConfiguration:videoStreamingConfiguration audioStreamingConfiguration:audioStreamingConfiguration stream:stream videoOrientation:orientation];
self.session.delegate =self;
预览摄像头拍摄效果
将预览视图添加为当前视图的子视图
[self.view addSubview:self.session.previewView];
取一个最简单的场景,就是点击一个按钮,然后触发发起直播的操作。
UIButton *button = [UIButtonbuttonWithType:UIButtonTypeSystem];[buttonsetTitle:@"start"forState:UIControlStateNormal];button.frame = CGRectMake(0,0,100,44);button.center = CGPointMake(CGRectGetMidX([UIScreenmainScreen].bounds), CGRectGetHeight([UIScreenmainScreen].bounds) -80);[buttonaddTarget:selfaction:@selector(actionButtonPressed:)forControlEvents:UIControlEventTouchUpInside];[self.viewaddSubview:button];
};
- (void)actionButtonPressed:(id)sender { [self.sessionstartWithCompleted:^(BOOLsuccess) {
if(success) {
NSLog(@"Streaming started.");
}else{
NSLog(@"Oops.");
}
}];
}
如果运行后,点击按钮提示Oops.,就要检查一下你之前创建PLStream对象时填写的StreamJson是否有漏填或者填错的内容。
void(^noPermissionBlock)(void) = ^{
// 处理未授权情况
};
// 检查摄像头是否有授权
PLAuthorizationStatus status = [PLCameraStreamingSession cameraAuthorizationStatus];
if(PLAuthorizationStatusNotDetermined == status) {
[PLCameraStreamingSession requestCameraAccessWithCompletionHandler:^(BOOLgranted) {
// 回调确保在主线程,可以安全对 UI 做操作
granted ? permissionBlock() : noPermissionBlock();
}];
}else if(PLAuthorizationStatusAuthorized == status) {
permissionBlock();
}else{
noPermissionBlock();
}
推流操作
// 开始推流,无论 security policy 是 static 还是 dynamic,都无需再单独计算推流地址
[self.session startWithCompleted:^(BOOLsuccess) {
// 这里的代码在主线程运行,所以可以放心对 UI 控件做操作
if(success) {
// 连接成功后的处理
// 成功后,在这里才可以读取 self.session.pushURL,start 失败和之前不能确保读取到正确的 URL
}else{
// 连接失败后的处理
}}];
// 停止推流
[self.session stop];
销毁推流 session
[self.session destroy];
编码参数
移动端因网络环境不稳定及用户电量宝贵等原因,并不建议直接使用最高码率和分辨率来做推流,以最佳编码参数来做设置可以带来更好的推流效果和用户体验。
如果你不能确定该如何配置各个编码参数,也不用担心,PLCameraStreamingKit提供了一个编码配置的类来帮你快速完成配置,你可以通过使用 SDK 预先定义好的 quality 来构建编码推流配置。
视频编码参数
// 视频推流质量
/*!
* @abstract Video streaming quality low 1
*
* @discussion 具体参数 fps: 12, profile level: baseline31, video bitrate: 150Kbps
*/
externNSString*kPLVideoStreamingQualityLow1;
/*!
* @abstract Video streaming quality low 2
*
* @discussion 具体参数 fps: 15, profile level: baseline31, video bitrate: 264Kbps
*/
externNSString*kPLVideoStreamingQualityLow2;
/*!
* @abstract Video streaming quality low 3
*
* @discussion 具体参数 fps: 15, profile level: baseline31, video bitrate: 350Kbps
*/
externNSString*kPLVideoStreamingQualityLow3;
/*!
* @abstract Video streaming quality medium 1
*
* @discussion 具体参数 fps: 30, profile level: baseline31, video bitrate: 512Kbps
*/
externNSString*kPLVideoStreamingQualityMedium1;
/*!
* @abstract Video streaming quality medium 2
*
* @discussion 具体参数 fps: 30, profile level: baseline31, video bitrate: 800Kbps
*/
externNSString*kPLVideoStreamingQualityMedium2;
/*!
* @abstract Video streaming quality medium 3
*
* @discussion 具体参数 fps: 30, profile level: baseline31, video bitrate: 1000Kbps
*/
externNSString*kPLVideoStreamingQualityMedium3;
/*!
* @abstract Video streaming quality high 1
*
* @discussion 具体参数 fps: 30, profile level: baseline31, video bitrate: 1200Kbps
*/
externNSString*kPLVideoStreamingQualityHigh1;
/*!
* @abstract Video streaming quality high 2
*
* @discussion 具体参数 fps: 30, profile level: baseline31, video bitrate: 1500Kbps
*/
externNSString*kPLVideoStreamingQualityHigh2;
/*!
* @abstract Video streaming quality high 3
*
* @discussion 具体参数 fps: 30, profile level: baseline31, video bitrate: 2000Kbps
*/
externNSString*kPLVideoStreamingQualityHigh3;
需要明确以上两者,便可以直接获取到最佳的视频编码配置。
// 该方法每次都会生成一个新的配置,不是单例方法。默认情况下,对应的参数为分辨率 (320, 480), video quality PLStreamingQualityMedium1
PLVideoStreamingConfiguration *videoConfiguration = [PLVideoStreamingConfiguration defaultConfiguration];
// 你也可以指定自己想要的分辨率和已有的 video quality 参数
PLVideoStreamingConfiguration *videoConfiguration = [PLVideoStreamingConfiguration configurationWithVideoSize:CGSizeMake(320,480) videoQuality:kPLVideoStreamingQualityHigh1];
// 当已有的分辨率无法满足你的需求时,你可以自己定义所有参数,但请务必确保你清楚参数的含义
PLVideoStreamingConfiguration *videoConfiguration = [[PLVideoStreamingConfiguration alloc] initWithVideoSize:CGSizeMake(width, height) videoFrameRate:30videoMaxKeyframeInterval:90videoBitrate:1200*1000videoProfileLevel:AVVideoProfileLevelH264Main32]];
Video Quality 具体参数
Quality FPS ProfileLevel Video BitRate(Kbps)
kPLVideoStreamingQualityLow1 12 Baseline 31150
kPLVideoStreamingQualityLow2 15 Baseline 31264
kPLVideoStreamingQualityLow3 15 Baseline 31350
kPLVideoStreamingQualityMedium1 30 Baseline 31512
kPLVideoStreamingQualityMedium2 30 Baseline 31800
kPLVideoStreamingQualityMedium3 30 Baseline 311000
kPLVideoStreamingQualityHigh1 30 Baseline 311200
kPLVideoStreamingQualityHigh2 30 Baseline 311500
kPLVideoStreamingQualityHigh3 30 Baseline 312000
音频编码参数
// 音频推流质量
/*!
* @abstract Audio streaming quality high 1
*
* @discussion 具体参数 audio sample rate: 44MHz, audio bitrate: 96Kbps
*/
externNSString*kPLAudioStreamingQualityHigh1;
/*!
* @abstract Audio streaming quality high 2
*
* @discussion 具体参数 audio sample rate: 44MHz, audio bitrate: 128Kbps
*/
externNSString*kPLAudioStreamingQualityHigh2;
生成音频编码配置
// 音频配置默认使用 high2 作为质量选项
PLAudioStreamingConfiguration *audioConfiguration = [PLAudioStreamingConfiguration defaultConfiguration];
// 如果你需要自己定义音频质量
PLAudioStreamingConfiguration *audioConfiguration = [PLAudioStreamingConfiguration configurationWithAudioQuality:kPLAudioStreamingQualityHigh1];
Audio Quality 具体参数
QualityAudio Samplerate(MHz)) Audio BitRate(Kbps)
kPLAudioStreamingQualityHigh1 44 96
kPLAudioStreamingQualityHigh2 44 128
在创建好编码配置对象后,就可以用它来初始化PLCameraStreamingSession了。
流状态变更及处理处理
实现PLCameraStreamingSessionDelegate或PLAudioStreamingSessionDelegate的回调方法,可以及时的得知流状态的变更及推流错误
- (void)cameraStreamingSession:(PLCameraStreamingSession *)session streamStateDidChange:(PLStreamState)state {
// 当流状态变更为非 Error 时,会回调到这里
}
- (void)cameraStreamingSession:(PLCameraStreamingSession *)session didDisconnectWithError:(NSError*)error {
// 当流状态变为 Error, 会携带 NSError 对象回调这个方法
}
- (void)streamingSession:(PLStreamingSession *)session streamStatusDidUpdate:(PLStreamStatus *)status {
// 当开始推流时,会每间隔 3s 调用该回调方法来反馈该 3s 内的流状态,包括视频帧率、音频帧率、音视频总码率
}
变更推流质量及策略
在推流时,可以配合发送 buffer 自己设定不同的策略,来满足不同的网络环境。
使用 buffer 可用的方法
// BufferDelegate
@protocolPLStreamingSendingBufferDelegate
- (void)streamingSessionSendingBufferDidEmpty:(id)session;
- (void)streamingSessionSendingBufferDidFull:(id)session;
@end
// StreamingSession 中的 buffer 相关内容@interfacePLCameraStreamingSession(SendingBuffer)
@property(nonatomic, PL_WEAK)id bufferDelegate;
/// [0..1], 不可超出这个范围, 默认为 0.5
@property(nonatomic,assign)CGFloat threshold;
/// Buffer 最多可包含的包数,默认为300
@property(nonatomic,assign)NSUInteger maxCount;
@property(nonatomic,assign,readonly)NSUInteger currentCount;
@end
buffer 是一个可以缓存待发送内容的队列,它按照帧数作为缓存长度的判定,可以通过 maxCount 来读取和设定,buffer 的阈值设定体现你期望的变更推流质量的策略,默认阈值为 buffer 的 50%(0.5)。
当 buffer 变为空时,会回调
- (void)streamingSessionSendingBufferDidEmpty:(id)session;
当 buffer 满时,会回调
- (void)streamingSessionSendingBufferDidFull:(id)session;
当你希望在 streamStatus 变化,buffer empty 或者 buffer full 时变化 video configuration,可以调用 session 的 reloadVideoConfiguration: 方法
[self.session reloadVideoConfiguration:newConfiguraiton];
水印
-(void)setWaterMarkWithImage:(UIImage *)wateMarkImage position:(CGPoint)position;
该方法将为直播流添加一个水印,水印的大小由wateMarkImage的大小决定,位置由 position 决定,需要注意的是这些值都是以采集数据的像素点为单位的。例如我们使用AVCaptureSessionPreset1280x720进行采集,同时wateMarkImage.size为(100, 100)对应的origin为(200, 300),那么水印的位置将在大小为1280x720的采集画幅中位于(200, 300)的位置,大小为(100, 100)。
移除水印
-(void)clearWaterMark;
美颜
按照默认参数开启或关闭美颜
-(void)setBeautifyModeOn:(BOOL)beautifyModeOn;
设置美颜程度,范围为 0 ~ 1
-(void)setBeautify:(CGFloat)beautify;
设置美白程度,范围为 0 ~ 1
-(void)setWhiten:(CGFloat)whiten;
设置红润程度,范围为 0 ~ 1
-(void)setRedden:(CGFloat)redden;
集成到 Swift 工程
配置你的 Podfile 文件,添加如下配置
use_frameworks!
pod'PLCameraStreamingKit', :podspec=>'https://raw.githubusercontent.com/pili-engineering/PLCameraStreamingKit/master/PLCameraStreamingKitForSwift.podspec'
pod'PLStreamingKit'
pod install 或 pod update 安装依赖;
打开你工程的 workspace,在 Pods 工程中选中 PLCameraStreamingKit TARGETS,右侧 Tab 选择 "Build Phases",在 "Link Binary With Libraries" 中将 <工程目录>/Pods/PLStreamingKit/Pod/Library/lib/ 中的libPLStreamingKit.a 库加入;
在 Objective-C bridging header 中加入一行
#import
Objective-C bridging header 通常以 ProjectName-Bridging-Header.h 命名,如果没有 Objective-C bridging header,可以在 Swift 工程中新建一个 Objective-C File,Xcode 会弹出对话框询问是否配置 Objective-C bridging header,确认后,Xcode 会帮你创建好 Objective-C bridging header;
Done!现在在需要的地方 import PLCameraStreamingKit 就可以使用了。
文档支持
PLCameraStreamingKit 使用 HeaderDoc 注释来做文档支持。开发者无需单独查阅文档,直接通过 Xcode 就可以查看接口和类的相关信息,减少不必要的麻烦。
本文参考于 https://github.com/pili-engineering/PLCameraStreamingKit/wiki