本文介绍了可以使用NSURLProtocol的子类播放视频,使用MPMovieController还是AVFoundation?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在尝试将视频播放到具有自定义NSURLProtocol子类中定义的自定义方案的URL。最初我使用MPMoviePlayerController试图完成此任务,但在遇到问题并检查堆栈溢出后,我发现MPMoviePlayerController没有按预期处理NSURLProtocol子类。

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 attempt to accomplish this, but after running into problems and checking stack overflow, I found that the MPMoviePlayerController does not handle NSURLProtocol subclasses as expected.

结果我决定查看AVFoundation框架,但是,似乎这似乎也没有用。我只是想知道这是否可能,或者我是否想穿过墙壁?

As a result I decided to look at the AVFoundation framework, however, it seems that this also doesn't seem to work. I just wanted to know if this was possible, or am I trying to walk through walls?

使用AVFoundation,我正在使用的方法如下所示。值得一提的是,当使用标准URL来访问互联网上托管的视频时,这种方法很有效,但不适用于自定义NSURLProtocol。

Using AVFoundation, the approach I'm using is shown below. It's probably worth mentioning that this works when using a standard URL to a video hosted on the internet, but doesn't work with the custom NSURLProtocol.

// this doesn't work
//AVPlayer *player = [[AVPlayer alloc] initWithURL:[NSURL urlWithString:@"custom URL scheme"]];
// this works
AVPlayer *player = [[AVPlayer alloc] initWithURL:[NSURL urlWithString:@"some url to video on remote server"]];

AVPlayerLayer *layer = [AVAVPlayerLayer playerLayerWithPlayer:player];
// configure the layer
[self.view.layer addSublayer:layer];

[player play];

为了从定义的NSURLProtocol子类中播放,是否还需要做些什么?

Is there something different that would need to be done in order to play from the defined NSURLProtocol subclass?

推荐答案

最近,我设法让NSURLProtocol与MPMoviePlayerController一起使用。这主要是有用的,因为MPMoviePlayerController只接受NSURL,因此它不允许我们传递cookie或标头(用于身份验证)。使用NSURLProtocol允许这样做。我以为我会在这里为社区分享一些代码。

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.

基本上,通过使用NSURLProtocol,我们可以拦截MPMoviePlayerController和流请求之间的通信,注入一路上的cookie,或者可能将流保存在离线状态,或者用猫视频等替换它......要做到这一点,你需要创建一个新类我的扩展NSURLProtocol:

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

用法:

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

这篇关于可以使用NSURLProtocol的子类播放视频,使用MPMovieController还是AVFoundation?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-09 18:23