2014-11-24 22 views
0

背景:我在MPMoviePlayer不支持的服務器端有自定義的身份驗證機制。所以,我決定有一個本地環回HTTP服務器,它將接受播放器的初始請求並提供HLS清單文件。通過iOS上的本地HTTP服務器回放HLS

我處於播放器向本地HTTP服務器發起請求的位置,然後我的本地HTTP服務器從服務器獲取清單文件並將其作爲http響應寫回播放器。但之後MPMoviePlayer不再播放視頻。

有人可以幫助我實現這一目標嗎?

#import "QumuMediaPlayerProxy.h" 

#import "GZIP.h" 


#define WELCOME_MSG 0 

#define ECHO_MSG  1 

#define WARNING_MSG 2 


#define READ_TIMEOUT 15.0 

#define READ_TIMEOUT_EXTENSION 10.0 


@interface QumuMediaPlayerProxy() 

@property NSURL *contentURL; 


@end 


@implementation QumuMediaPlayerProxy 


+(NSURL*)getProxyURL{ 

    return [NSURL URLWithString:[NSString stringWithFormat:@"http://192.168.2.11:%d%@", SERVER_PORT, @"/nkm.do"]]; 

} 

- (id)initWithURL:(NSURL*)contentURL 

{ 

    if((self = [super init])) 

    { 



     socketQueue = dispatch_queue_create("socketQueue", NULL); 



     listenSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:socketQueue]; 



     connectedSockets = [[NSMutableArray alloc] initWithCapacity:1]; 



     isRunning = NO; 



     self.contentURL = contentURL; 

    } 

    return self; 

} 




- (void)startOnPort:(int)port 

{ 

    if(!isRunning) 

    { 



     if (port < 0 || port > 65535) 

     { 

      port = 0; 

     } 



     NSError *error = nil; 

     if(![listenSocket acceptOnPort:port error:&error]) 

     { 

      NSLog(@"Error starting QumuMediaPlayerProxy: %@", error.debugDescription); 

      return; 

     } 



     NSLog(@"QumuMediaPlayerProxy started on port %hu", [listenSocket localPort]); 

     isRunning = YES; 



    } 

} 


-(void)stop 

{ 

    if(isRunning) 

    { 

     // Stop accepting connections 

     [listenSocket disconnect]; 



     // Stop any client connections 

     @synchronized(connectedSockets) 

     { 

      NSUInteger i; 

      for (i = 0; i < [connectedSockets count]; i++) 

      { 

       // Call disconnect on the socket, 

       // which will invoke the socketDidDisconnect: method, 

       // which will remove the socket from the list. 

       [[connectedSockets objectAtIndex:i] disconnect]; 

      } 

     } 



     NSLog(@"Stopped QumuMediaPlayerProxy"); 

     isRunning = false; 



    } 


} 


- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket 

{ 

    // This method is executed on the socketQueue (not the main thread) 



    @synchronized(connectedSockets) 

    { 

     [connectedSockets addObject:newSocket]; 

     NSLog(@"==Accepted client=="); 


    } 



    [newSocket readDataWithTimeout:-1 tag:0]; 

} 


- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag 

{ 

    // This method is executed on the socketQueue (not the main thread) 



    if (tag == ECHO_MSG) 

    { 

     [sock readDataToData:[GCDAsyncSocket CRLFData] withTimeout:READ_TIMEOUT tag:0]; 

    } 

} 


- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag 

{ 

    // This method is executed on the socketQueue (not the main thread) 



    dispatch_async(dispatch_get_main_queue(), ^{ 

     @autoreleasepool { 



      NSData *strData = [data subdataWithRange:NSMakeRange(0, [data length] - 2)]; 

      NSString *msg = [[NSString alloc] initWithData:strData encoding:NSUTF8StringEncoding]; 

      if (msg) 

      { 

       NSLog(@"msg===>%@",msg); 

       NSLog(@"contentURL===>%@",self.contentURL.absoluteString); 

       NSString *getStr = [msg componentsSeparatedByString:@"\n"][0]; 

       NSString *requestedURL = [getStr substringWithRange:NSMakeRange(4, getStr.length-9)]; 

       //NSString *host = @"http://127.0.0.1:6910/"; 

       NSString *host = @"http://192.168.2.11:6910/"; 


       NSURL *requestURL = self.contentURL; 

       if(![requestedURL containsString:@"nkm.do"]){ 

        NSString *actualHost = [self.contentURL.absoluteString stringByReplacingOccurrencesOfString:self.contentURL.lastPathComponent withString:@""]; 


        requestURL = [NSURL URLWithString:[actualHost stringByAppendingString:requestedURL]]; 

       } 

       NSData *manifestData = [[QumuJSONHelper getInstance] fetchM3U8Playlist:requestURL]; 

       NSString *manifestStr = [[NSString alloc] initWithData:manifestData encoding:NSUTF8StringEncoding]; 

       NSLog(@"manifestStr===>%@",manifestStr); 


      /* NSArray *manifestArray = [manifestStr componentsSeparatedByString:@"\n"]; 

       NSString *modifiedManifest = @""; 

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

        NSString *token = manifestArray[i]; 

        if([token containsString:@"#EXT-X-STREAM-INF"]){ 

         NSLog(@"== Found tag EXT-X-STREAM-INF =="); 

         modifiedManifest = [modifiedManifest stringByAppendingString:token]; 

         modifiedManifest = [modifiedManifest stringByAppendingString:@"\n"]; 


         token = manifestArray[++i]; 

         // token = [@"https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/" stringByAppendingString:token]; 

         token = [host stringByAppendingString:token]; 

         NSLog(@"Modified URL===>%@",token); 



        } 

        modifiedManifest = [modifiedManifest stringByAppendingString:token]; 

        modifiedManifest = [modifiedManifest stringByAppendingString:@"\n"]; 


       } 

       modifiedManifest = [modifiedManifest stringByReplacingOccurrencesOfString:@"URI=\"" withString:[NSString stringWithFormat:@"URI=\"%@",host]]; 

       NSLog(@"modifiedManifest===>%@",modifiedManifest);*/ 



          NSString *response = @"HTTP/1.1 200 OK"; 



       response = [response stringByAppendingString:@"\r\nContent-Type: application/vnd.apple.mpegurl;charset=UTF-8"]; 

       response = [response stringByAppendingFormat:@"\r\nContent-Length: %ld", (unsigned long)manifestData.length]; 

       response = [response stringByAppendingString:@"\r\nConnection: keep-alive"]; 


       response = [response stringByAppendingString:@"\r\n\r\n"]; 




       NSLog(@"response header ===>%@",response); 

       NSData *responseData = [response dataUsingEncoding:NSUTF8StringEncoding]; 

       [sock writeData:responseData withTimeout:-1 tag:0]; 

       [sock writeData:manifestData withTimeout:-1 tag:0]; 





      } 

      else 

      { 

       NSLog(@"Error converting received data into UTF-8 String"); 

      } 







     } 

    }); 



    // Echo message back to client 

    [sock writeData:data withTimeout:-1 tag:ECHO_MSG]; 

} 


/** 

* This method is called if a read has timed out. 

* It allows us to optionally extend the timeout. 

* We use this method to issue a warning to the user prior to disconnecting them. 

**/ 

- (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag 

       elapsed:(NSTimeInterval)elapsed 

       bytesDone:(NSUInteger)length 

{ 

    if (elapsed <= READ_TIMEOUT) 

    { 

     NSString *warningMsg = @"Are you still there?\r\n"; 

     NSData *warningData = [warningMsg dataUsingEncoding:NSUTF8StringEncoding]; 



     [sock writeData:warningData withTimeout:-1 tag:WARNING_MSG]; 



     return READ_TIMEOUT_EXTENSION; 

    } 



    return 0.0; 

} 


- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err 

{ 

    if (sock != listenSocket) 

    { 

     dispatch_async(dispatch_get_main_queue(), ^{ 

      @autoreleasepool { 



       NSLog(@"Client Disconnected"); 



      } 

     }); 



     @synchronized(connectedSockets) 

     { 

      [connectedSockets removeObject:sock]; 

     } 

    } 

} 


-(void)dealloc{ 

    // [self stop]; 

} 


@end 

在此先感謝。

+0

我知道這不是很有幫助,但我不確定HLS協議是否允許從本地主機播放。幾個月前,我正在嘗試一種類似的技術,並且在Apple媒體開發論壇的某個地方,我發現這是不可能的。我想離線播放,希望能夠下載.ts文件來使用配置爲流式傳輸的播放器。因爲這是不可能的,我最終只是下載了一個mp4文件並更換了我的播放器來支持它。 – timgcarlson 2014-11-24 18:18:38

+0

假設您可以訪問Apple開發論壇,請查看此帖... https://devforums.apple.com/message/1031399#1031399(baleighsdad是Apple HLS團隊的工程師)。 – timgcarlson 2014-11-24 18:19:17

+0

感謝您的鏈接timgcarlson。我目前正在使用MPMoviePlayerController。我正在離線使用MPMoviePlayerController成功傳輸MP4文件。我想用HLS視頻做同樣的事情。在我的場景中,我不必在本地流式傳輸整個視頻。我只是希望能夠提供HLS清單,因爲這是受客戶端證書身份驗證機制保護的,並且MPMoviePlayerController無法處理身份驗證。我應該改用AVPlayer嗎? – Madala 2014-11-26 09:56:49

回答

2

我在

寫一個附加回波消息發送回服務器
  • (無效)插座:(GCDAsyncSocket *)襪子didReadData:(NSData的*)數據withTag:(長)標籤

一旦我刪除它,一切開始按預期工作。只要提到這一點,以防有人想使用上面的代碼。

相關問題