前一段时间做了一个视频播放下载应用,抓取的是优酷的视频,虽然优酷有自己的开发平台http://open.youku.com/,但未真正的实现。所以只能靠抓取视频源,Youku的视频采取了加密+动态的获取方式,视频地址需要访问网站动态获取,而结果则还需经过解密等操作。我们的目的只解析到网站视频的m3u8地址,好在在ios 的web可以实现:

           // 初始化webView

           UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(, , , )];

           [webViewsetDelegate:self];

           //加载网址

          NSURLRequest *request =[NSURLRequestrequestWithURL:url

                                              cachePolicy:NSURLRequestReloadIgnoringLocalCacheData

                                          timeoutInterval:5.0];

        [webView loadRequest:request];

          //在UIWebViewDelegate方法中解析

  #pragma mark - UIWebViewDelegate Methods

  - (void)webViewDidStartLoad:(UIWebView *)aWebView
{
[indicatorView startAnimating];
} - (void)webViewDidFinishLoad:(UIWebView *)aWebView
{
[indicatorView stopAnimating];
/*
30 NSString *lJs = @"document.documentElement.innerHTML";
31 NSString *lHtml1 = [webView stringByEvaluatingJavaScriptFromString:lJs];
32 NSLog(@"html内容:%@",lHtml1);
33
34 // NSString *lJs2 = @"(document.getElementsByTagName(\"video\")[0]).getElementsByTagName(\"source\")[0].src"; //qiyi
35 NSString *lJs2 = @"(document.getElementsByTagName(\"video\")[0]).src";// youku,tudou,ku6 ,souhu
36 NSString *lm3u8 = [webView stringByEvaluatingJavaScriptFromString:lJs2];
37 NSLog(@"video source:%@",lm3u8);
38 */ NSString *str = nil;
BOOL isYoukuTudouSource = [self isYoukuTudouSource];
if (isYoukuTudouSource){ str = [webView stringByEvaluatingJavaScriptFromString:@"document.getElementsByTagName('video')[0].getAttribute('src');"];
if (![str isEqualToString:@""]){ NSString *tempStr =str;
//NSLog(@"======%@",tempStr);
NSRange range = [ str rangeOfString:@"http://"];
if (range.length==){
range = [videolinkStr rangeOfString:@"youku.com"];
if (range.length>){
str = [@"http://v.youku.com" stringByAppendingString:tempStr];
}
}
}
}else{
BOOL sourcemode = [self isSourceMode];
if (sourcemode){
str = [webView stringByEvaluatingJavaScriptFromString:@"document.getElementsByTagName('source')[0].getAttribute('src')"];
}
}
if (IfPass == NO) {//设置BOOL类型的IfPass主要目的避免重复加载获取。 if (str && ![str isEqualToString:@""]) {
[webView stopLoading];
if ([delegate respondsToSelector:@selector(authorizeWebView:didReceiveAuthorizeCode:)])
{
NSLog(@"地址信息=======%@",str);
IfPass = YES;
[delegate authorizeWebView:self didReceiveAuthorizeCode:str];
}
}
}else if (IfPass == YES){
[webView stopLoading];
//NSLog(@"地址信息=======%@",str);
}
//NSLog(@"Web获取视频地址信息=======%@",str);
} - (void)webView:(UIWebView *)aWebView didFailLoadWithError:(NSError *)error
{
[indicatorView stopAnimating];
} - (BOOL)webView:(UIWebView *)aWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{ return YES;
} -(BOOL) isSourceMode { NSRange yinyuetai = [videolinkStr rangeOfString:@"yinyuetai.com"];
NSRange iqiyi = [videolinkStr rangeOfString:@"iqiyi.com"];
NSRange qq = [videolinkStr rangeOfString:@"qq.com"];
return yinyuetai.length>||iqiyi.length>||qq.length>;
} - (BOOL) isYoukuTudouSource { NSRange youku = [videolinkStr rangeOfString:@"youku.com"];
NSRange tudou = [videolinkStr rangeOfString:@"tudou.com"];
//NSLog(@"youku length====%d===tudou length===%d",youku.length,tudou.length);
return youku.length>||tudou.length>;
}

客户端,webView加载解析会有延迟,所以这种方式不推荐。其实后台可以通过技术手段得到m3u8.接下来就是调用苹果自己的播放器播放。我单独创建了一个MyMoviePlayViewController类继承自

MPMoviePlayerViewController类,以方便我应对ios6和ios6之前版本的屏幕旋转问题。

self.myVideoUrlStr =@“视频m3u8地址”;

//这里我需要查询下视频总时间

NSURL *movieURL = [NSURL URLWithString:self.myVideoUrlStr];
NSDictionary *opts = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO]forKey:AVURLAssetPreferPreciseDurationAndTimingKey]; AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:movieURL options:opts]; // 初始化视频媒体文件
//int minute = 0;
int second = ;
second = urlAsset.duration.value / urlAsset.duration.timescale; // 获取视频总时长,单位秒 //设置播放器监听事件
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.moviePlayer]; //初始化视频媒体文件 MyMoviePlayViewController *moviePalyViewController = [[MyMoviePlayViewController alloc]initWithContentURL:[NSURL URLWithString:@""]]; [[moviePalyViewController view]setFrame:CGRectMake(, , , self.view.frame.size.height*/)];
moviePalyViewController.moviePlayer.view.frame =CGRectMake(, , , );
//moviePalyViewController.view.frame = CGRectMake(0, 0, 320, self.view.frame.size.height*216/460); [moviePalyViewController getVideoWithURL:[NSURL URLWithString:self.myVideoUrlStr]]; //视频监听调用方法。主要用来记录用户所观看的时间
- (void)movieFinishedCallback:(NSNotification*) notification { //NSLog(@"111111111视频播放完毕");
MPMoviePlayerController *player = [notification object];
CGFloat videotimedurationWatched; NSArray *events = player.accessLog.events;
int count = events.count;
//NSLog(@"events count = %d", count);
for (int i = ; i < count; ++i) { MPMovieAccessLogEvent *currenEvent = [events objectAtIndex:i];
// double byts = currenEvent.indicatedBitrate ;
//NSLog(@"5555555==视频播放当前时间======%f",currenEvent.durationWatched);
videotimedurationWatched = currenEvent.durationWatched;
} switch (player.playbackState) {
case MPMoviePlaybackStateStopped:{ }
break;
case MPMoviePlaybackStatePlaying:{
//NSLog(@"Playing");
}
break;
case MPMoviePlaybackStatePaused:{ AccountModel *tempmodel = [AccountModel shareInstance];
tempmodel.videotimeWatched = videotimedurationWatched;
//NSLog(@"Paused");//播放暂停,播放完毕调用
[self dismissModalViewControllerAnimated:YES];
return;
}
break;
case MPMoviePlaybackStateInterrupted:{
//NSLog(@"Interrupted");
}
break;
case MPMoviePlaybackStateSeekingForward:{
//NSLog(@"Forward");
}
break;
case MPMoviePlaybackStateSeekingBackward:{
//NSLog(@"Backward");
}
break;
default:
break;
} [[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:player];
}

有了在线播放功能还不够,还需要下载到本地播放,实现步骤如下:

(1) 在线解析m3u8文件内容,把里面的ts对应连接的资源下载本地的Document文件下。

(2) 把下载下来的资源使用本地路径重新拼接成一个新的本地m3u8文件。

(3) 然后在开启一个http服务端,把m3u8共享成连接地址,让播放器播放。

具体实现请查看这位仁兄给的Demo,开启一个http服务端使用到了http服务端,就用CocoaHTTPServer可以把工作做好  CocoaHTTPServer小,重量轻,可嵌入HTTP服务器的Mac OS X或iOS应用程序。

有时,开发人员在他们的应用程序需要一个嵌入式HTTP服务器。也许它是一个服务器应用程序的远程监控。也许这是一个桌面应用程序使用HTTP后端的通信。它提供了:
•内置支持卓悦广播
•IPv4和IPv6支持
·异步网络,使用GCD和标准插座
•密码保护支持
•SSL/ TLS加密支持
•非常快速和高效的内存
•可扩展性(完全建立在GCD)
•重注释掉的代码
•很容易扩展
•支持WebDAV!

下面 介绍有关视频格式的:

在线视频一般都是基于flash和flv来实现的,而众所周知,iOS的safari不支持网页中的flash,但支持html5的video标记。FLV视频格式:许多在线视频网站都采用此视频格式。如搜狐视频、新浪播客、六间房、56、优酷、酷6、土豆,youtube等。FLV已经成为当前视频文件的主流格式。

优酷开发了“优酷通用播放器”,您可以将视频嵌入到任意页面和设备中,这样视频就可以被各种终端用户观看,包括PC浏览器,iPad和iPhone,较高版本Android平板和手机。优酷播放器现在只有在线播放能力,不提供播放离线文件的功能。

iOS 设备上启用HTTP Live Streaming非常简单,也是苹果官方推荐的方式。Adobe 的 Flash 流媒体服务器的新版本也支持这个技术的。

有关HLS可以参考HLS直播分析与实现  ,搭建HTTP Live Streaming直播系统  

关于流媒体(m3u8)的播放与下载的更多相关文章

  1. Loadrunner脚本开发-基于HTTP协议的流媒体视频在线播放服务器性能测试

    脚本开发-基于HTTP协议的流媒体视频在线播放服务器性能测试 by:授客 QQ:1033553122   目的 实现基于http协议的流媒体在线视频播放,服务器性能测试脚本,模拟用户浏览器方式在线播放 ...

  2. EasyPlayer开源流媒体移动端播放器推出RTSP-RTMP-HTTP-HLS全功能Pro版

    EasyPlayerPro介绍 Android EasyPlayerPro专业版全功能播放器,是由EasyDarwin开源团队维护的一款支持RTSP.RTMP.HTTP.HLS多种流媒体协议的播放器版 ...

  3. 使用Vitamio打造自己的Android万能播放器(7)——在线播放(下载视频)

    前言 本章将实现非常实用的功能——下载在线视频.涉及到多线程.线程更新UI等技术,还需思考产品的设计,如何将新加的功能更好的融入到现有的产品中,并不是简单的加一个界面就行了,欢迎大家交流产品设计和技术 ...

  4. Jquery音频播放插件下载地址(有Html、JS、CSS、音频)

    有详细的html文件.全部JS代码文件.Css样式文件.测试音频资料 音频播放插件下载链接(百度云): http://pan.baidu.com/s/1pKC904F 提取码评论留邮箱发送,谢谢!

  5. HTML5 video标签播放视频下载原理

    HTML5 video https://github.com/remy/html5demos/blob/master/demos/video.html <video preload=" ...

  6. 关于大视频video播放的问题以及解决方案(m3u8的播放)

    在HTML5里,提供了<video>标签,可以直接播放视频,video的使用很简单: <video width="320" height="240&qu ...

  7. rtsp 流媒体服务器,播放器

    https://github.com/EasyDSS/EasyPlayer-RTSP-Android EasyPlayer EasyPlayer RTSP Android 播放器是由紫鲸团队开发和维护 ...

  8. ionic2中使用videogular2实现m3u8文件播放

    // 安装依赖 npm i videogular2 --save npm i hls.js --save // 在index.html中引入 <script src="assets/h ...

  9. A站(ACFun)爬虫爬取并播放、下载视频(JAVA)

    本文使用的工具有vlc+ffmpeg+phantomjs 一般视频网站的视频地址暴露的方式有两种: 1.html直接暴露 2.通过ajax异步返回. A站使用的方式是第二种.针对第一种方式,直接使用j ...

随机推荐

  1. ios has denied the launch request.

    ios has denied the launch request. You can choose either of the two ways. Solution 1: Open System Pr ...

  2. UVA 10572 Black & White (状压DP)

    题意:有一个n*m的矩阵,其中部分格子已经涂黑,部分涂白,要求为其他格子也上黑/白色,问有多少种涂法可以满足一下要求: (1)任意2*2的子矩阵不可以同色. (2)所有格子必须上色. (3)只能有两个 ...

  3. 剑指offer44 扑克牌顺序

    注意一个边界条件:必须是连续的,如果前后两个数是一样的也不满足条件 class Solution { public: bool IsContinuous( vector<int> numb ...

  4. OpenCV2:第十一章 图像转换

    一.简介 二.例子 #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #inclu ...

  5. Luogu P3938 斐波那契

    Luogu P3938 斐波那契 第一眼看到这题,想到的是LCA,于是开始想怎么建树,倒是想出了\(n^{2}\)算法,看了下数据范围,果断放弃 想了想这数据范围,大的有点不正常,这让我想起了当年被小 ...

  6. Protocol(协议)、Delegate(委托)、DataSource(数据源)

    这里以 UITableViewController 和 UITableView 的关系为例: //--------------------------------------------------- ...

  7. C++系统学习之八:IO库

    新的C++标准中有三分之二的内容都是描述标准库.接下来重点学习其中几种核心库设施,这些是应该熟练掌握的. 标准库的核心是很多容器类(顺序容器和关联容器等)和一簇泛型算法(该类算法通常在顺序容器一定范围 ...

  8. (47)zabbix报警媒介:Ez Texting

    Ez Texting是zabbix的技术合作伙伴,主要提供短信服务,用手机注册账号,便可以使用它来发送短信了,不过他只支持美国和加拿大的手机号码,并且应该是收费的.没有美国/加拿大手机号码的朋友请绕行 ...

  9. (35)zabbix Event acknowledgment事件确认

    概述 以往服务器出现报警,运维人员处理完事之后,报警自动取消,但是下一次出现同样一个错误,但是换了一个运维人员,他可能需要重新排查问题,直到问题处理完毕. 针对这种情况,zabbix提供了event ...

  10. linux-ngnix服务(一)

    httpd MPM: prefork:进程模型,两级结构,主进程master负责生成子进程,每个子进程负责响应一个请求 worker:线程模型,三级结构,主进程master负责生成子进程,每个子进程负 ...