JZVideoPlayerView.m 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. //
  2. // JZVideoPlayerView.m
  3. // aoyouHH
  4. //
  5. // Created by jinzelu on 15/5/29.
  6. // Copyright (c) 2015年 jinzelu. All rights reserved.
  7. //
  8. #import "JZVideoPlayerView.h"
  9. // 2.获得RGB颜色
  10. #define RGBA(r, g, b, a) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a]
  11. #define RGB(r, g, b) RGBA(r, g, b, 1.0f)
  12. #define navigationBarColor RGB(56, 184, 80)
  13. // 3.是否为4inch
  14. #define fourInch ([UIScreen mainScreen].bounds.size.height == 568)
  15. // 4.屏幕大小尺寸
  16. #define screen_width [UIScreen mainScreen].bounds.size.width
  17. #define screen_height [UIScreen mainScreen].bounds.size.height
  18. @interface JZVideoPlayerView ()
  19. {
  20. id playbackObserver;
  21. UIView *loadView;
  22. UIActivityIndicatorView *activityIndicatorView;
  23. NSTimer *timer;
  24. BOOL viewIsShowing;
  25. }
  26. @end
  27. @implementation JZVideoPlayerView
  28. -(id)initWithFrame:(CGRect)frame contentURL:(NSURL *)contentURL{
  29. self = [super initWithFrame:frame];
  30. if (self) {
  31. self.backgroundColor = [UIColor blackColor];
  32. // [self resetContentView];
  33. }
  34. return self;
  35. }
  36. -(void)resetContentViewWithContentURL:(NSURL *)url{
  37. self.playerItem = [AVPlayerItem playerItemWithURL:url];
  38. self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
  39. self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
  40. self.playerLayer.frame = self.frame;
  41. [self.layer addSublayer:self.playerLayer];
  42. [self initLoadingView];
  43. [self initControlView];
  44. viewIsShowing = YES;
  45. //添加监听
  46. [self addNotification];
  47. [self addObserverToPlayerItem:self.playerItem];
  48. [self addProgressObserver];
  49. }
  50. -(void)dealloc{
  51. [self removeObserverToPlayerItem:self.playerItem];
  52. [self.player removeTimeObserver:playbackObserver];
  53. [[NSNotificationCenter defaultCenter] removeObserver:self];
  54. }
  55. -(void)setFrame:(CGRect)frame{
  56. [super setFrame:frame];
  57. [self.playerLayer setFrame:frame];
  58. }
  59. -(void)setIsFullScreen:(BOOL)isFullScreen{
  60. _isFullScreen = isFullScreen;
  61. if (isFullScreen) {
  62. //
  63. }else{
  64. //
  65. }
  66. }
  67. -(void)play{
  68. [self.player play];
  69. self.isPlaying = YES;
  70. [self.playBtn setSelected:YES];
  71. }
  72. -(void)pause{
  73. [self.player pause];
  74. self.isPlaying = NO;
  75. [self.playBtn setSelected:NO];
  76. }
  77. -(void)stop{
  78. }
  79. -(void)initLoadingView{
  80. loadView = [[UIView alloc] initWithFrame:self.playerLayer.frame];
  81. NSLog(@"playerLayer:=====%f %f",self.playerLayer.frame.size.width,self.playerLayer.frame.size.height);
  82. loadView.backgroundColor = [UIColor clearColor];
  83. //
  84. activityIndicatorView = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
  85. [activityIndicatorView setCenter:loadView.center];
  86. [activityIndicatorView setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhiteLarge];
  87. [activityIndicatorView startAnimating];
  88. [loadView addSubview:activityIndicatorView];
  89. [self addSubview:loadView];
  90. }
  91. //初始化播放,进度条,时间等视图
  92. -(void)initControlView{
  93. int frameWidth = self.frame.size.width;
  94. int frameHeight = self.frame.size.height;
  95. //上面的遮罩
  96. self.playerHUDTopView = [[UIView alloc] initWithFrame:CGRectMake(0, 20, frameWidth, 44)];
  97. [self addSubview:self.playerHUDTopView];
  98. self.backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  99. self.backBtn.frame = CGRectMake(15, 0, 30, 30);
  100. [self.backBtn addTarget:self action:@selector(OnBackBtn:) forControlEvents:UIControlEventTouchUpInside];
  101. [self.backBtn setImage:[UIImage imageNamed:@"back"] forState:UIControlStateNormal];
  102. [self.playerHUDTopView addSubview:self.backBtn];
  103. //下面的遮罩
  104. self.playerHUDBottomView = [[UIView alloc] initWithFrame:CGRectMake(0, frameHeight-44, frameWidth, 44)];
  105. self.playerHUDBottomView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
  106. [self addSubview:self.playerHUDBottomView];
  107. //播放,暂停按钮
  108. self.playBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  109. self.playBtn.frame = CGRectMake(8, 10, 20, 20);
  110. [self.playBtn addTarget:self action:@selector(OnPlayBtn:) forControlEvents:UIControlEventTouchUpInside];
  111. [self.playBtn setSelected:NO];
  112. [self.playBtn setBackgroundImage:[UIImage imageNamed:@"full_pause_icon"] forState:UIControlStateSelected];
  113. [self.playBtn setBackgroundImage:[UIImage imageNamed:@"full_play_icon"] forState:UIControlStateNormal];
  114. [self.playBtn setTintColor:[UIColor clearColor]];
  115. [self.playerHUDBottomView addSubview:self.playBtn];
  116. //全屏按钮
  117. self.zoomBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  118. self.zoomBtn.frame = CGRectMake(frameWidth-27, 10, 20, 20);
  119. [self.zoomBtn addTarget:self action:@selector(OnZoomBtn:) forControlEvents:UIControlEventTouchUpInside];
  120. [self.zoomBtn setSelected:NO];
  121. [self.zoomBtn setBackgroundImage:[UIImage imageNamed:@"zoomout1"] forState:UIControlStateSelected];
  122. [self.zoomBtn setBackgroundImage:[UIImage imageNamed:@"zoomin1"] forState:UIControlStateNormal];
  123. [self.zoomBtn setTintColor:[UIColor clearColor]];
  124. [self.playerHUDBottomView addSubview:self.zoomBtn];
  125. //缓冲进度条
  126. self.loadProgressView = [[UIProgressView alloc] init];
  127. self.loadProgressView.frame = CGRectMake(32, 17, frameWidth-60, 14);
  128. self.loadProgressView.progressViewStyle = UIProgressViewStyleBar;
  129. self.loadProgressView.progressTintColor = RGB(181, 181, 181);
  130. self.loadProgressView.backgroundColor = [UIColor greenColor];
  131. self.loadProgressView.progress = 0;
  132. [self.playerHUDBottomView addSubview:self.loadProgressView];
  133. //播放进度条
  134. self.progressBar = [[UISlider alloc] init];
  135. self.progressBar.frame = CGRectMake(30, 11, frameWidth-60, 14);
  136. [self.progressBar addTarget:self action:@selector(progressBarChanged:) forControlEvents:UIControlEventValueChanged];
  137. [self.progressBar addTarget:self action:@selector(progressBarChangeEnded:) forControlEvents:UIControlEventTouchUpInside];
  138. [self.progressBar setMinimumTrackTintColor:RGB(242, 96, 0)];
  139. [self.progressBar setMaximumTrackTintColor:[UIColor clearColor]]; //设置成透明
  140. // [self.progressBar trackRectForBounds:CGRectMake(0, 0, frameWidth-60, 5)];
  141. [self.progressBar setThumbTintColor:[UIColor clearColor]];
  142. //滑块图片
  143. UIImage *thumbImage = [UIImage imageNamed:@"account_cache_isplay"];
  144. //注意这里要加UIControlStateHightlighted的状态,否则当拖动滑块时滑块将变成原生的控件
  145. [self.progressBar setThumbImage:thumbImage forState:UIControlStateHighlighted];
  146. [self.progressBar setThumbImage:thumbImage forState:UIControlStateNormal];
  147. [self.playerHUDBottomView addSubview:self.progressBar];
  148. //播放时间
  149. self.playTime = [[UILabel alloc] initWithFrame:CGRectMake(30, 20, 200, 20)];
  150. self.playTime.text = @"00:00:00/00:00:00";
  151. self.playTime.font = [UIFont systemFontOfSize:13];
  152. self.playTime.textAlignment = NSTextAlignmentLeft;
  153. self.playTime.textColor = [UIColor whiteColor];
  154. [self.playerHUDBottomView addSubview:self.playTime];
  155. }
  156. -(void)initPlayTime{
  157. NSString *currentTime = [self getStringFromCMTime:self.player.currentTime];
  158. NSString *totalTime = [self getStringFromCMTime:self.player.currentItem.asset.duration];
  159. self.playTime.text = [NSString stringWithFormat:@"%@/%@",currentTime,totalTime];
  160. NSLog(@"totalTime:%@",totalTime);
  161. }
  162. //添加计时器,显示/隐藏播放栏
  163. -(void)startTimer{
  164. if (timer == nil) {
  165. timer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(initHUDViewShowing:) userInfo:nil repeats:YES];
  166. }
  167. }
  168. -(void)stopTimer{
  169. if (timer) {
  170. [timer invalidate];
  171. timer = nil;
  172. }
  173. }
  174. -(void)initHUDViewShowing:(NSTimer *)timer{
  175. [self showHud:viewIsShowing];
  176. }
  177. -(void)showHud:(BOOL)showing{
  178. __weak __typeof(self) weakself = self;
  179. if (showing) {//隐藏
  180. viewIsShowing = !showing;
  181. weakself.playerHUDBottomView.hidden = YES;
  182. [weakself stopTimer];
  183. }else{//显示
  184. viewIsShowing = !showing;
  185. weakself.playerHUDBottomView.hidden = NO;
  186. [weakself startTimer];
  187. }
  188. }
  189. -(void)layoutSubviews{
  190. [super layoutSubviews];
  191. UIDeviceOrientation deviceOrientation = [[UIDevice currentDevice] orientation];
  192. if (UIDeviceOrientationIsLandscape(deviceOrientation)) {
  193. NSLog(ASLocalizedString(@"横屏"));
  194. self.isFullScreen = YES;
  195. [self initLandscape];
  196. }else{
  197. NSLog(ASLocalizedString(@"竖屏"));
  198. self.isFullScreen = NO;
  199. [self initPortraint];
  200. }
  201. }
  202. //initLandscape与initPortraint里面一样
  203. -(void)initLandscape{
  204. NSLog(@"====%f",self.playerLayer.frame.size.width);
  205. float frameWidth = self.frame.size.width;
  206. float frameHeight = self.frame.size.height;
  207. NSLog(ASLocalizedString(@"横屏:width=%f height=%f"),frameWidth,frameHeight);
  208. self.playerHUDBottomView.frame = CGRectMake(0, frameHeight-44, frameWidth, 44);
  209. self.zoomBtn.frame = CGRectMake(frameWidth-27, 10, 20, 20);
  210. self.progressBar.frame = CGRectMake(30, 11, frameWidth-60, 14);
  211. self.loadProgressView.frame = CGRectMake(32, 17, frameWidth-60, 14);
  212. }
  213. //
  214. -(void)initPortraint{
  215. float frameWidth = self.frame.size.width;
  216. float frameHeight = self.frame.size.height;
  217. NSLog(ASLocalizedString(@"竖屏:width=%f height=%f"),frameWidth,frameHeight);
  218. self.playerHUDBottomView.frame = CGRectMake(0, frameHeight-44, frameWidth, 44);
  219. self.zoomBtn.frame = CGRectMake(frameWidth-27, 10, 20, 20);
  220. self.progressBar.frame = CGRectMake(30, 11, frameWidth-60, 14);
  221. self.loadProgressView.frame = CGRectMake(32, 17, frameWidth-60, 14);
  222. }
  223. //监听touch事件
  224. -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
  225. CGPoint point = [(UITouch *)[touches anyObject] locationInView:self];
  226. if (CGRectContainsPoint(self.playerLayer.frame, point)) {
  227. [self showHud:viewIsShowing];
  228. }
  229. }
  230. -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
  231. NSLog(@"touchesMoved");
  232. }
  233. -(void)OnPlayBtn:(UIButton *)sender{
  234. if (self.isPlaying) {
  235. [self pause];
  236. }else{
  237. [self play];
  238. }
  239. }
  240. -(void)OnZoomBtn:(UIButton *)sender{
  241. NSLog(ASLocalizedString(@"全屏/非全屏"));
  242. self.isFullScreen = !self.isFullScreen;
  243. if (self.isFullScreen) {
  244. [self.zoomBtn setSelected:YES];
  245. }else{
  246. [self.zoomBtn setSelected:NO];
  247. }
  248. [self.delegate playerViewZoomButtonClicked:self];
  249. }
  250. -(void)OnBackBtn:(UIButton *)sender{
  251. if (self.isFullScreen) {
  252. self.isFullScreen = !self.isFullScreen;
  253. [self.delegate playerViewZoomButtonClicked:self];
  254. }else{
  255. [self.delegate JZOnBackBtn];
  256. }
  257. }
  258. -(void)progressBarChanged:(UISlider *)sender{
  259. if (self.isPlaying) {
  260. [self.player pause];
  261. }
  262. CMTime seekTime = CMTimeMakeWithSeconds(sender.value*(double)self.player.currentItem.asset.duration.value/(double)self.player.currentItem.asset.duration.timescale, self.player.currentTime.timescale);
  263. [self.player seekToTime:seekTime];
  264. }
  265. -(void)progressBarChangeEnded:(UISlider *)sender{
  266. [self startTimer];
  267. if (self.isPlaying) {
  268. [self.player play];
  269. }
  270. }
  271. //添加播放进度条更新
  272. -(void)addProgressObserver{
  273. __weak __typeof(self) weakself = self;
  274. AVPlayerItem *playerItem = self.player.currentItem;
  275. NSLog(ASLocalizedString(@"//添加播放进度条更新"));
  276. playbackObserver = [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time){
  277. float current = CMTimeGetSeconds(time);
  278. float total = CMTimeGetSeconds(playerItem.duration);
  279. NSLog(ASLocalizedString(@"当前已经播放%.2fs。"),current);
  280. //更新进度条
  281. float progress = current/total;
  282. weakself.progressBar.value = progress;
  283. NSString *currentTime = [weakself getStringFromCMTime:weakself.player.currentTime];
  284. NSString *totalTime = [weakself getStringFromCMTime:playerItem.duration];
  285. weakself.playTime.text = [NSString stringWithFormat:@"%@/%@",currentTime,totalTime];
  286. }];
  287. }
  288. -(void)addNotification{
  289. //给AVPlayerItem添加播放完成通知
  290. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];
  291. }
  292. -(void)playbackFinished:(NSNotification *)notification{
  293. NSLog(ASLocalizedString(@"视频播放完成"));
  294. }
  295. /**
  296. * 给AVPlayerItem添加监控
  297. *
  298. * @param playerItem AVPlayerItem对象
  299. */
  300. -(void)addObserverToPlayerItem:(AVPlayerItem *)playerItem{
  301. //监控状态属性,注意AVPlayer也有一个status属性,通过监控它的status也可以获得播放状态
  302. [playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
  303. //监控网络加载情况属性
  304. [playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
  305. //监控缓冲区大小
  306. [playerItem addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];
  307. [self performSelectorInBackground:@selector(initPlayTime) withObject:nil];
  308. }
  309. /**
  310. * 移除KVO观察
  311. */
  312. -(void)removeObserverToPlayerItem:(AVPlayerItem *)playerItem{
  313. [playerItem removeObserver:self forKeyPath:@"status"];
  314. [playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
  315. [playerItem removeObserver:self forKeyPath:@"playbackBufferEmpty"];
  316. }
  317. #pragma mark - 观察视频播放各个监听触发
  318. -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
  319. if ([keyPath isEqualToString:@"status"]) {//播放状态
  320. AVPlayerStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];
  321. switch (status) {
  322. case AVPlayerStatusFailed:
  323. NSLog(ASLocalizedString(@"播放失败"));
  324. [loadView setHidden:NO];
  325. break;
  326. case AVPlayerStatusReadyToPlay:
  327. NSLog(ASLocalizedString(@"正在播放...视频中长度为:%f"),CMTimeGetSeconds(self.playerItem.duration));
  328. [loadView setHidden:YES];
  329. break;
  330. default:
  331. NSLog(@"default:");
  332. break;
  333. }
  334. }else if ([keyPath isEqualToString:@"loadedTimeRanges"]){//缓冲
  335. NSArray *array = self.playerItem.loadedTimeRanges;
  336. CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];//本次缓冲时间
  337. float startSeconds = CMTimeGetSeconds(timeRange.start);
  338. float durationSeconds = CMTimeGetSeconds(timeRange.duration);
  339. NSTimeInterval totalBuffer = startSeconds + durationSeconds;//缓冲总长度
  340. float durationTime = CMTimeGetSeconds([[self.player currentItem] duration]);//总时间
  341. NSLog(ASLocalizedString(@"共缓冲:%.2f,总时长为:%f"),totalBuffer,durationTime);
  342. [self.loadProgressView setProgress:totalBuffer/durationTime animated:YES];
  343. if (self.playerIsBuffering && self.isPlaying) {
  344. [self.player play];
  345. self.playerIsBuffering = NO;
  346. }
  347. }else if ([keyPath isEqualToString:@"playbackBufferEmpty"]){
  348. if(self.player.currentItem.playbackBufferEmpty){
  349. NSLog(ASLocalizedString(@"缓冲区为空"));
  350. self.playerIsBuffering = YES;
  351. }else{
  352. NSLog(ASLocalizedString(@"缓冲区不为空======"));
  353. }
  354. }else{
  355. NSLog(@"++++++++++");
  356. }
  357. }
  358. -(NSString*)getStringFromCMTime:(CMTime)time
  359. {
  360. Float64 currentSeconds = CMTimeGetSeconds(time);
  361. int mins = currentSeconds/60.0;
  362. int hours = mins / 60.0f;
  363. int secs = fmodf(currentSeconds, 60.0);
  364. mins = fmodf(mins, 60.0f);
  365. NSString *hoursString = hours < 10 ? [NSString stringWithFormat:@"0%d", hours] : [NSString stringWithFormat:@"%d", hours];
  366. NSString *minsString = mins < 10 ? [NSString stringWithFormat:@"0%d", mins] : [NSString stringWithFormat:@"%d", mins];
  367. NSString *secsString = secs < 10 ? [NSString stringWithFormat:@"0%d", secs] : [NSString stringWithFormat:@"%d", secs];
  368. return [NSString stringWithFormat:@"%@:%@:%@", hoursString,minsString, secsString];
  369. }
  370. /*
  371. // Only override drawRect: if you perform custom drawing.
  372. // An empty implementation adversely affects performance during animation.
  373. - (void)drawRect:(CGRect)rect {
  374. // Drawing code
  375. }
  376. */
  377. @end