Skip to content

Instantly share code, notes, and snippets.

@AntiMoron
Created December 11, 2017 16:20
Show Gist options
  • Save AntiMoron/901666072dd3dc0815e658f56d07fbb7 to your computer and use it in GitHub Desktop.
Save AntiMoron/901666072dd3dc0815e658f56d07fbb7 to your computer and use it in GitHub Desktop.
TXLVB播放rtmp推流
#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
#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