ios開啟本地播發(fā)代理流纹,解析三方服務(wù)器上的視頻,防止視頻地址失效

申明:這篇只是自己的一些研究逢倍,請(qǐng)不要用于商業(yè)用途捧颅。如果影響到了你的利益,請(qǐng)你聯(lián)系我较雕。

? ? ?獲取三方的視頻碉哑,因?yàn)槿降囊曨l地址可能幾分鐘就會(huì)失效亮蒋。那么視頻有可能播放不了幾分鐘就會(huì)播發(fā)不了扣典。所以就需要在本地開啟一個(gè)播放代理。(目前這個(gè)需要服務(wù)器配合,客戶端不能夠自己去三方的網(wǎng)站去解析視頻)慎玖,以下所有的操作都是建立在自己的服務(wù)器上進(jìn)行贮尖。接下來(lái)會(huì)研究不需要依賴服務(wù)器,直接在本地解析優(yōu)酷真正的地址.

用到三方庫(kù):GCDWebServer(攔截視頻url請(qǐng)求)趁怔,AFNetworking

原理:

? ? ? ? ? ?1):本地開啟HttpServer服務(wù)湿硝,去捕獲到所有的視頻播發(fā)請(qǐng)求薪前。

? ? ? ? ? ?2):獲取到返回來(lái)視頻的視頻文件描述文件,將該描述文件存起來(lái)关斜,并且解析出來(lái)所有視頻片段的ts的url示括,保存所有的url。

? ? ? ? ? ?3):將返回來(lái)的描述文件中真實(shí)的播放地址替換成本地的地址痢畜,將修改后的描述文件直接扔給播放器垛膝。目的:利用重定向,可以獲取到所有經(jīng)過(guò)本地服務(wù)器的請(qǐng)求的url地址丁稀。

? ? ? ? ? ?4):因?yàn)椴シ牌魅フ?qǐng)求每一個(gè)視頻片段吼拥,本地就能捕獲到這些地址。再用這些本地的地址去匹配我們保存的真實(shí)地址线衫。映射出真實(shí)地址凿可。

? ? ? ? ? ?5):判斷真實(shí)的地址是否是可用的。不可用授账,那么重復(fù)第一步(目的是更新本地真實(shí)的地址)矿酵,可用,那么直接就扔給播放器去播放視頻

上原理圖:

直接上重要的代碼:

一)解析出視頻的每一個(gè)片段的的地址

? ? ? ? 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)根據(jù)視頻地址解析出視頻的描述文件

????????????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":@"獲取數(shù)據(jù)內(nèi)容失敗"}];

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

????????????}

? ? ? ? 4)判斷解析出來(lái)的文件格式是否是正確的

????????????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":@"數(shù)據(jù)格式錯(cuò)誤"}];

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

? ? ? ? ? ? ? ? ? ?}

????????????????return;

????????????????}

? ? ? ? 5)解析出mei一個(gè)片段的真正的地址

????????????- (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);

????????????????}

????????}

二)在本地播放器捕獲到所有的播放請(qǐng)求,利用重定向獲取到真實(shí)的播放地址

? ??????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];

????????????????????????????/ /驗(yàn)證播發(fā)地址是否過(guò)期

????????????????????????????if([strongSelf playUrleffective:urlStr])//過(guò)期重新去請(qǐng)求數(shù)據(jù){

????????????????????????????????????NSLog(@"播發(fā)片段的地址已經(jīng)過(guò)期了,正在重新獲取播放地址");

????????????????????????????????????if(strongSelf.playFlag!=0){

????????????????????????????????????????????????strongSelf.playFlag++;

????????????????????????????????????????????????//過(guò)期需要重新去獲取數(shù)據(jù)

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[strongSelf getPlayUrl];

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?urlStr = [strongSelf.m3u8PlayUrlDic objectForKey:m3u8LocalUrl];

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

????????????????????????????????????????????????return [GCDWebServerDataResponse responseWithRedirect:url permanent:NO];

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}

????????????????????????????????????????else//播發(fā)不了需要跳轉(zhuǎn)到網(wǎng)頁(yè){

????????????????????????????????????????????????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];

}

申明:以上只是自己的一些愛好研究敞咧,請(qǐng)不要用于商業(yè)棘捣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市休建,隨后出現(xiàn)的幾起案子乍恐,更是在濱河造成了極大的恐慌,老刑警劉巖测砂,帶你破解...
    沈念sama閱讀 211,376評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茵烈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡砌些,警方通過(guò)查閱死者的電腦和手機(jī)呜投,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)存璃,“玉大人仑荐,你說(shuō)我怎么就攤上這事∽荻” “怎么了粘招?”我有些...
    開封第一講書人閱讀 156,966評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)偎球。 經(jīng)常有香客問(wèn)我洒扎,道長(zhǎng)辑甜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,432評(píng)論 1 283
  • 正文 為了忘掉前任袍冷,我火速辦了婚禮磷醋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘难裆。我一直安慰自己子檀,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評(píng)論 6 385
  • 文/花漫 我一把揭開白布乃戈。 她就那樣靜靜地躺著褂痰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪症虑。 梳的紋絲不亂的頭發(fā)上缩歪,一...
    開封第一講書人閱讀 49,792評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音谍憔,去河邊找鬼匪蝙。 笑死,一個(gè)胖子當(dāng)著我的面吹牛习贫,可吹牛的內(nèi)容都是我干的逛球。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼苫昌,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼颤绕!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起祟身,我...
    開封第一講書人閱讀 37,701評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤奥务,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后袜硫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體氯葬,經(jīng)...
    沈念sama閱讀 44,143評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評(píng)論 2 327
  • 正文 我和宋清朗相戀三年婉陷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了帚称。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,626評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡秽澳,死狀恐怖世杀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肝集,我是刑警寧澤瞻坝,帶...
    沈念sama閱讀 34,292評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響所刀,放射性物質(zhì)發(fā)生泄漏衙荐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評(píng)論 3 313
  • 文/蒙蒙 一浮创、第九天 我趴在偏房一處隱蔽的房頂上張望忧吟。 院中可真熱鬧,春花似錦斩披、人聲如沸溜族。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)煌抒。三九已至,卻和暖如春厕倍,著一層夾襖步出監(jiān)牢的瞬間寡壮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工讹弯, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留况既,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓组民,卻偏偏與公主長(zhǎng)得像棒仍,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子臭胜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容