How to play movie with a URL using a custom NSURLProtocol?
Asked Answered
G

4

8

As you know,play a movie with MPMoviePlayerController object using

[[MPMoviePlayerController alloc] initWithContentURL: aURL];

now ,i want to achieve a custom NSURLProtocol in which i will decrypt a movie source that had be encrypt by AlgorithmDES. Is that possibility? thanks for giving any ideas.need you help~

Galvanoscope answered 8/12, 2010 at 1:27 Comment(1)
Hi , I want to implement same feature like you.I have Encrypted video file on server. and I want to play same video with streaming. How can its possible? ThanksOverside
B
13

UPDATE: I spoke to Apple about this and it's not possible to use MPMoviePlayerController with a NSURLProtocol subclass at the moment!


Hej,

I am not sure but it could be possible. I am currently working on something similar but haven't got it fully working. What I have found out is that MPMoviePlayerController interacts with my custom NSURLProtocol subclass BUT it seems to be important to take the HTTPHeaders of the NSURLRequest into account because they define a range of bytes the MPMoviePlayerController needs.

If you dump them in your NSURLProtocol subclass you will get something like this twice for the start:

2011-01-16 17:00:47.287 iPhoneApp[1177:5f03] Start loading from request: {
Range = "bytes=0-1";

}

So my GUESS is that as long as you can provide the correct range and return a mp4 file that can be played by the MPMoviePlayerController it should be possible!

EDIT: Here is a interesting link: Protecting resources in iPhone and iPad apps

Bricklayer answered 16/1, 2011 at 16:10 Comment(17)
i find out that the player need parse url by itself,it couldn't work out as if i find the way of the player how to parse url,but the apple would not provide us for it .Galvanoscope
I don't see any methods in NSURLProtocol that contain this custom start loading with range. Probably a private method. Anyone have a clue on this?Underbodice
In the startLoading method of your NSURLProtocol subclass call NSDictionary* headers = [self.request allHTTPHeaderFields]; if([[headers allKeys] containsObject:@"Range"]) { NSLog(@"Range: %@",[headers objectForKey:@"Range"]); }Bricklayer
I have written a custom protocol that implements range requests and returns identical data and headers, but still gets the -11850 error (server not correctly configured) - any idea how AVPlayer/MPMoviePlayer determines that the server is configured with range requests?Eer
According to the protocol, you need your server to return Accept-Ranges: <type> as a HTTP header. Usually <type> is bytes.Hannelorehanner
@RobertDiamond Were you ever able to get the custom protocol to work?Cripple
@AndrewTheis no, it's just not possible. We moved to AVAudioPlayerEer
iOS 7 seems to have fixed this, I'd give it another go :)Cripple
@AndrewTheis can you qualify your statement? Or provide a citation for it now working?Whomsoever
@Whomsoever Well it now sends more than a 0-1 request, but seems to break after the second request (which is a 0-X). This leads me to believe it may have been fixed in iOS 7, but the response it is getting is not what it is expecting.Cripple
@AndrewTheis I'm seeing the same thing, a 0-2 request, then a request for more bytes, and then the same request over and over. My responses are matching exactly what I've seen using a proxy. I have a feeling that there is an expectation from AVFoundation's loader that the connection will not be closed between requests and unfortunately the NSURLProtocol will follow the same pattern as standard NSURLConnections which is to close the connection between each request.Whomsoever
@Whomsoever I sent in a DTS ticket to Apple, and they responded that is still not possible to use NSURLProtocol to serve up video files in iOS 7. They suggested filing a feature enhancement request on radar.Cripple
@AndrewTheis Did you follow up with the feature enhancement on radar? It seems like a serious overlook from Apple. URLs should be Universal.Montage
@Meda, yes we (mophie) have submitted a feature enhancement radar, as well as communicated this directly to our channels at Apple. I can dig up the radar number later.Cripple
Please do so when you've got the time, I will try to raise awareness, and makes no sense to crate another request.Montage
@AndrewTheis did you get any update on being able to use NSURLProtocol to serve video files?Treasurehouse
I want to add that you need return HTTPURLResonse instead of URLResponseReuven
D
6

The solution is to proxy requests through a local HTTP server. I have accomplished this using CocoaHTTPServer.

Look at the HTTPAsyncFileResponse example.

Diondione answered 14/1, 2014 at 3:9 Comment(2)
I am going to implement a local server for streaming video. But I don't know how to start :(. Could you please share me how to create it. Thanks a lotDrawing
I tried AVAssetResourceLoader approach and can't get it to work. Seems too much work for something simple (I just want custom header in AVPlayer URL request). Can you give guidelines on how to implement this with CocoaHTTPServer?Lambent
D
5

There is one more solution as of iOS 7. You can use a AVAssetResourceLoaderDelegate for AVAssetResourceLoader. But this will only work with AVPlayer then.

There is a demo project by apple called AVARLDelegateDemo have a look at it and you should find what you need. (I think linking to it isn't a good idea, so just search for it in the Developer Library on developer.apple.com) Then use any custom URL scheme (without declaring a NSURLProtocol) and handle that URL scheme in the AVAssetResourceLoaderDelegate.

If there is a huge interest I could provide a proof of concept gist.

Dredger answered 12/6, 2014 at 13:10 Comment(1)
Combine this with the iOS8 AVPlayerViewController and this is the best solution I have found. Well done for finding this.Vala
M
1
@property AVPlayerViewController *avPlayerVC;
@property NSData *yourDataSource

// initialise avPlayerVC
    NSURL *dummyURL     = [NSURL URLWithString:@"foobar://dummy.mov"];// a non-reachable URL will force the use of the resourceLoader
    AVURLAsset *asset   = [AVURLAsset assetWithURL:dummyURL];
    [asset.resourceLoader setDelegate:self queue:dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0)];

    AVPlayerItem *item = [AVPlayerItem playerItemWithAsset:asset];

    self.avPlayerVC.player = [AVPlayer playerWithPlayerItem:item];
    self.avPlayerVC.player.actionAtItemEnd  = AVPlayerActionAtItemEndNone;



// implement AVAssetResourceLoaderDelegate

- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest {

    loadingRequest.contentInformationRequest.contentType    = (__bridge NSString *)kUTTypeQuickTimeMovie;
    loadingRequest.contentInformationRequest.contentLength  = self.yourDataSource.length;
    loadingRequest.contentInformationRequest.byteRangeAccessSupported   = YES;

    NSRange range = NSMakeRange((NSUInteger)loadingRequest.dataRequest.requestedOffset, loadingRequest.dataRequest.requestedLength);
    [loadingRequest.dataRequest respondWithData:[self.yourDataSource subdataWithRange:range]];

    [loadingRequest finishLoading];
    return YES;
}

Notice the use of a dummy URL to force AVPlayer to use the AVAssetResourceLoaderDelegate methods instead of accessing the URL directly.

Mckinnie answered 29/11, 2016 at 7:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.