• 关于流媒体(m3u8)的播放与下载


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

      1         // 初始化webView
      2 
      3         UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 280, 390)];
      4 
      5         [webViewsetDelegate:self];
      6 
      7         //加载网址
      8 
      9        NSURLRequest *request =[NSURLRequestrequestWithURL:url
     10 
     11                                             cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
     12 
     13                                         timeoutInterval:5.0];
     14 
     15       [webView loadRequest:request];
     16 
     17         //在UIWebViewDelegate方法中解析
     18 
     19 #pragma mark - UIWebViewDelegate Methods
     20 
     21 - (void)webViewDidStartLoad:(UIWebView *)aWebView
     22 {
     23     [indicatorView startAnimating];
     24 }
     25 
     26 - (void)webViewDidFinishLoad:(UIWebView *)aWebView
     27 {
     28     [indicatorView stopAnimating];
     29     /*
     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     */
     39     
     40     NSString  *str = nil;
     41     BOOL isYoukuTudouSource = [self isYoukuTudouSource];
     42     if (isYoukuTudouSource){
     43      
     44         str = [webView stringByEvaluatingJavaScriptFromString:@"document.getElementsByTagName('video')[0].getAttribute('src');"];
     45         if (![str isEqualToString:@""]){
     46             
     47             NSString *tempStr =str;
     48             //NSLog(@"======%@",tempStr);
     49             NSRange range = [ str rangeOfString:@"http://"];
     50             if (range.length==0){
     51                 range = [videolinkStr rangeOfString:@"youku.com"];
     52                 if (range.length>0){
     53                     str = [@"http://v.youku.com" stringByAppendingString:tempStr];
     54                 }
     55             }
     56         }
     57     }else{
     58         BOOL sourcemode = [self isSourceMode];
     59         if (sourcemode){
     60             str = [webView stringByEvaluatingJavaScriptFromString:@"document.getElementsByTagName('source')[0].getAttribute('src')"];
     61         }
     62     }    
     63     if (IfPass == NO) {//设置BOOL类型的IfPass主要目的避免重复加载获取。
     64         
     65         if (str && ![str isEqualToString:@""]) {
     66             [webView stopLoading];
     67             if ([delegate respondsToSelector:@selector(authorizeWebView:didReceiveAuthorizeCode:)])
     68             {
     69                 NSLog(@"地址信息=======%@",str);
     70                 IfPass = YES;
     71                 [delegate authorizeWebView:self didReceiveAuthorizeCode:str];
     72             }
     73         }
     74     }else if (IfPass == YES){
     75         [webView stopLoading];
     76         //NSLog(@"地址信息=======%@",str);
     77     }
     78     //NSLog(@"Web获取视频地址信息=======%@",str);
     79 }
     80 
     81 - (void)webView:(UIWebView *)aWebView didFailLoadWithError:(NSError *)error
     82 {
     83     [indicatorView stopAnimating];
     84 }
     85 
     86 - (BOOL)webView:(UIWebView *)aWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
     87 {
     88 
     89     return YES;
     90 }
     91 
     92 
     93 -(BOOL) isSourceMode {
     94    
     95     NSRange yinyuetai = [videolinkStr rangeOfString:@"yinyuetai.com"];
     96     NSRange iqiyi = [videolinkStr rangeOfString:@"iqiyi.com"];
     97     NSRange qq = [videolinkStr rangeOfString:@"qq.com"];
     98     return yinyuetai.length>4||iqiyi.length>4||qq.length>4;
     99 }
    100 
    101 - (BOOL) isYoukuTudouSource {
    102 
    103     NSRange youku = [videolinkStr rangeOfString:@"youku.com"];
    104     NSRange tudou = [videolinkStr rangeOfString:@"tudou.com"];
    105     //NSLog(@"youku length====%d===tudou length===%d",youku.length,tudou.length);
    106     return youku.length>4||tudou.length>4;
    107 }
    View Code

    客户端,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 = 0;
            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(0, 0, 320, self.view.frame.size.height*216/460)];
            moviePalyViewController.moviePlayer.view.frame =CGRectMake(0, 0, 320, 216);
            //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 = 0; 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];
    }
    View Code

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

      (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!

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

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

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

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

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

            

     

     

     

  • 相关阅读:
    [HNOI2012]永无乡
    [HNOI2011]括号修复 / [JSOI2011]括号序列
    [NOI2005]维护数列
    文艺平衡树(Splay)
    SP2713 GSS4
    SP1716 GSS3
    Cookie和Session
    Session和Cookie的区别与联系
    Django ORM 多对多操作 使用聚合函数和分组 F查询与Q查询
    csrf攻击
  • 原文地址:https://www.cnblogs.com/jiangshiyong/p/3155063.html
Copyright © 2020-2023  润新知