>背景:我在服务器端有一个自定义身份验证机制,MPMoviePlayer不支持该机制。因此,我决定使用一个本地环回 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:@"rnContent-Type: application/vnd.apple.mpegurl;charset=UTF-8"];
response = [response stringByAppendingFormat:@"rnContent-Length: %ld", (unsigned long)manifestData.length];
response = [response stringByAppendingString:@"rnConnection: keep-alive"];
response = [response stringByAppendingString:@"rnrn"];
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?rn";
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
提前谢谢。
我正在将额外的回显消息写回服务器
- (
- void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
一旦我删除它,一切都开始按预期工作。只是提到这一点,以防有人想使用上面发布的代码。