MPMoviePlayerController and back-end HLS core server

I am currently displaying a video in an iOS app using MPMoviePlayerController. Files are transferred from our server server, which requires authentication. This is an authenticated key based on the key in the authorization HTTP header.

It worked great with individual video files. Now we tried to implement adaptive HLS streaming, and we ran into it. Currently, I use my own subclass NSURLProtocolto catch requests made to our server server and enter the appropriate authorization header. For HLS, it just doesn't work.

When we looked at the server logs, we clearly saw that the first request to the m3u8 file worked fine. Then all subsequent calls (other m3u8 and ts files as well) are forbidden 403. It seems that it is MPMoviePlayerControllernot used NSURLProtocolfor other files. (side note: it works on the simulator, but not on the physical device, which allows me to think that both of them are not implemented equally).

Create an instance of MPMoviePlayerController

self.videoController = [[MPMoviePlayerController alloc] initWithContentURL:video.videoURL];

URL protocol interception

+ (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request {
    NSMutableURLRequest *newRequest = request.mutableCopy;
    [newRequest setValue:@"HIDDEN" forHTTPHeaderField:@"Authorization"];
    return newRequest;
}

Any ideas, suggestions, work around?

+4
source share
3 answers

After checking with Apple Developer technical support, I realized what I want to achieve is impossible (and not supported).

Here is a quote from the answer:

, NSURLProtocol .., , HTTP- . , , mediaserverd. , .

0

NSURLProtocol, MPMoviePlayerController . cookie , , - . , NSURLProtocol:

, :

GAURLProtocol.h

#import <Foundation/Foundation.h>

@interface GAURLProtocol : NSURLProtocol
+ (void) register;
+ (void) injectURL:(NSString*) urlString cookie:(NSString*)cookie;
@end

GAURLProtocol.m

#import "GAURLProtocol.h"

@interface GAURLProtocol() <NSURLConnectionDelegate> {
    NSMutableURLRequest* myRequest;
    NSURLConnection * connection;
}
@end

static NSString* injectedURL = nil;
static NSString* myCookie = nil;

@implementation GAURLProtocol

+ (void) register
{
    [NSURLProtocol registerClass:[self class]];
}

// public static function to call when injecting a cookie
+ (void) injectURL:(NSString*) urlString cookie:(NSString*)cookie
{
    injectedURL = urlString;
    myCookie = cookie;
}

+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
    if([[[request allHTTPHeaderFields] objectForKey:@"Heeehey"] isEqualToString:@"Huuu"])
    {
        return NO;
    }
    return [[[request URL] absoluteString] isEqualToString:injectedURL];
}

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
    return request;
}

// intercept the request and handle it yourself
- (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id<NSURLProtocolClient>)client {

    if (self = [super initWithRequest:request cachedResponse:cachedResponse client:client]) {
        myRequest = request.mutableCopy;
        [myRequest setValue:@"Huuu" forHTTPHeaderField:@"Heeehey"]; // add your own signature to the request
    }
    return self;
}

// load the request
- (void)startLoading {
    //  inject your cookie
    [myRequest setValue:myCookie forHTTPHeaderField:@"Cookie"];
    connection = [[NSURLConnection alloc] initWithRequest:myRequest delegate:self];
}

// overload didReceive data
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [[self client] URLProtocol:self didLoadData:data];
}

// overload didReceiveResponse
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse *)response {
    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:[myRequest cachePolicy]];
}

// overload didFinishLoading
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [[self client] URLProtocolDidFinishLoading:self];
}

// overload didFail
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    [[self client] URLProtocol:self didFailWithError:error];
}

// handle load cancelation
- (void)stopLoading {
    [connection cancel];
}

@end

// register protocol
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [NSURLProtocol registerClass:[GAURLProtocol class]];
    return YES;
}

[GAURLProtocol injectURL:@"http://example.com/video.mp4" cookie:@"cookie=f23r3121"];
MPMoviePlayerController * moviePlayer = [[MPMoviePlayerController alloc]initWithContentURL:@"http://example.com/video.mp4"];
[moviePlayer play];
0

@ Marc-Alexandre Bérubé I might think of a workaround: Launch the proxy server in your application to proxy all the video URLs. Download all the video content by entering the necessary auth headers in the request and return the contents through the proxy server to the media player to display it. This approach may not work for large videos, since video rendering will only start after the entire video is downloaded.

0
source

All Articles