This commit is contained in:
DDIsFriend
2023-08-28 18:29:21 +08:00
parent c73a6ff1d4
commit 8d563860f1
290 changed files with 9542 additions and 9626 deletions

View File

@@ -0,0 +1,127 @@
//
// UIImageView+ZFCache.h
// ZFPlayer
//
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <UIKit/UIKit.h>
typedef void (^ZFDownLoadDataCallBack)(NSData *data, NSError *error);
typedef void (^ZFDownloadProgressBlock)(unsigned long long total, unsigned long long current);
@interface ZFImageDownloader : NSObject<NSURLSessionDownloadDelegate>
@property (nonatomic, strong) NSURLSession *session;
@property (nonatomic, strong) NSURLSessionDownloadTask *task;
@property (nonatomic, assign) unsigned long long totalLength;
@property (nonatomic, assign) unsigned long long currentLength;
@property (nonatomic, copy) ZFDownloadProgressBlock progressBlock;
@property (nonatomic, copy) ZFDownLoadDataCallBack callbackOnFinished;
- (void)startDownloadImageWithUrl:(NSString *)url
progress:(ZFDownloadProgressBlock)progress
finished:(ZFDownLoadDataCallBack)finished;
@end
typedef void (^ZFImageBlock)(UIImage *image);
@interface UIImageView (ZFCache)
/**
* Get/Set the callback block when download the image finished.
*
* The image object from network or from disk.
*/
@property (nonatomic, copy) ZFImageBlock completion;
/**
* Image downloader
*/
@property (nonatomic, strong) ZFImageDownloader *imageDownloader;
/**
* Specify the URL to download images fails, the number of retries, the default is 2
*/
@property (nonatomic, assign) NSUInteger attemptToReloadTimesForFailedURL;
/**
* Will automatically download to cutting for UIImageView size of image.The default value is NO.
* If set to YES, then the download after a successful store only after cutting the image
*/
@property (nonatomic, assign) BOOL shouldAutoClipImageToViewSize;
/**
* Set the imageView `image` with an `url` and a placeholder.
*
* The download is asynchronous and cached.
*
* @param url The url for the image.
* @param placeholderImageName The image name to be set initially, until the image request finishes.
*/
- (void)setImageWithURLString:(NSString *)url placeholderImageName:(NSString *)placeholderImageName;
/**
* Set the imageView `image` with an `url` and a placeholder.
*
* The download is asynchronous and cached.
*
* @param url The url for the image.
* @param placeholderImage The image to be set initially, until the image request finishes.
*/
- (void)setImageWithURLString:(NSString *)url placeholder:(UIImage *)placeholderImage;
/**
* Set the imageView `image` with an `url`, placeholder.
*
* The download is asynchronous and cached.
*
* @param url The url for the image.
* @param placeholderImage The image to be set initially, until the image request finishes.
* @param completion A block called when operation has been completed. This block has no return value
* and takes the requested UIImage as first parameter. In case of error the image parameter
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
* indicating if the image was retrieved from the local cache or from the network.
* The fourth parameter is the original image url.
*/
- (void)setImageWithURLString:(NSString *)url
placeholder:(UIImage *)placeholderImage
completion:(void (^)(UIImage *image))completion;
/**
* Set the imageView `image` with an `url`, placeholder.
*
* The download is asynchronous and cached.
*
* @param url The url for the image.
* @param placeholderImageName The image name to be set initially, until the image request finishes.
* @param completion A block called when operation has been completed. This block has no return value
* and takes the requested UIImage as first parameter. In case of error the image parameter
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
* indicating if the image was retrieved from the local cache or from the network.
* The fourth parameter is the original image url.
*/
- (void)setImageWithURLString:(NSString *)url
placeholderImageName:(NSString *)placeholderImageName
completion:(void (^)(UIImage *image))completion;
@end

View File

@@ -0,0 +1,411 @@
//
// UIImageView+ZFCache.m
// ZFPlayer
//
// Copyright (c) 2016 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "UIImageView+ZFCache.h"
#import <objc/runtime.h>
#import <CommonCrypto/CommonDigest.h>
@implementation ZFImageDownloader
- (void)startDownloadImageWithUrl:(NSString *)url
progress:(ZFDownloadProgressBlock)progress
finished:(ZFDownLoadDataCallBack)finished {
self.progressBlock = progress;
self.callbackOnFinished = finished;
if ([NSURL URLWithString:url] == nil) {
if (finished) { finished(nil, nil); }
return;
}
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:60];
[request addValue:@"image/*" forHTTPHeaderField:@"Accept"];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
self.session = [NSURLSession sessionWithConfiguration:config
delegate:self
delegateQueue:queue];
NSURLSessionDownloadTask *task = [self.session downloadTaskWithRequest:request];
[task resume];
self.task = task;
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
NSData *data = [NSData dataWithContentsOfURL:location];
if (self.progressBlock) {
self.progressBlock(self.totalLength, self.currentLength);
}
if (self.callbackOnFinished) {
self.callbackOnFinished(data, nil);
//
self.callbackOnFinished = nil;
}
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
self.currentLength = totalBytesWritten;
self.totalLength = totalBytesExpectedToWrite;
if (self.progressBlock) {
self.progressBlock(self.totalLength, self.currentLength);
}
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
if ([error code] != NSURLErrorCancelled) {
if (self.callbackOnFinished) {
self.callbackOnFinished(nil, error);
}
self.callbackOnFinished = nil;
}
}
@end
@interface NSString (md5)
+ (NSString *)cachedFileNameForKey:(NSString *)key;
+ (NSString *)zf_cachePath;
+ (NSString *)zf_keyForRequest:(NSURLRequest *)request;
@end
@implementation NSString (md5)
+ (NSString *)zf_keyForRequest:(NSURLRequest *)request {
return request.URL.absoluteString;
}
+ (NSString *)zf_cachePath {
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *directoryPath = [NSString stringWithFormat:@"%@/%@/%@",cachePath,@"default",@"com.hackemist.SDWebImageCache.default"];
return directoryPath;
}
+ (NSString *)cachedFileNameForKey:(NSString *)key {
const char *str = [key UTF8String];
if (str == NULL) {
str = "";
}
unsigned char r[CC_MD5_DIGEST_LENGTH];
CC_MD5(str, (CC_LONG)strlen(str), r);
NSString *filename = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%@",
r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10],
r[11], r[12], r[13], r[14], r[15], [[key pathExtension] isEqualToString:@""] ? @"" : [NSString stringWithFormat:@".%@", [key pathExtension]]];
return filename;
}
@end
@interface UIApplication (ZFCacheImage)
@property (nonatomic, strong, readonly) NSMutableDictionary *zf_cacheFaileTimes;
- (UIImage *)zf_cacheImageForRequest:(NSURLRequest *)request;
- (void)zf_cacheImage:(UIImage *)image forRequest:(NSURLRequest *)request;
- (void)zf_cacheFailRequest:(NSURLRequest *)request;
- (NSUInteger)zf_failTimesForRequest:(NSURLRequest *)request;
@end
@implementation UIApplication (ZFCacheImage)
- (NSMutableDictionary *)zf_cacheFaileTimes {
NSMutableDictionary *dict = objc_getAssociatedObject(self, _cmd);
if (!dict) {
dict = [[NSMutableDictionary alloc] init];
}
return dict;
}
- (void)setZf_cacheFaileTimes:(NSMutableDictionary *)zf_cacheFaileTimes {
objc_setAssociatedObject(self, @selector(zf_cacheFaileTimes), zf_cacheFaileTimes, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)zf_clearCache {
[self.zf_cacheFaileTimes removeAllObjects];
self.zf_cacheFaileTimes = nil;
}
- (void)zf_clearDiskCaches {
NSString *directoryPath = [NSString zf_cachePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:directoryPath isDirectory:nil]) {
dispatch_queue_t ioQueue = dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL);
dispatch_async(ioQueue, ^{
[[NSFileManager defaultManager] removeItemAtPath:directoryPath error:nil];
[[NSFileManager defaultManager] createDirectoryAtPath:directoryPath
withIntermediateDirectories:YES
attributes:nil
error:nil];
});
}
[self zf_clearCache];
}
- (UIImage *)zf_cacheImageForRequest:(NSURLRequest *)request {
if (request) {
NSString *directoryPath = [NSString zf_cachePath];
NSString *path = [NSString stringWithFormat:@"%@/%@", directoryPath, [NSString cachedFileNameForKey:[NSString zf_keyForRequest:request]]];
return [UIImage imageWithContentsOfFile:path];
}
return nil;
}
- (NSUInteger)zf_failTimesForRequest:(NSURLRequest *)request {
NSNumber *faileTimes = [self.zf_cacheFaileTimes objectForKey:[NSString cachedFileNameForKey:[NSString zf_keyForRequest:request]]];
if (faileTimes && [faileTimes respondsToSelector:@selector(integerValue)]) {
return faileTimes.integerValue;
}
return 0;
}
- (void)zf_cacheFailRequest:(NSURLRequest *)request {
NSNumber *faileTimes = [self.zf_cacheFaileTimes objectForKey:[NSString cachedFileNameForKey:[NSString zf_keyForRequest:request]]];
NSUInteger times = 0;
if (faileTimes && [faileTimes respondsToSelector:@selector(integerValue)]) {
times = [faileTimes integerValue];
}
times++;
[self.zf_cacheFaileTimes setObject:@(times) forKey:[NSString cachedFileNameForKey:[NSString zf_keyForRequest:request]]];
}
- (void)zf_cacheImage:(UIImage *)image forRequest:(NSURLRequest *)request {
if (!image || !request) { return; }
NSString *directoryPath = [NSString zf_cachePath];
if (![[NSFileManager defaultManager] fileExistsAtPath:directoryPath isDirectory:nil]) {
NSError *error = nil;
[[NSFileManager defaultManager] createDirectoryAtPath:directoryPath
withIntermediateDirectories:YES
attributes:nil
error:&error];
if (error) { return; }
}
NSString *path = [NSString stringWithFormat:@"%@/%@", directoryPath, [NSString cachedFileNameForKey:[NSString zf_keyForRequest:request]]];
NSData *data = UIImagePNGRepresentation(image);
if (data) {
[[NSFileManager defaultManager] createFileAtPath:path contents:data attributes:nil];
}
}
@end
@implementation UIImageView (ZFCache)
#pragma mark - getter
- (ZFImageBlock)completion {
return objc_getAssociatedObject(self, _cmd);
}
- (ZFImageDownloader *)imageDownloader {
return objc_getAssociatedObject(self, _cmd);
}
- (NSUInteger)attemptToReloadTimesForFailedURL {
NSUInteger count = [objc_getAssociatedObject(self, _cmd) integerValue];
if (count == 0) { count = 2; }
return count;
}
- (BOOL)shouldAutoClipImageToViewSize {
return [objc_getAssociatedObject(self, _cmd) boolValue];
}
#pragma mark - setter
- (void)setCompletion:(ZFImageBlock)completion {
objc_setAssociatedObject(self, @selector(completion), completion, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (void)setImageDownloader:(ZFImageDownloader *)imageDownloader {
objc_setAssociatedObject(self, @selector(imageDownloader), imageDownloader, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)setAttemptToReloadTimesForFailedURL:(NSUInteger)attemptToReloadTimesForFailedURL {
objc_setAssociatedObject(self, @selector(attemptToReloadTimesForFailedURL), @(attemptToReloadTimesForFailedURL), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)setShouldAutoClipImageToViewSize:(BOOL)shouldAutoClipImageToViewSize {
objc_setAssociatedObject(self, @selector(shouldAutoClipImageToViewSize), @(shouldAutoClipImageToViewSize), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#pragma mark - public method
- (void)setImageWithURLString:(NSString *)url
placeholderImageName:(NSString *)placeholderImageName {
return [self setImageWithURLString:url placeholderImageName:placeholderImageName completion:nil];
}
- (void)setImageWithURLString:(NSString *)url placeholder:(UIImage *)placeholderImage {
return [self setImageWithURLString:url placeholder:placeholderImage completion:nil];
}
- (void)setImageWithURLString:(NSString *)url
placeholderImageName:(NSString *)placeholderImage
completion:(void (^)(UIImage *image))completion {
NSString *path = [[NSBundle mainBundle] pathForResource:placeholderImage ofType:nil];
UIImage *image = [UIImage imageWithContentsOfFile:path];
if (image == nil) { image = [UIImage imageNamed:placeholderImage]; }
[self setImageWithURLString:url placeholder:image completion:completion];
}
- (void)setImageWithURLString:(NSString *)url
placeholder:(UIImage *)placeholderImageName
completion:(void (^)(UIImage *image))completion {
[self.layer removeAllAnimations];
self.completion = completion;
if (url == nil || [url isKindOfClass:[NSNull class]] || (![url hasPrefix:@"http://"] && ![url hasPrefix:@"https://"])) {
[self setImage:placeholderImageName isFromCache:YES];
if (completion) {
self.completion(self.image);
}
return;
}
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[self downloadWithReqeust:request holder:placeholderImageName];
}
#pragma mark - private method
- (void)downloadWithReqeust:(NSURLRequest *)theRequest holder:(UIImage *)holder {
UIImage *cachedImage = [[UIApplication sharedApplication] zf_cacheImageForRequest:theRequest];
if (cachedImage) {
[self setImage:cachedImage isFromCache:YES];
if (self.completion) {
self.completion(cachedImage);
}
return;
}
[self setImage:holder isFromCache:YES];
if ([[UIApplication sharedApplication] zf_failTimesForRequest:theRequest] >= self.attemptToReloadTimesForFailedURL) {
return;
}
[self cancelRequest];
self.imageDownloader = nil;
__weak __typeof(self) weakSelf = self;
self.imageDownloader = [[ZFImageDownloader alloc] init];
[self.imageDownloader startDownloadImageWithUrl:theRequest.URL.absoluteString progress:nil finished:^(NSData *data, NSError *error) {
// success
if (data != nil && error == nil) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
UIImage *image = [UIImage imageWithData:data];
UIImage *finalImage = image;
if (image) {
if (weakSelf.shouldAutoClipImageToViewSize) {
// cutting
if (fabs(weakSelf.frame.size.width - image.size.width) != 0
&& fabs(weakSelf.frame.size.height - image.size.height) != 0) {
finalImage = [self clipImage:image toSize:weakSelf.frame.size isScaleToMax:YES];
}
}
[[UIApplication sharedApplication] zf_cacheImage:finalImage forRequest:theRequest];
} else {
[[UIApplication sharedApplication] zf_cacheFailRequest:theRequest];
}
dispatch_async(dispatch_get_main_queue(), ^{
if (finalImage) {
[weakSelf setImage:finalImage isFromCache:NO];
if (weakSelf.completion) {
weakSelf.completion(weakSelf.image);
}
} else {// error data
if (weakSelf.completion) {
weakSelf.completion(weakSelf.image);
}
}
});
});
} else { // error
[[UIApplication sharedApplication] zf_cacheFailRequest:theRequest];
if (weakSelf.completion) {
weakSelf.completion(weakSelf.image);
}
}
}];
}
- (void)setImage:(UIImage *)image isFromCache:(BOOL)isFromCache {
self.image = image;
if (!isFromCache) {
CATransition *animation = [CATransition animation];
[animation setDuration:0.6f];
[animation setType:kCATransitionFade];
animation.removedOnCompletion = YES;
[self.layer addAnimation:animation forKey:@"transition"];
}
}
- (void)cancelRequest {
[self.imageDownloader.task cancel];
}
- (UIImage *)clipImage:(UIImage *)image toSize:(CGSize)size isScaleToMax:(BOOL)isScaleToMax {
CGFloat scale = [UIScreen mainScreen].scale;
UIGraphicsBeginImageContextWithOptions(size, NO, scale);
CGSize aspectFitSize = CGSizeZero;
if (image.size.width != 0 && image.size.height != 0) {
CGFloat rateWidth = size.width / image.size.width;
CGFloat rateHeight = size.height / image.size.height;
CGFloat rate = isScaleToMax ? MAX(rateHeight, rateWidth) : MIN(rateHeight, rateWidth);
aspectFitSize = CGSizeMake(image.size.width * rate, image.size.height * rate);
}
[image drawInRect:CGRectMake(0, 0, aspectFitSize.width, aspectFitSize.height)];
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return finalImage;
}
@end

View File

@@ -0,0 +1,45 @@
//
// UIView+ZFFrame.h
// ZFPlayer
//
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <UIKit/UIKit.h>
@interface UIView (ZFFrame)
@property (nonatomic) CGFloat zf_x;
@property (nonatomic) CGFloat zf_y;
@property (nonatomic) CGFloat zf_width;
@property (nonatomic) CGFloat zf_height;
@property (nonatomic) CGFloat zf_top;
@property (nonatomic) CGFloat zf_bottom;
@property (nonatomic) CGFloat zf_left;
@property (nonatomic) CGFloat zf_right;
@property (nonatomic) CGFloat zf_centerX;
@property (nonatomic) CGFloat zf_centerY;
@property (nonatomic) CGPoint zf_origin;
@property (nonatomic) CGSize zf_size;
@end

View File

@@ -0,0 +1,149 @@
//
// UIView+ZFFrame.m
// ZFPlayer
//
// Copyright (c) 2016 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "UIView+ZFFrame.h"
@implementation UIView (ZFFrame)
- (CGFloat)zf_x {
return self.frame.origin.x;
}
- (void)setZf_x:(CGFloat)zf_x {
CGRect newFrame = self.frame;
newFrame.origin.x = zf_x;
self.frame = newFrame;
}
- (CGFloat)zf_y {
return self.frame.origin.y;
}
- (void)setZf_y:(CGFloat)zf_y {
CGRect newFrame = self.frame;
newFrame.origin.y = zf_y;
self.frame = newFrame;
}
- (CGFloat)zf_width {
return CGRectGetWidth(self.bounds);
}
- (void)setZf_width:(CGFloat)zf_width {
CGRect newFrame = self.frame;
newFrame.size.width = zf_width;
self.frame = newFrame;
}
- (CGFloat)zf_height {
return CGRectGetHeight(self.bounds);
}
- (void)setZf_height:(CGFloat)zf_height {
CGRect newFrame = self.frame;
newFrame.size.height = zf_height;
self.frame = newFrame;
}
- (CGFloat)zf_top {
return self.frame.origin.y;
}
- (void)setZf_top:(CGFloat)zf_top {
CGRect newFrame = self.frame;
newFrame.origin.y = zf_top;
self.frame = newFrame;
}
- (CGFloat)zf_bottom {
return self.frame.origin.y + self.frame.size.height;
}
- (void)setZf_bottom:(CGFloat)zf_bottom {
CGRect newFrame = self.frame;
newFrame.origin.y = zf_bottom - self.frame.size.height;
self.frame = newFrame;
}
- (CGFloat)zf_left {
return self.frame.origin.x;
}
- (void)setZf_left:(CGFloat)zf_left {
CGRect newFrame = self.frame;
newFrame.origin.x = zf_left;
self.frame = newFrame;
}
- (CGFloat)zf_right {
return self.frame.origin.x + self.frame.size.width;
}
- (void)setZf_right:(CGFloat)zf_right {
CGRect newFrame = self.frame;
newFrame.origin.x = zf_right - self.frame.size.width;
self.frame = newFrame;
}
- (CGFloat)zf_centerX {
return self.center.x;
}
- (void)setZf_centerX:(CGFloat)zf_centerX {
CGPoint newCenter = self.center;
newCenter.x = zf_centerX;
self.center = newCenter;
}
- (CGFloat)zf_centerY {
return self.center.y;
}
- (void)setZf_centerY:(CGFloat)zf_centerY {
CGPoint newCenter = self.center;
newCenter.y = zf_centerY;
self.center = newCenter;
}
- (CGPoint)zf_origin {
return self.frame.origin;
}
- (void)setZf_origin:(CGPoint)zf_origin {
CGRect newFrame = self.frame;
newFrame.origin = zf_origin;
self.frame = newFrame;
}
- (CGSize)zf_size {
return self.frame.size;
}
- (void)setZf_size:(CGSize)zf_size {
CGRect newFrame = self.frame;
newFrame.size = zf_size;
self.frame = newFrame;
}
@end

View File

@@ -0,0 +1,120 @@
//
// ZFLandScapeControlView.h
// ZFPlayer
//
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <UIKit/UIKit.h>
#import "ZFSliderView.h"
#if __has_include(<ZFPlayer/ZFPlayerController.h>)
#import <ZFPlayer/ZFPlayerController.h>
#else
#import "ZFPlayerController.h"
#endif
NS_ASSUME_NONNULL_BEGIN
@interface ZFLandScapeControlView : UIView
/// 顶部工具栏
@property (nonatomic, strong, readonly) UIView *topToolView;
/// 返回按钮
@property (nonatomic, strong, readonly) UIButton *backBtn;
/// 标题
@property (nonatomic, strong, readonly) UILabel *titleLabel;
/// 底部工具栏
@property (nonatomic, strong, readonly) UIView *bottomToolView;
/// 播放或暂停按钮
@property (nonatomic, strong, readonly) UIButton *playOrPauseBtn;
/// 播放的当前时间
@property (nonatomic, strong, readonly) UILabel *currentTimeLabel;
/// 滑杆
@property (nonatomic, strong, readonly) ZFSliderView *slider;
/// 视频总时间
@property (nonatomic, strong, readonly) UILabel *totalTimeLabel;
/// 锁定屏幕按钮
@property (nonatomic, strong, readonly) UIButton *lockBtn;
/// 播放器
@property (nonatomic, weak) ZFPlayerController *player;
/// slider滑动中
@property (nonatomic, copy, nullable) void(^sliderValueChanging)(CGFloat value,BOOL forward);
/// slider滑动结束
@property (nonatomic, copy, nullable) void(^sliderValueChanged)(CGFloat value);
/// 返回按钮点击回调
@property (nonatomic, copy) void(^backBtnClickCallback)(void);
/// 如果是暂停状态seek完是否播放默认YES
@property (nonatomic, assign) BOOL seekToPlay;
/// 全屏模式
@property (nonatomic, assign) ZFFullScreenMode fullScreenMode;
/// 重置控制层
- (void)resetControlView;
/// 显示控制层
- (void)showControlView;
/// 隐藏控制层
- (void)hideControlView;
/// 设置播放时间
- (void)videoPlayer:(ZFPlayerController *)videoPlayer currentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime;
/// 设置缓冲时间
- (void)videoPlayer:(ZFPlayerController *)videoPlayer bufferTime:(NSTimeInterval)bufferTime;
/// 是否响应该手势
- (BOOL)shouldResponseGestureWithPoint:(CGPoint)point withGestureType:(ZFPlayerGestureType)type touch:(nonnull UITouch *)touch;
/// 视频尺寸改变
- (void)videoPlayer:(ZFPlayerController *)videoPlayer presentationSizeChanged:(CGSize)size;
/// 标题和全屏模式
- (void)showTitle:(NSString *_Nullable)title fullScreenMode:(ZFFullScreenMode)fullScreenMode;
/// 根据当前播放状态取反
- (void)playOrPause;
/// 播放按钮状态
- (void)playBtnSelectedState:(BOOL)selected;
/// 调节播放进度slider和当前时间更新
- (void)sliderValueChanged:(CGFloat)value currentTimeString:(NSString *)timeString;
/// 滑杆结束滑动
- (void)sliderChangeEnded;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,462 @@
//
// ZFLandScapeControlView.m
// ZFPlayer
//
// Copyright (c) 2016 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "ZFLandScapeControlView.h"
#import "UIView+ZFFrame.h"
#import "ZFUtilities.h"
#if __has_include(<ZFPlayer/ZFPlayer.h>)
#import <ZFPlayer/ZFPlayerConst.h>
#else
#import "ZFPlayerConst.h"
#endif
@interface ZFLandScapeControlView () <ZFSliderViewDelegate>
///
@property (nonatomic, strong) UIView *topToolView;
///
@property (nonatomic, strong) UIButton *backBtn;
///
@property (nonatomic, strong) UILabel *titleLabel;
///
@property (nonatomic, strong) UIView *bottomToolView;
///
@property (nonatomic, strong) UIButton *playOrPauseBtn;
///
@property (nonatomic, strong) UILabel *currentTimeLabel;
///
@property (nonatomic, strong) ZFSliderView *slider;
///
@property (nonatomic, strong) UILabel *totalTimeLabel;
///
@property (nonatomic, strong) UIButton *lockBtn;
@property (nonatomic, assign) BOOL isShow;
@end
@implementation ZFLandScapeControlView
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self addSubview:self.topToolView];
[self.topToolView addSubview:self.backBtn];
[self.topToolView addSubview:self.titleLabel];
[self addSubview:self.bottomToolView];
[self.bottomToolView addSubview:self.playOrPauseBtn];
[self.bottomToolView addSubview:self.currentTimeLabel];
[self.bottomToolView addSubview:self.slider];
[self.bottomToolView addSubview:self.totalTimeLabel];
[self addSubview:self.lockBtn];
//
[self makeSubViewsAction];
[self resetControlView];
/// statusBarFrame changed
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(layoutControllerViews) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
CGFloat min_x = 0;
CGFloat min_y = 0;
CGFloat min_w = 0;
CGFloat min_h = 0;
CGFloat min_view_w = self.bounds.size.width;
CGFloat min_view_h = self.bounds.size.height;
CGFloat min_margin = 9;
min_x = 0;
min_y = 0;
min_w = min_view_w;
min_h = iPhoneX ? 110 : 80;
self.topToolView.frame = CGRectMake(min_x, min_y, min_w, min_h);
min_x = (iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 44: 15;
if (@available(iOS 13.0, *)) {
min_y = UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation) ? 10 : (iPhoneX ? 40 : 20);
} else {
min_y = (iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 10: (iPhoneX ? 40 : 20);
}
min_w = 40;
min_h = 40;
self.backBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
min_x = self.backBtn.zf_right + 5;
min_y = 0;
min_w = min_view_w - min_x - 15 ;
min_h = 30;
self.titleLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
self.titleLabel.zf_centerY = self.backBtn.zf_centerY;
min_h = iPhoneX ? 100 : 73;
min_x = 0;
min_y = min_view_h - min_h;
min_w = min_view_w;
self.bottomToolView.frame = CGRectMake(min_x, min_y, min_w, min_h);
min_x = (iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 44: 15;
min_y = 32;
min_w = 30;
min_h = 30;
self.playOrPauseBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
min_x = self.playOrPauseBtn.zf_right + 4;
min_y = 0;
min_w = 62;
min_h = 30;
self.currentTimeLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
self.currentTimeLabel.zf_centerY = self.playOrPauseBtn.zf_centerY;
min_w = 62;
min_x = self.bottomToolView.zf_width - min_w - ((iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 44: min_margin);
min_y = 0;
min_h = 30;
self.totalTimeLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
self.totalTimeLabel.zf_centerY = self.playOrPauseBtn.zf_centerY;
min_x = self.currentTimeLabel.zf_right + 4;
min_y = 0;
min_w = self.totalTimeLabel.zf_left - min_x - 4;
min_h = 30;
self.slider.frame = CGRectMake(min_x, min_y, min_w, min_h);
self.slider.zf_centerY = self.playOrPauseBtn.zf_centerY;
min_x = (iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 50: 18;
min_y = 0;
min_w = 40;
min_h = 40;
self.lockBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
self.lockBtn.zf_centerY = self.zf_centerY;
if (!self.isShow) {
self.topToolView.zf_y = -self.topToolView.zf_height;
self.bottomToolView.zf_y = self.zf_height;
self.lockBtn.zf_left = iPhoneX ? -82: -47;
} else {
self.lockBtn.zf_left = iPhoneX ? 50: 18;
if (self.player.isLockedScreen) {
self.topToolView.zf_y = -self.topToolView.zf_height;
self.bottomToolView.zf_y = self.zf_height;
} else {
self.topToolView.zf_y = 0;
self.bottomToolView.zf_y = self.zf_height - self.bottomToolView.zf_height;
}
}
}
- (void)makeSubViewsAction {
[self.backBtn addTarget:self action:@selector(backBtnClickAction:) forControlEvents:UIControlEventTouchUpInside];
[self.playOrPauseBtn addTarget:self action:@selector(playPauseButtonClickAction:) forControlEvents:UIControlEventTouchUpInside];
[self.lockBtn addTarget:self action:@selector(lockButtonClickAction:) forControlEvents:UIControlEventTouchUpInside];
}
#pragma mark - action
- (void)layoutControllerViews {
[self layoutIfNeeded];
[self setNeedsLayout];
}
- (void)backBtnClickAction:(UIButton *)sender {
self.lockBtn.selected = NO;
self.player.lockedScreen = NO;
self.lockBtn.selected = NO;
if (self.player.orientationObserver.supportInterfaceOrientation & ZFInterfaceOrientationMaskPortrait) {
[self.player enterFullScreen:NO animated:YES];
}
if (self.backBtnClickCallback) {
self.backBtnClickCallback();
}
}
- (void)playPauseButtonClickAction:(UIButton *)sender {
[self playOrPause];
}
///
- (void)playOrPause {
self.playOrPauseBtn.selected = !self.playOrPauseBtn.isSelected;
self.playOrPauseBtn.isSelected? [self.player.currentPlayerManager play]: [self.player.currentPlayerManager pause];
}
- (void)playBtnSelectedState:(BOOL)selected {
self.playOrPauseBtn.selected = selected;
}
- (void)lockButtonClickAction:(UIButton *)sender {
sender.selected = !sender.selected;
self.player.lockedScreen = sender.selected;
}
#pragma mark - ZFSliderViewDelegate
- (void)sliderTouchBegan:(float)value {
self.slider.isdragging = YES;
}
- (void)sliderTouchEnded:(float)value {
if (self.player.totalTime > 0) {
self.slider.isdragging = YES;
if (self.sliderValueChanging) self.sliderValueChanging(value, self.slider.isForward);
@zf_weakify(self)
[self.player seekToTime:self.player.totalTime*value completionHandler:^(BOOL finished) {
@zf_strongify(self)
if (finished) {
self.slider.isdragging = NO;
if (self.sliderValueChanged) self.sliderValueChanged(value);
if (self.seekToPlay) {
[self.player.currentPlayerManager play];
}
}
}];
} else {
self.slider.isdragging = NO;
self.slider.value = 0;
}
}
- (void)sliderValueChanged:(float)value {
if (self.player.totalTime == 0) {
self.slider.value = 0;
return;
}
self.slider.isdragging = YES;
NSString *currentTimeString = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
self.currentTimeLabel.text = currentTimeString;
if (self.sliderValueChanging) self.sliderValueChanging(value,self.slider.isForward);
}
- (void)sliderTapped:(float)value {
[self sliderTouchEnded:value];
NSString *currentTimeString = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
self.currentTimeLabel.text = currentTimeString;
}
#pragma mark - public method
/// ControlView
- (void)resetControlView {
self.slider.value = 0;
self.slider.bufferValue = 0;
self.currentTimeLabel.text = @"00:00";
self.totalTimeLabel.text = @"00:00";
self.backgroundColor = [UIColor clearColor];
self.playOrPauseBtn.selected = YES;
self.titleLabel.text = @"";
self.topToolView.alpha = 1;
self.bottomToolView.alpha = 1;
self.isShow = NO;
}
- (void)showControlView {
self.lockBtn.alpha = 1;
self.isShow = YES;
if (self.player.isLockedScreen) {
self.topToolView.zf_y = -self.topToolView.zf_height;
self.bottomToolView.zf_y = self.zf_height;
} else {
self.topToolView.zf_y = 0;
self.bottomToolView.zf_y = self.zf_height - self.bottomToolView.zf_height;
}
self.lockBtn.zf_left = iPhoneX ? 50: 18;
self.player.statusBarHidden = NO;
if (self.player.isLockedScreen) {
self.topToolView.alpha = 0;
self.bottomToolView.alpha = 0;
} else {
self.topToolView.alpha = 1;
self.bottomToolView.alpha = 1;
}
}
- (void)hideControlView {
self.isShow = NO;
self.topToolView.zf_y = -self.topToolView.zf_height;
self.bottomToolView.zf_y = self.zf_height;
self.lockBtn.zf_left = iPhoneX ? -82: -47;
self.player.statusBarHidden = YES;
self.topToolView.alpha = 0;
self.bottomToolView.alpha = 0;
self.lockBtn.alpha = 0;
}
- (BOOL)shouldResponseGestureWithPoint:(CGPoint)point withGestureType:(ZFPlayerGestureType)type touch:(nonnull UITouch *)touch {
CGRect sliderRect = [self.bottomToolView convertRect:self.slider.frame toView:self];
if (CGRectContainsPoint(sliderRect, point)) {
return NO;
}
if (self.player.isLockedScreen && type != ZFPlayerGestureTypeSingleTap) { // tap
return NO;
}
return YES;
}
- (void)videoPlayer:(ZFPlayerController *)videoPlayer presentationSizeChanged:(CGSize)size {
self.lockBtn.hidden = self.player.orientationObserver.fullScreenMode == ZFFullScreenModePortrait;
}
- (void)videoPlayer:(ZFPlayerController *)videoPlayer currentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime {
if (!self.slider.isdragging) {
NSString *currentTimeString = [ZFUtilities convertTimeSecond:currentTime];
self.currentTimeLabel.text = currentTimeString;
NSString *totalTimeString = [ZFUtilities convertTimeSecond:totalTime];
self.totalTimeLabel.text = totalTimeString;
self.slider.value = videoPlayer.progress;
}
}
- (void)videoPlayer:(ZFPlayerController *)videoPlayer bufferTime:(NSTimeInterval)bufferTime {
self.slider.bufferValue = videoPlayer.bufferProgress;
}
- (void)showTitle:(NSString *)title fullScreenMode:(ZFFullScreenMode)fullScreenMode {
self.titleLabel.text = title;
self.player.orientationObserver.fullScreenMode = fullScreenMode;
self.lockBtn.hidden = fullScreenMode == ZFFullScreenModePortrait;
}
/// slider
- (void)sliderValueChanged:(CGFloat)value currentTimeString:(NSString *)timeString {
self.slider.value = value;
self.currentTimeLabel.text = timeString;
self.slider.isdragging = YES;
[UIView animateWithDuration:0.3 animations:^{
self.slider.sliderBtn.transform = CGAffineTransformMakeScale(1.2, 1.2);
}];
}
///
- (void)sliderChangeEnded {
self.slider.isdragging = NO;
[UIView animateWithDuration:0.3 animations:^{
self.slider.sliderBtn.transform = CGAffineTransformIdentity;
}];
}
#pragma mark - setter
- (void)setFullScreenMode:(ZFFullScreenMode)fullScreenMode {
_fullScreenMode = fullScreenMode;
self.player.orientationObserver.fullScreenMode = fullScreenMode;
self.lockBtn.hidden = fullScreenMode == ZFFullScreenModePortrait;
}
#pragma mark - getter
- (UIView *)topToolView {
if (!_topToolView) {
_topToolView = [[UIView alloc] init];
UIImage *image = ZFPlayer_Image(@"ZFPlayer_top_shadow");
_topToolView.layer.contents = (id)image.CGImage;
}
return _topToolView;
}
- (UIButton *)backBtn {
if (!_backBtn) {
_backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[_backBtn setImage:ZFPlayer_Image(@"ZFPlayer_back_full") forState:UIControlStateNormal];
}
return _backBtn;
}
- (UILabel *)titleLabel {
if (!_titleLabel) {
_titleLabel = [[UILabel alloc] init];
_titleLabel.textColor = [UIColor whiteColor];
_titleLabel.font = [UIFont systemFontOfSize:15.0];
}
return _titleLabel;
}
- (UIView *)bottomToolView {
if (!_bottomToolView) {
_bottomToolView = [[UIView alloc] init];
UIImage *image = ZFPlayer_Image(@"ZFPlayer_bottom_shadow");
_bottomToolView.layer.contents = (id)image.CGImage;
}
return _bottomToolView;
}
- (UIButton *)playOrPauseBtn {
if (!_playOrPauseBtn) {
_playOrPauseBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[_playOrPauseBtn setImage:ZFPlayer_Image(@"ZFPlayer_play") forState:UIControlStateNormal];
[_playOrPauseBtn setImage:ZFPlayer_Image(@"ZFPlayer_pause") forState:UIControlStateSelected];
}
return _playOrPauseBtn;
}
- (UILabel *)currentTimeLabel {
if (!_currentTimeLabel) {
_currentTimeLabel = [[UILabel alloc] init];
_currentTimeLabel.textColor = [UIColor whiteColor];
_currentTimeLabel.font = [UIFont systemFontOfSize:14.0f];
_currentTimeLabel.textAlignment = NSTextAlignmentCenter;
}
return _currentTimeLabel;
}
- (ZFSliderView *)slider {
if (!_slider) {
_slider = [[ZFSliderView alloc] init];
_slider.delegate = self;
_slider.maximumTrackTintColor = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:0.8];
_slider.bufferTrackTintColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.5];
_slider.minimumTrackTintColor = [UIColor whiteColor];
[_slider setThumbImage:ZFPlayer_Image(@"ZFPlayer_slider") forState:UIControlStateNormal];
_slider.sliderHeight = 2;
}
return _slider;
}
- (UILabel *)totalTimeLabel {
if (!_totalTimeLabel) {
_totalTimeLabel = [[UILabel alloc] init];
_totalTimeLabel.textColor = [UIColor whiteColor];
_totalTimeLabel.font = [UIFont systemFontOfSize:14.0f];
_totalTimeLabel.textAlignment = NSTextAlignmentCenter;
}
return _totalTimeLabel;
}
- (UIButton *)lockBtn {
if (!_lockBtn) {
_lockBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[_lockBtn setImage:ZFPlayer_Image(@"ZFPlayer_unlock-nor") forState:UIControlStateNormal];
[_lockBtn setImage:ZFPlayer_Image(@"ZFPlayer_lock-nor") forState:UIControlStateSelected];
}
return _lockBtn;
}
@end

View File

@@ -0,0 +1,66 @@
//
// ZFLoadingView.h
// ZFPlayer
//
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, ZFLoadingType) {
ZFLoadingTypeKeep,
ZFLoadingTypeFadeOut,
};
@interface ZFLoadingView : UIView
/// default is ZFLoadingTypeKeep.
@property (nonatomic, assign) ZFLoadingType animType;
/// default is whiteColor.
@property (nonatomic, strong, null_resettable) UIColor *lineColor;
/// Sets the line width of the spinner's circle.
@property (nonatomic) CGFloat lineWidth;
/// Sets whether the view is hidden when not animating.
@property (nonatomic) BOOL hidesWhenStopped;
/// Property indicating the duration of the animation, default is 1.5s.
@property (nonatomic, readwrite) NSTimeInterval duration;
/// anima state
@property (nonatomic, assign, readonly, getter=isAnimating) BOOL animating;
/**
* Starts animation of the spinner.
*/
- (void)startAnimating;
/**
* Stops animation of the spinnner.
*/
- (void)stopAnimating;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,183 @@
//
// ZFLoadingView.m
// ZFPlayer
//
// Copyright (c) 2016 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "ZFLoadingView.h"
@interface ZFLoadingView ()
@property (nonatomic, strong, readonly) CAShapeLayer *shapeLayer;
@property (nonatomic, assign, getter=isAnimating) BOOL animating;
@property (nonatomic, assign) BOOL strokeShow;
@end
@implementation ZFLoadingView
@synthesize lineColor = _lineColor;
@synthesize shapeLayer = _shapeLayer;
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self initialize];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self initialize];
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
[self initialize];
}
- (void)initialize {
[self.layer addSublayer:self.shapeLayer];
self.duration = 1;
self.lineWidth = 1;
self.lineColor = [UIColor whiteColor];
self.userInteractionEnabled = NO;
}
- (void)layoutSubviews {
[super layoutSubviews];
CGFloat width = MIN(self.bounds.size.width, self.bounds.size.height);
CGFloat height = width;
self.shapeLayer.frame = CGRectMake(0, 0, width, height);
CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
CGFloat radius = MIN(CGRectGetWidth(self.bounds) / 2, CGRectGetHeight(self.bounds) / 2) - self.shapeLayer.lineWidth / 2;
CGFloat startAngle = (CGFloat)(0);
CGFloat endAngle = (CGFloat)(2*M_PI);
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
self.shapeLayer.path = path.CGPath;
}
- (void)startAnimating {
if (self.animating) return;
self.animating = YES;
if (self.animType == ZFLoadingTypeFadeOut) [self fadeOutShow];
CABasicAnimation *rotationAnim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotationAnim.toValue = [NSNumber numberWithFloat:2 * M_PI];
rotationAnim.duration = self.duration;
rotationAnim.repeatCount = CGFLOAT_MAX;
rotationAnim.removedOnCompletion = NO;
[self.shapeLayer addAnimation:rotationAnim forKey:@"rotation"];
if (self.hidesWhenStopped) {
self.hidden = NO;
}
}
- (void)stopAnimating {
if (!self.animating) return;
self.animating = NO;
[self.shapeLayer removeAllAnimations];
if (self.hidesWhenStopped) {
self.hidden = YES;
}
}
- (void)fadeOutShow {
CABasicAnimation *headAnimation = [CABasicAnimation animation];
headAnimation.keyPath = @"strokeStart";
headAnimation.duration = self.duration / 1.5f;
headAnimation.fromValue = @(0.f);
headAnimation.toValue = @(0.25f);
CABasicAnimation *tailAnimation = [CABasicAnimation animation];
tailAnimation.keyPath = @"strokeEnd";
tailAnimation.duration = self.duration / 1.5f;
tailAnimation.fromValue = @(0.f);
tailAnimation.toValue = @(1.f);
CABasicAnimation *endHeadAnimation = [CABasicAnimation animation];
endHeadAnimation.keyPath = @"strokeStart";
endHeadAnimation.beginTime = self.duration / 1.5f;
endHeadAnimation.duration = self.duration / 3.0f;
endHeadAnimation.fromValue = @(0.25f);
endHeadAnimation.toValue = @(1.f);
CABasicAnimation *endTailAnimation = [CABasicAnimation animation];
endTailAnimation.keyPath = @"strokeEnd";
endTailAnimation.beginTime = self.duration / 1.5f;
endTailAnimation.duration = self.duration / 3.0f;
endTailAnimation.fromValue = @(1.f);
endTailAnimation.toValue = @(1.f);
CAAnimationGroup *animations = [CAAnimationGroup animation];
[animations setDuration:self.duration];
[animations setAnimations:@[headAnimation, tailAnimation, endHeadAnimation, endTailAnimation]];
animations.repeatCount = INFINITY;
animations.removedOnCompletion = NO;
[self.shapeLayer addAnimation:animations forKey:@"strokeAnim"];
if (self.hidesWhenStopped) {
self.hidden = NO;
}
}
#pragma mark - setter and getter
- (CAShapeLayer *)shapeLayer {
if (!_shapeLayer) {
_shapeLayer = [CAShapeLayer layer];
_shapeLayer.strokeColor = self.lineColor.CGColor;
_shapeLayer.fillColor = [UIColor clearColor].CGColor;
_shapeLayer.strokeStart = 0.1;
_shapeLayer.strokeEnd = 1;
_shapeLayer.lineCap = @"round";
_shapeLayer.anchorPoint = CGPointMake(0.5, 0.5);
}
return _shapeLayer;
}
- (UIColor *)lineColor {
if (!_lineColor) {
return [UIColor whiteColor];
}
return _lineColor;
}
- (void)setLineWidth:(CGFloat)lineWidth {
_lineWidth = lineWidth;
self.shapeLayer.lineWidth = lineWidth;
}
- (void)setLineColor:(UIColor *)lineColor {
if (!lineColor) return;
_lineColor = lineColor;
self.shapeLayer.strokeColor = lineColor.CGColor;
}
- (void)setHidesWhenStopped:(BOOL)hidesWhenStopped {
_hidesWhenStopped = hidesWhenStopped;
self.hidden = !self.isAnimating && hidesWhenStopped;
}
@end

View File

@@ -0,0 +1,39 @@
//
// ZFNetworkSpeedMonitor.h
// ZFPlayer
//
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
extern NSString *const ZFDownloadNetworkSpeedNotificationKey;
extern NSString *const ZFUploadNetworkSpeedNotificationKey;
extern NSString *const ZFNetworkSpeedNotificationKey;
@interface ZFNetworkSpeedMonitor : NSObject
@property (nonatomic, copy, readonly) NSString *downloadNetworkSpeed;
@property (nonatomic, copy, readonly) NSString *uploadNetworkSpeed;
- (void)startNetworkSpeedMonitor;
- (void)stopNetworkSpeedMonitor;
@end

View File

@@ -0,0 +1,167 @@
//
// ZFNetworkSpeedMonitor.m
// ZFPlayer
//
// Copyright (c) 2016 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "ZFNetworkSpeedMonitor.h"
#if __has_include(<ZFPlayer/ZFPlayerLogManager.h>)
#import <ZFPlayer/ZFPlayerLogManager.h>
#else
#import "ZFPlayerLogManager.h"
#endif
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <net/if_dl.h>
NSString *const ZFDownloadNetworkSpeedNotificationKey = @"ZFDownloadNetworkSpeedNotificationKey";
NSString *const ZFUploadNetworkSpeedNotificationKey = @"ZFUploadNetworkSpeedNotificationKey";
NSString *const ZFNetworkSpeedNotificationKey = @"ZFNetworkSpeedNotificationKey";
@interface ZFNetworkSpeedMonitor () {
//
uint32_t _iBytes;
uint32_t _oBytes;
uint32_t _allFlow;
// wifi
uint32_t _wifiIBytes;
uint32_t _wifiOBytes;
uint32_t _wifiFlow;
// 3G
uint32_t _wwanIBytes;
uint32_t _wwanOBytes;
uint32_t _wwanFlow;
}
@property (nonatomic, strong) NSTimer *timer;
@end
@implementation ZFNetworkSpeedMonitor
- (instancetype)init {
if (self = [super init]) {
_iBytes = _oBytes = _allFlow = _wifiIBytes = _wifiOBytes = _wifiFlow = _wwanIBytes = _wwanOBytes = _wwanFlow = 0;
}
return self;
}
//
- (void)startNetworkSpeedMonitor {
if (!_timer) {
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(checkNetworkSpeed) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
[_timer fire];
}
}
//
- (void)stopNetworkSpeedMonitor {
if ([_timer isValid]) {
[_timer invalidate];
_timer = nil;
}
}
- (NSString *)stringWithbytes:(int)bytes {
if (bytes < 1024) { // B
return [NSString stringWithFormat:@"%dB", bytes];
} else if (bytes >= 1024 && bytes < 1024 * 1024) { // KB
return [NSString stringWithFormat:@"%.0fKB", (double)bytes / 1024];
} else if (bytes >= 1024 * 1024 && bytes < 1024 * 1024 * 1024) { // MB
return [NSString stringWithFormat:@"%.1fMB", (double)bytes / (1024 * 1024)];
} else { // GB
return [NSString stringWithFormat:@"%.1fGB", (double)bytes / (1024 * 1024 * 1024)];
}
}
- (void)checkNetworkSpeed {
struct ifaddrs *ifa_list = 0, *ifa;
if (getifaddrs(&ifa_list) == -1) return;
uint32_t iBytes = 0;
uint32_t oBytes = 0;
uint32_t allFlow = 0;
uint32_t wifiIBytes = 0;
uint32_t wifiOBytes = 0;
uint32_t wifiFlow = 0;
uint32_t wwanIBytes = 0;
uint32_t wwanOBytes = 0;
uint32_t wwanFlow = 0;
for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
if (AF_LINK != ifa->ifa_addr->sa_family) continue;
if (!(ifa->ifa_flags & IFF_UP) && !(ifa->ifa_flags & IFF_RUNNING)) continue;
if (ifa->ifa_data == 0) continue;
// network
if (strncmp(ifa->ifa_name, "lo", 2)) {
struct if_data* if_data = (struct if_data*)ifa->ifa_data;
iBytes += if_data->ifi_ibytes;
oBytes += if_data->ifi_obytes;
allFlow = iBytes + oBytes;
}
//wifi
if (!strcmp(ifa->ifa_name, "en0")) {
struct if_data* if_data = (struct if_data*)ifa->ifa_data;
wifiIBytes += if_data->ifi_ibytes;
wifiOBytes += if_data->ifi_obytes;
wifiFlow = wifiIBytes + wifiOBytes;
}
//3G or gprs
if (!strcmp(ifa->ifa_name, "pdp_ip0")) {
struct if_data* if_data = (struct if_data*)ifa->ifa_data;
wwanIBytes += if_data->ifi_ibytes;
wwanOBytes += if_data->ifi_obytes;
wwanFlow = wwanIBytes + wwanOBytes;
}
}
freeifaddrs(ifa_list);
if (_iBytes != 0) {
_downloadNetworkSpeed = [[self stringWithbytes:iBytes - _iBytes] stringByAppendingString:@"/s"];
NSMutableDictionary *userInfo = @{}.mutableCopy;
userInfo[ZFNetworkSpeedNotificationKey] = _downloadNetworkSpeed;
[[NSNotificationCenter defaultCenter] postNotificationName:ZFDownloadNetworkSpeedNotificationKey object:nil userInfo:userInfo];
ZFPlayerLog(@"downloadNetworkSpeed : %@",_downloadNetworkSpeed);
}
_iBytes = iBytes;
if (_oBytes != 0) {
_uploadNetworkSpeed = [[self stringWithbytes:oBytes - _oBytes] stringByAppendingString:@"/s"];
NSMutableDictionary *userInfo = @{}.mutableCopy;
userInfo[ZFNetworkSpeedNotificationKey] = _uploadNetworkSpeed;
[[NSNotificationCenter defaultCenter] postNotificationName:ZFUploadNetworkSpeedNotificationKey object:nil userInfo:userInfo];
ZFPlayerLog(@"uploadNetworkSpeed :%@",_uploadNetworkSpeed);
}
_oBytes = oBytes;
}
@end

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 513 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 761 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 615 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -0,0 +1,151 @@
//
// ZFPlayerControlView.h
// ZFPlayer
//
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <UIKit/UIKit.h>
#import "ZFPortraitControlView.h"
#import "ZFLandScapeControlView.h"
#import "ZFSpeedLoadingView.h"
#import "ZFSmallFloatControlView.h"
#if __has_include(<ZFPlayer/ZFPlayerMediaControl.h>)
#import <ZFPlayer/ZFPlayerMediaControl.h>
#else
#import "ZFPlayerMediaControl.h"
#endif
@interface ZFPlayerControlView : UIView <ZFPlayerMediaControl>
/// 竖屏控制层的View
@property (nonatomic, strong, readonly) ZFPortraitControlView *portraitControlView;
/// 横屏控制层的View
@property (nonatomic, strong, readonly) ZFLandScapeControlView *landScapeControlView;
/// 加载loading
@property (nonatomic, strong, readonly) ZFSpeedLoadingView *activity;
/// 快进快退View
@property (nonatomic, strong, readonly) UIView *fastView;
/// 快进快退进度progress
@property (nonatomic, strong, readonly) ZFSliderView *fastProgressView;
/// 快进快退时间
@property (nonatomic, strong, readonly) UILabel *fastTimeLabel;
/// 快进快退ImageView
@property (nonatomic, strong, readonly) UIImageView *fastImageView;
/// 加载失败按钮
@property (nonatomic, strong, readonly) UIButton *failBtn;
/// 底部播放进度
@property (nonatomic, strong, readonly) ZFSliderView *bottomPgrogress;
/// 封面图
@property (nonatomic, strong, readonly) UIImageView *coverImageView;
/// 高斯模糊的背景图
@property (nonatomic, strong, readonly) UIImageView *bgImgView;
/// 高斯模糊视图
@property (nonatomic, strong, readonly) UIView *effectView;
/// 小窗口控制层
@property (nonatomic, strong, readonly) ZFSmallFloatControlView *floatControlView;
/// 快进视图是否显示动画默认NO.
@property (nonatomic, assign) BOOL fastViewAnimated;
/// 视频之外区域是否高斯模糊显示默认YES.
@property (nonatomic, assign) BOOL effectViewShow;
/// 如果是暂停状态seek完是否播放默认YES
@property (nonatomic, assign) BOOL seekToPlay;
/// 返回按钮点击回调
@property (nonatomic, copy) void(^backBtnClickCallback)(void);
/// 控制层显示或者隐藏
@property (nonatomic, readonly) BOOL controlViewAppeared;
/// 控制层显示或者隐藏的回调
@property (nonatomic, copy) void(^controlViewAppearedCallback)(BOOL appeared);
/// 控制层自动隐藏的时间默认2.5秒
@property (nonatomic, assign) NSTimeInterval autoHiddenTimeInterval;
/// 控制层显示、隐藏动画的时长默认0.25秒
@property (nonatomic, assign) NSTimeInterval autoFadeTimeInterval;
/// 横向滑动控制播放进度时是否显示控制层,默认 YES.
@property (nonatomic, assign) BOOL horizontalPanShowControlView;
/// prepare时候是否显示控制层,默认 NO.
@property (nonatomic, assign) BOOL prepareShowControlView;
/// prepare时候是否显示loading,默认 NO.
@property (nonatomic, assign) BOOL prepareShowLoading;
/// 是否自定义禁止pan手势默认 NO.
@property (nonatomic, assign) BOOL customDisablePanMovingDirection;
/// 全屏模式
@property (nonatomic, assign) ZFFullScreenMode fullScreenMode;
/**
设置标题、封面、全屏模式
@param title 视频的标题
@param coverUrl 视频的封面,占位图默认是灰色的
@param fullScreenMode 全屏模式
*/
- (void)showTitle:(NSString *)title coverURLString:(NSString *)coverUrl fullScreenMode:(ZFFullScreenMode)fullScreenMode;
/**
设置标题、封面、默认占位图、全屏模式
@param title 视频的标题
@param coverUrl 视频的封面
@param placeholder 指定封面的placeholder
@param fullScreenMode 全屏模式
*/
- (void)showTitle:(NSString *)title coverURLString:(NSString *)coverUrl placeholderImage:(UIImage *)placeholder fullScreenMode:(ZFFullScreenMode)fullScreenMode;
/**
设置标题、UIImage封面、全屏模式
@param title 视频的标题
@param image 视频的封面UIImage
@param fullScreenMode 全屏模式
*/
- (void)showTitle:(NSString *)title coverImage:(UIImage *)image fullScreenMode:(ZFFullScreenMode)fullScreenMode;
//- (void)showFullScreen
/**
重置控制层
*/
- (void)resetControlView;
@end

View File

@@ -0,0 +1,836 @@
//
// ZFPlayerControlView.m
// ZFPlayer
//
// Copyright (c) 2016 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "ZFPlayerControlView.h"
#import <AVKit/AVKit.h>
#import <AVFoundation/AVFoundation.h>
#import "UIView+ZFFrame.h"
#import "ZFSliderView.h"
#import "ZFUtilities.h"
#import "UIImageView+ZFCache.h"
#import <MediaPlayer/MediaPlayer.h>
#import "ZFVolumeBrightnessView.h"
#if __has_include(<ZFPlayer/ZFPlayer.h>)
#import <ZFPlayer/ZFPlayerConst.h>
#else
#import "ZFPlayerConst.h"
#endif
@interface ZFPlayerControlView () <ZFSliderViewDelegate>
/// View
@property (nonatomic, strong) ZFPortraitControlView *portraitControlView;
/// View
@property (nonatomic, strong) ZFLandScapeControlView *landScapeControlView;
/// loading
@property (nonatomic, strong) ZFSpeedLoadingView *activity;
/// 退View
@property (nonatomic, strong) UIView *fastView;
/// 退progress
@property (nonatomic, strong) ZFSliderView *fastProgressView;
/// 退
@property (nonatomic, strong) UILabel *fastTimeLabel;
/// 退ImageView
@property (nonatomic, strong) UIImageView *fastImageView;
///
@property (nonatomic, strong) UIButton *failBtn;
///
@property (nonatomic, strong) ZFSliderView *bottomPgrogress;
///
@property (nonatomic, assign, getter=isShowing) BOOL showing;
///
@property (nonatomic, assign, getter=isPlayEnd) BOOL playeEnd;
@property (nonatomic, assign) BOOL controlViewAppeared;
@property (nonatomic, assign) NSTimeInterval sumTime;
@property (nonatomic, strong) dispatch_block_t afterBlock;
@property (nonatomic, strong) ZFSmallFloatControlView *floatControlView;
@property (nonatomic, strong) ZFVolumeBrightnessView *volumeBrightnessView;
@property (nonatomic, strong) UIImageView *bgImgView;
@property (nonatomic, strong) UIView *effectView;
@end
@implementation ZFPlayerControlView
@synthesize player = _player;
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self addAllSubViews];
self.landScapeControlView.hidden = YES;
self.floatControlView.hidden = YES;
self.seekToPlay = YES;
self.effectViewShow = YES;
self.horizontalPanShowControlView = YES;
self.autoFadeTimeInterval = 0.25;
self.autoHiddenTimeInterval = 2.5;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(volumeChanged:)
name:@"AVSystemController_SystemVolumeDidChangeNotification"
object:nil];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
CGFloat min_x = 0;
CGFloat min_y = 0;
CGFloat min_w = 0;
CGFloat min_h = 0;
CGFloat min_view_w = self.zf_width;
CGFloat min_view_h = self.zf_height;
self.portraitControlView.frame = self.bounds;
self.landScapeControlView.frame = self.bounds;
self.floatControlView.frame = self.bounds;
self.coverImageView.frame = self.bounds;
self.bgImgView.frame = self.bounds;
self.effectView.frame = self.bounds;
min_w = 80;
min_h = 80;
self.activity.frame = CGRectMake(min_x, min_y, min_w, min_h);
self.activity.zf_centerX = self.zf_centerX;
self.activity.zf_centerY = self.zf_centerY + 10;
min_w = 150;
min_h = 30;
self.failBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
self.failBtn.center = self.center;
min_w = 140;
min_h = 80;
self.fastView.frame = CGRectMake(min_x, min_y, min_w, min_h);
self.fastView.center = self.center;
min_w = 32;
min_x = (self.fastView.zf_width - min_w) / 2;
min_y = 5;
min_h = 32;
self.fastImageView.frame = CGRectMake(min_x, min_y, min_w, min_h);
min_x = 0;
min_y = self.fastImageView.zf_bottom + 2;
min_w = self.fastView.zf_width;
min_h = 20;
self.fastTimeLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
min_x = 12;
min_y = self.fastTimeLabel.zf_bottom + 5;
min_w = self.fastView.zf_width - 2 * min_x;
min_h = 10;
self.fastProgressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
min_x = 0;
min_y = min_view_h - 1;
min_w = min_view_w;
min_h = 1;
self.bottomPgrogress.frame = CGRectMake(min_x, min_y, min_w, min_h);
min_x = 0;
min_y = iPhoneX ? 54 : 30;
min_w = 170;
min_h = 35;
self.volumeBrightnessView.frame = CGRectMake(min_x, min_y, min_w, min_h);
self.volumeBrightnessView.zf_centerX = self.zf_centerX;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];
[self cancelAutoFadeOutControlView];
}
///
- (void)addAllSubViews {
[self addSubview:self.portraitControlView];
[self addSubview:self.landScapeControlView];
[self addSubview:self.floatControlView];
[self addSubview:self.activity];
[self addSubview:self.failBtn];
[self addSubview:self.fastView];
[self.fastView addSubview:self.fastImageView];
[self.fastView addSubview:self.fastTimeLabel];
[self.fastView addSubview:self.fastProgressView];
[self addSubview:self.bottomPgrogress];
[self addSubview:self.volumeBrightnessView];
}
- (void)autoFadeOutControlView {
self.controlViewAppeared = YES;
[self cancelAutoFadeOutControlView];
@zf_weakify(self)
self.afterBlock = dispatch_block_create(0, ^{
@zf_strongify(self)
[self hideControlViewWithAnimated:YES];
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.autoHiddenTimeInterval * NSEC_PER_SEC)), dispatch_get_main_queue(),self.afterBlock);
}
/// controlView
- (void)cancelAutoFadeOutControlView {
if (self.afterBlock) {
dispatch_block_cancel(self.afterBlock);
self.afterBlock = nil;
}
}
///
- (void)hideControlViewWithAnimated:(BOOL)animated {
self.controlViewAppeared = NO;
if (self.controlViewAppearedCallback) {
self.controlViewAppearedCallback(NO);
}
[UIView animateWithDuration:animated ? self.autoFadeTimeInterval : 0 animations:^{
if (self.player.isFullScreen) {
[self.landScapeControlView hideControlView];
} else {
if (!self.player.isSmallFloatViewShow) {
[self.portraitControlView hideControlView];
}
}
} completion:^(BOOL finished) {
self.bottomPgrogress.hidden = NO;
}];
}
///
- (void)showControlViewWithAnimated:(BOOL)animated {
self.controlViewAppeared = YES;
if (self.controlViewAppearedCallback) {
self.controlViewAppearedCallback(YES);
}
[self autoFadeOutControlView];
[UIView animateWithDuration:animated ? self.autoFadeTimeInterval : 0 animations:^{
if (self.player.isFullScreen) {
[self.landScapeControlView showControlView];
} else {
if (!self.player.isSmallFloatViewShow) {
[self.portraitControlView showControlView];
}
}
} completion:^(BOOL finished) {
self.bottomPgrogress.hidden = YES;
}];
}
///
- (void)volumeChanged:(NSNotification *)notification {
NSDictionary *userInfo = notification.userInfo;
NSString *reasonstr = userInfo[@"AVSystemController_AudioVolumeChangeReasonNotificationParameter"];
if ([reasonstr isEqualToString:@"ExplicitVolumeChange"]) {
float volume = [ userInfo[@"AVSystemController_AudioVolumeNotificationParameter"] floatValue];
if (self.player.isFullScreen) {
[self.volumeBrightnessView updateProgress:volume withVolumeBrightnessType:ZFVolumeBrightnessTypeVolume];
} else {
[self.volumeBrightnessView addSystemVolumeView];
}
}
}
#pragma mark - Public Method
///
- (void)resetControlView {
[self.portraitControlView resetControlView];
[self.landScapeControlView resetControlView];
[self cancelAutoFadeOutControlView];
self.bottomPgrogress.value = 0;
self.bottomPgrogress.bufferValue = 0;
self.floatControlView.hidden = YES;
self.failBtn.hidden = YES;
self.volumeBrightnessView.hidden = YES;
self.portraitControlView.hidden = self.player.isFullScreen;
self.landScapeControlView.hidden = !self.player.isFullScreen;
if (self.controlViewAppeared) {
[self showControlViewWithAnimated:NO];
} else {
[self hideControlViewWithAnimated:NO];
}
}
///
- (void)showTitle:(NSString *)title coverURLString:(NSString *)coverUrl fullScreenMode:(ZFFullScreenMode)fullScreenMode {
UIImage *placeholder = [ZFUtilities imageWithColor:[UIColor colorWithRed:220/255.0 green:220/255.0 blue:220/255.0 alpha:1] size:self.bgImgView.bounds.size];
[self showTitle:title coverURLString:coverUrl placeholderImage:placeholder fullScreenMode:fullScreenMode];
}
///
- (void)showTitle:(NSString *)title coverURLString:(NSString *)coverUrl placeholderImage:(UIImage *)placeholder fullScreenMode:(ZFFullScreenMode)fullScreenMode {
[self resetControlView];
[self layoutIfNeeded];
[self setNeedsDisplay];
[self.portraitControlView showTitle:title fullScreenMode:fullScreenMode];
[self.landScapeControlView showTitle:title fullScreenMode:fullScreenMode];
/// coverImageView
[self.player.currentPlayerManager.view.coverImageView setImageWithURLString:coverUrl placeholder:placeholder];
[self.bgImgView setImageWithURLString:coverUrl placeholder:placeholder];
if (self.prepareShowControlView) {
[self showControlViewWithAnimated:NO];
} else {
[self hideControlViewWithAnimated:NO];
}
}
/// UIImage
- (void)showTitle:(NSString *)title coverImage:(UIImage *)image fullScreenMode:(ZFFullScreenMode)fullScreenMode {
[self resetControlView];
[self layoutIfNeeded];
[self setNeedsDisplay];
[self.portraitControlView showTitle:title fullScreenMode:fullScreenMode];
[self.landScapeControlView showTitle:title fullScreenMode:fullScreenMode];
self.coverImageView.image = image;
self.bgImgView.image = image;
if (self.prepareShowControlView) {
[self showControlViewWithAnimated:NO];
} else {
[self hideControlViewWithAnimated:NO];
}
}
#pragma mark - ZFPlayerControlViewDelegate
/// NO
- (BOOL)gestureTriggerCondition:(ZFPlayerGestureControl *)gestureControl gestureType:(ZFPlayerGestureType)gestureType gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer touch:(nonnull UITouch *)touch {
CGPoint point = [touch locationInView:self];
if (self.player.isSmallFloatViewShow && !self.player.isFullScreen && gestureType != ZFPlayerGestureTypeSingleTap) {
return NO;
}
if (self.player.isFullScreen) {
if (!self.customDisablePanMovingDirection) {
///
self.player.disablePanMovingDirection = ZFPlayerDisablePanMovingDirectionNone;
}
return [self.landScapeControlView shouldResponseGestureWithPoint:point withGestureType:gestureType touch:touch];
} else {
if (!self.customDisablePanMovingDirection) {
if (self.player.scrollView) { ///
self.player.disablePanMovingDirection = ZFPlayerDisablePanMovingDirectionVertical;
} else { ///
self.player.disablePanMovingDirection = ZFPlayerDisablePanMovingDirectionNone;
}
}
return [self.portraitControlView shouldResponseGestureWithPoint:point withGestureType:gestureType touch:touch];
}
}
///
- (void)gestureSingleTapped:(ZFPlayerGestureControl *)gestureControl {
if (!self.player) return;
if (self.player.isSmallFloatViewShow && !self.player.isFullScreen) {
[self.player enterFullScreen:YES animated:YES];
} else {
if (self.controlViewAppeared) {
[self hideControlViewWithAnimated:YES];
} else {
///
[self hideControlViewWithAnimated:NO];
[self showControlViewWithAnimated:YES];
}
}
}
///
- (void)gestureDoubleTapped:(ZFPlayerGestureControl *)gestureControl {
if (self.player.isFullScreen) {
[self.landScapeControlView playOrPause];
} else {
[self.portraitControlView playOrPause];
}
}
///
- (void)gestureBeganPan:(ZFPlayerGestureControl *)gestureControl panDirection:(ZFPanDirection)direction panLocation:(ZFPanLocation)location {
if (direction == ZFPanDirectionH) {
self.sumTime = self.player.currentTime;
}
}
///
- (void)gestureChangedPan:(ZFPlayerGestureControl *)gestureControl panDirection:(ZFPanDirection)direction panLocation:(ZFPanLocation)location withVelocity:(CGPoint)velocity {
if (direction == ZFPanDirectionH) {
//
self.sumTime += velocity.x / 200;
// sumTime
NSTimeInterval totalMovieDuration = self.player.totalTime;
if (totalMovieDuration == 0) return;
if (self.sumTime > totalMovieDuration) self.sumTime = totalMovieDuration;
if (self.sumTime < 0) self.sumTime = 0;
BOOL style = NO;
if (velocity.x > 0) style = YES;
if (velocity.x < 0) style = NO;
if (velocity.x == 0) return;
[self sliderValueChangingValue:self.sumTime/totalMovieDuration isForward:style];
} else if (direction == ZFPanDirectionV) {
if (location == ZFPanLocationLeft) { ///
self.player.brightness -= (velocity.y) / 10000;
[self.volumeBrightnessView updateProgress:self.player.brightness withVolumeBrightnessType:ZFVolumeBrightnessTypeumeBrightness];
} else if (location == ZFPanLocationRight) { ///
self.player.volume -= (velocity.y) / 10000;
if (self.player.isFullScreen) {
[self.volumeBrightnessView updateProgress:self.player.volume withVolumeBrightnessType:ZFVolumeBrightnessTypeVolume];
}
}
}
}
///
- (void)gestureEndedPan:(ZFPlayerGestureControl *)gestureControl panDirection:(ZFPanDirection)direction panLocation:(ZFPanLocation)location {
@zf_weakify(self)
if (direction == ZFPanDirectionH && self.sumTime >= 0 && self.player.totalTime > 0) {
[self.player seekToTime:self.sumTime completionHandler:^(BOOL finished) {
if (finished) {
@zf_strongify(self)
///
[self.portraitControlView sliderChangeEnded];
[self.landScapeControlView sliderChangeEnded];
self.bottomPgrogress.isdragging = NO;
if (self.controlViewAppeared) {
[self autoFadeOutControlView];
}
}
}];
if (self.seekToPlay) {
[self.player.currentPlayerManager play];
}
self.sumTime = 0;
}
}
///
- (void)gesturePinched:(ZFPlayerGestureControl *)gestureControl scale:(float)scale {
if (scale > 1) {
self.player.currentPlayerManager.scalingMode = ZFPlayerScalingModeAspectFill;
} else {
self.player.currentPlayerManager.scalingMode = ZFPlayerScalingModeAspectFit;
}
}
///
- (void)videoPlayer:(ZFPlayerController *)videoPlayer prepareToPlay:(NSURL *)assetURL {
[self hideControlViewWithAnimated:NO];
}
///
- (void)videoPlayer:(ZFPlayerController *)videoPlayer playStateChanged:(ZFPlayerPlaybackState)state {
if (state == ZFPlayerPlayStatePlaying) {
[self.portraitControlView playBtnSelectedState:YES];
[self.landScapeControlView playBtnSelectedState:YES];
self.failBtn.hidden = YES;
/// loading
if (videoPlayer.currentPlayerManager.loadState == ZFPlayerLoadStateStalled && !self.prepareShowLoading) {
[self.activity startAnimating];
} else if ((videoPlayer.currentPlayerManager.loadState == ZFPlayerLoadStateStalled || videoPlayer.currentPlayerManager.loadState == ZFPlayerLoadStatePrepare) && self.prepareShowLoading) {
[self.activity startAnimating];
}
} else if (state == ZFPlayerPlayStatePaused) {
[self.portraitControlView playBtnSelectedState:NO];
[self.landScapeControlView playBtnSelectedState:NO];
/// loading
[self.activity stopAnimating];
self.failBtn.hidden = YES;
} else if (state == ZFPlayerPlayStatePlayFailed) {
self.failBtn.hidden = NO;
[self.activity stopAnimating];
}
}
///
- (void)videoPlayer:(ZFPlayerController *)videoPlayer loadStateChanged:(ZFPlayerLoadState)state {
if (state == ZFPlayerLoadStatePrepare) {
self.coverImageView.hidden = NO;
[self.portraitControlView playBtnSelectedState:videoPlayer.currentPlayerManager.shouldAutoPlay];
[self.landScapeControlView playBtnSelectedState:videoPlayer.currentPlayerManager.shouldAutoPlay];
} else if (state == ZFPlayerLoadStatePlaythroughOK || state == ZFPlayerLoadStatePlayable) {
self.coverImageView.hidden = YES;
if (self.effectViewShow) {
self.effectView.hidden = NO;
} else {
self.effectView.hidden = YES;
self.player.currentPlayerManager.view.backgroundColor = [UIColor blackColor];
}
}
if (state == ZFPlayerLoadStateStalled && videoPlayer.currentPlayerManager.isPlaying && !self.prepareShowLoading) {
[self.activity startAnimating];
} else if ((state == ZFPlayerLoadStateStalled || state == ZFPlayerLoadStatePrepare) && videoPlayer.currentPlayerManager.isPlaying && self.prepareShowLoading) {
[self.activity startAnimating];
} else {
[self.activity stopAnimating];
}
}
///
- (void)videoPlayer:(ZFPlayerController *)videoPlayer currentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime {
[self.portraitControlView videoPlayer:videoPlayer currentTime:currentTime totalTime:totalTime];
[self.landScapeControlView videoPlayer:videoPlayer currentTime:currentTime totalTime:totalTime];
if (!self.bottomPgrogress.isdragging) {
self.bottomPgrogress.value = videoPlayer.progress;
}
}
///
- (void)videoPlayer:(ZFPlayerController *)videoPlayer bufferTime:(NSTimeInterval)bufferTime {
[self.portraitControlView videoPlayer:videoPlayer bufferTime:bufferTime];
[self.landScapeControlView videoPlayer:videoPlayer bufferTime:bufferTime];
self.bottomPgrogress.bufferValue = videoPlayer.bufferProgress;
}
- (void)videoPlayer:(ZFPlayerController *)videoPlayer presentationSizeChanged:(CGSize)size {
[self.landScapeControlView videoPlayer:videoPlayer presentationSizeChanged:size];
}
/// view
- (void)videoPlayer:(ZFPlayerController *)videoPlayer orientationWillChange:(ZFOrientationObserver *)observer {
self.portraitControlView.hidden = observer.isFullScreen;
self.landScapeControlView.hidden = !observer.isFullScreen;
if (videoPlayer.isSmallFloatViewShow) {
self.floatControlView.hidden = observer.isFullScreen;
self.portraitControlView.hidden = YES;
if (observer.isFullScreen) {
self.controlViewAppeared = NO;
[self cancelAutoFadeOutControlView];
}
}
if (self.controlViewAppeared) {
[self showControlViewWithAnimated:NO];
} else {
[self hideControlViewWithAnimated:NO];
}
if (observer.isFullScreen) {
[self.volumeBrightnessView removeSystemVolumeView];
} else {
[self.volumeBrightnessView addSystemVolumeView];
}
}
/// view
- (void)videoPlayer:(ZFPlayerController *)videoPlayer orientationDidChanged:(ZFOrientationObserver *)observer {
if (self.controlViewAppeared) {
[self showControlViewWithAnimated:NO];
} else {
[self hideControlViewWithAnimated:NO];
}
}
///
- (void)lockedVideoPlayer:(ZFPlayerController *)videoPlayer lockedScreen:(BOOL)locked {
[self showControlViewWithAnimated:YES];
}
/// view
- (void)playerDidAppearInScrollView:(ZFPlayerController *)videoPlayer {
if (!self.player.stopWhileNotVisible && !videoPlayer.isFullScreen) {
self.floatControlView.hidden = YES;
self.portraitControlView.hidden = NO;
}
}
/// view
- (void)playerDidDisappearInScrollView:(ZFPlayerController *)videoPlayer {
if (!self.player.stopWhileNotVisible && !videoPlayer.isFullScreen) {
self.floatControlView.hidden = NO;
self.portraitControlView.hidden = YES;
}
}
- (void)videoPlayer:(ZFPlayerController *)videoPlayer floatViewShow:(BOOL)show {
self.floatControlView.hidden = !show;
self.portraitControlView.hidden = show;
}
#pragma mark - Private Method
- (void)sliderValueChangingValue:(CGFloat)value isForward:(BOOL)forward {
if (self.horizontalPanShowControlView) {
///
[self showControlViewWithAnimated:NO];
[self cancelAutoFadeOutControlView];
}
self.fastProgressView.value = value;
self.fastView.hidden = NO;
self.fastView.alpha = 1;
if (forward) {
self.fastImageView.image = ZFPlayer_Image(@"ZFPlayer_fast_forward");
} else {
self.fastImageView.image = ZFPlayer_Image(@"ZFPlayer_fast_backward");
}
NSString *draggedTime = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
NSString *totalTime = [ZFUtilities convertTimeSecond:self.player.totalTime];
self.fastTimeLabel.text = [NSString stringWithFormat:@"%@ / %@",draggedTime,totalTime];
///
[self.portraitControlView sliderValueChanged:value currentTimeString:draggedTime];
[self.landScapeControlView sliderValueChanged:value currentTimeString:draggedTime];
self.bottomPgrogress.isdragging = YES;
self.bottomPgrogress.value = value;
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideFastView) object:nil];
[self performSelector:@selector(hideFastView) withObject:nil afterDelay:0.1];
if (self.fastViewAnimated) {
[UIView animateWithDuration:0.4 animations:^{
self.fastView.transform = CGAffineTransformMakeTranslation(forward?8:-8, 0);
}];
}
}
///
- (void)hideFastView {
[UIView animateWithDuration:0.4 animations:^{
self.fastView.transform = CGAffineTransformIdentity;
self.fastView.alpha = 0;
} completion:^(BOOL finished) {
self.fastView.hidden = YES;
}];
}
///
- (void)failBtnClick:(UIButton *)sender {
[self.player.currentPlayerManager reloadPlayer];
}
#pragma mark - setter
- (void)setPlayer:(ZFPlayerController *)player {
_player = player;
self.landScapeControlView.player = player;
self.portraitControlView.player = player;
///
[player.currentPlayerManager.view insertSubview:self.bgImgView atIndex:0];
[self.bgImgView addSubview:self.effectView];
self.bgImgView.frame = player.currentPlayerManager.view.bounds;
self.bgImgView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.effectView.frame = self.bgImgView.bounds;
}
- (void)setSeekToPlay:(BOOL)seekToPlay {
_seekToPlay = seekToPlay;
self.portraitControlView.seekToPlay = seekToPlay;
self.landScapeControlView.seekToPlay = seekToPlay;
}
- (void)setEffectViewShow:(BOOL)effectViewShow {
_effectViewShow = effectViewShow;
if (effectViewShow) {
self.bgImgView.hidden = NO;
} else {
self.bgImgView.hidden = YES;
}
}
- (void)setFullScreenMode:(ZFFullScreenMode)fullScreenMode {
_fullScreenMode = fullScreenMode;
self.portraitControlView.fullScreenMode = fullScreenMode;
self.landScapeControlView.fullScreenMode = fullScreenMode;
self.player.orientationObserver.fullScreenMode = fullScreenMode;
}
#pragma mark - getter
- (UIImageView *)bgImgView {
if (!_bgImgView) {
_bgImgView = [[UIImageView alloc] init];
_bgImgView.userInteractionEnabled = YES;
}
return _bgImgView;
}
- (UIView *)effectView {
if (!_effectView) {
if (@available(iOS 8.0, *)) {
UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
_effectView = [[UIVisualEffectView alloc] initWithEffect:effect];
} else {
UIToolbar *effectView = [[UIToolbar alloc] init];
effectView.barStyle = UIBarStyleBlackTranslucent;
_effectView = effectView;
}
}
return _effectView;
}
- (ZFPortraitControlView *)portraitControlView {
if (!_portraitControlView) {
@zf_weakify(self)
_portraitControlView = [[ZFPortraitControlView alloc] init];
_portraitControlView.sliderValueChanging = ^(CGFloat value, BOOL forward) {
@zf_strongify(self)
NSString *draggedTime = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
///
[self.landScapeControlView sliderValueChanged:value currentTimeString:draggedTime];
self.fastProgressView.value = value;
self.bottomPgrogress.isdragging = YES;
self.bottomPgrogress.value = value;
[self cancelAutoFadeOutControlView];
};
_portraitControlView.sliderValueChanged = ^(CGFloat value) {
@zf_strongify(self)
[self.landScapeControlView sliderChangeEnded];
self.fastProgressView.value = value;
self.bottomPgrogress.isdragging = NO;
self.bottomPgrogress.value = value;
[self autoFadeOutControlView];
};
}
return _portraitControlView;
}
- (ZFLandScapeControlView *)landScapeControlView {
if (!_landScapeControlView) {
@zf_weakify(self)
_landScapeControlView = [[ZFLandScapeControlView alloc] init];
_landScapeControlView.sliderValueChanging = ^(CGFloat value, BOOL forward) {
@zf_strongify(self)
NSString *draggedTime = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
///
[self.portraitControlView sliderValueChanged:value currentTimeString:draggedTime];
self.fastProgressView.value = value;
self.bottomPgrogress.isdragging = YES;
self.bottomPgrogress.value = value;
[self cancelAutoFadeOutControlView];
};
_landScapeControlView.sliderValueChanged = ^(CGFloat value) {
@zf_strongify(self)
[self.portraitControlView sliderChangeEnded];
self.fastProgressView.value = value;
self.bottomPgrogress.isdragging = NO;
self.bottomPgrogress.value = value;
[self autoFadeOutControlView];
};
}
return _landScapeControlView;
}
- (ZFSpeedLoadingView *)activity {
if (!_activity) {
_activity = [[ZFSpeedLoadingView alloc] init];
}
return _activity;
}
- (UIView *)fastView {
if (!_fastView) {
_fastView = [[UIView alloc] init];
_fastView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
_fastView.layer.cornerRadius = 4;
_fastView.layer.masksToBounds = YES;
_fastView.hidden = YES;
}
return _fastView;
}
- (UIImageView *)fastImageView {
if (!_fastImageView) {
_fastImageView = [[UIImageView alloc] init];
}
return _fastImageView;
}
- (UILabel *)fastTimeLabel {
if (!_fastTimeLabel) {
_fastTimeLabel = [[UILabel alloc] init];
_fastTimeLabel.textColor = [UIColor whiteColor];
_fastTimeLabel.textAlignment = NSTextAlignmentCenter;
_fastTimeLabel.font = [UIFont systemFontOfSize:14.0];
_fastTimeLabel.adjustsFontSizeToFitWidth = YES;
}
return _fastTimeLabel;
}
- (ZFSliderView *)fastProgressView {
if (!_fastProgressView) {
_fastProgressView = [[ZFSliderView alloc] init];
_fastProgressView.maximumTrackTintColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.4];
_fastProgressView.minimumTrackTintColor = [UIColor whiteColor];
_fastProgressView.sliderHeight = 2;
_fastProgressView.isHideSliderBlock = NO;
}
return _fastProgressView;
}
- (UIButton *)failBtn {
if (!_failBtn) {
_failBtn = [UIButton buttonWithType:UIButtonTypeSystem];
[_failBtn setTitle:@"加载失败,点击重试" forState:UIControlStateNormal];
[_failBtn addTarget:self action:@selector(failBtnClick:) forControlEvents:UIControlEventTouchUpInside];
[_failBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
_failBtn.titleLabel.font = [UIFont systemFontOfSize:14.0];
_failBtn.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
_failBtn.hidden = YES;
}
return _failBtn;
}
- (ZFSliderView *)bottomPgrogress {
if (!_bottomPgrogress) {
_bottomPgrogress = [[ZFSliderView alloc] init];
_bottomPgrogress.maximumTrackTintColor = [UIColor clearColor];
_bottomPgrogress.minimumTrackTintColor = [UIColor whiteColor];
_bottomPgrogress.bufferTrackTintColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.5];
_bottomPgrogress.sliderHeight = 1;
_bottomPgrogress.isHideSliderBlock = NO;
}
return _bottomPgrogress;
}
- (ZFSmallFloatControlView *)floatControlView {
if (!_floatControlView) {
_floatControlView = [[ZFSmallFloatControlView alloc] init];
@zf_weakify(self)
_floatControlView.closeClickCallback = ^{
@zf_strongify(self)
if (self.player.containerType == ZFPlayerContainerTypeCell) {
[self.player stopCurrentPlayingCell];
} else if (self.player.containerType == ZFPlayerContainerTypeView) {
[self.player stopCurrentPlayingView];
}
[self resetControlView];
};
}
return _floatControlView;
}
- (ZFVolumeBrightnessView *)volumeBrightnessView {
if (!_volumeBrightnessView) {
_volumeBrightnessView = [[ZFVolumeBrightnessView alloc] init];
_volumeBrightnessView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.7];
_volumeBrightnessView.hidden = YES;
}
return _volumeBrightnessView;
}
- (void)setBackBtnClickCallback:(void (^)(void))backBtnClickCallback {
_backBtnClickCallback = [backBtnClickCallback copy];
self.landScapeControlView.backBtnClickCallback = _backBtnClickCallback;
}
@end

View File

@@ -0,0 +1,111 @@
//
// ZFPortraitControlView.h
// ZFPlayer
//
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <UIKit/UIKit.h>
#import "ZFSliderView.h"
#if __has_include(<ZFPlayer/ZFPlayerController.h>)
#import <ZFPlayer/ZFPlayerController.h>
#else
#import "ZFPlayerController.h"
#endif
NS_ASSUME_NONNULL_BEGIN
@interface ZFPortraitControlView : UIView
/// 底部工具栏
@property (nonatomic, strong, readonly) UIView *bottomToolView;
/// 顶部工具栏
@property (nonatomic, strong, readonly) UIView *topToolView;
/// 标题
@property (nonatomic, strong, readonly) UILabel *titleLabel;
/// 播放或暂停按钮
@property (nonatomic, strong, readonly) UIButton *playOrPauseBtn;
/// 播放的当前时间
@property (nonatomic, strong, readonly) UILabel *currentTimeLabel;
/// 滑杆
@property (nonatomic, strong, readonly) ZFSliderView *slider;
/// 视频总时间
@property (nonatomic, strong, readonly) UILabel *totalTimeLabel;
/// 全屏按钮
@property (nonatomic, strong, readonly) UIButton *fullScreenBtn;
/// 播放器
@property (nonatomic, weak) ZFPlayerController *player;
/// slider滑动中
@property (nonatomic, copy, nullable) void(^sliderValueChanging)(CGFloat value,BOOL forward);
/// slider滑动结束
@property (nonatomic, copy, nullable) void(^sliderValueChanged)(CGFloat value);
/// 如果是暂停状态seek完是否播放默认YES
@property (nonatomic, assign) BOOL seekToPlay;
/// 全屏模式
@property (nonatomic, assign) ZFFullScreenMode fullScreenMode;
/// 重置控制层
- (void)resetControlView;
/// 显示控制层
- (void)showControlView;
/// 隐藏控制层
- (void)hideControlView;
/// 设置播放时间
- (void)videoPlayer:(ZFPlayerController *)videoPlayer currentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime;
/// 设置缓冲时间
- (void)videoPlayer:(ZFPlayerController *)videoPlayer bufferTime:(NSTimeInterval)bufferTime;
/// 是否响应该手势
- (BOOL)shouldResponseGestureWithPoint:(CGPoint)point withGestureType:(ZFPlayerGestureType)type touch:(nonnull UITouch *)touch;
/// 标题和全屏模式
- (void)showTitle:(NSString *_Nullable)title fullScreenMode:(ZFFullScreenMode)fullScreenMode;
/// 根据当前播放状态取反
- (void)playOrPause;
/// 播放按钮状态
- (void)playBtnSelectedState:(BOOL)selected;
/// 调节播放进度slider和当前时间更新
- (void)sliderValueChanged:(CGFloat)value currentTimeString:(NSString *)timeString;
/// 滑杆结束滑动
- (void)sliderChangeEnded;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,387 @@
//
// ZFPortraitControlView.m
// ZFPlayer
//
// Copyright (c) 2016 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "ZFPortraitControlView.h"
#import "UIView+ZFFrame.h"
#import "ZFUtilities.h"
#if __has_include(<ZFPlayer/ZFPlayer.h>)
#import <ZFPlayer/ZFPlayerConst.h>
#else
#import "ZFPlayerConst.h"
#endif
@interface ZFPortraitControlView () <ZFSliderViewDelegate>
///
@property (nonatomic, strong) UIView *bottomToolView;
///
@property (nonatomic, strong) UIView *topToolView;
///
@property (nonatomic, strong) UILabel *titleLabel;
///
@property (nonatomic, strong) UIButton *playOrPauseBtn;
///
@property (nonatomic, strong) UILabel *currentTimeLabel;
///
@property (nonatomic, strong) ZFSliderView *slider;
///
@property (nonatomic, strong) UILabel *totalTimeLabel;
///
@property (nonatomic, strong) UIButton *fullScreenBtn;
@property (nonatomic, assign) BOOL isShow;
@end
@implementation ZFPortraitControlView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
//
[self addSubview:self.topToolView];
[self addSubview:self.bottomToolView];
[self addSubview:self.playOrPauseBtn];
[self.topToolView addSubview:self.titleLabel];
[self.bottomToolView addSubview:self.currentTimeLabel];
[self.bottomToolView addSubview:self.slider];
[self.bottomToolView addSubview:self.totalTimeLabel];
[self.bottomToolView addSubview:self.fullScreenBtn];
//
[self makeSubViewsAction];
[self resetControlView];
self.clipsToBounds = YES;
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
CGFloat min_x = 0;
CGFloat min_y = 0;
CGFloat min_w = 0;
CGFloat min_h = 0;
CGFloat min_view_w = self.bounds.size.width;
CGFloat min_view_h = self.bounds.size.height;
CGFloat min_margin = 9;
min_x = 0;
min_y = 0;
min_w = min_view_w;
min_h = 40;
self.topToolView.frame = CGRectMake(min_x, min_y, min_w, min_h);
min_x = 15;
min_y = 5;
min_w = min_view_w - min_x - 15;
min_h = 30;
self.titleLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
min_h = 40;
min_x = 0;
min_y = min_view_h - min_h;
min_w = min_view_w;
self.bottomToolView.frame = CGRectMake(min_x, min_y, min_w, min_h);
min_x = 0;
min_y = 0;
min_w = 44;
min_h = min_w;
self.playOrPauseBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
self.playOrPauseBtn.center = self.center;
min_x = min_margin;
min_w = 62;
min_h = 28;
min_y = (self.bottomToolView.zf_height - min_h)/2;
self.currentTimeLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
min_w = 28;
min_h = min_w;
min_x = self.bottomToolView.zf_width - min_w - min_margin;
min_y = 0;
self.fullScreenBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
self.fullScreenBtn.zf_centerY = self.currentTimeLabel.zf_centerY;
min_w = 62;
min_h = 28;
min_x = self.fullScreenBtn.zf_left - min_w - 4;
min_y = 0;
self.totalTimeLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
self.totalTimeLabel.zf_centerY = self.currentTimeLabel.zf_centerY;
min_x = self.currentTimeLabel.zf_right + 4;
min_y = 0;
min_w = self.totalTimeLabel.zf_left - min_x - 4;
min_h = 30;
self.slider.frame = CGRectMake(min_x, min_y, min_w, min_h);
self.slider.zf_centerY = self.currentTimeLabel.zf_centerY;
if (!self.isShow) {
self.topToolView.zf_y = -self.topToolView.zf_height;
self.bottomToolView.zf_y = self.zf_height;
self.playOrPauseBtn.alpha = 0;
} else {
self.topToolView.zf_y = 0;
self.bottomToolView.zf_y = self.zf_height - self.bottomToolView.zf_height;
self.playOrPauseBtn.alpha = 1;
}
}
- (void)makeSubViewsAction {
[self.playOrPauseBtn addTarget:self action:@selector(playPauseButtonClickAction:) forControlEvents:UIControlEventTouchUpInside];
[self.fullScreenBtn addTarget:self action:@selector(fullScreenButtonClickAction:) forControlEvents:UIControlEventTouchUpInside];
}
#pragma mark - action
- (void)playPauseButtonClickAction:(UIButton *)sender {
[self playOrPause];
}
- (void)fullScreenButtonClickAction:(UIButton *)sender {
[self.player enterFullScreen:YES animated:YES];
}
///
- (void)playOrPause {
self.playOrPauseBtn.selected = !self.playOrPauseBtn.isSelected;
self.playOrPauseBtn.isSelected? [self.player.currentPlayerManager play]: [self.player.currentPlayerManager pause];
}
- (void)playBtnSelectedState:(BOOL)selected {
self.playOrPauseBtn.selected = selected;
}
#pragma mark - ZFSliderViewDelegate
- (void)sliderTouchBegan:(float)value {
self.slider.isdragging = YES;
}
- (void)sliderTouchEnded:(float)value {
if (self.player.totalTime > 0) {
self.slider.isdragging = YES;
if (self.sliderValueChanging) self.sliderValueChanging(value, self.slider.isForward);
@zf_weakify(self)
[self.player seekToTime:self.player.totalTime*value completionHandler:^(BOOL finished) {
@zf_strongify(self)
if (finished) {
self.slider.isdragging = NO;
if (self.sliderValueChanged) self.sliderValueChanged(value);
}
}];
if (self.seekToPlay) {
[self.player.currentPlayerManager play];
}
} else {
self.slider.isdragging = NO;
self.slider.value = 0;
}
}
- (void)sliderValueChanged:(float)value {
if (self.player.totalTime == 0) {
self.slider.value = 0;
return;
}
self.slider.isdragging = YES;
NSString *currentTimeString = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
self.currentTimeLabel.text = currentTimeString;
if (self.sliderValueChanging) self.sliderValueChanging(value,self.slider.isForward);
}
- (void)sliderTapped:(float)value {
[self sliderTouchEnded:value];
NSString *currentTimeString = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
self.currentTimeLabel.text = currentTimeString;
}
#pragma mark - public method
/** ControlView */
- (void)resetControlView {
self.bottomToolView.alpha = 1;
self.slider.value = 0;
self.slider.bufferValue = 0;
self.currentTimeLabel.text = @"00:00";
self.totalTimeLabel.text = @"00:00";
self.backgroundColor = [UIColor clearColor];
self.playOrPauseBtn.selected = YES;
self.titleLabel.text = @"";
}
- (void)showControlView {
self.topToolView.alpha = 1;
self.bottomToolView.alpha = 1;
self.isShow = YES;
self.topToolView.zf_y = 0;
self.bottomToolView.zf_y = self.zf_height - self.bottomToolView.zf_height;
self.playOrPauseBtn.alpha = 1;
self.player.statusBarHidden = NO;
}
- (void)hideControlView {
self.isShow = NO;
self.topToolView.zf_y = -self.topToolView.zf_height;
self.bottomToolView.zf_y = self.zf_height;
self.player.statusBarHidden = NO;
self.playOrPauseBtn.alpha = 0;
self.topToolView.alpha = 0;
self.bottomToolView.alpha = 0;
}
- (BOOL)shouldResponseGestureWithPoint:(CGPoint)point withGestureType:(ZFPlayerGestureType)type touch:(nonnull UITouch *)touch {
CGRect sliderRect = [self.bottomToolView convertRect:self.slider.frame toView:self];
if (CGRectContainsPoint(sliderRect, point)) {
return NO;
}
return YES;
}
- (void)videoPlayer:(ZFPlayerController *)videoPlayer currentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime {
if (!self.slider.isdragging) {
NSString *currentTimeString = [ZFUtilities convertTimeSecond:currentTime];
self.currentTimeLabel.text = currentTimeString;
NSString *totalTimeString = [ZFUtilities convertTimeSecond:totalTime];
self.totalTimeLabel.text = totalTimeString;
self.slider.value = videoPlayer.progress;
}
}
- (void)videoPlayer:(ZFPlayerController *)videoPlayer bufferTime:(NSTimeInterval)bufferTime {
self.slider.bufferValue = videoPlayer.bufferProgress;
}
- (void)showTitle:(NSString *)title fullScreenMode:(ZFFullScreenMode)fullScreenMode {
self.titleLabel.text = title;
self.player.orientationObserver.fullScreenMode = fullScreenMode;
}
/// slider
- (void)sliderValueChanged:(CGFloat)value currentTimeString:(NSString *)timeString {
self.slider.value = value;
self.currentTimeLabel.text = timeString;
self.slider.isdragging = YES;
[UIView animateWithDuration:0.3 animations:^{
self.slider.sliderBtn.transform = CGAffineTransformMakeScale(1.2, 1.2);
}];
}
///
- (void)sliderChangeEnded {
self.slider.isdragging = NO;
[UIView animateWithDuration:0.3 animations:^{
self.slider.sliderBtn.transform = CGAffineTransformIdentity;
}];
}
#pragma mark - setter
- (void)setFullScreenMode:(ZFFullScreenMode)fullScreenMode {
_fullScreenMode = fullScreenMode;
self.player.orientationObserver.fullScreenMode = fullScreenMode;
}
#pragma mark - getter
- (UIView *)topToolView {
if (!_topToolView) {
_topToolView = [[UIView alloc] init];
UIImage *image = ZFPlayer_Image(@"ZFPlayer_top_shadow");
_topToolView.layer.contents = (id)image.CGImage;
}
return _topToolView;
}
- (UILabel *)titleLabel {
if (!_titleLabel) {
_titleLabel = [[UILabel alloc] init];
_titleLabel.textColor = [UIColor whiteColor];
_titleLabel.font = [UIFont systemFontOfSize:15.0];
}
return _titleLabel;
}
- (UIView *)bottomToolView {
if (!_bottomToolView) {
_bottomToolView = [[UIView alloc] init];
UIImage *image = ZFPlayer_Image(@"ZFPlayer_bottom_shadow");
_bottomToolView.layer.contents = (id)image.CGImage;
}
return _bottomToolView;
}
- (UIButton *)playOrPauseBtn {
if (!_playOrPauseBtn) {
_playOrPauseBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[_playOrPauseBtn setImage:ZFPlayer_Image(@"new_allPlay_44x44_") forState:UIControlStateNormal];
[_playOrPauseBtn setImage:ZFPlayer_Image(@"new_allPause_44x44_") forState:UIControlStateSelected];
}
return _playOrPauseBtn;
}
- (UILabel *)currentTimeLabel {
if (!_currentTimeLabel) {
_currentTimeLabel = [[UILabel alloc] init];
_currentTimeLabel.textColor = [UIColor whiteColor];
_currentTimeLabel.font = [UIFont systemFontOfSize:14.0f];
_currentTimeLabel.textAlignment = NSTextAlignmentCenter;
}
return _currentTimeLabel;
}
- (ZFSliderView *)slider {
if (!_slider) {
_slider = [[ZFSliderView alloc] init];
_slider.delegate = self;
_slider.maximumTrackTintColor = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:0.8];
_slider.bufferTrackTintColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.5];
_slider.minimumTrackTintColor = [UIColor whiteColor];
[_slider setThumbImage:ZFPlayer_Image(@"ZFPlayer_slider") forState:UIControlStateNormal];
_slider.sliderHeight = 2;
}
return _slider;
}
- (UILabel *)totalTimeLabel {
if (!_totalTimeLabel) {
_totalTimeLabel = [[UILabel alloc] init];
_totalTimeLabel.textColor = [UIColor whiteColor];
_totalTimeLabel.font = [UIFont systemFontOfSize:14.0f];
_totalTimeLabel.textAlignment = NSTextAlignmentCenter;
}
return _totalTimeLabel;
}
- (UIButton *)fullScreenBtn {
if (!_fullScreenBtn) {
_fullScreenBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[_fullScreenBtn setImage:ZFPlayer_Image(@"ZFPlayer_fullscreen") forState:UIControlStateNormal];
}
return _fullScreenBtn;
}
@end

View File

@@ -0,0 +1,118 @@
//
// ZFSliderView.h
// ZFPlayer
//
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <UIKit/UIKit.h>
@protocol ZFSliderViewDelegate <NSObject>
@optional
// 滑块滑动开始
- (void)sliderTouchBegan:(float)value;
// 滑块滑动中
- (void)sliderValueChanged:(float)value;
// 滑块滑动结束
- (void)sliderTouchEnded:(float)value;
// 滑杆点击
- (void)sliderTapped:(float)value;
@end
@interface ZFSliderButton : UIButton
@end
@interface ZFSliderView : UIView
@property (nonatomic, weak) id<ZFSliderViewDelegate> delegate;
/** 滑块 */
@property (nonatomic, strong, readonly) ZFSliderButton *sliderBtn;
/** 默认滑杆的颜色 */
@property (nonatomic, strong) UIColor *maximumTrackTintColor;
/** 滑杆进度颜色 */
@property (nonatomic, strong) UIColor *minimumTrackTintColor;
/** 缓存进度颜色 */
@property (nonatomic, strong) UIColor *bufferTrackTintColor;
/** loading进度颜色 */
@property (nonatomic, strong) UIColor *loadingTintColor;
/** 默认滑杆的图片 */
@property (nonatomic, strong) UIImage *maximumTrackImage;
/** 滑杆进度的图片 */
@property (nonatomic, strong) UIImage *minimumTrackImage;
/** 缓存进度的图片 */
@property (nonatomic, strong) UIImage *bufferTrackImage;
/** 滑杆进度 */
@property (nonatomic, assign) float value;
/** 缓存进度 */
@property (nonatomic, assign) float bufferValue;
/** 是否允许点击默认是YES */
@property (nonatomic, assign) BOOL allowTapped;
/** 是否允许点击默认是YES */
@property (nonatomic, assign) BOOL animate;
/** 设置滑杆的高度 */
@property (nonatomic, assign) CGFloat sliderHeight;
/** 设置滑杆的圆角 */
@property (nonatomic, assign) CGFloat sliderRadius;
/** 是否隐藏滑块默认为NO */
@property (nonatomic, assign) BOOL isHideSliderBlock;
/// 是否正在拖动
@property (nonatomic, assign) BOOL isdragging;
/// 向前还是向后拖动
@property (nonatomic, assign) BOOL isForward;
@property (nonatomic, assign) CGSize thumbSize;
/**
* Starts animation of the spinner.
*/
- (void)startAnimating;
/**
* Stops animation of the spinnner.
*/
- (void)stopAnimating;
// 设置滑块背景色
- (void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state;
// 设置滑块图片
- (void)setThumbImage:(UIImage *)image forState:(UIControlState)state;
@end

View File

@@ -0,0 +1,426 @@
//
// ZFSliderView.m
// ZFPlayer
//
// Copyright (c) 2016 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "ZFSliderView.h"
#import "UIView+ZFFrame.h"
/** */
static const CGFloat kSliderBtnWH = 19.0;
/** */
static const CGFloat kProgressH = 1.0;
/** slider*/
static const CGFloat kAnimate = 0.3;
@implementation ZFSliderButton
//
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
CGRect bounds = self.bounds;
//
bounds = CGRectInset(bounds, -20, -20);
// boundsyes
return CGRectContainsPoint(bounds, point);
}
@end
@interface ZFSliderView ()
/** */
@property (nonatomic, strong) UIImageView *bgProgressView;
/** */
@property (nonatomic, strong) UIImageView *bufferProgressView;
/** */
@property (nonatomic, strong) UIImageView *sliderProgressView;
/** */
@property (nonatomic, strong) ZFSliderButton *sliderBtn;
@property (nonatomic, strong) UIView *loadingBarView;
@property (nonatomic, assign) BOOL isLoading;
@property (nonatomic, strong) UITapGestureRecognizer *tapGesture;
@end
@implementation ZFSliderView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.allowTapped = YES;
self.animate = YES;
[self addSubViews];
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
self.allowTapped = YES;
self.animate = YES;
[self addSubViews];
}
- (void)layoutSubviews {
[super layoutSubviews];
if (isnan(self.value) || isnan(self.bufferValue)) return;
CGFloat min_x = 0;
CGFloat min_y = 0;
CGFloat min_w = 0;
CGFloat min_h = 0;
CGFloat min_view_w = self.bounds.size.width;
CGFloat min_view_h = self.bounds.size.height;
min_x = 0;
min_w = min_view_w;
min_y = 0;
min_h = self.sliderHeight;
self.bgProgressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
min_x = 0;
min_y = 0;
min_w = self.thumbSize.width;
min_h = self.thumbSize.height;
self.sliderBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
self.sliderBtn.zf_centerX = self.bgProgressView.zf_width * self.value;
min_x = 0;
min_y = 0;
if (self.sliderBtn.hidden) {
min_w = self.bgProgressView.zf_width * self.value;
} else {
min_w = self.sliderBtn.zf_centerX;
}
min_h = self.sliderHeight;
self.sliderProgressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
min_x = 0;
min_y = 0;
min_w = self.bgProgressView.zf_width * self.bufferValue;
min_h = self.sliderHeight;
self.bufferProgressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
min_w = 0.1;
min_h = self.sliderHeight;
min_x = (min_view_w - min_w)/2;
min_y = (min_view_h - min_h)/2;
self.loadingBarView.frame = CGRectMake(min_x, min_y, min_w, min_h);
self.bgProgressView.zf_centerY = min_view_h * 0.5;
self.bufferProgressView.zf_centerY = min_view_h * 0.5;
self.sliderProgressView.zf_centerY = min_view_h * 0.5;
self.sliderBtn.zf_centerY = min_view_h * 0.5;
}
/**
*/
- (void)addSubViews {
self.thumbSize = CGSizeMake(kSliderBtnWH, kSliderBtnWH);
self.sliderHeight = kProgressH;
self.backgroundColor = [UIColor clearColor];
[self addSubview:self.bgProgressView];
[self addSubview:self.bufferProgressView];
[self addSubview:self.sliderProgressView];
[self addSubview:self.sliderBtn];
[self addSubview:self.loadingBarView];
//
self.tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
[self addGestureRecognizer:self.tapGesture];
//
UIPanGestureRecognizer *sliderGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(sliderGesture:)];
[self addGestureRecognizer:sliderGesture];
}
#pragma mark - Setter
- (void)setMaximumTrackTintColor:(UIColor *)maximumTrackTintColor {
_maximumTrackTintColor = maximumTrackTintColor;
self.bgProgressView.backgroundColor = maximumTrackTintColor;
}
- (void)setMinimumTrackTintColor:(UIColor *)minimumTrackTintColor {
_minimumTrackTintColor = minimumTrackTintColor;
self.sliderProgressView.backgroundColor = minimumTrackTintColor;
}
- (void)setBufferTrackTintColor:(UIColor *)bufferTrackTintColor {
_bufferTrackTintColor = bufferTrackTintColor;
self.bufferProgressView.backgroundColor = bufferTrackTintColor;
}
- (void)setLoadingTintColor:(UIColor *)loadingTintColor {
_loadingTintColor = loadingTintColor;
self.loadingBarView.backgroundColor = loadingTintColor;
}
- (void)setMaximumTrackImage:(UIImage *)maximumTrackImage {
_maximumTrackImage = maximumTrackImage;
self.bgProgressView.image = maximumTrackImage;
self.maximumTrackTintColor = [UIColor clearColor];
}
- (void)setMinimumTrackImage:(UIImage *)minimumTrackImage {
_minimumTrackImage = minimumTrackImage;
self.sliderProgressView.image = minimumTrackImage;
self.minimumTrackTintColor = [UIColor clearColor];
}
- (void)setBufferTrackImage:(UIImage *)bufferTrackImage {
_bufferTrackImage = bufferTrackImage;
self.bufferProgressView.image = bufferTrackImage;
self.bufferTrackTintColor = [UIColor clearColor];
}
- (void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state {
[self.sliderBtn setBackgroundImage:image forState:state];
}
- (void)setThumbImage:(UIImage *)image forState:(UIControlState)state {
[self.sliderBtn setImage:image forState:state];
}
- (void)setValue:(float)value {
if (isnan(value)) return;
value = MIN(1.0, value);
_value = value;
if (self.sliderBtn.hidden) {
self.sliderProgressView.zf_width = self.bgProgressView.zf_width * value;
} else {
self.sliderBtn.zf_centerX = self.bgProgressView.zf_width * value;
self.sliderProgressView.zf_width = self.sliderBtn.zf_centerX;
}
}
- (void)setBufferValue:(float)bufferValue {
if (isnan(bufferValue)) return;
bufferValue = MIN(1.0, bufferValue);
_bufferValue = bufferValue;
self.bufferProgressView.zf_width = self.bgProgressView.zf_width * bufferValue;
}
- (void)setAllowTapped:(BOOL)allowTapped {
_allowTapped = allowTapped;
if (!allowTapped) {
[self removeGestureRecognizer:self.tapGesture];
}
}
- (void)setSliderHeight:(CGFloat)sliderHeight {
if (isnan(sliderHeight)) return;
_sliderHeight = sliderHeight;
self.bgProgressView.zf_height = sliderHeight;
self.bufferProgressView.zf_height = sliderHeight;
self.sliderProgressView.zf_height = sliderHeight;
}
- (void)setSliderRadius:(CGFloat)sliderRadius {
if (isnan(sliderRadius)) return;
_sliderRadius = sliderRadius;
self.bgProgressView.layer.cornerRadius = sliderRadius;
self.bufferProgressView.layer.cornerRadius = sliderRadius;
self.sliderProgressView.layer.cornerRadius = sliderRadius;
self.bgProgressView.layer.masksToBounds = YES;
self.bufferProgressView.layer.masksToBounds = YES;
self.sliderProgressView.layer.masksToBounds = YES;
}
- (void)setIsHideSliderBlock:(BOOL)isHideSliderBlock {
_isHideSliderBlock = isHideSliderBlock;
//
if (isHideSliderBlock) {
self.sliderBtn.hidden = YES;
self.bgProgressView.zf_left = 0;
self.bufferProgressView.zf_left = 0;
self.sliderProgressView.zf_left = 0;
self.allowTapped = NO;
}
}
/**
* Starts animation of the spinner.
*/
- (void)startAnimating {
if (self.isLoading) return;
self.isLoading = YES;
self.bufferProgressView.hidden = YES;
self.sliderProgressView.hidden = YES;
self.sliderBtn.hidden = YES;
self.loadingBarView.hidden = NO;
[self.loadingBarView.layer removeAllAnimations];
CAAnimationGroup *animationGroup = [[CAAnimationGroup alloc] init];
animationGroup.duration = 0.4;
animationGroup.beginTime = CACurrentMediaTime() + 0.4;
animationGroup.repeatCount = MAXFLOAT;
animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
CABasicAnimation *scaleAnimation = [CABasicAnimation animation];
scaleAnimation.keyPath = @"transform.scale.x";
scaleAnimation.fromValue = @(1000.0f);
scaleAnimation.toValue = @(self.zf_width * 10);
CABasicAnimation *alphaAnimation = [CABasicAnimation animation];
alphaAnimation.keyPath = @"opacity";
alphaAnimation.fromValue = @(1.0f);
alphaAnimation.toValue = @(0.0f);
[animationGroup setAnimations:@[scaleAnimation, alphaAnimation]];
[self.loadingBarView.layer addAnimation:animationGroup forKey:@"loading"];
}
/**
* Stops animation of the spinnner.
*/
- (void)stopAnimating {
self.isLoading = NO;
self.bufferProgressView.hidden = NO;
self.sliderProgressView.hidden = NO;
self.sliderBtn.hidden = self.isHideSliderBlock;
self.loadingBarView.hidden = YES;
[self.loadingBarView.layer removeAllAnimations];
}
#pragma mark - User Action
- (void)sliderGesture:(UIGestureRecognizer *)gesture {
switch (gesture.state) {
case UIGestureRecognizerStateBegan: {
[self sliderBtnTouchBegin:self.sliderBtn];
}
break;
case UIGestureRecognizerStateChanged: {
[self sliderBtnDragMoving:self.sliderBtn point:[gesture locationInView:self.bgProgressView]];
}
break;
case UIGestureRecognizerStateEnded: {
[self sliderBtnTouchEnded:self.sliderBtn];
}
break;
default:
break;
}
}
- (void)sliderBtnTouchBegin:(UIButton *)btn {
if ([self.delegate respondsToSelector:@selector(sliderTouchBegan:)]) {
[self.delegate sliderTouchBegan:self.value];
}
if (self.animate) {
[UIView animateWithDuration:kAnimate animations:^{
btn.transform = CGAffineTransformMakeScale(1.2, 1.2);
}];
}
}
- (void)sliderBtnTouchEnded:(UIButton *)btn {
if ([self.delegate respondsToSelector:@selector(sliderTouchEnded:)]) {
[self.delegate sliderTouchEnded:self.value];
}
if (self.animate) {
[UIView animateWithDuration:kAnimate animations:^{
btn.transform = CGAffineTransformIdentity;
}];
}
}
- (void)sliderBtnDragMoving:(UIButton *)btn point:(CGPoint)touchPoint {
//
CGPoint point = touchPoint;
// btn 0-(self.width - btn.width)
CGFloat value = (point.x - btn.zf_width * 0.5) / self.bgProgressView.zf_width;
// value0-1
value = value >= 1.0 ? 1.0 : value <= 0.0 ? 0.0 : value;
if (self.value == value) return;
self.isForward = self.value < value;
self.value = value;
if ([self.delegate respondsToSelector:@selector(sliderValueChanged:)]) {
[self.delegate sliderValueChanged:value];
}
}
- (void)tapped:(UITapGestureRecognizer *)tap {
CGPoint point = [tap locationInView:self.bgProgressView];
//
CGFloat value = (point.x - self.sliderBtn.zf_width * 0.5) * 1.0 / self.bgProgressView.zf_width;
value = value >= 1.0 ? 1.0 : value <= 0 ? 0 : value;
self.value = value;
if ([self.delegate respondsToSelector:@selector(sliderTapped:)]) {
[self.delegate sliderTapped:value];
}
}
#pragma mark - getter
- (UIView *)bgProgressView {
if (!_bgProgressView) {
_bgProgressView = [UIImageView new];
_bgProgressView.backgroundColor = [UIColor grayColor];
_bgProgressView.contentMode = UIViewContentModeScaleAspectFill;
_bgProgressView.clipsToBounds = YES;
}
return _bgProgressView;
}
- (UIView *)bufferProgressView {
if (!_bufferProgressView) {
_bufferProgressView = [UIImageView new];
_bufferProgressView.backgroundColor = [UIColor whiteColor];
_bufferProgressView.contentMode = UIViewContentModeScaleAspectFill;
_bufferProgressView.clipsToBounds = YES;
}
return _bufferProgressView;
}
- (UIView *)sliderProgressView {
if (!_sliderProgressView) {
_sliderProgressView = [UIImageView new];
_sliderProgressView.backgroundColor = [UIColor redColor];
_sliderProgressView.contentMode = UIViewContentModeScaleAspectFill;
_sliderProgressView.clipsToBounds = YES;
}
return _sliderProgressView;
}
- (ZFSliderButton *)sliderBtn {
if (!_sliderBtn) {
_sliderBtn = [ZFSliderButton buttonWithType:UIButtonTypeCustom];
[_sliderBtn setAdjustsImageWhenHighlighted:NO];
}
return _sliderBtn;
}
- (UIView *)loadingBarView {
if (!_loadingBarView) {
_loadingBarView = [[UIView alloc] init];
_loadingBarView.backgroundColor = [UIColor whiteColor];
_loadingBarView.hidden = YES;
}
return _loadingBarView;
}
@end

View File

@@ -0,0 +1,31 @@
//
// ZFSmallFloatControlView.h
// ZFPlayer
//
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <UIKit/UIKit.h>
@interface ZFSmallFloatControlView : UIView
@property (nonatomic, copy, nullable) void(^closeClickCallback)(void);
@end

View File

@@ -0,0 +1,72 @@
//
// ZFSmallFloatControlView.m
// ZFPlayer
//
// Copyright (c) 2016 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "ZFSmallFloatControlView.h"
#import "ZFUtilities.h"
@interface ZFSmallFloatControlView ()
@property (nonatomic, strong) UIButton *closeBtn;
@end
@implementation ZFSmallFloatControlView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self addSubview:self.closeBtn];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
CGFloat min_x = 0;
CGFloat min_y = 0;
CGFloat min_w = 0;
CGFloat min_h = 0;
CGFloat min_view_w = self.bounds.size.width;
min_x = min_view_w-20;
min_y = -10;
min_w = 30;
min_h = min_w;
self.closeBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
}
- (void)closeBtnClick:(UIButton *)sender {
if (self.closeClickCallback) self.closeClickCallback();
}
- (UIButton *)closeBtn {
if (!_closeBtn) {
_closeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[_closeBtn setImage:ZFPlayer_Image(@"ZFPlayer_close") forState:UIControlStateNormal];
[_closeBtn addTarget:self action:@selector(closeBtnClick:) forControlEvents:UIControlEventTouchUpInside];
}
return _closeBtn;
}
@end

View File

@@ -0,0 +1,27 @@
//
// ZFSpeedLoadingView.h
// Pods-ZFPlayer_Example
//
// Created by 紫枫 on 2018/6/27.
//
#import <UIKit/UIKit.h>
#import "ZFLoadingView.h"
@interface ZFSpeedLoadingView : UIView
@property (nonatomic, strong) ZFLoadingView *loadingView;
@property (nonatomic, strong) UILabel *speedTextLabel;
/**
* Starts animation of the spinner.
*/
- (void)startAnimating;
/**
* Stops animation of the spinnner.
*/
- (void)stopAnimating;
@end

View File

@@ -0,0 +1,117 @@
//
// ZFSpeedLoadingView.m
// Pods-ZFPlayer_Example
//
// Created by on 2018/6/27.
//
#import "ZFSpeedLoadingView.h"
#import "ZFNetworkSpeedMonitor.h"
#import "UIView+ZFFrame.h"
@interface ZFSpeedLoadingView ()
@property (nonatomic, strong) ZFNetworkSpeedMonitor *speedMonitor;
@end
@implementation ZFSpeedLoadingView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self initialize];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self initialize];
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
[self initialize];
}
- (void)initialize {
self.userInteractionEnabled = NO;
[self addSubview:self.loadingView];
[self addSubview:self.speedTextLabel];
[self.speedMonitor startNetworkSpeedMonitor];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkSpeedChanged:) name:ZFDownloadNetworkSpeedNotificationKey object:nil];
}
- (void)dealloc {
[self.speedMonitor stopNetworkSpeedMonitor];
[[NSNotificationCenter defaultCenter] removeObserver:self name:ZFDownloadNetworkSpeedNotificationKey object:nil];
}
- (void)layoutSubviews {
[super layoutSubviews];
CGFloat min_x = 0;
CGFloat min_y = 0;
CGFloat min_w = 0;
CGFloat min_h = 0;
CGFloat min_view_w = self.zf_width;
CGFloat min_view_h = self.zf_height;
min_w = 44;
min_h = min_w;
min_x = (min_view_w - min_w) / 2;
min_y = (min_view_h - min_h) / 2 - 10;
self.loadingView.frame = CGRectMake(min_x, min_y, min_w, min_h);
min_x = 0;
min_y = self.loadingView.zf_bottom+5;
min_w = min_view_w;
min_h = 20;
self.speedTextLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
}
- (void)networkSpeedChanged:(NSNotification *)sender {
NSString *downloadSpped = [sender.userInfo objectForKey:ZFNetworkSpeedNotificationKey];
self.speedTextLabel.text = downloadSpped;
}
- (void)startAnimating {
[self.loadingView startAnimating];
self.hidden = NO;
}
- (void)stopAnimating {
[self.loadingView stopAnimating];
self.hidden = YES;
}
- (UILabel *)speedTextLabel {
if (!_speedTextLabel) {
_speedTextLabel = [UILabel new];
_speedTextLabel.textColor = [UIColor whiteColor];
_speedTextLabel.font = [UIFont systemFontOfSize:12.0];
_speedTextLabel.textAlignment = NSTextAlignmentCenter;
}
return _speedTextLabel;
}
- (ZFNetworkSpeedMonitor *)speedMonitor {
if (!_speedMonitor) {
_speedMonitor = [[ZFNetworkSpeedMonitor alloc] init];
}
return _speedMonitor;
}
- (ZFLoadingView *)loadingView {
if (!_loadingView) {
_loadingView = [[ZFLoadingView alloc] init];
_loadingView.lineWidth = 0.8;
_loadingView.duration = 1;
_loadingView.hidesWhenStopped = YES;
}
return _loadingView;
}
@end

View File

@@ -0,0 +1,47 @@
//
// ZFUtilities.m
// ZFPlayer
//
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
/// iPhoneX iPhoneXS iPhoneXS Max iPhoneXR 机型判断
#define iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? ((NSInteger)(([[UIScreen mainScreen] currentMode].size.height/[[UIScreen mainScreen] currentMode].size.width)*100) == 216) : NO)
#define ZFPlayer_Image(file) [ZFUtilities imageNamed:file]
// 屏幕的宽
#define ZFPlayer_ScreenWidth [[UIScreen mainScreen] bounds].size.width
// 屏幕的高
#define ZFPlayer_ScreenHeight [[UIScreen mainScreen] bounds].size.height
@interface ZFUtilities : NSObject
+ (NSString *)convertTimeSecond:(NSInteger)timeSecond;
+ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size;
+ (UIImage *)imageNamed:(NSString *)name;
@end

View File

@@ -0,0 +1,74 @@
//
// ZFUtilities.m
// ZFPlayer
//
// Copyright (c) 2016 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "ZFUtilities.h"
@implementation ZFUtilities
+ (NSString *)convertTimeSecond:(NSInteger)timeSecond {
NSString *theLastTime = nil;
long second = timeSecond;
if (timeSecond < 60) {
theLastTime = [NSString stringWithFormat:@"00:%02zd", second];
} else if(timeSecond >= 60 && timeSecond < 3600){
theLastTime = [NSString stringWithFormat:@"%02zd:%02zd", second/60, second%60];
} else if(timeSecond >= 3600){
theLastTime = [NSString stringWithFormat:@"%02zd:%02zd:%02zd", second/3600, second%3600/60, second%60];
}
return theLastTime;
}
+ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size {
if (!color || size.width <= 0 || size.height <= 0) return nil;
CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
+ (NSBundle *)bundle {
static NSBundle *bundle = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
bundle = [NSBundle bundleWithPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"ZFPlayer" ofType:@"bundle"]];
});
return bundle;
}
+ (UIImage *)imageNamed:(NSString *)name {
if (name.length == 0) return nil;
int scale = (int)UIScreen.mainScreen.scale;
if (scale < 2) scale = 2;
else if (scale > 3) scale = 3;
NSString *n = [NSString stringWithFormat:@"%@@%dx", name, scale];
UIImage *image = [UIImage imageWithContentsOfFile:[self.bundle pathForResource:n ofType:@"png"]];
if (!image) image = [UIImage imageWithContentsOfFile:[self.bundle pathForResource:name ofType:@"png"]];
return image;
}
@end

View File

@@ -0,0 +1,46 @@
//
// ZFVolumeBrightnessView.h
// ZFPlayer
//
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSInteger, ZFVolumeBrightnessType) {
ZFVolumeBrightnessTypeVolume, // volume
ZFVolumeBrightnessTypeumeBrightness // brightness
};
@interface ZFVolumeBrightnessView : UIView
@property (nonatomic, assign, readonly) ZFVolumeBrightnessType volumeBrightnessType;
@property (nonatomic, strong, readonly) UIProgressView *progressView;
@property (nonatomic, strong, readonly) UIImageView *iconImageView;
- (void)updateProgress:(CGFloat)progress withVolumeBrightnessType:(ZFVolumeBrightnessType)volumeBrightnessType;
/// 添加系统音量view
- (void)addSystemVolumeView;
/// 移除系统音量view
- (void)removeSystemVolumeView;
@end

View File

@@ -0,0 +1,162 @@
//
// ZFVolumeBrightnessView.m
// ZFPlayer
//
// Copyright (c) 2016 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "ZFVolumeBrightnessView.h"
#import <MediaPlayer/MediaPlayer.h>
#import "ZFUtilities.h"
@interface ZFVolumeBrightnessView ()
@property (nonatomic, strong) UIProgressView *progressView;
@property (nonatomic, strong) UIImageView *iconImageView;
@property (nonatomic, assign) ZFVolumeBrightnessType volumeBrightnessType;
@property (nonatomic, strong) MPVolumeView *volumeView;
@end
@implementation ZFVolumeBrightnessView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self addSubview:self.iconImageView];
[self addSubview:self.progressView];
[self hideTipView];
}
return self;
}
- (void)dealloc {
[self addSystemVolumeView];
}
- (void)layoutSubviews {
[super layoutSubviews];
CGFloat min_x = 0;
CGFloat min_y = 0;
CGFloat min_w = 0;
CGFloat min_h = 0;
CGFloat min_view_w = self.frame.size.width;
CGFloat min_view_h = self.frame.size.height;
CGFloat margin = 10;
min_x = margin;
min_w = 20;
min_h = min_w;
min_y = (min_view_h-min_h)/2;
self.iconImageView.frame = CGRectMake(min_x, min_y, min_w, min_h);
min_x = CGRectGetMaxX(self.iconImageView.frame) + margin;
min_h = 2;
min_y = (min_view_h-min_h)/2;
min_w = min_view_w - min_x - margin;
self.progressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
self.layer.cornerRadius = min_view_h/2;
self.layer.masksToBounds = YES;
}
- (void)hideTipView {
[UIView animateWithDuration:0.5 animations:^{
self.alpha = 0;
} completion:^(BOOL finished) {
self.hidden = YES;
}];
}
/// view
- (void)addSystemVolumeView {
[self.volumeView removeFromSuperview];
}
/// view
- (void)removeSystemVolumeView {
[[UIApplication sharedApplication].keyWindow addSubview:self.volumeView];
}
- (void)updateProgress:(CGFloat)progress withVolumeBrightnessType:(ZFVolumeBrightnessType)volumeBrightnessType {
if (progress >= 1) {
progress = 1;
} else if (progress <= 0) {
progress = 0;
}
self.progressView.progress = progress;
self.volumeBrightnessType = volumeBrightnessType;
UIImage *playerImage = nil;
if (volumeBrightnessType == ZFVolumeBrightnessTypeVolume) {
if (progress == 0) {
playerImage = ZFPlayer_Image(@"ZFPlayer_muted");
} else if (progress > 0 && progress < 0.5) {
playerImage = ZFPlayer_Image(@"ZFPlayer_volume_low");
} else {
playerImage = ZFPlayer_Image(@"ZFPlayer_volume_high");
}
} else if (volumeBrightnessType == ZFVolumeBrightnessTypeumeBrightness) {
if (progress >= 0 && progress < 0.5) {
playerImage = ZFPlayer_Image(@"ZFPlayer_brightness_low");
} else {
playerImage = ZFPlayer_Image(@"ZFPlayer_brightness_high");
}
}
self.iconImageView.image = playerImage;
self.hidden = NO;
self.alpha = 1;
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideTipView) object:nil];
[self performSelector:@selector(hideTipView) withObject:nil afterDelay:1.5];
}
- (void)setVolumeBrightnessType:(ZFVolumeBrightnessType)volumeBrightnessType {
_volumeBrightnessType = volumeBrightnessType;
if (volumeBrightnessType == ZFVolumeBrightnessTypeVolume) {
self.iconImageView.image = ZFPlayer_Image(@"ZFPlayer_volume");
} else {
self.iconImageView.image = ZFPlayer_Image(@"ZFPlayer_brightness");
}
}
- (UIProgressView *)progressView {
if (!_progressView) {
_progressView = [[UIProgressView alloc] init];
_progressView.progressTintColor = [UIColor whiteColor];
_progressView.trackTintColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.4];;
}
return _progressView;
}
- (UIImageView *)iconImageView {
if (!_iconImageView) {
_iconImageView = [UIImageView new];
}
return _iconImageView;
}
- (MPVolumeView *)volumeView {
if (!_volumeView) {
_volumeView = [[MPVolumeView alloc] init];
_volumeView.frame = CGRectMake(-1000, -1000, 100, 100);
}
return _volumeView;
}
@end

View File

@@ -0,0 +1,79 @@
/*
* IJKAVMoviePlayerController.h
*
* Copyright (c) 2014 Bilibili
* Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* ijkPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
File: AVPlayerDemoPlaybackViewController.h
Abstract: UIViewController managing a playback view, thumbnail view, and associated playback UI.
Version: 1.3
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
Inc. ("Apple") in consideration of your agreement to the following
terms, and your use, installation, modification or redistribution of
this Apple software constitutes acceptance of these terms. If you do
not agree with these terms, please do not use, install, modify or
redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and
subject to these terms, Apple grants you a personal, non-exclusive
license, under Apple's copyrights in this original Apple software (the
"Apple Software"), to use, reproduce, modify and redistribute the Apple
Software, with or without modifications, in source and/or binary forms;
provided that if you redistribute the Apple Software in its entirety and
without modifications, you must retain this notice and the following
text and disclaimers in all such redistributions of the Apple Software.
Neither the name, trademarks, service marks or logos of Apple Inc. may
be used to endorse or promote products derived from the Apple Software
without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or
implied, are granted by Apple herein, including but not limited to any
patent rights that may be infringed by your derivative works or by other
works in which the Apple Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Copyright (C) 2014 Apple Inc. All Rights Reserved.
*/
#import "IJKMediaPlayback.h"
@interface IJKAVMoviePlayerController : NSObject <IJKMediaPlayback>
- (id)initWithContentURL:(NSURL *)aUrl;
- (id)initWithContentURLString:(NSString *)aUrl;
+ (id)getInstance:(NSString *)aUrl;
@end

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2016 Bilibili
* Copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* ijkPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#import <Foundation/Foundation.h>
@interface IJKFFMonitor : NSObject
- (instancetype)init;
@property(nonatomic) NSDictionary *mediaMeta;
@property(nonatomic) NSDictionary *videoMeta;
@property(nonatomic) NSDictionary *audioMeta;
@property(nonatomic, readonly) int64_t duration; // milliseconds
@property(nonatomic, readonly) int64_t bitrate; // bit / sec
@property(nonatomic, readonly) float fps; // frame / sec
@property(nonatomic, readonly) int width; // width
@property(nonatomic, readonly) int height; // height
@property(nonatomic, readonly) NSString *vcodec; // video codec
@property(nonatomic, readonly) NSString *acodec; // audio codec
@property(nonatomic, readonly) int sampleRate;
@property(nonatomic, readonly) int64_t channelLayout;
@property(nonatomic) NSString *vdecoder;
@property(nonatomic) int tcpError;
@property(nonatomic) NSString *remoteIp;
@property(nonatomic) int httpError;
@property(nonatomic) NSString *httpUrl;
@property(nonatomic) NSString *httpHost;
@property(nonatomic) int httpCode;
@property(nonatomic) int64_t httpOpenTick;
@property(nonatomic) int64_t httpSeekTick;
@property(nonatomic) int httpOpenCount;
@property(nonatomic) int httpSeekCount;
@property(nonatomic) int64_t lastHttpOpenDuration;
@property(nonatomic) int64_t lastHttpSeekDuration;
@property(nonatomic) int64_t filesize;
@property(nonatomic) int64_t prepareStartTick;
@property(nonatomic) int64_t prepareDuration;
@property(nonatomic) int64_t firstVideoFrameLatency;
@property(nonatomic) int64_t lastPrerollStartTick;
@property(nonatomic) int64_t lastPrerollDuration;
@end

View File

@@ -0,0 +1,155 @@
/*
* IJKFFMoviePlayerController.h
*
* Copyright (c) 2013 Bilibili
* Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* ijkPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#import "IJKMediaPlayback.h"
#import "IJKFFMonitor.h"
#import "IJKFFOptions.h"
#import "IJKSDLGLViewProtocol.h"
// media meta
#define k_IJKM_KEY_FORMAT @"format"
#define k_IJKM_KEY_DURATION_US @"duration_us"
#define k_IJKM_KEY_START_US @"start_us"
#define k_IJKM_KEY_BITRATE @"bitrate"
// stream meta
#define k_IJKM_KEY_TYPE @"type"
#define k_IJKM_VAL_TYPE__VIDEO @"video"
#define k_IJKM_VAL_TYPE__AUDIO @"audio"
#define k_IJKM_VAL_TYPE__UNKNOWN @"unknown"
#define k_IJKM_KEY_CODEC_NAME @"codec_name"
#define k_IJKM_KEY_CODEC_PROFILE @"codec_profile"
#define k_IJKM_KEY_CODEC_LONG_NAME @"codec_long_name"
// stream: video
#define k_IJKM_KEY_WIDTH @"width"
#define k_IJKM_KEY_HEIGHT @"height"
#define k_IJKM_KEY_FPS_NUM @"fps_num"
#define k_IJKM_KEY_FPS_DEN @"fps_den"
#define k_IJKM_KEY_TBR_NUM @"tbr_num"
#define k_IJKM_KEY_TBR_DEN @"tbr_den"
#define k_IJKM_KEY_SAR_NUM @"sar_num"
#define k_IJKM_KEY_SAR_DEN @"sar_den"
// stream: audio
#define k_IJKM_KEY_SAMPLE_RATE @"sample_rate"
#define k_IJKM_KEY_CHANNEL_LAYOUT @"channel_layout"
#define kk_IJKM_KEY_STREAMS @"streams"
typedef enum IJKLogLevel {
k_IJK_LOG_UNKNOWN = 0,
k_IJK_LOG_DEFAULT = 1,
k_IJK_LOG_VERBOSE = 2,
k_IJK_LOG_DEBUG = 3,
k_IJK_LOG_INFO = 4,
k_IJK_LOG_WARN = 5,
k_IJK_LOG_ERROR = 6,
k_IJK_LOG_FATAL = 7,
k_IJK_LOG_SILENT = 8,
} IJKLogLevel;
@interface IJKFFMoviePlayerController : NSObject <IJKMediaPlayback>
- (id)initWithContentURL:(NSURL *)aUrl
withOptions:(IJKFFOptions *)options;
- (id)initWithContentURLString:(NSString *)aUrlString
withOptions:(IJKFFOptions *)options;
- (id)initWithMoreContent:(NSURL *)aUrl
withOptions:(IJKFFOptions *)options
withGLView:(UIView<IJKSDLGLViewProtocol> *)glView;
- (id)initWithMoreContentString:(NSString *)aUrlString
withOptions:(IJKFFOptions *)options
withGLView:(UIView<IJKSDLGLViewProtocol> *)glView;
- (void)prepareToPlay;
- (void)play;
- (void)pause;
- (void)stop;
- (BOOL)isPlaying;
- (int64_t)trafficStatistic;
- (float)dropFrameRate;
- (void)setPauseInBackground:(BOOL)pause;
- (BOOL)isVideoToolboxOpen;
- (void)setHudValue:(NSString *)value forKey:(NSString *)key;
+ (void)setLogReport:(BOOL)preferLogReport;
+ (void)setLogLevel:(IJKLogLevel)logLevel;
+ (BOOL)checkIfFFmpegVersionMatch:(BOOL)showAlert;
+ (BOOL)checkIfPlayerVersionMatch:(BOOL)showAlert
version:(NSString *)version;
@property(nonatomic, readonly) CGFloat fpsInMeta;
@property(nonatomic, readonly) CGFloat fpsAtOutput;
@property(nonatomic) BOOL shouldShowHudView;
- (void)setOptionValue:(NSString *)value
forKey:(NSString *)key
ofCategory:(IJKFFOptionCategory)category;
- (void)setOptionIntValue:(int64_t)value
forKey:(NSString *)key
ofCategory:(IJKFFOptionCategory)category;
- (void)setFormatOptionValue: (NSString *)value forKey:(NSString *)key;
- (void)setCodecOptionValue: (NSString *)value forKey:(NSString *)key;
- (void)setSwsOptionValue: (NSString *)value forKey:(NSString *)key;
- (void)setPlayerOptionValue: (NSString *)value forKey:(NSString *)key;
- (void)setFormatOptionIntValue: (int64_t)value forKey:(NSString *)key;
- (void)setCodecOptionIntValue: (int64_t)value forKey:(NSString *)key;
- (void)setSwsOptionIntValue: (int64_t)value forKey:(NSString *)key;
- (void)setPlayerOptionIntValue: (int64_t)value forKey:(NSString *)key;
@property (nonatomic, retain) id<IJKMediaUrlOpenDelegate> segmentOpenDelegate;
@property (nonatomic, retain) id<IJKMediaUrlOpenDelegate> tcpOpenDelegate;
@property (nonatomic, retain) id<IJKMediaUrlOpenDelegate> httpOpenDelegate;
@property (nonatomic, retain) id<IJKMediaUrlOpenDelegate> liveOpenDelegate;
@property (nonatomic, retain) id<IJKMediaNativeInvokeDelegate> nativeInvokeDelegate;
- (void)didShutdown;
#pragma mark KVO properties
@property (nonatomic, readonly) IJKFFMonitor *monitor;
@end
#define IJK_FF_IO_TYPE_READ (1)
void IJKFFIOStatDebugCallback(const char *url, int type, int bytes);
void IJKFFIOStatRegister(void (*cb)(const char *url, int type, int bytes));
void IJKFFIOStatCompleteDebugCallback(const char *url,
int64_t read_bytes, int64_t total_size,
int64_t elpased_time, int64_t total_duration);
void IJKFFIOStatCompleteRegister(void (*cb)(const char *url,
int64_t read_bytes, int64_t total_size,
int64_t elpased_time, int64_t total_duration));

View File

@@ -0,0 +1,75 @@
/*
* IJKFFOptions.h
*
* Copyright (c) 2013-2015 Bilibili
* Copyright (c) 2013-2015 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* ijkPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#import <Foundation/Foundation.h>
typedef enum IJKFFOptionCategory {
kIJKFFOptionCategoryFormat = 1,
kIJKFFOptionCategoryCodec = 2,
kIJKFFOptionCategorySws = 3,
kIJKFFOptionCategoryPlayer = 4,
kIJKFFOptionCategorySwr = 5,
} IJKFFOptionCategory;
// for codec option 'skip_loop_filter' and 'skip_frame'
typedef enum IJKAVDiscard {
/* We leave some space between them for extensions (drop some
* keyframes for intra-only or drop just some bidir frames). */
IJK_AVDISCARD_NONE =-16, ///< discard nothing
IJK_AVDISCARD_DEFAULT = 0, ///< discard useless packets like 0 size packets in avi
IJK_AVDISCARD_NONREF = 8, ///< discard all non reference
IJK_AVDISCARD_BIDIR = 16, ///< discard all bidirectional frames
IJK_AVDISCARD_NONKEY = 32, ///< discard all frames except keyframes
IJK_AVDISCARD_ALL = 48, ///< discard all
} IJKAVDiscard;
struct IjkMediaPlayer;
@interface IJKFFOptions : NSObject
+(IJKFFOptions *)optionsByDefault;
-(void)applyTo:(struct IjkMediaPlayer *)mediaPlayer;
- (void)setOptionValue:(NSString *)value
forKey:(NSString *)key
ofCategory:(IJKFFOptionCategory)category;
- (void)setOptionIntValue:(int64_t)value
forKey:(NSString *)key
ofCategory:(IJKFFOptionCategory)category;
-(void)setFormatOptionValue: (NSString *)value forKey:(NSString *)key;
-(void)setCodecOptionValue: (NSString *)value forKey:(NSString *)key;
-(void)setSwsOptionValue: (NSString *)value forKey:(NSString *)key;
-(void)setPlayerOptionValue: (NSString *)value forKey:(NSString *)key;
-(void)setFormatOptionIntValue: (int64_t)value forKey:(NSString *)key;
-(void)setCodecOptionIntValue: (int64_t)value forKey:(NSString *)key;
-(void)setSwsOptionIntValue: (int64_t)value forKey:(NSString *)key;
-(void)setPlayerOptionIntValue: (int64_t)value forKey:(NSString *)key;
@property(nonatomic) BOOL showHudView;
@end

View File

@@ -0,0 +1,39 @@
/*
* IJKKVOController.h
*
* Copyright (c) 2014 Bilibili
* Copyright (c) 2014 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* ijkPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#import <Foundation/Foundation.h>
@interface IJKKVOController : NSObject
- (id)initWithTarget:(NSObject *)target;
- (void)safelyAddObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath
options:(NSKeyValueObservingOptions)options
context:(void *)context;
- (void)safelyRemoveObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath;
- (void)safelyRemoveAllObservers;
@end

View File

@@ -0,0 +1,32 @@
/*
* IJKMPMoviePlayerController.h
*
* Copyright (c) 2013 Bilibili
* Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* ijkPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#import "IJKMediaPlayback.h"
#import <MediaPlayer/MediaPlayer.h>
@interface IJKMPMoviePlayerController : MPMoviePlayerController <IJKMediaPlayback>
- (id)initWithContentURL:(NSURL *)aUrl;
- (id)initWithContentURLString:(NSString *)aUrl;
@end

View File

@@ -0,0 +1,63 @@
/*
* IJKMediaFramework.h
*
* Copyright (c) 2013 Bilibili
* Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* ijkPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#import <UIKit/UIKit.h>
//! Project version number for IJKMediaFramework.
FOUNDATION_EXPORT double IJKMediaFrameworkVersionNumber;
//! Project version string for IJKMediaFramework.
FOUNDATION_EXPORT const unsigned char IJKMediaFrameworkVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <IJKMediaFrameworkWithSSL/PublicHeader.h>
#import <IJKMediaFramework/IJKMediaPlayback.h>
#import <IJKMediaFramework/IJKMPMoviePlayerController.h>
#import <IJKMediaFramework/IJKFFOptions.h>
#import <IJKMediaFramework/IJKFFMoviePlayerController.h>
#import <IJKMediaFramework/IJKAVMoviePlayerController.h>
#import <IJKMediaFramework/IJKMediaModule.h>
#import <IJKMediaFramework/IJKMediaPlayer.h>
#import <IJKMediaFramework/IJKNotificationManager.h>
#import <IJKMediaFramework/IJKKVOController.h>
#import <IJKMediaFramework/IJKSDLGLViewProtocol.h>
// backward compatible for old names
#define IJKMediaPlaybackIsPreparedToPlayDidChangeNotification IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification
#define IJKMoviePlayerLoadStateDidChangeNotification IJKMPMoviePlayerLoadStateDidChangeNotification
#define IJKMoviePlayerPlaybackDidFinishNotification IJKMPMoviePlayerPlaybackDidFinishNotification
#define IJKMoviePlayerPlaybackDidFinishReasonUserInfoKey IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey
#define IJKMoviePlayerPlaybackStateDidChangeNotification IJKMPMoviePlayerPlaybackStateDidChangeNotification
#define IJKMoviePlayerIsAirPlayVideoActiveDidChangeNotification IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification
#define IJKMoviePlayerVideoDecoderOpenNotification IJKMPMoviePlayerVideoDecoderOpenNotification
#define IJKMoviePlayerFirstVideoFrameRenderedNotification IJKMPMoviePlayerFirstVideoFrameRenderedNotification
#define IJKMoviePlayerFirstAudioFrameRenderedNotification IJKMPMoviePlayerFirstAudioFrameRenderedNotification
#define IJKMoviePlayerFirstAudioFrameDecodedNotification IJKMPMoviePlayerFirstAudioFrameDecodedNotification
#define IJKMoviePlayerFirstVideoFrameDecodedNotification IJKMPMoviePlayerFirstVideoFrameDecodedNotification
#define IJKMoviePlayerOpenInputNotification IJKMPMoviePlayerOpenInputNotification
#define IJKMoviePlayerFindStreamInfoNotification IJKMPMoviePlayerFindStreamInfoNotification
#define IJKMoviePlayerComponentOpenNotification IJKMPMoviePlayerComponentOpenNotification
#define IJKMPMoviePlayerAccurateSeekCompleteNotification IJKMPMoviePlayerAccurateSeekCompleteNotification
#define IJKMoviePlayerSeekAudioStartNotification IJKMPMoviePlayerSeekAudioStartNotification
#define IJKMoviePlayerSeekVideoStartNotification IJKMPMoviePlayerSeekVideoStartNotification

View File

@@ -0,0 +1,33 @@
/*
* IJKMediaModule.h
*
* Copyright (c) 2013 Bilibili
* Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* ijkPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#import <Foundation/Foundation.h>
@interface IJKMediaModule : NSObject
+ (IJKMediaModule *)sharedModule;
@property(atomic, getter=isAppIdleTimerDisabled) BOOL appIdleTimerDisabled;
@property(atomic, getter=isMediaModuleIdleTimerDisabled) BOOL mediaModuleIdleTimerDisabled;
@end

View File

@@ -0,0 +1,227 @@
/*
* IJKMediaPlayback.h
*
* Copyright (c) 2013 Bilibili
* Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* ijkPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSInteger, IJKMPMovieScalingMode) {
IJKMPMovieScalingModeNone, // No scaling
IJKMPMovieScalingModeAspectFit, // Uniform scale until one dimension fits
IJKMPMovieScalingModeAspectFill, // Uniform scale until the movie fills the visible bounds. One dimension may have clipped contents
IJKMPMovieScalingModeFill // Non-uniform scale. Both render dimensions will exactly match the visible bounds
};
typedef NS_ENUM(NSInteger, IJKMPMoviePlaybackState) {
IJKMPMoviePlaybackStateStopped,
IJKMPMoviePlaybackStatePlaying,
IJKMPMoviePlaybackStatePaused,
IJKMPMoviePlaybackStateInterrupted,
IJKMPMoviePlaybackStateSeekingForward,
IJKMPMoviePlaybackStateSeekingBackward
};
typedef NS_OPTIONS(NSUInteger, IJKMPMovieLoadState) {
IJKMPMovieLoadStateUnknown = 0,
IJKMPMovieLoadStatePlayable = 1 << 0,
IJKMPMovieLoadStatePlaythroughOK = 1 << 1, // Playback will be automatically started in this state when shouldAutoplay is YES
IJKMPMovieLoadStateStalled = 1 << 2, // Playback will be automatically paused in this state, if started
};
typedef NS_ENUM(NSInteger, IJKMPMovieFinishReason) {
IJKMPMovieFinishReasonPlaybackEnded,
IJKMPMovieFinishReasonPlaybackError,
IJKMPMovieFinishReasonUserExited
};
// -----------------------------------------------------------------------------
// Thumbnails
typedef NS_ENUM(NSInteger, IJKMPMovieTimeOption) {
IJKMPMovieTimeOptionNearestKeyFrame,
IJKMPMovieTimeOptionExact
};
@protocol IJKMediaPlayback;
#pragma mark IJKMediaPlayback
@protocol IJKMediaPlayback <NSObject>
- (void)prepareToPlay;
- (void)play;
- (void)pause;
- (void)stop;
- (BOOL)isPlaying;
- (void)shutdown;
- (void)setPauseInBackground:(BOOL)pause;
@property(nonatomic, readonly) UIView *view;
@property(nonatomic) NSTimeInterval currentPlaybackTime;
@property(nonatomic, readonly) NSTimeInterval duration;
@property(nonatomic, readonly) NSTimeInterval playableDuration;
@property(nonatomic, readonly) NSInteger bufferingProgress;
@property(nonatomic, readonly) BOOL isPreparedToPlay;
@property(nonatomic, readonly) IJKMPMoviePlaybackState playbackState;
@property(nonatomic, readonly) IJKMPMovieLoadState loadState;
@property(nonatomic, readonly) int isSeekBuffering;
@property(nonatomic, readonly) int isAudioSync;
@property(nonatomic, readonly) int isVideoSync;
@property(nonatomic, readonly) int64_t numberOfBytesTransferred;
@property(nonatomic, readonly) CGSize naturalSize;
@property(nonatomic) IJKMPMovieScalingMode scalingMode;
@property(nonatomic) BOOL shouldAutoplay;
@property (nonatomic) BOOL allowsMediaAirPlay;
@property (nonatomic) BOOL isDanmakuMediaAirPlay;
@property (nonatomic, readonly) BOOL airPlayMediaActive;
@property (nonatomic) float playbackRate;
@property (nonatomic) float playbackVolume;
- (UIImage *)thumbnailImageAtCurrentTime;
#pragma mark Notifications
#ifdef __cplusplus
#define IJK_EXTERN extern "C" __attribute__((visibility ("default")))
#else
#define IJK_EXTERN extern __attribute__((visibility ("default")))
#endif
// -----------------------------------------------------------------------------
// MPMediaPlayback.h
// Posted when the prepared state changes of an object conforming to the MPMediaPlayback protocol changes.
// This supersedes MPMoviePlayerContentPreloadDidFinishNotification.
IJK_EXTERN NSString *const IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification;
// -----------------------------------------------------------------------------
// MPMoviePlayerController.h
// Movie Player Notifications
// Posted when the scaling mode changes.
IJK_EXTERN NSString* const IJKMPMoviePlayerScalingModeDidChangeNotification;
// Posted when movie playback ends or a user exits playback.
IJK_EXTERN NSString* const IJKMPMoviePlayerPlaybackDidFinishNotification;
IJK_EXTERN NSString* const IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey; // NSNumber (IJKMPMovieFinishReason)
// Posted when the playback state changes, either programatically or by the user.
IJK_EXTERN NSString* const IJKMPMoviePlayerPlaybackStateDidChangeNotification;
// Posted when the network load state changes.
IJK_EXTERN NSString* const IJKMPMoviePlayerLoadStateDidChangeNotification;
// Posted when the movie player begins or ends playing video via AirPlay.
IJK_EXTERN NSString* const IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification;
// -----------------------------------------------------------------------------
// Movie Property Notifications
// Calling -prepareToPlay on the movie player will begin determining movie properties asynchronously.
// These notifications are posted when the associated movie property becomes available.
IJK_EXTERN NSString* const IJKMPMovieNaturalSizeAvailableNotification;
// -----------------------------------------------------------------------------
// Extend Notifications
IJK_EXTERN NSString *const IJKMPMoviePlayerVideoDecoderOpenNotification;
IJK_EXTERN NSString *const IJKMPMoviePlayerFirstVideoFrameRenderedNotification;
IJK_EXTERN NSString *const IJKMPMoviePlayerFirstAudioFrameRenderedNotification;
IJK_EXTERN NSString *const IJKMPMoviePlayerFirstAudioFrameDecodedNotification;
IJK_EXTERN NSString *const IJKMPMoviePlayerFirstVideoFrameDecodedNotification;
IJK_EXTERN NSString *const IJKMPMoviePlayerOpenInputNotification;
IJK_EXTERN NSString *const IJKMPMoviePlayerFindStreamInfoNotification;
IJK_EXTERN NSString *const IJKMPMoviePlayerComponentOpenNotification;
IJK_EXTERN NSString *const IJKMPMoviePlayerDidSeekCompleteNotification;
IJK_EXTERN NSString *const IJKMPMoviePlayerDidSeekCompleteTargetKey;
IJK_EXTERN NSString *const IJKMPMoviePlayerDidSeekCompleteErrorKey;
IJK_EXTERN NSString *const IJKMPMoviePlayerDidAccurateSeekCompleteCurPos;
IJK_EXTERN NSString *const IJKMPMoviePlayerAccurateSeekCompleteNotification;
IJK_EXTERN NSString *const IJKMPMoviePlayerSeekAudioStartNotification;
IJK_EXTERN NSString *const IJKMPMoviePlayerSeekVideoStartNotification;
@end
#pragma mark IJKMediaUrlOpenDelegate
// Must equal to the defination in ijkavformat/ijkavformat.h
typedef NS_ENUM(NSInteger, IJKMediaEvent) {
// Notify Events
IJKMediaEvent_WillHttpOpen = 1, // attr: url
IJKMediaEvent_DidHttpOpen = 2, // attr: url, error, http_code
IJKMediaEvent_WillHttpSeek = 3, // attr: url, offset
IJKMediaEvent_DidHttpSeek = 4, // attr: url, offset, error, http_code
// Control Message
IJKMediaCtrl_WillTcpOpen = 0x20001, // IJKMediaUrlOpenData: no args
IJKMediaCtrl_DidTcpOpen = 0x20002, // IJKMediaUrlOpenData: error, family, ip, port, fd
IJKMediaCtrl_WillHttpOpen = 0x20003, // IJKMediaUrlOpenData: url, segmentIndex, retryCounter
IJKMediaCtrl_WillLiveOpen = 0x20005, // IJKMediaUrlOpenData: url, retryCounter
IJKMediaCtrl_WillConcatSegmentOpen = 0x20007, // IJKMediaUrlOpenData: url, segmentIndex, retryCounter
};
#define IJKMediaEventAttrKey_url @"url"
#define IJKMediaEventAttrKey_host @"host"
#define IJKMediaEventAttrKey_error @"error"
#define IJKMediaEventAttrKey_time_of_event @"time_of_event"
#define IJKMediaEventAttrKey_http_code @"http_code"
#define IJKMediaEventAttrKey_offset @"offset"
#define IJKMediaEventAttrKey_file_size @"file_size"
// event of IJKMediaUrlOpenEvent_xxx
@interface IJKMediaUrlOpenData: NSObject
- (id)initWithUrl:(NSString *)url
event:(IJKMediaEvent)event
segmentIndex:(int)segmentIndex
retryCounter:(int)retryCounter;
@property(nonatomic, readonly) IJKMediaEvent event;
@property(nonatomic, readonly) int segmentIndex;
@property(nonatomic, readonly) int retryCounter;
@property(nonatomic, retain) NSString *url;
@property(nonatomic, assign) int fd;
@property(nonatomic, strong) NSString *msg;
@property(nonatomic) int error; // set a negative value to indicate an error has occured.
@property(nonatomic, getter=isHandled) BOOL handled; // auto set to YES if url changed
@property(nonatomic, getter=isUrlChanged) BOOL urlChanged; // auto set to YES by url changed
@end
@protocol IJKMediaUrlOpenDelegate <NSObject>
- (void)willOpenUrl:(IJKMediaUrlOpenData*) urlOpenData;
@end
@protocol IJKMediaNativeInvokeDelegate <NSObject>
- (int)invoke:(IJKMediaEvent)event attributes:(NSDictionary *)attributes;
@end

View File

@@ -0,0 +1,32 @@
/*
* IJKMediaPlayer.h
*
* Copyright (c) 2013 Bilibili
* Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* ijkPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#import "IJKMediaPlayback.h"
#import "IJKMPMoviePlayerController.h"
#import "IJKFFOptions.h"
#import "IJKFFMoviePlayerController.h"
#import "IJKAVMoviePlayerController.h"
#import "IJKMediaModule.h"

View File

@@ -0,0 +1,37 @@
/*
* IJKNotificationManager.h
*
* Copyright (c) 2016 Bilibili
* Copyright (c) 2016 Zhang Rui <bbcallen@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* ijkPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#import <Foundation/Foundation.h>
@interface IJKNotificationManager : NSObject
- (nullable instancetype)init;
- (void)addObserver:(nonnull id)observer
selector:(nonnull SEL)aSelector
name:(nullable NSString *)aName
object:(nullable id)anObject;
- (void)removeAllObservers:(nonnull id)observer;
@end

View File

@@ -0,0 +1,50 @@
/*
* IJKSDLGLViewProtocol.h
*
* Copyright (c) 2017 Bilibili
* Copyright (c) 2017 raymond <raymondzheng1412@gmail.com>
*
* This file is part of ijkPlayer.
*
* ijkPlayer is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* ijkPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with ijkPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef IJKSDLGLViewProtocol_h
#define IJKSDLGLViewProtocol_h
#import <UIKit/UIKit.h>
typedef struct IJKOverlay IJKOverlay;
struct IJKOverlay {
int w;
int h;
UInt32 format;
int planes;
UInt16 *pitches;
UInt8 **pixels;
int sar_num;
int sar_den;
CVPixelBufferRef pixel_buffer;
};
@protocol IJKSDLGLViewProtocol <NSObject>
- (UIImage*) snapshot;
@property(nonatomic, readonly) CGFloat fps;
@property(nonatomic) CGFloat scaleFactor;
@property(nonatomic) BOOL isThirdGLView;
- (void) display_pixels: (IJKOverlay *) overlay;
@end
#endif /* IJKSDLGLViewProtocol_h */

View File

@@ -0,0 +1,6 @@
framework module IJKMediaFramework {
umbrella header "IJKMediaFramework.h"
export *
module * { export * }
}

View File

@@ -0,0 +1,45 @@
//
// ZFIJKPlayerManager.h
// ZFPlayer
//
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
#if __has_include(<ZFPlayer/ZFPlayerMediaPlayback.h>)
#import <ZFPlayer/ZFPlayerMediaPlayback.h>
#else
#import "ZFPlayerMediaPlayback.h"
#endif
#if __has_include(<IJKMediaFramework/IJKMediaFramework.h>)
#import <IJKMediaFramework/IJKMediaFramework.h>
@interface ZFIJKPlayerManager : NSObject <ZFPlayerMediaPlayback>
@property (nonatomic, strong, readonly) IJKFFMoviePlayerController *player;
@property (nonatomic, strong, readonly) IJKFFOptions *options;
@property (nonatomic, assign) NSTimeInterval timeRefreshInterval;
@end
#endif

View File

@@ -0,0 +1,458 @@
//
// ZFIJKPlayerManager.m
// ZFPlayer
//
// Copyright (c) 2016 ( http://github.com/renzifeng )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "ZFIJKPlayerManager.h"
#if __has_include(<ZFPlayer/ZFPlayer.h>)
#import <ZFPlayer/ZFPlayer.h>
#import <ZFPlayer/ZFPlayerConst.h>
#else
#import "ZFPlayer.h"
#import "ZFPlayerConst.h"
#endif
#if __has_include(<IJKMediaFramework/IJKMediaFramework.h>)
@interface ZFIJKPlayerManager ()
@property (nonatomic, strong) IJKFFMoviePlayerController *player;
@property (nonatomic, strong) IJKFFOptions *options;
@property (nonatomic, assign) CGFloat lastVolume;
@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic, assign) BOOL isReadyToPlay;
@end
@implementation ZFIJKPlayerManager
@synthesize view = _view;
@synthesize currentTime = _currentTime;
@synthesize totalTime = _totalTime;
@synthesize playerPlayTimeChanged = _playerPlayTimeChanged;
@synthesize playerBufferTimeChanged = _playerBufferTimeChanged;
@synthesize playerDidToEnd = _playerDidToEnd;
@synthesize bufferTime = _bufferTime;
@synthesize playState = _playState;
@synthesize loadState = _loadState;
@synthesize assetURL = _assetURL;
@synthesize playerPrepareToPlay = _playerPrepareToPlay;
@synthesize playerReadyToPlay = _playerReadyToPlay;
@synthesize playerPlayStateChanged = _playerPlayStateChanged;
@synthesize playerLoadStateChanged = _playerLoadStateChanged;
@synthesize seekTime = _seekTime;
@synthesize muted = _muted;
@synthesize volume = _volume;
@synthesize presentationSize = _presentationSize;
@synthesize isPlaying = _isPlaying;
@synthesize rate = _rate;
@synthesize isPreparedToPlay = _isPreparedToPlay;
@synthesize shouldAutoPlay = _shouldAutoPlay;
@synthesize scalingMode = _scalingMode;
@synthesize playerPlayFailed = _playerPlayFailed;
@synthesize presentationSizeChanged = _presentationSizeChanged;
- (void)dealloc {
[self stop];
}
- (instancetype)init {
self = [super init];
if (self) {
_scalingMode = ZFPlayerScalingModeAspectFit;
_shouldAutoPlay = YES;
}
return self;
}
- (void)prepareToPlay {
if (!_assetURL) return;
_isPreparedToPlay = YES;
[self initializePlayer];
if (self.shouldAutoPlay) {
[self play];
}
self.loadState = ZFPlayerLoadStatePrepare;
if (self.playerPrepareToPlay) self.playerPrepareToPlay(self, self.assetURL);
}
- (void)reloadPlayer {
[self prepareToPlay];
}
- (void)play {
if (!_isPreparedToPlay) {
[self prepareToPlay];
} else {
[self.player play];
if (self.timer) [self.timer setFireDate:[NSDate date]];
self.player.playbackRate = self.rate;
_isPlaying = YES;
self.playState = ZFPlayerPlayStatePlaying;
}
}
- (void)pause {
if (self.timer) [self.timer setFireDate:[NSDate distantFuture]];
[self.player pause];
_isPlaying = NO;
self.playState = ZFPlayerPlayStatePaused;
}
- (void)stop {
[self removeMovieNotificationObservers];
[self.player shutdown];
[self.player.view removeFromSuperview];
self.player = nil;
_assetURL = nil;
[self.timer invalidate];
self.presentationSize = CGSizeZero;
self.timer = nil;
_isPlaying = NO;
_isPreparedToPlay = NO;
self->_currentTime = 0;
self->_totalTime = 0;
self->_bufferTime = 0;
self.isReadyToPlay = NO;
self.playState = ZFPlayerPlayStatePlayStopped;
}
- (void)replay {
@zf_weakify(self)
[self seekToTime:0 completionHandler:^(BOOL finished) {
@zf_strongify(self)
if (finished) {
[self play];
}
}];
}
- (void)seekToTime:(NSTimeInterval)time completionHandler:(void (^ __nullable)(BOOL finished))completionHandler {
if (self.player.duration > 0) {
self.player.currentPlaybackTime = time;
if (completionHandler) completionHandler(YES);
} else {
self.seekTime = time;
}
}
- (UIImage *)thumbnailImageAtCurrentTime {
return [self.player thumbnailImageAtCurrentTime];
}
#pragma mark - private method
- (void)initializePlayer {
// IJKFFMoviePlayerController
if (self.player) {
[self removeMovieNotificationObservers];
[self.player shutdown];
[self.player.view removeFromSuperview];
self.player = nil;
}
self.player = [[IJKFFMoviePlayerController alloc] initWithContentURL:self.assetURL withOptions:self.options];
self.player.shouldAutoplay = self.shouldAutoPlay;
[self.player prepareToPlay];
self.view.playerView = self.player.view;
self.scalingMode = self->_scalingMode;
[self addPlayerNotificationObservers];
}
- (void)addPlayerNotificationObservers {
///
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(loadStateDidChange:)
name:IJKMPMoviePlayerLoadStateDidChangeNotification
object:_player];
/// 退
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(moviePlayBackFinish:)
name:IJKMPMoviePlayerPlaybackDidFinishNotification
object:_player];
///
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(mediaIsPreparedToPlayDidChange:)
name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification
object:_player];
///
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(moviePlayBackStateDidChange:)
name:IJKMPMoviePlayerPlaybackStateDidChangeNotification
object:_player];
///
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(sizeAvailableChange:)
name:IJKMPMovieNaturalSizeAvailableNotification
object:self.player];
}
- (void)removeMovieNotificationObservers {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:IJKMPMoviePlayerLoadStateDidChangeNotification
object:_player];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:IJKMPMoviePlayerPlaybackDidFinishNotification
object:_player];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification
object:_player];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:IJKMPMoviePlayerPlaybackStateDidChangeNotification
object:_player];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:IJKMPMovieNaturalSizeAvailableNotification
object:_player];
}
- (void)timerUpdate {
if (self.player.currentPlaybackTime > 0 && !self.isReadyToPlay) {
self.isReadyToPlay = YES;
self.loadState = ZFPlayerLoadStatePlaythroughOK;
}
self->_currentTime = self.player.currentPlaybackTime > 0 ? self.player.currentPlaybackTime : 0;
self->_totalTime = self.player.duration;
self->_bufferTime = self.player.playableDuration;
if (self.playerPlayTimeChanged) self.playerPlayTimeChanged(self, self.currentTime, self.totalTime);
if (self.playerBufferTimeChanged) self.playerBufferTimeChanged(self, self.bufferTime);
}
#pragma - notification
///
- (void)moviePlayBackFinish:(NSNotification *)notification {
int reason = [[[notification userInfo] valueForKey:IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
switch (reason) {
case IJKMPMovieFinishReasonPlaybackEnded: {
ZFPlayerLog(@"playbackStateDidChange: 播放完毕: %d\n", reason);
self.playState = ZFPlayerPlayStatePlayStopped;
if (self.playerDidToEnd) self.playerDidToEnd(self);
}
break;
case IJKMPMovieFinishReasonUserExited: {
ZFPlayerLog(@"playbackStateDidChange: 用户退出播放: %d\n", reason);
}
break;
case IJKMPMovieFinishReasonPlaybackError: {
ZFPlayerLog(@"playbackStateDidChange: 播放出现错误: %d\n", reason);
self.playState = ZFPlayerPlayStatePlayFailed;
if (self.playerPlayFailed) self.playerPlayFailed(self, @(reason));
}
break;
default:
ZFPlayerLog(@"playbackPlayBackDidFinish: ???: %d\n", reason);
break;
}
}
//
- (void)mediaIsPreparedToPlayDidChange:(NSNotification *)notification {
ZFPlayerLog(@"加载状态变成了已经缓存完成,如果设置了自动播放, 会自动播放");
//
if (!self.timer) {
self.timer = [NSTimer scheduledTimerWithTimeInterval:self.timeRefreshInterval > 0 ? self.timeRefreshInterval : 0.1 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}
if (self.isPlaying) {
[self play];
self.muted = self.muted;
if (self.seekTime > 0) {
[self seekToTime:self.seekTime completionHandler:nil];
self.seekTime = 0; // ,
[self play];
}
}
if (self.playerReadyToPlay) self.playerReadyToPlay(self, self.assetURL);
}
#pragma mark -
/**
IJKMPMovieLoadStateUnknown == 0
IJKMPMovieLoadStatePlayable == 1
IJKMPMovieLoadStatePlaythroughOK == 2
IJKMPMovieLoadStateStalled == 4
*/
- (void)loadStateDidChange:(NSNotification*)notification {
IJKMPMovieLoadState loadState = self.player.loadState;
if ((loadState & IJKMPMovieLoadStatePlayable)) {
ZFPlayerLog(@"加载状态变成了缓存数据足够开始播放,但是视频并没有缓存完全");
if (self.player.currentPlaybackTime > 0) {
self.loadState = ZFPlayerLoadStatePlayable;
}
} else if ((loadState & IJKMPMovieLoadStatePlaythroughOK)) {
//
ZFPlayerLog(@"加载状态变成了已经缓存完成,如果设置了自动播放, 会自动播放");
} else if ((loadState & IJKMPMovieLoadStateStalled)) {
//
ZFPlayerLog(@"网速不好等因素导致了暂停");
self.loadState = ZFPlayerLoadStateStalled;
} else {
ZFPlayerLog(@"加载状态变成了未知状态");
self.loadState = ZFPlayerLoadStateUnknown;
}
}
//
- (void)moviePlayBackStateDidChange:(NSNotification *)notification {
switch (self.player.playbackState) {
case IJKMPMoviePlaybackStateStopped: {
ZFPlayerLog(@"播放器的播放状态变了,现在是停止状态 %d: stoped", (int)_player.playbackState);
// (, ), ,
self.playState = ZFPlayerPlayStatePlayStopped;
}
break;
case IJKMPMoviePlaybackStatePlaying: {
ZFPlayerLog(@"播放器的播放状态变了,现在是播放状态 %d: playing", (int)_player.playbackState);
}
break;
case IJKMPMoviePlaybackStatePaused: {
ZFPlayerLog(@"播放器的播放状态变了,现在是暂停状态 %d: paused", (int)_player.playbackState);
}
break;
case IJKMPMoviePlaybackStateInterrupted: {
ZFPlayerLog(@"播放器的播放状态变了,现在是中断状态 %d: interrupted", (int)_player.playbackState);
}
break;
case IJKMPMoviePlaybackStateSeekingForward: {
ZFPlayerLog(@"播放器的播放状态变了,现在是向前拖动状态:%d forward",(int)self.player.playbackState);
}
break;
case IJKMPMoviePlaybackStateSeekingBackward: {
ZFPlayerLog(@"放器的播放状态变了,现在是向后拖动状态 %d: backward", (int)_player.playbackState);
}
break;
default: {
ZFPlayerLog(@"播放器的播放状态变了,现在是未知状态 %d: unknown", (int)_player.playbackState);
}
break;
}
}
///
- (void)sizeAvailableChange:(NSNotification *)notify {
self.presentationSize = self.player.naturalSize;
self.view.presentationSize = self.presentationSize;
if (self.presentationSizeChanged) {
self.presentationSizeChanged(self, self->_presentationSize);
}
}
#pragma mark - getter
- (ZFPlayerView *)view {
if (!_view) {
_view = [[ZFPlayerView alloc] init];
}
return _view;
}
- (float)rate {
return _rate == 0 ?1:_rate;
}
- (IJKFFOptions *)options {
if (!_options) {
_options = [IJKFFOptions optionsByDefault];
/// seek
[_options setPlayerOptionIntValue:1 forKey:@"enable-accurate-seek"];
/// http
[_options setOptionIntValue:1 forKey:@"dns_cache_clear" ofCategory:kIJKFFOptionCategoryFormat];
}
return _options;
}
#pragma mark - setter
- (void)setPlayState:(ZFPlayerPlaybackState)playState {
_playState = playState;
if (self.playerPlayStateChanged) self.playerPlayStateChanged(self, playState);
}
- (void)setLoadState:(ZFPlayerLoadState)loadState {
_loadState = loadState;
if (self.playerLoadStateChanged) self.playerLoadStateChanged(self, loadState);
}
- (void)setAssetURL:(NSURL *)assetURL {
if (self.player) [self stop];
_assetURL = assetURL;
[self prepareToPlay];
}
- (void)setRate:(float)rate {
_rate = rate;
if (self.player && fabsf(_player.playbackRate) > 0.00001f) {
self.player.playbackRate = rate;
}
}
- (void)setMuted:(BOOL)muted {
_muted = muted;
if (muted) {
self.lastVolume = self.player.playbackVolume;
self.player.playbackVolume = 0;
} else {
/// Fix first called the lastVolume is 0.
if (self.lastVolume == 0) self.lastVolume = self.player.playbackVolume;
self.player.playbackVolume = self.lastVolume;
}
}
- (void)setScalingMode:(ZFPlayerScalingMode)scalingMode {
_scalingMode = scalingMode;
self.view.scalingMode = scalingMode;
switch (scalingMode) {
case ZFPlayerScalingModeNone:
self.player.scalingMode = IJKMPMovieScalingModeNone;
break;
case ZFPlayerScalingModeAspectFit:
self.player.scalingMode = IJKMPMovieScalingModeAspectFit;
break;
case ZFPlayerScalingModeAspectFill:
self.player.scalingMode = IJKMPMovieScalingModeAspectFill;
break;
case ZFPlayerScalingModeFill:
self.player.scalingMode = IJKMPMovieScalingModeFill;
break;
default:
break;
}
}
- (void)setVolume:(float)volume {
_volume = MIN(MAX(0, volume), 1);
self.player.playbackVolume = volume;
}
@end
#endif

19
Pods/DDZFPlayerKit_Private/LICENSE generated Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2023 DDIsFriend <DDIsFriend@163.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

29
Pods/DDZFPlayerKit_Private/README.md generated Normal file
View File

@@ -0,0 +1,29 @@
# DDZFPlayerKit_Private
[![CI Status](https://img.shields.io/travis/DDIsFriend/DDZFPlayerKit_Private.svg?style=flat)](https://travis-ci.org/DDIsFriend/DDZFPlayerKit_Private)
[![Version](https://img.shields.io/cocoapods/v/DDZFPlayerKit_Private.svg?style=flat)](https://cocoapods.org/pods/DDZFPlayerKit_Private)
[![License](https://img.shields.io/cocoapods/l/DDZFPlayerKit_Private.svg?style=flat)](https://cocoapods.org/pods/DDZFPlayerKit_Private)
[![Platform](https://img.shields.io/cocoapods/p/DDZFPlayerKit_Private.svg?style=flat)](https://cocoapods.org/pods/DDZFPlayerKit_Private)
## Example
To run the example project, clone the repo, and run `pod install` from the Example directory first.
## Requirements
## Installation
DDZFPlayerKit_Private is available through [CocoaPods](https://cocoapods.org). To install
it, simply add the following line to your Podfile:
```ruby
pod 'DDZFPlayerKit_Private'
```
## Author
DDIsFriend, DDIsFriend@163.com
## License
DDZFPlayerKit_Private is available under the MIT license. See the LICENSE file for more info.