美文网首页
视频播放器封装支持下载、缓存

视频播放器封装支持下载、缓存

作者: 鬼才冯三郎 | 来源:发表于2023-10-29 11:44 被阅读0次

我们实现了AVAssetResourceLoaderDelegate协议来拦截视频加载请求,并将其缓存起来。通过在resourceLoader:shouldWaitForLoadingOfRequestedResource:方法中处理请求,我们可以检查是否已经存在缓存数据,如果是,则直接使用缓存数据,否则发起下载请求。

在startDataRequest方法中,我们使用NSURLSessionDataTask来异步下载视频数据,并在下载完成后// Player.h

import <UIKit/UIKit.h>

import <AVFoundation/AVFoundation.h>

@interface Player : NSObject<AVAssetResourceLoaderDelegate>

@property (nonatomic, strong) NSURL *videoURL;
@property (nonatomic, strong) AVPlayer *player;
@property (nonatomic, strong) AVPlayerLayer *playerLayer;

  • (instancetype)initWithVideoURL:(NSURL*)videoURL;
  • (void)play;
  • (void)pause;
  • (void)stop;
  • (void)downloadVideoWithCompletion:(void (^)(BOOL success, NSError *error))completion;

@end

// Player.m

import "Player.h"

@implementation Player {
AVAssetResourceLoadingRequest *_loadingRequest;
NSMutableData *_cachedData;
}

  • (instancetype)initWithVideoURL:(NSURL*)videoURL {
    self = [super init];
    if (self) {
    self.videoURL = videoURL;
    [self setupPlayer];
    }
    return self;
    }

  • (void)setupPlayer {
    AVURLAsset asset = [AVURLAsset URLAssetWithURL:self.videoURL options:nil];
    [asset.resourceLoader setDelegate:self queue:dispatch_get_main_queue()];
    AVPlayerItem
    playerItem = [AVPlayerItem playerItemWithAsset:asset];
    self.player = [AVPlayer playerWithPlayerItem:playerItem];
    self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
    self.playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
    }

  • (void)play {
    [self.player play];
    }

  • (void)pause {
    [self.player pause];
    }

  • (void)stop {
    [self.player pause];
    [self.player seekToTime:kCMTimeZero];
    }

  • (void)downloadVideoWithCompletion:(void (^)(BOOL success, NSError *error))completion {
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:self.videoURL completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    if (error) {
    completion(NO, error);
    } else {
    NSString *documentDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
    NSString *destinationPath = [documentDirectory stringByAppendingPathComponent:@"downloadedVideo.mp4"];
    NSURL *destinationURL = [NSURL fileURLWithPath:destinationPath];

          NSError *moveError = nil;
          [[NSFileManager defaultManager] moveItemAtURL:location toURL:destinationURL error:&moveError];
          
          if (moveError) {
              completion(NO, moveError);
          } else {
              completion(YES, nil);
          }
      }
    

    }];
    [downloadTask resume];
    }

pragma mark - AVAssetResourceLoaderDelegate

  • (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest {
    if (!_loadingRequest) {
    NSURLComponents *urlComponents = [[NSURLComponents alloc] initWithURL:self.videoURL resolvingAgainstBaseURL:NO];
    urlComponents.scheme = @"cached";
    NSURL *customURL = [urlComponents URL];

      if (customURL && _cachedData) {
          NSData *requestedData = [_cachedData copy];
          [self processRequest:loadingRequest withCachedData:requestedData];
          return YES;
      } else {
          _loadingRequest = loadingRequest;
          [self startDataRequest];
      }
    

    } else {
    // Another loading request is already in progress, so we cannot process the new request concurrently
    [loadingRequest finishLoadingWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:nil]];
    return YES;
    }
    return YES;
    }

  • (void)startDataRequest {
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:self.videoURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    if (error) {
    [_loadingRequest finishLoadingWithError:error];
    } else {
    [_loadingRequest
    dataRequestDidReceiveResponse:[[NSHTTPURLResponse alloc] initWithURL:_loadingRequest.request.URL statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:response.allHeaderFields]];
    [_loadingRequest.dataRequest
    respondWithData:data];
    [_loadingRequest finishLoading];
    _loadingRequest = nil;

          // Cache the loaded data
          _cachedData = [NSMutableData dataWithData:data];
      }
    

    }];
    [dataTask resume];
    }

  • (void)processRequest:(AVAssetResourceLoadingRequest *)loadingRequest withCachedData:(NSData *)cachedData {
    [loadingRequest
    dataRequestDidReceiveResponse:[[NSHTTPURLResponse alloc] initWithURL:loadingRequest.request.URL statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:nil]];

    NSUInteger offset = (NSUInteger)loadingRequest.dataRequest.requestedOffset;
    NSUInteger length = (NSUInteger)loadingRequest.dataRequest.requestedLength;
    NSRange requestedRange = NSMakeRange(offset, length);
    NSData *requestedData = [cachedData subdataWithRange:requestedRange];

    [loadingRequest.dataRequest respondWithData:requestedData];
    [loadingRequest finishLoading];
    }

@end

相关文章

网友评论

      本文标题:视频播放器封装支持下载、缓存

      本文链接:https://www.haomeiwen.com/subject/rbhvidtx.html