QNPHAssetResource.m 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. //
  2. // QNPHAssetResource.m
  3. // QiniuSDK
  4. //
  5. // Created by 何舒 on 16/2/14.
  6. // Copyright © 2016年 Qiniu. All rights reserved.
  7. //
  8. #import "QNPHAssetResource.h"
  9. #import <Photos/Photos.h>
  10. #import "QNResponseInfo.h"
  11. #if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000)
  12. enum {
  13. kAMASSETMETADATA_PENDINGREADS = 1,
  14. kAMASSETMETADATA_ALLFINISHED = 0
  15. };
  16. @interface QNPHAssetResource () {
  17. BOOL _hasGotInfo;
  18. }
  19. @property (nonatomic) PHAsset *phAsset;
  20. @property (nonatomic) PHAssetResource *phAssetResource;
  21. @property (nonatomic) int64_t fileSize;
  22. @property (nonatomic) int64_t fileModifyTime;
  23. @property (nonatomic, strong) NSData *assetData;
  24. @property (nonatomic, strong) NSURL *assetURL;
  25. @property (nonatomic, strong) NSLock *lock;
  26. @end
  27. @implementation QNPHAssetResource
  28. - (instancetype)init:(PHAssetResource *)phAssetResource
  29. error:(NSError *__autoreleasing *)error {
  30. if (self = [super init]) {
  31. PHAsset *phasset = [PHAsset fetchAssetsWithBurstIdentifier:self.phAssetResource.assetLocalIdentifier options:nil][0];
  32. NSDate *createTime = phasset.creationDate;
  33. int64_t t = 0;
  34. if (createTime != nil) {
  35. t = [createTime timeIntervalSince1970];
  36. }
  37. _fileModifyTime = t;
  38. _phAssetResource = phAssetResource;
  39. _lock = [[NSLock alloc] init];
  40. [self getInfo];
  41. }
  42. return self;
  43. }
  44. - (NSData *)read:(long)offset
  45. size:(long)size
  46. error:(NSError **)error {
  47. NSData *data = nil;
  48. @try {
  49. [_lock lock];
  50. NSRange subRange = NSMakeRange(offset, size);
  51. if (!self.assetData) {
  52. self.assetData = [self fetchDataFromAsset:self.phAssetResource error:error];
  53. }
  54. data = [self.assetData subdataWithRange:subRange];
  55. } @catch (NSException *exception) {
  56. *error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : exception.reason}];
  57. NSLog(@"read file failed reason: %@ \n%@", exception.reason, exception.callStackSymbols);
  58. } @finally {
  59. [_lock unlock];
  60. }
  61. return data;
  62. }
  63. - (NSData *)readAllWithError:(NSError **)error {
  64. return [self read:0 size:(long)_fileSize error:error];
  65. }
  66. - (void)close {
  67. }
  68. - (NSString *)path {
  69. return self.assetURL.path;
  70. }
  71. - (int64_t)modifyTime {
  72. return _fileModifyTime;
  73. }
  74. - (int64_t)size {
  75. return _fileSize;
  76. }
  77. - (void)getInfo {
  78. if (!_hasGotInfo) {
  79. _hasGotInfo = YES;
  80. NSConditionLock *assetReadLock = [[NSConditionLock alloc] initWithCondition:kAMASSETMETADATA_PENDINGREADS];
  81. NSString *pathToWrite = [NSTemporaryDirectory() stringByAppendingString:self.phAssetResource.originalFilename];
  82. NSURL *localpath = [NSURL fileURLWithPath:pathToWrite];
  83. PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new];
  84. options.networkAccessAllowed = YES;
  85. [[PHAssetResourceManager defaultManager] writeDataForAssetResource:self.phAssetResource toFile:localpath options:options completionHandler:^(NSError *_Nullable error) {
  86. if (error == nil) {
  87. AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:localpath options:nil];
  88. NSNumber *fileSize = nil;
  89. [urlAsset.URL getResourceValue:&fileSize forKey:NSURLFileSizeKey error:nil];
  90. self.fileSize = [fileSize unsignedLongLongValue];
  91. self.assetURL = urlAsset.URL;
  92. self.assetData = [NSData dataWithData:[NSData dataWithContentsOfURL:urlAsset.URL]];
  93. } else {
  94. NSLog(@"%@", error);
  95. }
  96. BOOL blHave = [[NSFileManager defaultManager] fileExistsAtPath:pathToWrite];
  97. if (!blHave) {
  98. return;
  99. } else {
  100. [[NSFileManager defaultManager] removeItemAtPath:pathToWrite error:nil];
  101. }
  102. [assetReadLock lock];
  103. [assetReadLock unlockWithCondition:kAMASSETMETADATA_ALLFINISHED];
  104. }];
  105. [assetReadLock lockWhenCondition:kAMASSETMETADATA_ALLFINISHED];
  106. [assetReadLock unlock];
  107. assetReadLock = nil;
  108. }
  109. }
  110. - (NSData *)fetchDataFromAsset:(PHAssetResource *)videoResource error:(NSError **)err {
  111. __block NSData *tmpData = [NSData data];
  112. __block NSError *innerError = *err;
  113. NSConditionLock *assetReadLock = [[NSConditionLock alloc] initWithCondition:kAMASSETMETADATA_PENDINGREADS];
  114. NSString *pathToWrite = [NSTemporaryDirectory() stringByAppendingString:videoResource.originalFilename];
  115. NSURL *localpath = [NSURL fileURLWithPath:pathToWrite];
  116. PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new];
  117. options.networkAccessAllowed = YES;
  118. [[PHAssetResourceManager defaultManager] writeDataForAssetResource:videoResource toFile:localpath options:options completionHandler:^(NSError *_Nullable error) {
  119. if (error == nil) {
  120. AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:localpath options:nil];
  121. NSData *videoData = [NSData dataWithContentsOfURL:urlAsset.URL];
  122. tmpData = [NSData dataWithData:videoData];
  123. } else {
  124. innerError = error;
  125. }
  126. BOOL blHave = [[NSFileManager defaultManager] fileExistsAtPath:pathToWrite];
  127. if (!blHave) {
  128. return;
  129. } else {
  130. [[NSFileManager defaultManager] removeItemAtPath:pathToWrite error:nil];
  131. }
  132. [assetReadLock lock];
  133. [assetReadLock unlockWithCondition:kAMASSETMETADATA_ALLFINISHED];
  134. }];
  135. [assetReadLock lockWhenCondition:kAMASSETMETADATA_ALLFINISHED];
  136. [assetReadLock unlock];
  137. assetReadLock = nil;
  138. return tmpData;
  139. }
  140. @end
  141. #endif