Created
December 11, 2017 16:20
-
-
Save AntiMoron/901666072dd3dc0815e658f56d07fbb7 to your computer and use it in GitHub Desktop.
TXLVB播放rtmp推流
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <UIKit/UIKit.h> | |
@interface RPLiveRtmpView : UIView | |
// 播放视频地址 | |
@property(nonatomic, strong) NSString* movieSource; | |
// 被添加的viewController | |
@property(nonatomic, weak) UIViewController* viewController; | |
// 播放url | |
-(BOOL)startRtmp; | |
// 停止url | |
-(void)stopRtmp; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "RPLiveRtmpView.h" | |
#import <AFNetworking/AFNetworking.h> | |
#import <TXLiteAVSDK_Smart/TXLivePlayer.h> | |
#import <TXLiteAVSDK_Smart/TXLivePlayConfig.h> | |
#import <TXLiteAVSDK_Smart/TXLivePlayListener.h> | |
#import <TXLiteAVSDK_Smart/TXLiveRecordTypeDef.h> | |
#import <TXLiteAVSDK_Smart/TXLiveRecordListener.h> | |
#import <TXLiteAVSDK_Smart/TXVideoCustomProcessDelegate.h> | |
#define CACHE_TIME_FAST 1.0f | |
#define CACHE_TIME_SMOOTH 5.0f | |
#define CACHE_TIME_AUTO_MIN 5.0f | |
#define CACHE_TIME_AUTO_MAX 10.0f | |
typedef NS_ENUM(NSInteger, ENUM_TYPE_CACHE_STRATEGY) | |
{ | |
CACHE_STRATEGY_FAST = 1, //极速 | |
CACHE_STRATEGY_SMOOTH = 2, //流畅 | |
CACHE_STRATEGY_AUTO = 3, //自动 | |
}; | |
// 目前很少崩溃,用了新代码后崩溃增多,看是不是后期改动导致。 回退到初始版本 | |
@interface RPLiveRtmpView()<TXLivePlayListener, | |
TXVideoCustomProcessDelegate> | |
// 播放视频view | |
// 正常播放view会恢复圆角等属性,附加一个view在上面可以解决 | |
@property (nonatomic, strong) UIView *mVideoContainer; | |
// 腾讯实时直播器 | |
@property(nonatomic, strong) TXLivePlayer* txLivePlayer; | |
// 配置 | |
@property(nonatomic, strong) TXLivePlayConfig* config; | |
// 缓存策略 | |
@property(nonatomic, assign) ENUM_TYPE_CACHE_STRATEGY cacheStrategy; | |
// 播放类型 | |
@property(nonatomic, assign) TX_Enum_PlayType playType; | |
// 是否允许缓存 | |
@property(nonatomic, assign) BOOL enableCache; | |
// 视频是否暂停 | |
@property(nonatomic, assign) BOOL videoPause; | |
@property(nonatomic, assign) NSTimeInterval startPlayTS; | |
// 加载View | |
@property(nonatomic, strong) UIActivityIndicatorView* indicatorView; | |
@end | |
@implementation RPLiveRtmpView | |
-(instancetype)initWithCoder:(NSCoder *)aDecoder { | |
self = [super initWithCoder:aDecoder]; | |
if(self) { | |
[self configViews]; | |
} | |
return self; | |
} | |
-(instancetype)initWithFrame:(CGRect)frame { | |
self = [super initWithFrame:frame]; | |
[self configViews]; | |
return self; | |
} | |
-(void) configViews { | |
self.clipsToBounds = YES; | |
self.mVideoContainer = [[UIView alloc] init]; | |
[self addSubview:self.mVideoContainer]; | |
self.videoPause = YES; | |
_enableCache = NO; | |
if(!_txLivePlayer) { | |
_txLivePlayer = [[TXLivePlayer alloc] init]; | |
_txLivePlayer.delegate = self; | |
} | |
if(!_config) { | |
_config = [[TXLivePlayConfig alloc] init]; | |
} | |
} | |
-(void) dealloc { | |
[self stopRtmp]; | |
_txLivePlayer = nil; | |
_config = nil; | |
} | |
#pragma mark - setters | |
// 设置拉流地址 | |
-(void) setMovieSource:(NSString *)movieSource { | |
if([_movieSource isEqualToString:movieSource]) { | |
return ; | |
} | |
_movieSource = movieSource; | |
[self stopRtmp]; | |
__weak typeof(self) wSelf = self; | |
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | |
[wSelf startRtmpWithPlayUrl:movieSource]; | |
}); | |
} | |
#pragma mark - 布局 | |
-(void)layoutSubviews { | |
[super layoutSubviews]; | |
self.mVideoContainer.frame = self.bounds; | |
self.indicatorView.center = CGPointMake(self.bounds.size.width * 0.5, self.bounds.size.height * 0.5); | |
} | |
#pragma mark - sdk delegates | |
// 设定播放流畅度 | |
- (void) setCacheStrategy:(ENUM_TYPE_CACHE_STRATEGY) nCacheStrategy { | |
switch (_cacheStrategy) { | |
case CACHE_STRATEGY_FAST: | |
_config.bAutoAdjustCacheTime = YES; | |
_config.minAutoAdjustCacheTime = CACHE_TIME_FAST; | |
_config.maxAutoAdjustCacheTime = CACHE_TIME_FAST; | |
[_txLivePlayer setConfig:_config]; | |
break; | |
case CACHE_STRATEGY_SMOOTH: | |
_config.bAutoAdjustCacheTime = NO; | |
_config.cacheTime = CACHE_TIME_SMOOTH; | |
[_txLivePlayer setConfig:_config]; | |
break; | |
case CACHE_STRATEGY_AUTO: | |
_config.bAutoAdjustCacheTime = YES; | |
_config.minAutoAdjustCacheTime = CACHE_TIME_FAST; | |
_config.maxAutoAdjustCacheTime = CACHE_TIME_SMOOTH; | |
[_txLivePlayer setConfig:_config]; | |
break; | |
default: | |
break; | |
} | |
} | |
// 检查直播流地址 | |
-(BOOL)checkPlayUrl:(NSString*)playUrl { | |
if ([playUrl hasPrefix:@"rtmp:"]) { | |
_playType = PLAY_TYPE_LIVE_RTMP; | |
if ([playUrl containsString:@"txSecret="]) { | |
_playType = PLAY_TYPE_LIVE_RTMP_ACC; | |
} | |
// else if (self.isRealtime) { | |
// [self toastTip:@"播放地址非合法的低延时播放地址!"]; | |
// } | |
} else if (([playUrl hasPrefix:@"https:"] || [playUrl hasPrefix:@"http:"]) && [playUrl rangeOfString:@".flv"].length > 0) { | |
_playType = PLAY_TYPE_LIVE_FLV; | |
} else{ | |
[RPToast toastString:@"播放地址不合法,直播目前仅支持rtmp,flv播放方式!" withInterval: 0.5]; | |
return NO; | |
} | |
return YES; | |
} | |
-(BOOL)startRtmpWithPlayUrl:(NSString*)playUrl { | |
if (![self checkPlayUrl:playUrl]) { | |
return NO; | |
} | |
if(!_txLivePlayer) { | |
_txLivePlayer = [[TXLivePlayer alloc] init]; | |
_txLivePlayer.delegate = self; | |
} | |
if(!_config) { | |
_config = [[TXLivePlayConfig alloc] init]; | |
} | |
if(_txLivePlayer) { | |
_txLivePlayer.delegate = self; | |
[_txLivePlayer setupVideoWidget:CGRectMake(0, 0, 0, 0) containView:_mVideoContainer insertIndex:0]; | |
if (_enableCache) { | |
_config.cacheFolderPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; | |
_config.maxCacheItems = 2; | |
} else { | |
_config.cacheFolderPath = nil; | |
} | |
_config.playerPixelFormatType = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange; | |
[_txLivePlayer setConfig:_config]; | |
int result = [_txLivePlayer startPlay:playUrl type:_playType]; | |
if( result != 0) { | |
NSLog(@"播放器启动失败"); | |
return NO; | |
} | |
//屏幕永远竖直 | |
[_txLivePlayer setRenderRotation:HOME_ORIENTATION_DOWN]; | |
[_txLivePlayer setRenderMode:RENDER_MODE_FILL_SCREEN]; | |
_videoPause = NO; | |
} | |
[self startLoadingAnimation]; | |
_startPlayTS = [[NSDate date] timeIntervalSince1970]; | |
return YES; | |
} | |
-(BOOL)startRtmp { | |
return [self startRtmpWithPlayUrl:_movieSource]; | |
} | |
// 停止播放推流 | |
-(void)stopRtmp { | |
[self stopLoadingAnimation]; | |
if(_txLivePlayer) { | |
[_txLivePlayer stopPlay]; | |
[_txLivePlayer removeVideoWidget]; | |
_txLivePlayer.delegate = nil; | |
_txLivePlayer = nil; | |
_config = nil; | |
} | |
[[NSNotificationCenter defaultCenter] postNotificationName:@"RPBUSINESSRESUMEMUSIC" object:nil userInfo:nil]; | |
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:nil]; | |
} | |
// 处理播放视频相关事件 | |
-(void) onPlayEvent:(int)EvtID withParam:(NSDictionary*)param { | |
NSDictionary* dict = param; | |
dispatch_async(dispatch_get_main_queue(), ^{ | |
if (EvtID == PLAY_EVT_RCV_FIRST_I_FRAME) { // 播放录制前几帧做初始化操作 | |
// [_txLivePlayer setupVideoWidget:CGRectMake(0, 0, 0, 0) containView:_mVideoContainer insertIndex:0]; | |
} else if (EvtID == PLAY_EVT_PLAY_BEGIN) { // 开始播放视频 | |
[self stopLoadingAnimation]; | |
} else if (EvtID == PLAY_ERR_NET_DISCONNECT || EvtID == PLAY_EVT_PLAY_END) { // 断开链接结束播放 | |
[self stopRtmp]; | |
[[UIApplication sharedApplication] setIdleTimerDisabled:NO]; | |
_videoPause = NO; | |
if (EvtID == PLAY_ERR_NET_DISCONNECT) { | |
NSString* Msg = (NSString*)[dict valueForKey:EVT_MSG]; | |
[RPToast toastString:Msg withInterval:0.5]; | |
} | |
} else if (EvtID == PLAY_EVT_PLAY_LOADING){ // 加载中 | |
[self startLoadingAnimation]; | |
} else if (EvtID == PLAY_EVT_CONNECT_SUCC) { // 链接成功 | |
BOOL isWifi = [AFNetworkReachabilityManager sharedManager].reachableViaWiFi; | |
if (!isWifi) { | |
__weak typeof(self) weakSelf = self; | |
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { | |
__strong typeof(weakSelf) sSelf = weakSelf; | |
if (_movieSource.length == 0) { | |
return; | |
} | |
if (status == AFNetworkReachabilityStatusReachableViaWiFi) { | |
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" | |
message:@"您要切换到Wifi再观看吗?" | |
preferredStyle:UIAlertControllerStyleAlert]; | |
[alert addAction:[UIAlertAction actionWithTitle:@"是" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { | |
[alert dismissViewControllerAnimated:YES completion:nil]; | |
[sSelf stopRtmp]; | |
[sSelf startRtmpWithPlayUrl:sSelf.movieSource]; | |
}]]; | |
[alert addAction:[UIAlertAction actionWithTitle:@"否" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { | |
[alert dismissViewControllerAnimated:YES completion:nil]; | |
}]]; | |
[sSelf.viewController presentViewController:alert animated:YES completion:nil]; | |
} | |
}]; | |
} | |
} | |
}); | |
} | |
-(UIActivityIndicatorView*) indicatorView { | |
if(!_indicatorView) { | |
_indicatorView = [[UIActivityIndicatorView alloc] init]; | |
_indicatorView.frame = CGRectMake(0, 0, 40, 40); | |
_indicatorView.center = CGPointMake(self.bounds.size.width * 0.5, self.bounds.size.height * 0.5); | |
[self addSubview:_indicatorView]; | |
} | |
return _indicatorView; | |
} | |
-(void) startLoadingAnimation { | |
self.indicatorView.hidden = NO; | |
[self.indicatorView startAnimating]; | |
[self bringSubviewToFront:self.indicatorView]; | |
} | |
-(void) stopLoadingAnimation { | |
self.indicatorView.hidden = YES; | |
[self.indicatorView stopAnimating]; | |
} | |
// 网络状况 | |
-(void) onNetStatus:(NSDictionary*) param { | |
} | |
@end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment