का उपयोग कर बड़ी वीडियो फ़ाइलों पर रोक लगा रहा है, मैं वीडियो फ़ाइलों के लिए AVPlayer के बफर डेटा को सहेजने के लिए this approach का उपयोग कर रहा हूं। इस प्रश्न में उत्तर के रूप में मिला Saving buffer data of AVPlayer।एवीप्लेयर संसाधन लोडर प्रतिनिधि
iPhone और iPad - आईओएस 8.1.3
मैं वीडियो खेलने के लिए आवश्यक परिवर्तन किए हैं और यह बहुत अच्छी तरह से जब मैं एक बहुत लंबे वीडियो (11-12 मिनट लंबा और में 85mb के बारे में खेलने की कोशिश को छोड़कर काम कर रहा है आकार) कनेक्शन लोड होने के लगभग 4 मिनट बाद वीडियो बंद हो जाएगा। मुझे playbackBufferEmpty और एक प्लेयर आइटम स्टॉल अधिसूचना के लिए एक ईवेंट मिलता है।
इस कोड
viewController.m
@property (nonatomic, strong) NSMutableData *videoData;
@property (nonatomic, strong) NSURLConnection *connection;
@property (nonatomic, strong) AVURLAsset *vidAsset;
@property (nonatomic, strong) AVPlayerItem *playerItem;
@property (nonatomic, strong) AVPlayerLayer *avlayer;
@property (nonatomic, strong) NSHTTPURLResponse *response;
@property (nonatomic, strong) NSMutableArray *pendingRequests;
/**
Startup a Video
*/
- (void)startVideo
{
self.vidAsset = [AVURLAsset URLAssetWithURL:[self videoURLWithCustomScheme:@"streaming"] options:nil];
[self.vidAsset.resourceLoader setDelegate:self queue:dispatch_get_main_queue()];
self.pendingRequests = [NSMutableArray array];
// Init Player Item
self.playerItem = [AVPlayerItem playerItemWithAsset:self.vidAsset];
[self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:NULL];
self.player = [[AVPlayer alloc] initWithPlayerItem:self.playerItem];
// Init a video Layer
self.avlayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
[self.avlayer setFrame:self.view.frame];
[self.view.layer addSublayer:self.avlayer];
}
- (NSURL *)getRemoteVideoURL
{
NSString *urlString = [@"http://path/to/your/long.mp4"];
return [NSURL URLWithString:urlString];
}
- (NSURL *)videoURLWithCustomScheme:(NSString *)scheme
{
NSURLComponents *components = [[NSURLComponents alloc] initWithURL:[self getRemoteVideoURL] resolvingAgainstBaseURL:NO];
components.scheme = scheme;
return [components URL];
}
/**
NSURLConnection Delegate Methods
*/
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(@"didReceiveResponse");
self.videoData = [NSMutableData data];
self.response = (NSHTTPURLResponse *)response;
[self processPendingRequests];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(@"Received Data - appending to video & processing request");
[self.videoData appendData:data];
[self processPendingRequests];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"connectionDidFinishLoading::WriteToFile");
[self processPendingRequests];
[self.videoData writeToFile:[self getVideoCachePath:self.vidSelected] atomically:YES];
}
/**
AVURLAsset resource loader methods
*/
- (void)processPendingRequests
{
NSMutableArray *requestsCompleted = [NSMutableArray array];
for (AVAssetResourceLoadingRequest *loadingRequest in self.pendingRequests)
{
[self fillInContentInformation:loadingRequest.contentInformationRequest];
BOOL didRespondCompletely = [self respondWithDataForRequest:loadingRequest.dataRequest];
if (didRespondCompletely)
{
[requestsCompleted addObject:loadingRequest];
[loadingRequest finishLoading];
}
}
[self.pendingRequests removeObjectsInArray:requestsCompleted];
}
- (void)fillInContentInformation:(AVAssetResourceLoadingContentInformationRequest *)contentInformationRequest
{
if (contentInformationRequest == nil || self.response == nil)
{
return;
}
NSString *mimeType = [self.response MIMEType];
CFStringRef contentType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef)(mimeType), NULL);
contentInformationRequest.byteRangeAccessSupported = YES;
contentInformationRequest.contentType = CFBridgingRelease(contentType);
contentInformationRequest.contentLength = [self.response expectedContentLength];
}
- (BOOL)respondWithDataForRequest:(AVAssetResourceLoadingDataRequest *)dataRequest
{
long long startOffset = dataRequest.requestedOffset;
if (dataRequest.currentOffset != 0)
{
startOffset = dataRequest.currentOffset;
}
// Don't have any data at all for this request
if (self.videoData.length < startOffset)
{
NSLog(@"NO DATA FOR REQUEST");
return NO;
}
// This is the total data we have from startOffset to whatever has been downloaded so far
NSUInteger unreadBytes = self.videoData.length - (NSUInteger)startOffset;
// Respond with whatever is available if we can't satisfy the request fully yet
NSUInteger numberOfBytesToRespondWith = MIN((NSUInteger)dataRequest.requestedLength, unreadBytes);
[dataRequest respondWithData:[self.videoData subdataWithRange:NSMakeRange((NSUInteger)startOffset, numberOfBytesToRespondWith)]];
long long endOffset = startOffset + dataRequest.requestedLength;
BOOL didRespondFully = self.videoData.length >= endOffset;
return didRespondFully;
}
- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest
{
if (self.connection == nil)
{
NSURL *interceptedURL = [loadingRequest.request URL];
NSURLComponents *actualURLComponents = [[NSURLComponents alloc] initWithURL:interceptedURL resolvingAgainstBaseURL:NO];
actualURLComponents.scheme = @"http";
NSURLRequest *request = [NSURLRequest requestWithURL:[actualURLComponents URL]];
self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[self.connection setDelegateQueue:[NSOperationQueue mainQueue]];
[self.connection start];
}
[self.pendingRequests addObject:loadingRequest];
return YES;
}
- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest
{
NSLog(@"didCancelLoadingRequest");
[self.pendingRequests removeObject:loadingRequest];
}
/**
KVO
*/
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == StatusObservationContext)
{
AVPlayerStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];
if (status == AVPlayerStatusReadyToPlay) {
[self initHud];
[self play:NO];
} else if (status == AVPlayerStatusFailed)
{
NSLog(@"ERROR::AVPlayerStatusFailed");
} else if (status == AVPlayerItemStatusUnknown)
{
NSLog(@"ERROR::AVPlayerItemStatusUnknown");
}
} else if (context == CurrentItemObservationContext) {
} else if (context == RateObservationContext) {
} else if (context == BufferObservationContext){
} else if (context == playbackLikelyToKeepUp) {
if (self.player.currentItem.playbackLikelyToKeepUp)
}
} else if (context == playbackBufferEmpty) {
if (self.player.currentItem.playbackBufferEmpty)
{
NSLog(@"Video Asset is playable: %d", self.videoAsset.isPlayable);
NSLog(@"Player Item Status: %ld", self.player.currentItem.status);
NSLog(@"Connection Request: %@", self.connection.currentRequest);
NSLog(@"Video Data: %lu", (unsigned long)self.videoData.length);
}
} else if(context == playbackBufferFull) {
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
समस्या यह है कि कनेक्शन के कुछ समय बाद लोड हो जाने प्रतीत हो रहा है का सार है, तो खिलाड़ी आइटम बफर खाली हो जाता है। इस समय मेरा विचार यह है कि जब कनेक्शन लोड हो जाता है और खिलाड़ी इटम बफर को गड़बड़ कर देता है तो कुछ तोड़ दिया जा रहा है।
हालांकि समय में बफर चला जाता है खाली playerItem स्थिति अच्छी है, वीडियो संपत्ति चलाया जा सकता है, वीडियो डेटा अच्छा
है अगर मैं चार्ल्स के माध्यम से वाईफ़ाई थ्रोटल और कनेक्शन धीमा, वीडियो चल जाएगा जब तक वीडियो वीडियो के अंत के कुछ ही मिनटों में लोडिंग समाप्त नहीं होता है।
यदि मैं समाप्त लोडिंग ईवेंट पर कनेक्शन शून्य सेट करता हूं, तो संसाधन लोडर एक नया कनेक्शन फायर करेगा जब waitForLoadingOfRequestedResource फिर से आग लग जाएगा। इस मामले में लोडिंग फिर से शुरू होती है और वीडियो खेलना जारी रखेगा।
मुझे यह उल्लेख करना चाहिए कि यदि मैं इसे सामान्य http url संपत्ति के रूप में चलाता हूं, तो यह लंबा वीडियो ठीक खेलता है, और डिवाइस से सहेजे जाने के बाद भी ठीक खेलता है और वहां से लोड होता है।
हाय पॉल, मैं जितनी जल्दी हो सके स्ट्रीमिंग शुरू करने के लिए वीडियो प्राप्त करने का प्रयास कर रहा हूं। लेकिन ऐसा लगता है कि मैं पूरी तरह से डाउनलोड होने के बाद ही वीडियो को प्लेबैक करने में सक्षम हूं। मैंने एमपी 3 फ़ाइलों के लिए आपके कोड के साथ-साथ मूल दृष्टिकोण की कोशिश की है। लेकिन AVPlayer उन्हें पूरी तरह से डाउनलोड होने तक वापस नहीं खेल रहा है। कोई सुझाव/विचार? – Nikolozi
आप किस प्रकार के वीडियो खेलने की कोशिश कर रहे हैं? हम प्रगतिशील एच .264 एमपी 4 फाइलों का उपयोग कर रहे हैं। आप अपने शीर्षकों पर भी एक नज़र डाल सकते हैं। इससे मदद मिल सकती है - https://transcoding.wordpress.com/2012/09/22/making-a-h-264-for-the-web-stream-instantly/ –
प्रतिक्रिया पॉल के लिए चीयर्स। बाहर निकला मैं एक खराब परीक्षण वीडियो फ़ाइल का उपयोग कर रहा था। मैं कुछ यादृच्छिक सर्वर से कुछ यादृच्छिक वीडियो का उपयोग कर रहा था। कोड हमारे सर्वर पर वीडियो के साथ ठीक काम किया। – Nikolozi