您的位置:首页 > 移动开发 > IOS开发

ios下视频边下载连播放实现

2014-07-23 14:41 281 查看
参见网上示例大概清楚了在线缓存播放原理

1,本地实现httpserver,MPMoviePlayerController通过访问本地资源来实现视频播放如(http://127.0.0.1/test.mp4)

2,自己实现下目标视频下载,并在返回文件头时,将content-length字段取出,并存入沙盒

2,文件下载中不断写入已下载资源

原来MPMoviePlayerController访问网络视频时会自动不断请求这个资源地址,我们通过不断往这个地址写入数据来实现本地缓存

参照源码博文

具体代码如下

#import <Foundation/Foundation.h>

typedef enum enWordResType
{
RES_TYPE_JPG,
RES_TYPE_MP3,
RES_TYPE_FLV,
RES_TYPE_UNKNOW,
}enWordResType;

//
// http下载任务委托
//
@class HttpDownloadUnit;
@protocol HttpDownloadUnitDelegate <NSObject>

-(void) HttpDownloadUnitProgress:(HttpDownloadUnit *)object percent:(int)nPercent;
-(void) HttpDownloadUnitCompleted:(HttpDownloadUnit *)object data:(NSData *)data;
-(void) HttpDownloadUnitError:(HttpDownloadUnit *)object error:(NSError *)error;

@end
//
//
//
@interface HttpDownloadUnit : NSObject<NSURLConnectionDelegate,NSURLConnectionDataDelegate>
{
NSURLConnection         *_conn;
NSMutableData           *_buffer;
int64_t                 _bytesTotal;
}
//属性定义
@property(nonatomic,retain) NSString *url;
@property(nonatomic,retain) id<HttpDownloadUnitDelegate> delegate;

//方法定义
//根据一个完整url返回一个不包含xxx.xxx.com的相对路径
+(NSString *)relativePath:(NSString *)strURL;
//根据文件名创建对应的本地路径
+(void)CreateFolderByPath:(NSString *)strFileName;
//取消
-(void)cancel;
-(void)startCache:(NSString *)strURL;
-(id)initWithURL:(NSString *)url;

@end


//
//  WordResCache.m
//  LearningEnglish
//
//  Created by w on 14-6-10.
//  Copyright (c) 2014年 xxx.com. All rights reserved.
//

#import "HttpDownloadUnit.h"
#import "LocalDataMgr.h"

@interface HttpDownloadUnit()

@end

@implementation HttpDownloadUnit

//
+(NSString *)relativePath:(NSString *)strURL;
{
//http://www.xxx.com/xx/xxx.xxx

NSRange sr;
sr.location = 7;  // "http://"
sr.length = strURL.length - 7;

NSRange range1 = [strURL rangeOfString:@"/" options:NSCaseInsensitiveSearch range:sr];
if (range1.length != 0)
{
return [strURL substringFromIndex:range1.location + 1];
}
return  nil;
}
//
-(void)cancel
{
[_conn cancel];
_conn = nil;
}
//
-(void)startCache:(NSString *)strURL
{
self.url = strURL;

if (_conn)
{
[_conn cancel];
_conn = nil;
}

[_buffer setLength:0];

NSURL *url                      = [[NSURL alloc] initWithString:strURL];
NSMutableURLRequest *urlReq     = [[NSMutableURLRequest alloc] initWithURL:url];
urlReq.timeoutInterval          = 10.0;
urlReq.HTTPMethod               = @"GET";
_conn = [NSURLConnection connectionWithRequest:urlReq delegate:self];
}
//
-(id)initWithURL:(NSString *)url
{
self = [super init];
if (self)
{
self.url = url;
_buffer = [[NSMutableData alloc] init];

[self startCache:url];
}
return self;
}

#pragma mark NSURLConnection Delegate
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
if (self.delegate && [self.delegate respondsToSelector:@selector(HttpDownloadUnitError:error:)])
[self.delegate HttpDownloadUnitError:self error:error];

NSLog(@"connection fail.");
}
//
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if(httpResponse && [httpResponse respondsToSelector:@selector(allHeaderFields)]){
NSDictionary *httpResponseHeaderFields = [httpResponse allHeaderFields];

_bytesTotal = [[httpResponseHeaderFields objectForKey:@"Content-Length"] longLongValue];

//NSLog(@"%lld", total_);
}
}
//
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[_buffer appendData:data];

int nPercent = (((float)_buffer.length / (float)_bytesTotal) * 100);
if (self.delegate &&  [self.delegate respondsToSelector:@selector(HttpDownloadUnitProgress:percent:)])
[self.delegate  HttpDownloadUnitProgress:self percent:nPercent];
}

//根据文件名创建对应的本地路径
+(void)CreateFolderByPath:(NSString *)strFileName
{

NSRange range = [strFileName rangeOfString:@"/" options:NSBackwardsSearch];

if (range.length > 0)
{
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *strFolder = [strFileName substringToIndex:range.location];
[fileMgr createDirectoryAtPath:strFolder withIntermediateDirectories:YES attributes:nil error:nil];
}

}

//
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *strRelativePath = [HttpDownloadUnit relativePath:self.url];
NSString *strLocalFile = [LocalDataMgr getLocalResFileName:strRelativePath];
//根据文件名创建对应的目录结构
[HttpDownloadUnit CreateFolderByPath:strLocalFile];

NSLog(@"保存本地文件:%@",strLocalFile);

[_buffer writeToFile:strLocalFile atomically:YES];

if (self.delegate && [self.delegate respondsToSelector:@selector(HttpDownloadUnitCompleted:data:)])
[self.delegate HttpDownloadUnitCompleted:self data:_buffer];

}

@end


//
//  httpVideoController.h
//  LearningEnglish
//
//  Created by w on 14-7-21.
//  Copyright (c) 2014年 xxx.com. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "VideoCacheUnit.h"

@interface httpVideoController : UIViewController<VideoCacheUnitDelegate>
{
VideoCacheUnit *_videoCacheUnit;
}

@end


//
//  httpVideoController.m
//  LearningEnglish
//
//  Created by w on 14-7-21.
//  Copyright (c) 2014年 xxx.com. All rights reserved.
//

#import "httpVideoController.h"
#import "VideoCacheUnit.h"
#import <MediaPlayer/MediaPlayer.h>

@interface httpVideoController ()
{

}
@end

@implementation httpVideoController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization

}
return self;
}

-(void)willStartVideCache
{
NSURL *url = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"http://127.0.0.1:%d/test.mp4",HTTP_SERVER_PORT]];

player = [[MPMoviePlayerController alloc] initWithContentURL:url];

// 设置播放器的大小(16:9)
[player.view setFrame:CGRectMake(0, 30, 320, 180)];
//设置样式,让播放器影藏工具条
[player setControlStyle:MPMovieControlStyleEmbedded];

// 将播放器视图添加到根视图
[self.view addSubview:player.view];
[player play];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onReadyPlay:) name:MPMoviePlayerReadyForDisplayDidChangeNotification object:nil];

}

MPMoviePlayerController *player ;
- (void)viewDidLoad
{
[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];

//NSArray *directoryPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

//NSString *documentDirectory = [directoryPaths objectAtIndex:0];

// DBNAME 是要查找的文件名字,文件全名

//NSString *filePath = [documentDirectory stringByAppendingPathComponent:@"test.mp4"];
//
// filePath = [[NSBundle mainBundle] pathForResource:@"q1" ofType:@"mp4"];
// NSLog(@"PATH=%@",filePath);
// 用这个方法来判断当前的文件是否存在,如果不存在,就创建一个文件

//NSURL *url = [[NSBundle mainBundle]URLForResource:@"q1" withExtension:@"mp4"];
//NSURL *url = [[NSURL alloc] initFileURLWithPath:filePath];
//NSURL *url = [NSURL URLWithString:@"http://static.tripbe.com/videofiles/20121214/9533522808.f4v.mp4"];

_videoCacheUnit = [[VideoCacheUnit alloc] initWithURL:@"http://static.tripbe.com/videofiles/20121214/9533522808.f4v.mp4"];
_videoCacheUnit.delegate = self;

// Do any additional setup after loading the view.
}

-(void)onReadyPlay:(NSNotification *)notify
{
[player play];

}

- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/

@end


初始化httpserver

-(void)startServer
{

NSError *error;
if([httpServer start:&error])
{
NSLog(@"Started HTTP Server on port %hu", [httpServer listeningPort]);
}
else
{
NSLog(@"Error starting HTTP Server: %@", error);
}

}

-(void)initHttpServer
{
httpServer = [[HTTPServer alloc] init];

[httpServer setType:@"_http._tcp."];

[httpServer setPort:HTTP_SERVER_PORT];

// Serve files from our embedded Web folder

NSString *webPath = [NSHomeDirectory() stringByAppendingPathComponent:@"WebRoot"];
webPath = NSTemporaryDirectory();

NSLog(@"webRoot=%@",webPath);

NSFileManager *fileManager=[NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:webPath])
{
[fileManager createDirectoryAtPath:webPath withIntermediateDirectories:YES attributes:nil error:nil];
}
[httpServer setDocumentRoot:webPath];

[self startServer];
}


修改httpserver中HTTPFileResponse.m

@implementation HTTPFileResponse

- (id)initWithFilePath:(NSString *)fpath forConnection:(HTTPConnection *)parent
{
// NSLog(@"filePath = %@",fpath);
if((self = [super init]))
{
HTTPLogTrace();

connection = parent; // Parents retain children, children do NOT retain parents

fileFD = NULL_FD;
filePath = [[fpath copy] stringByResolvingSymlinksInPath];
if (filePath == nil)
{
//HTTPLogWarn(@"%@: Init failed - Nil filePath", THIS_FILE);
return nil;
}
//NSLog(@"filePath = %@",filePath);
NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
if (fileAttributes == nil)
{
//HTTPLogWarn(@"%@: Init failed - Unable to get file attributes. filePath: %@", THIS_FILE, filePath);
return nil;
}
//fileLength = (UInt64)[[fileAttributes objectForKey:NSFileSize] unsignedLongLongValue];
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
fileLength = (UInt64)[userDefaults doubleForKey:cache_video_file_size];

//fileLength = 20955211;
fileOffset = 0;
//NSLog(@"fileAttributes = %@",fileAttributes);
//NSLog(@"fileLength = %llu",fileLength);
aborted = NO;

// We don't bother opening the file here.
// If this is a HEAD request we only need to know the fileLength.
}
return self;
}


部分视频出现如下错误

_itemFailedToPlayToEnd: {
kind = 1;
new = 2;
old = 0;
}
解决参见 /article/9304406.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: