https://www.jianshu.com/p/714ce954e628css
最近接手公司的直播项目,对之前遗留的问题作处理和优化, 因而顺便看了下阿里云直播的文档,在下面写下对直播的理解和遇到的问题, 阿里云售后特别好,一对一解决问题速度很快,若是遇到解决不了的问题能够发工单提问,效率很高产品->视频直播->文档&SDK->联系客服->工单支持而后选择本身遇到问题的产品类型提交工单便可,通常两个小时内能够获得回复
html
工欲善其事必先利其器,先作准备工做
Step1. 访问 阿里云官网,点左上角 登陆
Step2. 登陆视频直播控制台
在 视频直播服务产品主页登陆控制台。控制台会检查所依赖服务的开通状态,请按页面引导操做。
Step3. 在 域名管理 中,新建域名。直播域名须要进行备案审核,审核经过后便可使用,未备案的域名请先进行备案,
备案流程
Step4. CNAME绑定将您添加的直播域名的DNS CNAME纪录修改成直播域名管理详情页面上显示的CNAME绑定地址。咱们须要把阿里云提供的推流地址和直播域名进行绑定,这样当推流到直播域名时会推流到咱们的直播中心。
Step4. 获取推流和播放地址在 域名管理 中,点击直播加速域名 管理 :获取推流和直播地址
Step5. 鉴权配置直播流媒体的推送和播放采用同一套鉴权方案,能够在控制台的鉴权配置中进行配置,详细了解
鉴权配置。浏览器
推流
Step1. 获取鉴权后的推流地址:
直播控制台 - 域名管理 - 直播域名管理详情页 - 基本信息 取得推流地址以下: rtmp://video-center.alivecdn.com/AppName/StreamName?vhost=live.aliyun.com 使用直播控制台 - 域名管理 - 直播域名管理详情页 - 鉴权配置 页面的鉴权URL计算器计算鉴权URL: 输入推流地址(AppName、StreamName可自行修改)、鉴权KEY、有效时间,点击<生成>按钮便可获得鉴权URL。
Step2. 推流操做推流地址:rtmp://video-center.alivecdn.com/APPName/StreamName?vhost=live.aliyun.com
服务器
如下面的推流地址为例,参数设置为:FMS URL / URL: rtmp://video-center.alivecdn.com/AppName 播放路径/串码流(若是存在)/ 流秘钥: StreamName?vhost=live.aliyn.com 如您开启了鉴权,则鉴权参数也一并放在 Mac版obs的流密钥与Windows版播放路径/串码流(若是存在)中。
播放
客户能够根据实际业务场景灵活搭配使用,须要在移动端浏览器、移动H5端进行播放,建议使用HLS(M3U8)方式进行播放,无需集成SDK;非移动端或者已集成SDK的,低并发量并须要有更小的延时,可以使用RTMP,高并发量建议使用FLV。
Step1. Web页面后台直接预览使用OBS等工具使用鉴权URL推流后,可在 直播控制台 - 流管理 - 正在推流 页面查询到正在直播的推流记录,经过 直播地址 可查询播放地址,并可预览播放。
Step2. 经过VLC预览
下载VLC默认安装后无需作额外设置,文件—>打开网络串流,填写播放地址并点击打开后开始播放。
网络
iOS 推流SDK开发包
iOS推流使用说明session
目前SDK的横屏推流须要再推流界面的Controller中将手机竖屏锁定(只容许Portrait一个方向),若是须要横竖屏切换,须要对UI作一套横竖屏的适配,监控手机的状态并做出相应的布局
(下面是推流,直播界面的代码和设置)
注册通知,根据不一样状况作不一样判断
并发
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDeviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];//监控手机感应状态 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appResignActive) name:UIApplicationWillResignActiveNotification object:nil];//退入后台中止推流 由于iOS后台机制,不能知足充分的摄像头采集和GPU渲染 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];// 回到前台从新推流``` ` #pragma mark - 推流Session 建立 销毁`
(void)createSession{app
AlivcLConfiguration *configuration = [[AlivcLConfiguration alloc] init];
configuration.url = @"rtmp://video-center.alivecdn.com/3b42277fcb90445096dd72d4a11ef420/";
configuration.videoMaxBitRate = 1500 * 1000;
configuration.videoBitRate = 600 * 1000;
configuration.videoMinBitRate = 400 * 1000;
configuration.audioBitRate = 64 * 1000;
configuration.videoSize = CGSizeMake(360, 640);// 横屏状态宽高不须要互换
configuration.fps = 20;
configuration.preset = AVCaptureSessionPresetiFrame1280x720;
configuration.screenOrientation =
// AlivcLiveScreenVertical = 0,
// AlivcLiveScreenHorizontal = 1,;
// 重连时长
configuration.reconnectTimeout = 5;
// 水印
configuration.waterMaskImage = [UIImage imageNamed:@"watermask"];
configuration.waterMaskLocation = 1;
configuration.waterMaskMarginX = 10;
configuration.waterMaskMarginY = 10;
// 摄像头方向
if (self.currentPosition) {
configuration.position = self.currentPosition;
// AVCaptureDevicePositionBack 后置
// AVCaptureDevicePositionFront 前置
} else {
configuration.position = AVCaptureDevicePositionFront;
self.currentPosition = AVCaptureDevicePositionFront;
}
configuration.frontMirror = YES;async
// alloc session
self.liveSession = [[AlivcLiveSession alloc] initWithConfiguration:configuration];
self.liveSession.delegate = self;
// 是否静音推流
self.liveSession.enableMute = self.muteButton.selected;
// 开始预览
[self.liveSession alivcLiveVideoStartPreview];
// 开始推流
[self.liveSession alivcLiveVideoConnectServer];ide
NSLog(@"开始推流");
dispatch_async(dispatch_get_main_queue(), ^{
// 预览view
[self.view insertSubview:[self.liveSession previewView] atIndex:0];
});
self.exposureValue = 0;
}
(void)destroySession{
[self.liveSession alivcLiveVideoDisconnectServer];
[self.liveSession alivcLiveVideoStopPreview];
[self.liveSession.previewView removeFromSuperview];
self.liveSession = nil;
NSLog(@"销毁推流");
}```#pragma mark - Notification通知响应
- (void)appResignActive{ // 退入后台中止推流 由于iOS后台机制,不能知足充分的摄像头采集和GPU渲染 [self destroySession]; // 监听电话 _callCenter = [[CTCallCenter alloc] init]; _isCTCallStateDisconnected = NO; _callCenter.callEventHandler = ^(CTCall* call) { if ([call.callState isEqualToString:CTCallStateDisconnected]) { _isCTCallStateDisconnected = YES; } else if([call.callState isEqualToString:CTCallStateConnected]) { _callCenter = nil; } }; NSLog(@"退入后台"); } - (void)appBecomeActive{ if (_isCTCallStateDisconnected) { sleep(2); } // 回到前台从新推流 [self createSession]; NSLog(@"回到前台"); } - (void)handleDeviceOrientationDidChange:(UIInterfaceOrientation)interfaceOrientation { UIDevice *device = [UIDevice currentDevice] ; switch (device.orientation) { case UIDeviceOrientationFaceUp: NSLog(@"屏幕朝上平躺"); break; case UIDeviceOrientationFaceDown: NSLog(@"屏幕朝下平躺"); break; case UIDeviceOrientationUnknown: NSLog(@"未知方向"); break; case UIDeviceOrientationLandscapeLeft: { NSLog(@"屏幕向左横置"); [self destroySession];//摧毁推流 _isScreenHorizontal = YES; // 横屏 YES [self createSession]; //从新推流 } break; case UIDeviceOrientationLandscapeRight: NSLog(@"屏幕向右横置"); break; case UIDeviceOrientationPortrait: { NSLog(@"屏幕直立"); [self destroySession]; // 摧毁推流 _isScreenHorizontal = NO; //竖屏为NO [self createSession]; // 从新推流 } break; case UIDeviceOrientationPortraitUpsideDown: NSLog(@" 屏幕直立 上下颠倒"); break; default: NSLog(@"没法辨认"); break; } }``` `//推流代理,根据实际状况作出反应`
(void)alivcLiveVideoLiveSession:(AlivcLiveSession *)session error:(NSError *)error{
dispatch_async(dispatch_get_main_queue(), ^{
NSString *msg = [NSString stringWithFormat:@"%zd %@",error.code, error.localizedDescription];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Live Error" message:msg delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"从新链接", nil];
alertView.delegate = self;
[alertView show];
});
NSLog(@"liveSession Error : %@", error);
}
(void)alivcLiveVideoLiveSessionNetworkSlow:(AlivcLiveSession *)session {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"当前网络环境较差" delegate:nil cancelButtonTitle:@"肯定" otherButtonTitles: nil];
[alertView show];
self.textView.text = @"网速过慢,影响推流效果,拉流端会形成卡顿等,建议暂停直播";
NSLog(@"网速过慢");
}
(void)alivcLiveVideoLiveSessionConnectSuccess:(AlivcLiveSession *)session {
NSLog(@"推流 connect success!");
}
(void)alivcLiveVideoReconnectTimeout:(AlivcLiveSession *)session error:(NSError *)error {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:[NSString stringWithFormat:@"重连超时-error:%ld", error.code] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
[alertView show];
});
NSLog(@"重连超时");
}
(void)alivcLiveVideoOpenAudioSuccess:(AlivcLiveSession *)session {
// dispatch_async(dispatch_get_main_queue(), ^{
// UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"YES" message:@"麦克风打开成功" delegate:nil cancelButtonTitle:@"肯定" otherButtonTitles: nil];
// [alertView show];
// });
}
(void)alivcLiveVideoOpenVideoSuccess:(AlivcLiveSession *)session {
// dispatch_async(dispatch_get_main_queue(), ^{
// UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"YES" message:@"摄像头打开成功" delegate:nil cancelButtonTitle:@"肯定" otherButtonTitles: nil];
// [alertView show];
// });
}
(void)alivcLiveVideoLiveSession:(AlivcLiveSession *)session openAudioError:(NSError *)error {
dispatch_async(dispatch_get_main_queue(), ^{
// UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:@"麦克风获取失败" delegate:nil cancelButtonTitle:@"肯定" otherButtonTitles: nil];
// [alertView show];
});
}
(void)alivcLiveVideoLiveSession:(AlivcLiveSession *)session openVideoError:(NSError *)error {
// dispatch_async(dispatch_get_main_queue(), ^{
// UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:@"摄像头获取失败" delegate:nil cancelButtonTitle:@"肯定" otherButtonTitles: nil];
// [alertView show];
// });
}
(void)alivcLiveVideoLiveSession:(AlivcLiveSession *)session encodeAudioError:(NSError *)error {
// dispatch_async(dispatch_get_main_queue(), ^{
// UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:@"音频编码初始化失败" delegate:nil cancelButtonTitle:@"肯定" otherButtonTitles: nil];
// [alertView show];
// });
}
(void)alivcLiveVideoLiveSession:(AlivcLiveSession *)session encodeVideoError:(NSError *)error {
// dispatch_async(dispatch_get_main_queue(), ^{
// UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:@"视频编码初始化失败" delegate:nil cancelButtonTitle:@"肯定" otherButtonTitles: nil];
// [alertView show];
// });
}
(void)alivcLiveVideoLiveSession:(AlivcLiveSession *)session bitrateStatusChange:(ALIVC_LIVE_BITRATE_STATUS)bitrateStatus {
// dispatch_async(dispatch_get_main_queue(), ^{
// UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"YES" message:[NSString stringWithFormat:@"ALIVC_LIVE_BITRATE_STATUS = %ld", bitrateStatus] delegate:nil cancelButtonTitle:@"肯定" otherButtonTitles: nil];
// [alertView show];
// });
NSLog(@"码率变化 %ld", bitrateStatus);
}
(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex != alertView.cancelButtonIndex) {
[self.liveSession alivcLiveVideoConnectServer];
} else {
[self.liveSession alivcLiveVideoDisconnectServer];
}
}
> 视频播放
>> AlivcMediaPlayer
`iOS媒体播放器SDK是在iOS平台上使用的软件开发工具包(Software Developement Kit),为iOS开发者提供简单易用的接口,帮助开发者实现iOS平台上的媒体播放应用开发。该SDK对目前主流的视频格式都提供了良好的支持,支持本地和网络媒体的播放,弥补了系统播放器在媒体格式上的不足。(记得添加AliyunPlayerSDK.framework)
若是须要适配横竖屏要对UI作适配,只作横屏的话能够将页面旋转90度便可 ` ###### 播放器通知定义: AliVcMediaPlayerLoadDidPreparedNotification:播放器初始化视频文件完成通知,调用prepareToPlay函数,会发送该通知,表明视频文件已经准备完成,此时能够在这个通知中获取到视频的相关信息,如视频分辨率,视频时长等。 AliVcMediaPlayerPlaybackDidFinishNotification:播放完成通知。当视频播放完成后会收到此通知。播放完成会有几种状况, 1. 当用户调用stop后视频结束完成。 2. 视频正常播放结束。 ` AliVcMediaPlayerStartCachingNotification:播放器开始缓冲视频时发送该通知,当播放网络文件时,网络状态不佳或者调用seekTo时,此通知告诉用户网络下载数据已经开始缓冲。 AliVcMediaPlayerEndCachingNotification:播放器结束缓冲视频时发送该通知,当数据已经缓冲完,告诉用户已经缓冲结束,来更新相关UI显示。 AliVcMediaPlayerPlaybackErrorNotification:播放器播放失败发送该通知,并在该通知中能够获取到错误码。 AliVcMediaPlayerSeekingDidFinishNotification:播放器位置改变完成后发送该通知。 AliVcMediaPlayerFirstFrameNotification:播放器状态首帧显示后发送的通知。` 播放器通知发送逻辑: 1. 调用prepareToPlay成功后发送AliVcMediaPlayerLoadDidPreparedNotification通知,失败则会发送AliVcMediaPlayerPlaybackErrorNotification。 2. 调用play、pause、stop、prepareToPlay、seekTo失败后发送AliVcMediaPlayerPlaybackErrorNotification通知。 3. 调用stop/reset成功后播放视频结束发送AliVcMediaPlayerPlaybackDidFinishNotification通知,播放器自动播放结束也会发送AliVcMediaPlayerPlaybackDidFinishNotification通知。 4. 调用seekTo成功后发送AliVcMediaPlayerSeekingDidFinishNotification通知。 5. AliVcMediaPlayerStartCachingNotification和AliVcMediaPlayerEndCachingNotification通知,这个是在网络视频缓冲数据不足以够播放后会发送此通知,通常网络视频在调用seekTo后会发送此通知。` ` //初始化播放器的类`
-(void) playVideo
{
player = [[AliVcMediaPlayer alloc] init];
//建立播放器,传入显示窗口
/**