Possible to play video using a subclass of NSURLProtocol, using either MPMovieController or AVFoundation?

后端 未结 1 977
刺人心
刺人心 2020-12-14 13:20

I\'m currently trying to play a video to a URL that has the custom scheme defined in a custom NSURLProtocol subclass. Initially I was using MPMoviePlayerController in an att

相关标签:
1条回答
  • 2020-12-14 13:59

    Recently, I managed to get NSURLProtocol to work with MPMoviePlayerController. This is mainly useful because MPMoviePlayerController only accepts an NSURL so it didn't let us pass cookies or headers (for authentication). The use of NSURLProtocol allowed that. I thought I'd share some code here for the community for once.

    Basically, by using NSURLProtocol, we can intercept the communication between MPMoviePlayerController and the streamed request, to inject cookies along the way, or possibly save the stream offline, or replace it with cat videos ect... To do this, you need to create a new class My extending NSURLProtocol:

    MyURLProtocol.h:

    #import <Foundation/Foundation.h>
    
    @interface MyURLProtocol : NSURLProtocol
    + (void) register;
    + (void) injectURL:(NSString*) urlString cookie:(NSString*)cookie;
    @end
    

    MyURLProtocol.m:

    #import "MyURLProtocol.h"
    
    @interface MyURLProtocol() <NSURLConnectionDelegate> {
        NSMutableURLRequest* myRequest;
        NSURLConnection * connection;
    }
    @end
    
    static NSString* injectedURL = nil;
    static NSString* myCookie = nil;
    
    @implementation MyURLProtocol
    // register the class to intercept all HTTP calls
    + (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;
    }
    
    // decide whether or not the call should be intercepted
    + (BOOL)canInitWithRequest:(NSURLRequest *)request {
        if([[[request allHTTPHeaderFields] objectForKey:@"BANANA"] isEqualToString:@"DELICIOUS"])
        {
            return NO;
        }
        return [[[request URL] absoluteString] isEqualToString:injectedURL];
    }
    
    // required (don't know what this means)
    + (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:@"DELICIOUS" forHTTPHeaderField:@"BANANA"]; // 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
    

    usage:

    [MyURLProtocol register];
    [MyURLProtocol injectURL:@"http://server/your-video-url.mp4" cookie:@"mycookie=123"];
    MPMoviePlayerController* moviePlayer = [[MPMoviePlayerController alloc]initWithContentURL:@"http://server/your-video-url.mp4"];
    [moviePlayer play];
    
    0 讨论(0)
提交回复
热议问题