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

参见网上示例大概清楚了在线缓存播放原理

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;

}

解决参见  http://blog.csdn.net/zttjhm/article/details/8581189





评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值