123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- //
- // HXPreviewLivePhotoView.m
- // HXPhotoPickerExample
- //
- // Created by Silence on 2019/11/15.
- // Copyright © 2019 Silence. All rights reserved.
- //
- #import "HXPreviewLivePhotoView.h"
- #import "HXPhotoModel.h"
- #import "UIView+HXExtension.h"
- #import <PhotosUI/PhotosUI.h>
- #import "HXPhotoDefine.h"
- #import "HXCircleProgressView.h"
- #import "HXPhotoTools.h"
- #if __has_include(<SDWebImage/UIImageView+WebCache.h>)
- #import <SDWebImage/SDImageCache.h>
- #elif __has_include("SDImageCache.h")
- #import "SDImageCache.h"
- #endif
- #if __has_include(<SDWebImage/UIImageView+WebCache.h>)
- #import <SDWebImage/SDWebImageManager.h>
- #elif __has_include("SDWebImageManager.h")
- #import "SDWebImageManager.h"
- #endif
- #if __has_include(<YYWebImage/YYWebImage.h>)
- #import <YYWebImage/YYWebImage.h>
- #elif __has_include("YYWebImage.h")
- #import "YYWebImage.h"
- #elif __has_include(<YYKit/YYKit.h>)
- #import <YYKit/YYKit.h>
- #elif __has_include("YYKit.h")
- #import "YYKit.h"
- #endif
- @interface HXPreviewLivePhotoView ()<PHLivePhotoViewDelegate, NSURLConnectionDataDelegate>
- @property (strong, nonatomic) PHLivePhotoView *livePhotoView;
- @property (assign, nonatomic) BOOL livePhotoAnimating;
- @property (assign, nonatomic) PHImageRequestID requestID;
- @property (strong, nonatomic) HXCircleProgressView *progressView;
- @property (strong, nonatomic) HXHUD *loadingView;
- @property (strong, nonatomic) AVAssetWriter *writer;
- @property (strong, nonatomic) AVAssetReader *videoReader;
- @property (strong, nonatomic) AVAssetReader *audioReader;
- @property (strong, nonatomic) NSURLSessionDownloadTask *videoTask;
- @property (strong, nonatomic) id imageOperation;
- @property (assign, nonatomic) long long totalLength;
- @property (assign, nonatomic) long long imageCurrentLength;
- @property (assign, nonatomic) long long videoCurrentLength;
- @property (assign, nonatomic) BOOL cacheImage;
- @property (assign, nonatomic) BOOL cacheVideo;
- @end
- @implementation HXPreviewLivePhotoView
- - (instancetype)initWithFrame:(CGRect)frame {
- self = [super initWithFrame:frame];
- if (self) {
- [self addSubview:self.progressView];
- [self addSubview:self.livePhotoView];
- }
- return self;
- }
- - (void)setModel:(HXPhotoModel *)model {
- _model = model;
- if (self.requestID) {
- [[PHImageManager defaultManager] cancelImageRequest:self.requestID];
- [PHLivePhoto cancelLivePhotoRequestWithRequestID:self.requestID];
- self.requestID = -1;
- }
- if (_livePhotoView.livePhoto) {
- // [self.livePhotoView stopPlayback];
- // [self.livePhotoView startPlaybackWithStyle:PHLivePhotoViewPlaybackStyleFull];
- return;
- }
- if (self.model.iCloudRequestID) {
- [[PHImageManager defaultManager] cancelImageRequest:self.model.iCloudRequestID];
- self.model.iCloudRequestID = -1;
- }
- HXWeakSelf
- if (model.type == HXPhotoModelMediaTypeCameraPhoto) {
- if (model.cameraPhotoType == HXPhotoModelMediaTypeCameraPhotoTypeLocalLivePhoto) {
- BOOL hasVideoURL = [HXPhotoTools fileExistsAtLivePhotoVideoURL:self.model.videoURL];
- BOOL hasImageURL = [self imageCacheLocal];
- // BOOL hasImageURL = [HXPhotoTools fileExistsAtLivePhotoImageURL:self.model.imageURL];
- if (!hasVideoURL || !hasImageURL) {
- [self showLoading];
- }
- [self requestLocalLivePhoto];
- }else if (model.cameraPhotoType == HXPhotoModelMediaTypeCameraPhotoTypeNetWorkLivePhoto) {
- self.totalLength = 0;
- self.imageCurrentLength = 0;
- self.videoCurrentLength = 0;
- self.cacheVideo = [HXPhotoTools fileExistsAtVideoURL:model.livePhotoVideoURL];
- #if HasSDWebImage
- HXWeakSelf
- [[SDWebImageManager sharedManager].imageCache queryImageForKey:[[SDWebImageManager sharedManager] cacheKeyForURL:model.networkPhotoUrl] options:SDWebImageQueryMemoryData context:nil completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) {
- if (image) {
- weakSelf.cacheImage = YES;
- }
- if (!weakSelf.cacheVideo || !weakSelf.cacheImage) {
- [weakSelf showLoading];
- }
- [weakSelf getLivePhotoAssetLength];
- }];
- #elif HasYYKitOrWebImage
- HXWeakSelf
- YYWebImageManager *manager = [YYWebImageManager sharedManager];
- [manager.cache getImageForKey:[manager cacheKeyForURL:model.networkPhotoUrl] withType:YYImageCacheTypeAll withBlock:^(UIImage * _Nullable image, YYImageCacheType type) {
- if (image) {
- weakSelf.cacheImage = YES;
- }
- if (!weakSelf.cacheVideo || !weakSelf.cacheImage) {
- [weakSelf showLoading];
- }
- [weakSelf getLivePhotoAssetLength];
- }];
- #endif
- }
- return;
- }
- self.requestID = [self.model requestLivePhotoWithSize:self.model.endImageSize startRequestICloud:^(PHImageRequestID iCloudRequestId, HXPhotoModel *model) {
- if (weakSelf.model != model) return;
- if (weakSelf.model.isICloud) {
- weakSelf.progressView.hidden = NO;
- }
- weakSelf.requestID = iCloudRequestId;
- } progressHandler:^(double progress, HXPhotoModel *model) {
- if (weakSelf.model != model) return;
- if (weakSelf.model.isICloud) {
- weakSelf.progressView.hidden = NO;
- }
- weakSelf.progressView.progress = progress;
- } success:^(PHLivePhoto *livePhoto, HXPhotoModel *model, NSDictionary *info) {
- if (weakSelf.model != model) return;
- if (weakSelf.downloadICloudAssetComplete) {
- weakSelf.downloadICloudAssetComplete();
- }
- weakSelf.livePhotoView.livePhoto = livePhoto;
- if ([HXPhotoCommon photoCommon].livePhotoAutoPlay) {
- [weakSelf.livePhotoView startPlaybackWithStyle:PHLivePhotoViewPlaybackStyleFull];
- }
- } failed:^(NSDictionary *info, HXPhotoModel *model) {
- if (weakSelf.model != model) return;
- weakSelf.progressView.hidden = YES;
- }];
- }
- - (void)getLivePhotoAssetLength {
- if (self.cacheImage && self.cacheVideo) {
- [self downloadLivePhoto];
- return;
- }
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- NSMutableURLRequest *imageURLRequest = [NSMutableURLRequest requestWithURL:self.model.networkPhotoUrl];
- [imageURLRequest setHTTPMethod:@"HEAD"];
- NSHTTPURLResponse *imageResp = nil;
- NSError *imageErr = nil;
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored"-Wdeprecated-declarations"
- [NSURLConnection sendSynchronousRequest:imageURLRequest returningResponse:&imageResp error:&imageErr];
-
- if (self.cacheImage) {
- self.imageCurrentLength = imageResp.expectedContentLength;
- }
- NSMutableURLRequest *videoURLRequest = [NSMutableURLRequest requestWithURL:self.model.livePhotoVideoURL];
- [videoURLRequest setHTTPMethod:@"HEAD"];
-
- NSHTTPURLResponse *videoResp = nil;
- NSError *videoErr = nil;
- [NSURLConnection sendSynchronousRequest:videoURLRequest returningResponse:&videoResp error:&videoErr];
- #pragma clang diagnostic pop
- if (!imageErr && !videoErr) {
- self.totalLength = videoResp.expectedContentLength + imageResp.expectedContentLength;
- }
- if (self.cacheVideo) {
- self.videoCurrentLength = videoResp.expectedContentLength;
- }
- dispatch_async(dispatch_get_main_queue(), ^{
- [self downloadLivePhoto];
- });
- });
- }
- - (void)updateProgress {
- self.progressView.progress = (float)(self.imageCurrentLength + self.videoCurrentLength) / (float)self.totalLength;
- }
- - (void)downloadLivePhoto {
- [self hideLoading];
- if (!self.cacheImage || !self.cacheVideo) {
- [self updateProgress];
- self.progressView.hidden = NO;
- }
- __block BOOL imageDownloadCompletion = NO;
- __block BOOL videoDownloadCompletion = NO;
- HXWeakSelf
- self.imageOperation = [HXPhotoModel requestImageWithURL:self.model.networkPhotoUrl progress:^(NSInteger receivedSize, NSInteger expectedSize) {
- weakSelf.imageCurrentLength = receivedSize;
- [weakSelf updateProgress];
- } completion:^(UIImage * _Nullable image, NSURL * _Nullable url, NSError * _Nullable error) {
- weakSelf.imageOperation = nil;
- dispatch_async(dispatch_get_main_queue(), ^{
- imageDownloadCompletion = YES;
- if (error) {
- [[UIApplication sharedApplication].keyWindow hx_showImageHUDText:[NSBundle hx_localizedStringForKey:@"下载失败,请重试!"]];
- }
- if (image) {
- #if HasSDWebImage
- NSString *cacheKey = [[SDWebImageManager sharedManager] cacheKeyForURL:url];
- NSString *cachePath = [[SDImageCache sharedImageCache] cachePathForKey:cacheKey];
- weakSelf.model.imageURL = [NSURL fileURLWithPath:cachePath];
- #elif HasYYKitOrWebImage
- weakSelf.model.thumbPhoto = image;
- #endif
- if (videoDownloadCompletion) {
- BOOL hasImageURL = [weakSelf imageCacheLocal];
- BOOL hasVideoURL = [HXPhotoTools fileExistsAtLivePhotoVideoURL:weakSelf.model.videoURL];
- if (!hasVideoURL || !hasImageURL) {
- [weakSelf showLoading];
- }
- [weakSelf requestLocalLivePhoto];
- }
- }
- });
- }];
-
- self.videoTask = [[HXPhotoCommon photoCommon] downloadVideoWithURL:self.model.livePhotoVideoURL progress:^(float progress, long long downloadLength, long long totleLength, NSURL * _Nullable videoURL) {
- weakSelf.videoCurrentLength = downloadLength;
- [weakSelf updateProgress];
- } downloadSuccess:^(NSURL * _Nullable filePath, NSURL * _Nullable videoURL) {
- weakSelf.videoTask = nil;
- videoDownloadCompletion = YES;
- weakSelf.model.videoURL = filePath;
- if (imageDownloadCompletion) {
- BOOL hasImageURL = [weakSelf imageCacheLocal];
- BOOL hasVideoURL = [HXPhotoTools fileExistsAtLivePhotoVideoURL:weakSelf.model.videoURL];
- if (!hasVideoURL || !hasImageURL) {
- [weakSelf showLoading];
- }
- [weakSelf requestLocalLivePhoto];
- }
- } downloadFailure:^(NSError * _Nullable error, NSURL * _Nullable videoURL) {
- weakSelf.videoTask = nil;
- videoDownloadCompletion = YES;
- [weakSelf hideLoading];
- [[UIApplication sharedApplication].keyWindow hx_showImageHUDText:@"下载失败!"];
- }];
- }
- - (BOOL)imageCacheLocal {
- NSURL *imageURL;
- if (!self.model.imageURL) {
- NSString *fileName = [self.model.videoURL.lastPathComponent.stringByDeletingPathExtension stringByAppendingString:@"_local_img"];
- fileName = HXDiskCacheFileNameForKey(fileName, NO);
- fileName = [HXPhotoPickerLivePhotoImagesPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.jpg", fileName]];
- imageURL = [NSURL fileURLWithPath:fileName];
- }else {
- imageURL = self.model.imageURL;
- }
- return [HXPhotoTools fileExistsAtLivePhotoImageURL:imageURL];
- }
- - (void)requestLocalLivePhoto {
- self.progressView.hidden = YES;
- HXWeakSelf
- [self.model requestLocalLivePhotoWithReqeustID:^(PHLivePhotoRequestID requestID) {
- weakSelf.requestID = requestID;
- } header:^(AVAssetWriter * _Nullable writer, AVAssetReader * _Nullable videoReader, AVAssetReader * _Nullable audioReader) {
- weakSelf.writer = writer;
- weakSelf.videoReader = videoReader;
- weakSelf.audioReader = audioReader;
- } completion:^(PHLivePhoto * _Nullable livePhoto, HXPhotoModel * _Nullable model, NSDictionary * _Nullable info) {
- weakSelf.writer = nil;
- weakSelf.videoReader = nil;
- weakSelf.audioReader = nil;
- [weakSelf hideLoading];
- if (weakSelf.model != model) return;
- if (!livePhoto) {
- return;
- }
- if (weakSelf.downloadICloudAssetComplete) {
- weakSelf.downloadICloudAssetComplete();
- }
- [weakSelf.livePhotoView stopPlayback];
- weakSelf.livePhotoView.livePhoto = livePhoto;
- if ([HXPhotoCommon photoCommon].livePhotoAutoPlay) {
- [weakSelf.livePhotoView startPlaybackWithStyle:PHLivePhotoViewPlaybackStyleFull];
- }
- }];
- }
- - (void)cancelLivePhoto {
- [self hideLoading];
- if (self.imageOperation) {
- #if HasSDWebImage
- [(SDWebImageCombinedOperation *)self.imageOperation cancel];
- #elif HasYYKitOrWebImage
- [(YYWebImageOperation *)self.imageOperation cancel];
- #endif
- self.imageOperation = nil;
- }
- if (self.videoTask) {
- [self.videoTask cancel];
- self.videoTask = nil;
- }
- if (self.writer) {
- [self.writer cancelWriting];
- self.writer = nil;
- }
- if (self.videoReader) {
- [self.videoReader cancelReading];
- self.videoReader = nil;
- }
- if (self.audioReader) {
- [self.audioReader cancelReading];
- self.audioReader = nil;
- }
- if (self.requestID) {
- if (self.model.type == HXPhotoModelMediaTypeCameraPhoto &&
- (self.model.cameraPhotoType == HXPhotoModelMediaTypeCameraPhotoTypeLocalLivePhoto ||
- self.model.cameraPhotoType == HXPhotoModelMediaTypeCameraPhotoTypeNetWorkLivePhoto)) {
- [PHLivePhoto cancelLivePhotoRequestWithRequestID:self.requestID];
- }else {
- [[PHImageManager defaultManager] cancelImageRequest:self.requestID];
- }
- self.requestID = -1;
- }
- if (!self.stopCancel) {
- self.progressView.hidden = YES;
- self.progressView.progress = 0;
- if (_livePhotoView.livePhoto) {
- [self stopLivePhoto];
- self.livePhotoView.livePhoto = nil;
- }
- }
- self.stopCancel = NO;
- }
- - (void)layoutSubviews {
- [super layoutSubviews];
- if (!CGRectEqualToRect(self.livePhotoView.frame, self.bounds)) {
- self.livePhotoView.frame = self.bounds;
- }
- self.loadingView.hx_centerX = self.hx_w / 2;
- self.loadingView.hx_centerY = self.hx_h / 2;
- self.progressView.hx_centerX = self.hx_w / 2;
- self.progressView.hx_centerY = self.hx_h / 2;
- }
- #pragma mark - < PHLivePhotoViewDelegate >
- - (void)livePhotoView:(PHLivePhotoView *)livePhotoView willBeginPlaybackWithStyle:(PHLivePhotoViewPlaybackStyle)playbackStyle {
- self.livePhotoAnimating = YES;
- }
- - (void)livePhotoView:(PHLivePhotoView *)livePhotoView didEndPlaybackWithStyle:(PHLivePhotoViewPlaybackStyle)playbackStyle {
- if (livePhotoView == _livePhotoView) {
- if ([HXPhotoCommon photoCommon].livePhotoAutoPlay) {
- [livePhotoView startPlaybackWithStyle:PHLivePhotoViewPlaybackStyleFull];
- }
- }
- // [self stopLivePhoto];
- }
- - (void)stopLivePhoto {
- self.livePhotoAnimating = NO;
- [self.livePhotoView stopPlayback];
- }
- - (PHLivePhotoView *)livePhotoView {
- if (!_livePhotoView) {
- _livePhotoView = [[PHLivePhotoView alloc] init];
- _livePhotoView.clipsToBounds = YES;
- _livePhotoView.contentMode = UIViewContentModeScaleAspectFill;
- _livePhotoView.delegate = self;
- }
- return _livePhotoView;
- }
- - (HXCircleProgressView *)progressView {
- if (!_progressView) {
- _progressView = [[HXCircleProgressView alloc] init];
- _progressView.progress = 0;
- _progressView.hidden = YES;
- }
- return _progressView;
- }
- - (HXHUD *)loadingView {
- if (!_loadingView) {
- _loadingView = [[HXHUD alloc] initWithFrame:CGRectMake(0, 0, 95, 95) imageName:nil text:nil];
- [_loadingView showloading];
- }
- return _loadingView;
- }
- - (void)showLoading {
- [self addSubview:self.loadingView];
- }
- - (void)hideLoading {
- [self.loadingView removeFromSuperview];
- }
- @end
|