ios – AVPlayer使用资源加载器委托停止大型视频文件

ios – AVPlayer使用资源加载器委托停止大型视频文件,第1张

概述我正在使用 this approach保存视频文件的AVPlayer的缓冲区数据.在这个问题 Saving buffer data of AVPlayer中找到答案. iPhone和iPad – iOS 8.1.3 我做了必要的更改,播放视频,它的工作非常好,除非我尝试播放一个很长的视频(11-12分钟长,大约85mb),视频将在连接完成加载后大约4分钟停止.我收到一个playBufferEmpt 我正在使用 this approach保存视频文件的AVPlayer的缓冲区数据.在这个问题 Saving buffer data of AVPlayer中找到答案.

iPhone和iPad – iOS 8.1.3

我做了必要的更改,播放视频,它的工作非常好,除非我尝试播放一个很长的视频(11-12分钟长,大约85mb),视频将在连接完成加载后大约4分钟停止.我收到一个playBufferEmpty和播放器项目停止通知的事件.

这是代码的要点

vIEwController.m@property (nonatomic,strong) NSMutableData *vIDeoData;@property (nonatomic,strong) NSURLConnection *connection;@property (nonatomic,strong) AVURLAsset *vIDAsset;@property (nonatomic,strong) AVPlayerItem *playerItem;@property (nonatomic,strong) AVPlayerLayer *avlayer;@property (nonatomic,strong) NShttpURLResponse *response;@property (nonatomic,strong) NSMutableArray *pendingRequests;/**    Startup a VIDeo */- (voID)startVIDeo{    self.vIDAsset = [AVURLAsset URLAssetWithURL:[self vIDeoURLWithCustomScheme:@"streaming"] options:nil];    [self.vIDAsset.resourceLoader setDelegate:self queue:dispatch_get_main_queue()];    self.pendingRequests = [NSMutableArray array];    // Init Player Item    self.playerItem = [AVPlayerItem playerItemWithAsset:self.vIDAsset];    [self.playerItem addobserver:self forKeyPath:@"status" options:NSkeyvalueObservingOptionNew context:NulL];    self.player = [[AVPlayer alloc] initWithPlayerItem:self.playerItem];    // Init a vIDeo Layer    self.avlayer = [AVPlayerLayer playerLayerWithPlayer:self.player];    [self.avlayer setFrame:self.vIEw.frame];    [self.vIEw.layer addSublayer:self.avlayer];}- (NSURL *)getRemoteVIDeoURL{    Nsstring *urlString = [@"http://path/to/your/long.mp4"];    return [NSURL URLWithString:urlString];}- (NSURL *)vIDeoURLWithCustomScheme:(Nsstring *)scheme{    NSURLComponents *components = [[NSURLComponents alloc] initWithURL:[self getRemoteVIDeoURL] resolvingAgainstBaseURL:NO];    components.scheme = scheme;    return [components URL];}/**    NSURLConnection Delegate Methods */- (voID)connection:(NSURLConnection *)connection dIDReceiveResponse:(NSURLResponse *)response{    NSLog(@"dIDReceiveResponse");    self.vIDeoData = [NSMutableData data];    self.response = (NShttpURLResponse *)response;    [self processpendingRequests];}- (voID)connection:(NSURLConnection *)connection dIDReceiveData:(NSData *)data{    NSLog(@"Received Data - appending to vIDeo & processing request");    [self.vIDeoData appendData:data];    [self processpendingRequests];}- (voID)connectionDIDFinishLoading:(NSURLConnection *)connection{    NSLog(@"connectionDIDFinishLoading::Writetofile");    [self processpendingRequests];    [self.vIDeoData writetofile:[self getVIDeoCachePath:self.vIDSelected] atomically:YES];}/**    AVURLAsset resource loader methods */- (voID)processpendingRequests{    NSMutableArray *requestsCompleted = [NSMutableArray array];    for (AVAssetResourceLoadingRequest *loadingRequest in self.pendingRequests)    {        [self fillinContentinformation:loadingRequest.contentinformationRequest];        BOol dIDRespondCompletely = [self responDWithDataForRequest:loadingRequest.dataRequest];        if (dIDRespondCompletely)        {            [requestsCompleted addobject:loadingRequest];            [loadingRequest finishLoading];        }    }    [self.pendingRequests removeObjectsInArray:requestsCompleted];}- (voID)fillinContentinformation:(AVAssetResourceLoadingContentinformationRequest *)contentinformationRequest{    if (contentinformationRequest == nil || self.response == nil)    {        return;    }    Nsstring *mimeType = [self.response MIMEType];    CFStringRef ContentType = UTTypeCreatePreferredIDentifIErForTag(kUTTagClassMIMEType,(__brIDge CFStringRef)(mimeType),NulL);    contentinformationRequest.byterangeAccessSupported = YES;    contentinformationRequest.ContentType = CFBrIDgingrelease(ContentType);    contentinformationRequest.contentLength = [self.response expectedContentLength];}- (BOol)responDWithDataForRequest:(AVAssetResourceLoadingDataRequest *)dataRequest{    long long startOffset = dataRequest.requestedOffset;    if (dataRequest.currentOffset != 0)    {        startOffset = dataRequest.currentOffset;    }    // Don't have any data at all for this request    if (self.vIDeoData.length < startOffset)    {        NSLog(@"NO DATA FOR REQUEST");        return NO;    }    // This is the total data we have from startOffset to whatever has been downloaded so far    NSUInteger unreadBytes = self.vIDeoData.length - (NSUInteger)startOffset;    // Respond with whatever is available if we can't satisfy the request fully yet    NSUInteger numberOfBytesToResponDWith = MIN((NSUInteger)dataRequest.requestedLength,unreadBytes);    [dataRequest responDWithData:[self.vIDeoData subdataWithRange:NSMakeRange((NSUInteger)startOffset,numberOfBytesToResponDWith)]];    long long endOffset = startOffset + dataRequest.requestedLength;    BOol dIDRespondFully = self.vIDeoData.length >= endOffset;    return dIDRespondFully;}- (BOol)resourceLoader:(AVAssetResourceLoader *)resourceLoader shoulDWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest{    if (self.connection == nil)    {        NSURL *interceptedURL = [loadingRequest.request URL];        NSURLComponents *actualURLComponents = [[NSURLComponents alloc] initWithURL:interceptedURL resolvingAgainstBaseURL:NO];        actualURLComponents.scheme = @"http";        NSURLRequest *request = [NSURLRequest requestWithURL:[actualURLComponents URL]];        self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];        [self.connection setDelegateQueue:[NSOperationQueue mainQueue]];        [self.connection start];    }    [self.pendingRequests addobject:loadingRequest];    return YES;}- (voID)resourceLoader:(AVAssetResourceLoader *)resourceLoader dIDCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest{    NSLog(@"dIDCancelLoadingRequest");    [self.pendingRequests removeObject:loadingRequest];}/**    KVO */- (voID)observeValueForKeyPath:(Nsstring *)keyPath ofObject:(ID)object change:(NSDictionary *)change context:(voID *)context{    if (context == StatusObservationContext){    AVPlayerStatus status = [[change objectForKey:NSkeyvalueChangeNewKey] integerValue];    if (status == AVPlayerStatusReadytoplay) {        [self initHud];        [self play:NO];    } else if (status == AVPlayerStatusFailed)    {        NSLog(@"ERROR::AVPlayerStatusFailed");    } else if (status == AVPlayerItemStatusUnkNown)    {        NSLog(@"ERROR::AVPlayerItemStatusUnkNown");    }} else if (context == CurrentItemObservationContext) {} else if (context == RateObservationContext) {} else if (context == BufferObservationContext){} else if (context == playbacklikelyToKeepUp) {    if (self.player.currentItem.playbacklikelyToKeepUp)    }} else if (context == playbackBufferEmpty) {    if (self.player.currentItem.playbackBufferEmpty)    {        NSLog(@"VIDeo Asset is playable: %d",self.vIDeoAsset.isPlayable);        NSLog(@"Player Item Status: %ld",self.player.currentItem.status);        NSLog(@"Connection Request: %@",self.connection.currentRequest);        NSLog(@"VIDeo Data: %lu",(unsigned long)self.vIDeoData.length);    }} else if(context == playbackBufferFull) {} else {    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];}}

问题似乎是在连接完成加载后的某个时间,播放器项目缓冲区变空.我目前的想法是,当连接完成加载并弄坏了playerItem缓冲区时,正在释放某些东西.

然而,当缓冲区为空时,播放器的状态是好的,视频资源可以播放,视频数据是好的

如果我通过查询来限制WiFi,并减慢连接速度,只要连接在视频结束后几分钟内没有完成加载,视频就会播放.

如果我在完成的加载事件中设置了连接,那么当shoulDWaitForLoadingOfRequestedResource再次触发时,资源加载器将启动一个新的连接.在这种情况下,装载将重新开始,视频将继续播放.

我应该提到,如果我将其作为普通的http网址资源播放,这个长长的视频播放效果很好,并且在保存到设备并从那里加载之后也会播放.

解决方法 当资源加载器委托启动NSURLConnection时,连接会将NSData保存到待处理的请求并处理它们.当连接完成加载时,资源加载器重新负责处理加载请求.该代码将加载请求添加到挂起的请求数组中,但问题是它们未被处理.将方法更改为以下功能,它的工作原理.
//AVAssetResourceLoader- (BOol)resourceLoader:(AVAssetResourceLoader *)resourceLoader shoulDWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest{    if(isLoadingComplete == YES)    {        //NSLog(@"LOADING WAS COMPLETE");        [self.pendingRequests addobject:loadingRequest];        [self processpendingRequests];        return YES;    }    if (self.connection == nil)    {        NSURL *interceptedURL = [loadingRequest.request URL];        NSURLComponents *actualURLComponents = [[NSURLComponents alloc] initWithURL:interceptedURL resolvingAgainstBaseURL:NO];        actualURLComponents.scheme = @"http";        self.request = [NSURLRequest requestWithURL:[actualURLComponents URL]];        self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];        [self.connection setDelegateQueue:[NSOperationQueue mainQueue]];        isLoadingComplete = NO;        [self.connection start];    }    [self.pendingRequests addobject:loadingRequest];    return YES;}
总结

以上是内存溢出为你收集整理的ios – AVPlayer使用资源加载器委托停止大型视频文件全部内容,希望文章能够帮你解决ios – AVPlayer使用资源加载器委托停止大型视频文件所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1111391.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-29
下一篇2022-05-29

发表评论

登录后才能评论

评论列表(0条)

    保存