当前位置: 首页 > news >正文

手机微信网站凡科网站后台在哪里.

手机微信网站,凡科网站后台在哪里.,wordpress底部小工具栏,低价货源网站文章目录 IdiotAVplayer 实现视频切片缓存一 iOS视频边下边播原理一 分片下载的实现1 分片下载的思路2 IdiotAVplayer 实现架构 三 IdiotAVplayer 代码解析IdiotPlayerIdiotResourceLoaderIdiotDownLoader IdiotAVplayer 实现视频切片缓存 一 iOS视频边下边播原理 初始化AVUR…

文章目录

  • IdiotAVplayer 实现视频切片缓存
    • 一 iOS视频边下边播原理
    • 一 分片下载的实现
      • 1 分片下载的思路
      • 2 IdiotAVplayer 实现架构
    • 三 IdiotAVplayer 代码解析
      • IdiotPlayer
      • IdiotResourceLoader
      • IdiotDownLoader

IdiotAVplayer 实现视频切片缓存

一 iOS视频边下边播原理

初始化AVURLAsset 的时候,将资源链接中的http替换成其他字符串,并且将AVURLAsset的resourceLoader 设置代理对象,然后该代理对象实现AVAssetResourceLoaderDelegate 的代理方法

#pragma mark - AVAssetResourceLoaderDelegate
- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest {return YES;
}- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest {
}

在代理方法中实现资源的下载,保存, 并将下载好的资源塞给 loadingRequest, 实现视频的播放

一 分片下载的实现

简单的实现方案,就是将一个视频从头开始下载,或者从当前下载到的位置开始下载,然后下载到结束 这种方案对于短视频是可以的,因为短视频总共也没有多大,即使我们快进,从头下载开始到快进的地方也没有多少流量,用户体验影响不大,但是仍然浪费了中间的流量。
如果一个视频比较大,用户进行快进操作的话,从开头下载到用户快进的地方需要的时间很长,这时候,如果能根据用户快进的进度,根据用户的需要进行资源下载,那就是一个好的方案了。

1 分片下载的思路

步骤
1 首先根据链接获取本地资源
2 根据获取到的本地资源和视频请求request对比,计算需要新下载的资源 片段。
3 将本地的资源或者下载好的资源分片塞给请求对象request

2 IdiotAVplayer 实现架构

IdiotAVPlayer 负责实现视频播放功能

IdiotResourceLoader
负责实现
AVAssetResourceLoaderDelegate代理 方法,
负责将数据塞给AVAssetResourceLoadingRequest 请求,并管理AVAssetResourceLoadingRequest 请求,添加,移除,塞数据,快进的处理

IdiotDownLoader 负责 资源片段的获取,需要下载的片段的计算
NSURLSessionDelegate 代理方法的实现,并将下载好的数据传给IdiotResourceLoader, 还负责在读取本地数据的时候,将占用内存较大的视频资源分片读取到内存中传给 IdiotResourceLoader,避免造成因为资源较大而产生的内存撑爆问题

IdiotFileManager 负责管理下载的资源

三 IdiotAVplayer 代码解析

创建播放器,并设置resouceLoader代理

IdiotPlayer

    _resourceLoader = [[IdiotResourceLoader alloc] init];_resourceLoader.delegate = self;AVURLAsset * playerAsset = [AVURLAsset URLAssetWithURL:[_currentUrl idiotSchemeURL] options:nil];[playerAsset.resourceLoader setDelegate:_resourceLoader queue:_queue];_playerItem = [AVPlayerItem playerItemWithAsset:playerAsset];

IdiotResourceLoader

- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest {[self addLoadingRequest:loadingRequest];DLogDebug(@"loadingRequest == %@",loadingRequest)return YES;
}- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest {[self removeLoadingRequest:loadingRequest];
}- (void)removeLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest {dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);NSArray * temptaskList = [NSArray arrayWithArray:self.taskList];dispatch_semaphore_signal(semaphore);IdiotResourceTask * deleteTask = nil;for (IdiotResourceTask * task in temptaskList) {if ([task.loadingRequest isEqual:loadingRequest]) {deleteTask = task;break;}}if (deleteTask) {dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);[self.taskList removeObject:deleteTask];dispatch_semaphore_signal(semaphore);}}- (void)addLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest {if (self.currentResource) {if (loadingRequest.dataRequest.requestedOffset >= self.currentResource.requestOffset &&loadingRequest.dataRequest.requestedOffset <= self.currentResource.requestOffset + self.currentResource.cacheLength) {IdiotResourceTask * task = [[IdiotResourceTask alloc] init];task.loadingRequest = loadingRequest;task.resource = self.currentResource;dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);[self.taskList addObject:task];dispatch_semaphore_signal(semaphore);[self processRequestList];}else{if (self.seek) {[self newTaskWithLoadingRequest:loadingRequest];}else{IdiotResourceTask * task = [[IdiotResourceTask alloc] init];task.loadingRequest = loadingRequest;task.resource = self.currentResource;NSLog(@"哈哈哈哈哈啊哈哈这里这里这里添加22222 %lld  %lld %p\n", loadingRequest.dataRequest.requestedOffset, loadingRequest.dataRequest.currentOffset, task);dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);[self.taskList addObject:task];dispatch_semaphore_signal(semaphore);}}}else {[self newTaskWithLoadingRequest:loadingRequest];}
}- (void)newTaskWithLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest {long long fileLength = 0;if (self.currentResource) {fileLength = self.currentResource.fileLength;self.currentResource.cancel = YES;}IdiotResource * resource = [[IdiotResource alloc] init];resource.requestURL = loadingRequest.request.URL;resource.requestOffset = loadingRequest.dataRequest.requestedOffset;resource.resourceType = IdiotResourceTypeTask;if (fileLength > 0) {resource.fileLength = fileLength;}IdiotResourceTask * task = [[IdiotResourceTask alloc] init];task.loadingRequest = loadingRequest;task.resource = resource;self.currentResource = resource;dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);[self.taskList addObject:task];dispatch_semaphore_signal(semaphore);printf("哈哈哈这里事创建的这里事创建的%lld  %lld %lld  %p %p\n", resource.requestOffset, loadingRequest.dataRequest.requestedOffset, loadingRequest.dataRequest.currentOffset, loadingRequest, task);[IdiotDownLoader share].delegate = self;[[IdiotDownLoader share] start:self.currentResource];self.seek = NO;
}- (void)stopResourceLoader{[[IdiotDownLoader share] cancel];
}- (void)processRequestList {@synchronized (self) {dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);NSArray * temptaskList = [NSArray arrayWithArray:self.taskList];dispatch_semaphore_signal(semaphore);for (IdiotResourceTask * task in temptaskList) {NSInvocationOperation * invoke = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(finishLoadingWithLoadingRequest:) object:task];[_playQueue addOperation:invoke];}}
}- (void)finishLoadingWithLoadingRequest:(IdiotResourceTask *)task {//填充信息task.loadingRequest.contentInformationRequest.contentType = @"video/mp4";task.loadingRequest.contentInformationRequest.byteRangeAccessSupported = YES;task.loadingRequest.contentInformationRequest.contentLength = task.resource.fileLength;if (task.resource.fileLength <= 0) {DLogDebug(@"requestTask.fileLength <= 0");}//读文件,填充数据long long cacheLength = task.resource.cacheLength;long long requestedOffset = task.loadingRequest.dataRequest.requestedOffset;if (task.loadingRequest.dataRequest.currentOffset != 0) {requestedOffset = task.loadingRequest.dataRequest.currentOffset;}printf("哈哈哈1111执行执行执行%lld点 %lld 一 %lld %p  %p\n", task.loadingRequest.dataRequest.requestedOffset,task.loadingRequest.dataRequest.currentOffset, task.resource.requestOffset, task.loadingRequest, task);printf("哈哈哈数量数量%ld\n", self.taskList.count);for (IdiotResourceTask *task1 in self.taskList) {printf("哈哈哈啦啊啦这里这里数组里的%p %lld\n",task1, task.resource.requestOffset);}if (requestedOffset < task.resource.requestOffset) {printf("哈哈哈1111返回%lld点 %lld 一 %lld %p  %p\n", task.loadingRequest.dataRequest.requestedOffset,task.loadingRequest.dataRequest.currentOffset, task.resource.requestOffset, task.loadingRequest, task);return;}long long paddingOffset = requestedOffset - task.resource.requestOffset;long long canReadLength = cacheLength - paddingOffset;printf("哈哈哈能获取到的能获取到的%lld \n", canReadLength);if (canReadLength <= 0) {printf("哈哈哈返回222222 %lld\n", canReadLength);return;}long long respondLength = MIN(canReadLength, task.loadingRequest.dataRequest.requestedLength);NSFileHandle * handle = [IdiotFileManager fileHandleForReadingAtPath:task.resource.cachePath];[handle seekToFileOffset:paddingOffset];[task.loadingRequest.dataRequest respondWithData:[handle readDataOfLength:[[NSNumber numberWithLongLong:respondLength] unsignedIntegerValue]]];printf("哈哈哈匹配到匹配到%lld \n",respondLength);[handle closeFile];//如果完全响应了所需要的数据,则完成long long nowendOffset = requestedOffset + canReadLength;long long reqEndOffset = task.loadingRequest.dataRequest.requestedOffset + task.loadingRequest.dataRequest.requestedLength;printf("哈哈哈差别差别%lld\n",reqEndOffset - nowendOffset);if (nowendOffset >= reqEndOffset) {[task.loadingRequest finishLoading];printf("哈哈哈移除移除移除%lld %lld\n", nowendOffset, reqEndOffset);[self removeLoadingRequest:task.loadingRequest];return;}}#pragma mark - DownLoaderDataDelegate
- (void)didReceiveData:(IdiotDownLoader *__weak)downLoader{[self processRequestList];if (self.delegate&&[self.delegate respondsToSelector:@selector(didCacheProgressChange:)]) {__weak typeof(self) weakself = self;dispatch_async(dispatch_get_main_queue(), ^{__strong typeof(weakself) strongself = weakself;NSMutableArray * caches = [downLoader.resources mutableCopy];[caches addObject:self.currentResource];[strongself.delegate didCacheProgressChange:caches];});}}

下面单独介绍各个方法的实现

    if (self.currentResource) {if (loadingRequest.dataRequest.requestedOffset >= self.currentResource.requestOffset &&loadingRequest.dataRequest.requestedOffset <= self.currentResource.requestOffset + self.currentResource.cacheLength) {IdiotResourceTask * task = [[IdiotResourceTask alloc] init];task.loadingRequest = loadingRequest;task.resource = self.currentResource;dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);[self.taskList addObject:task];dispatch_semaphore_signal(semaphore);[self processRequestList];}else{if (self.seek) {[self newTaskWithLoadingRequest:loadingRequest];}else{IdiotResourceTask * task = [[IdiotResourceTask alloc] init];task.loadingRequest = loadingRequest;task.resource = self.currentResource;dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);[self.taskList addObject:task];dispatch_semaphore_signal(semaphore);}}}else {[self newTaskWithLoadingRequest:loadingRequest];}
}

上面方法中,的判断条件 self.currentResource 说明执行过newTaskWithLoadingRequest 方法了,因为在该方法中设置了self.currentResource,说明就不是第一次执行addLoadingRequest 添加request了,loadingRequest.dataRequest.requestedOffset >= self.currentResource.requestOffset &&
loadingRequest.dataRequest.requestedOffset <= self.currentResource.requestOffset + self.currentResource.cacheLength 该判断条件说明
新请求的offset 是大于当前的offset, 但是小于当前的offset + cachelength ,说明
当前的的本地资源是有一部分是可以塞给当前的 request的 ,所以在创建了新的任务task的同时,还执行了 [self processRequestList];
方法。下面的 else中 if (self.seek) 说明当前的request是因为用户拖拽进度条触发的,所以要重新创建一个source ,因为一个拖拽就会引起一个不连续的下载片段,而在IdiotAvplayer的设计中,每一个资源片段都要有一个resouce,
所以要执行newTaskWithLoadingRequest 方法
else说明不是拖拽的,则直接添加新的任务即可,等到新的下载好的资源到来,就会去塞给新添加的请求,而新的下载是不会停止的,直到到达资源的最后。


- (void)finishLoadingWithLoadingRequest:(IdiotResourceTask *)task {//填充信息task.loadingRequest.contentInformationRequest.contentType = @"video/mp4";task.loadingRequest.contentInformationRequest.byteRangeAccessSupported = YES;task.loadingRequest.contentInformationRequest.contentLength = task.resource.fileLength;if (task.resource.fileLength <= 0) {DLogDebug(@"requestTask.fileLength <= 0");}//读文件,填充数据long long cacheLength = task.resource.cacheLength;long long requestedOffset = task.loadingRequest.dataRequest.requestedOffset;if (task.loadingRequest.dataRequest.currentOffset != 0) {requestedOffset = task.loadingRequest.dataRequest.currentOffset;}if (requestedOffset < task.resource.requestOffset) {/*task.resource 是第一次播放或者拖拽才会创建的对象,其 requestOffset就是对应的那次请求的offset,这里的判断条件 requestedOffset < task.resource.requestOffset 说明 该request是 创建 resouce 之前的request,那么该resouce 对应的资源中满足该request,所以就返回*/  return;}long long paddingOffset = requestedOffset - task.resource.requestOffset;long long canReadLength = cacheLength - paddingOffset;if (canReadLength <= 0) {如果该resouce offset+ resouce的资源长度,仍然小与request 的offset,说明该资源完全在request的前面,无法满足该request,返回return;}long long respondLength = MIN(canReadLength, task.loadingRequest.dataRequest.requestedLength);NSFileHandle * handle = [IdiotFileManager fileHandleForReadingAtPath:task.resource.cachePath];[handle seekToFileOffset:paddingOffset];[task.loadingRequest.dataRequest respondWithData:[handle readDataOfLength:[[NSNumber numberWithLongLong:respondLength] unsignedIntegerValue]]];[handle closeFile];//如果完全响应了所需要的数据,则完成long long nowendOffset = requestedOffset + canReadLength;long long reqEndOffset = task.loadingRequest.dataRequest.requestedOffset + task.loadingRequest.dataRequest.requestedLength;if (nowendOffset >= reqEndOffset) {[task.loadingRequest finishLoading];[self removeLoadingRequest:task.loadingRequest];return;}}

如下图,分片缓存的资源在沙盒中的保存形式,是根据offset 分别保存的
请添加图片描述

IdiotDownLoader

- (void)start:(IdiotResource *)task {if (self.currentDataTask) {[self.currentDataTask cancel];}[self.taskDic setObject:task forKey:[NSString stringWithFormat:@"%zd",task.requestOffset]];//获取本地资源BOOL refresh = NO;while (!self.writing&&!refresh) {self.resources = [IdiotFileManager getResourceWithUrl:task.requestURL];refresh = YES;}IdiotResource * resource = nil;//找出对应的资源if (!self.resources.count) {//本地无资源resource = [[IdiotResource alloc] init];resource.requestURL = task.requestURL;resource.requestOffset = task.requestOffset;resource.fileLength = task.fileLength;resource.cachePath = task.cachePath;resource.cacheLength = 0;resource.resourceType = IdiotResourceTypeNet;//网络资源[self.resources addObject:resource];}else{//本地有资源for (IdiotResource * obj in self.resources) {if (task.requestOffset >= obj.requestOffset&&task.requestOffset < obj.requestOffset+obj.cacheLength) {/*该判断条件说明当前任务offset比获取的本地分片资源offset大,比本地分片资源offset+cachelength小,在本地资源中间,有重合的地方*/resource = obj;break;}}if (task.requestOffset > resource.requestOffset&&resource.resourceType == IdiotResourceTypeNet) {/*该resouce 是从上面的判断条件中获取的该判断说明当前任务比获取到的本地resouce offset大,并且是网路请求资源,说明本地没有资源,需要重新下载,这里新建一个IdiotResource,并且设置offset=task.offset就是为了从当前任务的offset开始下载,否则会中本得resouce 的offset开始下载,这样就会导致下载的比我们需要的多,并且用户会有一个卡住的体验,因为下载的不是用户需要的offset,这里这样写,保证下载的offset就是用户需要的,并且避免流量浪费  */long long adjustCacheLength = task.requestOffset - resource.requestOffset;IdiotResource * net = [[IdiotResource alloc] init];net.requestURL = task.requestURL;net.requestOffset = task.requestOffset;net.fileLength = task.fileLength;net.cachePath = task.cachePath;net.cacheLength = resource.cacheLength - adjustCacheLength;net.resourceType = IdiotResourceTypeNet;//网络资源resource.cacheLength = adjustCacheLength;NSInteger index = [self.resources indexOfObject:resource]+1;[self.resources insertObject:net atIndex:index];resource = net;}}self.currentResource = resource;[self fetchDataWith:task Resource:self.currentResource];}
- (void)fetchFromLocal:(IdiotResource *)sliceRequest withResource:(IdiotResource *)resource{if (sliceRequest.requestOffset == resource.requestOffset) {sliceRequest.cachePath = resource.cachePath;sliceRequest.fileLength = resource.fileLength;sliceRequest.cacheLength = resource.cacheLength;//直接开始下一个资源获取if (self.delegate && [self.delegate respondsToSelector:@selector(didReceiveData:)]) {[self.delegate didReceiveData:self];}[self willNextResource:sliceRequest];return;}NSFileHandle * readHandle = [IdiotFileManager fileHandleForReadingAtPath:resource.cachePath];unsigned long long seekOffset = sliceRequest.requestOffset < resource.requestOffset?0:sliceRequest.requestOffset-resource.requestOffset;[readHandle seekToFileOffset:seekOffset];//文件过大可分次读取long long canReadLength = resource.cacheLength-seekOffset;NSUInteger bufferLength = 5242880; //长度大于5M分次返回数据/*如果本地资源比较大,就分片塞数据,如果一下将整个资源读取到内存中,就会造成内存撑爆,导致严重的卡顿*/while (canReadLength >= bufferLength) {//长度大于1M分次返回数据canReadLength -= bufferLength;NSData * responseData = [readHandle readDataOfLength:bufferLength];[self didReceiveLocalData:responseData requestTask:sliceRequest complete:canReadLength==0?YES:NO];}if (canReadLength != 0) {NSData * responseData = [readHandle readDataOfLength:[[NSNumber numberWithLongLong:canReadLength] unsignedIntegerValue]];[readHandle closeFile];[self didReceiveLocalData:responseData requestTask:sliceRequest complete:YES];}else{[readHandle closeFile];}}
http://www.yayakq.cn/news/170079/

相关文章:

  • 上门做睫毛哪个网站南通网站建设解决方案
  • 湖北高端网站建设苏州做网站建设
  • 请问哪里可以做网站恶意镜像网站程序
  • 腾虎广州网站建设wordpress设置语言
  • 网站建设内容模板服装设计自学
  • 怎么样做个网站深圳做网站服务商
  • 怎么做一个免费的网站seo网站关键词优化报价
  • 海南省建设网站网站的建设目标是什么意思
  • 礼信堂 网站开发最新发布的手机有哪些
  • 珠海十大网站建设公司哪家好wordpress数据库乱码
  • 如何做推广麦当劳的网站泰和网站建设
  • 做app封装的网站做外国人的生意哪家网站好
  • 网站建设合作协议书做阿里巴巴类似的网站
  • 网站可以更换域名吗优化网站排名工具
  • 浙江省住房建设厅继续教育网站局域网搭建
  • 服务器做网站好国内亲子游做的最好的网站
  • 做一电影网站怎么赚钱wordpress基本主题
  • 网站网页设计基本理论网站建设国内公司
  • 郑州一站式网站搭建东莞市城乡建设网
  • iis 建立子网站wordpress图像大小设置
  • 湖北网站开发公司wordpress默认主题修改版
  • 门户网站开发 项目实施方案苏州设置网站建设
  • 免费网站服务器软件下载大全知名网络公司
  • wordpress建英文站抖音最火轻奢装修
  • 做互助盘网站多少钱搭建视频播放网站
  • 软件公司网站下载班级优化大师app
  • 企业网站设计策划怎么提交公司网站
  • 优秀作文网站推荐php在线做网站
  • 电商设计网站哪个好口碑好的无锡网站建设
  • 课程网站开发背景容城县网站开发