美文网首页
ios开启本地播发代理,解析三方服务器上的视频,防止视频地址失效

ios开启本地播发代理,解析三方服务器上的视频,防止视频地址失效

作者: 一只努力的猿 | 来源:发表于2017-12-06 10:38 被阅读0次

申明:这篇只是自己的一些研究,请不要用于商业用途。如果影响到了你的利益,请你联系我。

     获取三方的视频,因为三方的视频地址可能几分钟就会失效。那么视频有可能播放不了几分钟就会播发不了。所以就需要在本地开启一个播放代理。(目前这个需要服务器配合,客户端不能够自己去三方的网站去解析视频),以下所有的操作都是建立在自己的服务器上进行。接下来会研究不需要依赖服务器,直接在本地解析优酷真正的地址.

用到三方库:GCDWebServer(拦截视频url请求),AFNetworking

原理:

           1):本地开启HttpServer服务,去捕获到所有的视频播发请求。

           2):获取到返回来视频的视频文件描述文件,将该描述文件存起来,并且解析出来所有视频片段的ts的url,保存所有的url。

           3):将返回来的描述文件中真实的播放地址替换成本地的地址,将修改后的描述文件直接扔给播放器。目的:利用重定向,可以获取到所有经过本地服务器的请求的url地址。

           4):因为播放器去请求每一个视频片段,本地就能捕获到这些地址。再用这些本地的地址去匹配我们保存的真实地址。映射出真实地址。

           5):判断真实的地址是否是可用的。不可用,那么重复第一步(目的是更新本地真实的地址),可用,那么直接就扔给播放器去播放视频

上原理图:

直接上重要的代码:

一)解析出视频的每一个片段的的地址

        1)首先开启本地HttpServer

            self.webServer = [[GCDWebServer alloc] init];

            [self.webServer addDefaultHandlerForMethod:@"GET" requestClass:[GCDWebServerRequest class]     processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {

                }

                return [GCDWebServerDataResponse responseWithRedirect:request.URL permanent:YES];

            }];

            [self.webServer startWithPort:[self.port integerValue] bonjourName:nil];

        2)根据视频地址解析出视频的描述文件

            NSError *error;

            NSStringEncoding encoding;

           NSString *dataString = [[NSString alloc] initWithContentsOfURL:url usedEncoding:&encoding error:&error];

        3)判断是否解析成功

            if(dataString.length<=0)//获取切片失败 {

                   NSError *formatError = [[NSError alloc] initWithDomain:@"NSDataFormateError" code:8889 userInfo:@{@"info":@"获取数据内容失败"}];

                    [self.delegate M3U8Handler:self praseError:formatError];

            }

        4)判断解析出来的文件格式是否是正确的

            NSRange range = [dataString rangeOfString:@"#EXTINF"];

            if (range.location == NSNotFound) {

            if ([self.delegate respondsToSelector:@selector(M3U8Handler:praseError:)]) {

                    NSError *formatError = [[NSError alloc] initWithDomain:@"NSDataFormateError" code:8888 userInfo:@{@"info":@"数据格式错误"}];

                    [self.delegate M3U8Handler:self praseError:formatError];

                   }

                return;

                }

        5)解析出mei一个片段的真正的地址

            - (void)tsInfoWithM3U8String:(NSString *)m3u8Str baseUrlStr:(NSString *)baseUrlStr{

                    NSArray *components = nil;

                    if([m3u8Str componentsSeparatedByString:@"\r\n"].count>1) {

                            components = [m3u8Str componentsSeparatedByString:@"\r\n"];

                    }

                    else {

                        components = [m3u8Str componentsSeparatedByString:@"\n"];

                    }

                    NSMutableArray *durations = [NSMutableArray array];

                    NSMutableArray *urlArray = [NSMutableArray array];

                    for (NSString *infoString in components) {

                            NSRange durationRange = [infoString rangeOfString:@"#EXTINF:"];

                            NSRange tsRange = [infoString rangeOfString:@".ts"];

                            if (durationRange.location != NSNotFound){

                                    NSString *durationStr = [infoString substringFromIndex:durationRange.length];

                                    [durations addObject:durationStr];

                            }

                            else if (tsRange.location != NSNotFound){

                                    [urlArray addObject:infoString];

                            }

                    }

                for (int i = 0; i<durations.count; i++){

                        NSString *durationStr = durations[i];

                        NSString *tsURL = urlArray[i];

                        if(![tsURL hasPrefix:@"http://"])

                                tsURL = [baseUrlStr stringByAppendingString:tsURL];

                        SegmentInfo *tsInfo = [SegmentInfo infoWith:[durationStr doubleValue] tsURL:tsURL];

                         [self.segments addObject:tsInfo];

                }

        }

       6)伪造视频描述文件,将伪造的文件给播放器播放

        - (void)praseM3U8InfoFinish:(M3U8Handler *)handler{

            if(handler.segments.count<=0) return;

                    NSMutableArray * localUrl = [[NSMutableArray alloc] init];

            for (int i=0; i<handler.segments.count; i++){

                    SegmentInfo * mediaUrl = handler.segments[i];

                    NSString * indexStr = [NSString stringWithFormat:@"%d",(int)i];

                    NSString * extension = @"ts";

                    [self.m3u8PlayUrlDic setObject:mediaUrl.tsURL forKey:[[self getLocalUrlWithAddExtension:NO] stringByAppendingString:                       [self   getlocalWithIndex:indexStr extension:extension]]];

                    [localUrl addObject:[self getlocalWithIndex:indexStr extension:extension]];

            }

            NSMutableString * urlStr = [NSMutableString string];

            NSArray *components = [handler.dataStr componentsSeparatedByString:@"\n"];

            int i = 0;

            for (NSString * item in components){

                if(item.length<=0) continue;

                if([item hasPrefix:@"#"]) {

                        [urlStr appendString:[NSString stringWithFormat:@"%@\n",item]];

                }

                else {

                    NSString * url = [localUrl objectAtIndex:i];

                    [urlStr appendString:[NSString stringWithFormat:@"%@\n",url]];

                    i++;

                }

        }

        [self.localM3u8Dic setObject:urlStr forKey:[self getLocalUrlWithAddExtension:YES]];

        [localUrl removeAllObjects];

        //解析完成 通知播放器播放

        if(self.openServer){

               if(!self.isChangePlayeUrl){

                        self.isChangePlayeUrl = YES;

                        self.openServer(YES,0);

                }

        }

二)在本地播放器捕获到所有的播放请求,利用重定向获取到真实的播放地址

        self.webServer = [[GCDWebServer alloc] init];

        __weak typeof(self) weakSelf = self;

        __strong typeof(self) strongSelf = weakSelf;

        [self.webServer addDefaultHandlerForMethod:@"GET" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {

                strongSelf.isChangePlayeUrl = YES;

                NSString * m3u8LocalUrl = request.URL.absoluteString;

                if(m3u8LocalUrl.length>3){

                        NSString * flag = [m3u8LocalUrl substringFromIndex:m3u8LocalUrl.length-3];

                        if([flag hasPrefix:@"---"]){

                                    m3u8LocalUrl = [m3u8LocalUrl substringToIndex:m3u8LocalUrl.length-3];

                        }

                }

                if([[strongSelf.localM3u8Dic allKeys] containsObject:m3u8LocalUrl]){

                        NSString * content = [strongSelf.localM3u8Dic objectForKey:m3u8LocalUrl];

                        return [GCDWebServerDataResponse responseWithText:content];

                }

                else if([[strongSelf.m3u8PlayUrlDic allKeys] containsObject:m3u8LocalUrl]){

                            NSString * urlStr = [strongSelf.m3u8PlayUrlDic objectForKey:m3u8LocalUrl];

                            / /验证播发地址是否过期

                            if([strongSelf playUrleffective:urlStr])//过期重新去请求数据{

                                    NSLog(@"播发片段的地址已经过期了,正在重新获取播放地址");

                                    if(strongSelf.playFlag!=0){

                                                strongSelf.playFlag++;

                                                //过期需要重新去获取数据

                                                 [strongSelf getPlayUrl];

                                                 urlStr = [strongSelf.m3u8PlayUrlDic objectForKey:m3u8LocalUrl];

                                                NSURL * url = [[NSURL alloc] initWithString:urlStr];;

                                                return [GCDWebServerDataResponse responseWithRedirect:url permanent:NO];

                                         }

                                        else//播发不了需要跳转到网页{

                                                if(strongSelf.playFlag++==0) {

                                                        strongSelf.openServer(NO,1004);

                                                  }

                                                return [GCDWebServerDataResponse responseWithRedirect:nil permanent:NO];

                                        }

                            }

                            else {

                                strongSelf.playFlag++;

                                NSURL * url = [[NSURL alloc] initWithString:urlStr];;

                                return [GCDWebServerDataResponse responseWithRedirect:url permanent:NO];

                            }

                     }

                    return [GCDWebServerDataResponse responseWithRedirect:request.URL permanent:YES];

              }];

        [self.webServer startWithPort:[self.port integerValue] bonjourName:nil];

}

申明:以上只是自己的一些爱好研究,请不要用于商业。

相关文章

网友评论

      本文标题:ios开启本地播发代理,解析三方服务器上的视频,防止视频地址失效

      本文链接:https://www.haomeiwen.com/subject/hgpcixtx.html