2016-10-04 4 views
11

मेरे पास AVFoundation के AVPlayer (शायद आईओएस और मैकोज़ दोनों पर लागू) के उपयोग से संबंधित एक प्रश्न है। मैं मानक HTTP लाइव स्ट्रीमिंग के अलावा किसी चैनल से आने वाले प्लेबैक ऑडियो (असंपीड़ित WAV) डेटा को चलाने का प्रयास कर रहा हूं।AVPlayer फ़ाइल से AVAsset लोड करना जो बाहरी स्रोत (मैकोज़ और आईओएस के लिए) द्वारा जोड़ा गया है

मामला:
ऑडियो डाटा पैकेट अन्य डेटा app के साथ काम करने की जरूरत के साथ एक चैनल में संकुचित आते हैं। उदाहरण के लिए, वीडियो और ऑडियो एक ही चैनल में आते हैं और एक शीर्षलेख से अलग हो जाते हैं।
छानने के बाद, मैं ऑडियो डेटा प्राप्त है और उन्हें एक WAV प्रारूप करने के लिए संपीड़न हटाने (इस स्तर पर हेडर शामिल नहीं है)।
एक बार डाटा पैकेट तैयार हैं (9600 बाइट्स 24K के लिए प्रत्येक, स्टीरियो 16bit ऑडियो), वे AVPlayer का एक उदाहरण के लिए पारित कर रहे हैं (AVAudioPlayer एप्पल के अनुसार ऑडियो स्ट्रीमिंग के लिए उपयुक्त नहीं है)।

यह देखते हुए कि AVPlayer (आइटम या संपत्ति) स्मृति से लोड नहीं होता है (कोई initWithData: (NSData)) और या तो एक HTTP लाइव स्ट्रीम यूआरएल या एक फ़ाइल यूआरएल की आवश्यकता है, मैं डिस्क पर एक फ़ाइल (या तो मैकोज़ या आईओएस) , डब्ल्यूएवी हेडर जोड़ें और वहां असम्पीडित डेटा संलग्न करें।

AVURLAsset *audioAsset = [[AVURLAsset alloc] initWithURL:[NSURL fileURLWithPath:tempAudioFile] options:nil]; 
AVPlayerItem *audioItem = [[AVPlayerItem alloc] initWithAsset:audioAsset]; 
AVPlayer *audioPlayer = [[AVPlayer alloc] initWithPlayerItem:audioItem]; 

KVOs जोड़ने और फिर प्लेबैक प्रारंभ करने का प्रयास:

AVPlayer पर वापस, मैं निम्नलिखित बनाने

[audioPlayer play]; 

नतीजा यह है कि ऑडियो 1-2 सेकंड के लिए खेलता है और तो बंद हो जाता है (AVPlayerItemDidPlayToEndTimeNotification सटीक होना करने के लिए), जबकि डेटा दर्ज करने के लिए संलग्न करने के लिए जारी है। चूंकि पूरी चीज लूप पर है, [ऑडियोप्लेयर प्ले] शुरू होता है और रोकता है (दर == 0) कई बार।

सरलीकृत रूप में पूरी अवधारणा:

-(void)PlayAudioWithData:(NSData *data) //data in encoded format 
{ 
    NSData *decodedSound = [AudioDecoder DecodeData:data]; //decodes the data from the compressed format (Opus) to WAV 
    [Player CreateTemporaryFiles]; //This creates the temporary file by appending the header and waiting for input. 

    [Player SendDataToPlayer:decodedSound]; //this sends the decoded data to the Player to be stored to file. See below for appending. 

    Boolean prepared = [Player isPrepared]; //a check if AVPlayer, Item and Asset are initialized 
    if (!prepared)= [Player Prepare]; //creates the objects like above 
    Boolean playing = [Player isAudioPlaying]; //a check done on the AVPlayer if rate == 1 
    if (!playing) [Player startPlay]; //this is actually [audioPlayer play]; on AVPlayer Instance 
} 

-(void)SendDataToPlayer:(NSData *data) 
{ 
    //Two different methods here. First with NSFileHandle — not so sure about this though as it definitely locks the file. 
    //Initializations and deallocations happen elsewhere, just condensing code to give you an idea 
    NSFileHandle *audioFile = [NSFileHandle fileHandleForWritingAtPath:_tempAudioFile]; //happens else where 
    [audioFile seekToEndOfFile]; 
    [audioFile writeData:data]; 
    [audioFile closeFile]; //happens else where 

    //Second method is 
    NSOutputStream *audioFileStream = [NSOutputStream outputStreamWithURL:[NSURL fileURLWithPath:_tempStreamFile] append:YES]; 
    [audioFileStream open]; 
    [audioFileStream write:[data bytes] maxLength:data.length]; 
    [audioFileStream close]; 
} 

दोनों NSFileHandle और NSOutputStream, पूरी तरह से काम कर रहे WAV QuickTime, आइट्यून्स, वीएलसी आदि इसके अलावा द्वारा निभाई गई फ़ाइलों अगर मैं [प्लेयर SendDataToPlayer बाईपास: decodedSound ] और मानक डब्ल्यूएवी के साथ अस्थायी ऑडियो फ़ाइल प्रीलोडेड है, यह सामान्य रूप से भी खेलती है।

अभी तक, दो पक्ष हैं: ए) मेरे पास ऑडियो डेटा डिकंप्रेस्ड है और खेलने के लिए तैयार है b) मैं डेटा को ठीक से सहेजता हूं।

मैं जो करने की कोशिश कर रहा हूं वह एक पंक्ति में भेजना-लिखना है। यह मैं लगता है कि डेटा की बचत दायर करने के लिए बनाता है, फ़ाइल संसाधन के लिए अनन्य पहुँच हो जाता है और AVPlayer प्लेबैक जारी रखने की अनुमति नहीं है।

किसी को भी यह जानकारी है कि फाइल को NSFileHandle/NSOutputStream और AVPlayer दोनों में कैसे उपलब्ध रखना है?

या इससे भी बेहतर ... AVPlayer initWithData है? (Hehe ...)

किसी भी मदद की बहुत सराहना कर रहा है! अग्रिम धन्यवाद।

उत्तर

8

आप AVAssetResourceLoader पाइप के लिए अपने खुद के डेटा और मेटाडाटा एक AVAsset, में उपयोग कर सकते हैं जो आप तो AVPlayer साथ, प्रभाव में बना खेल सकते हैं एक [[AVPlayer alloc] initWithData:...]:

- (AVPlayer *)playerWithWavData:(NSData*)wavData { 
    self.strongDelegateReference = [[NSDataAssetResourceLoaderDelegate alloc] initWithData:wavData contentType:AVFileTypeWAVE]; 

    NSURL *url = [NSURL URLWithString:@"ns-data-scheme://"]; 
    AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:url options:nil]; 

    // or some other queue != main queue 
    [asset.resourceLoader setDelegate:self.strongDelegateReference queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; 

    AVPlayerItem *item = [[AVPlayerItem alloc] initWithAsset:asset]; 
    return [[AVPlayer alloc] initWithPlayerItem:item]; 
} 

जो तुम इतनी तरह उपयोग कर सकते हैं:

[self setupAudioSession]; 

NSURL *wavUrl = [[NSBundle mainBundle] URLForResource:@"foo" withExtension:@"wav"]; 
NSData *wavData = [NSData dataWithContentsOfURL:wavUrl]; 

self.player = [self playerWithWavData:wavData]; 

[self.player play]; 

बात यह है कि AVAssetResourceLoader बहुत शक्तिशाली है (unless you want to use AirPlay), तो आप शायदपर ऑडियो डेटा को खिलाने से बेहतर कर सकते हैंएक गांठ में - आप इसे AVAssetResourceLoader प्रतिनिधि में उपलब्ध कर सकते हैं क्योंकि यह उपलब्ध हो जाता है।

यहां सरल "एक गांठ" AVAssetResourceLoader प्रतिनिधि है। स्ट्रीमिंग के लिए इसे संशोधित करने के लिए यह आपके पास वर्तमान में मौजूद डेटा की मात्रा से अधिक contentLength सेट करने के लिए पर्याप्त होना चाहिए।

हैडर फ़ाइल:

#import <Foundation/Foundation.h> 
#import <AVFoundation/AVFoundation.h> 

@interface NSDataAssetResourceLoaderDelegate : NSObject <AVAssetResourceLoaderDelegate> 

- (instancetype)initWithData:(NSData *)data contentType:(NSString *)contentType; 

@end 

कार्यान्वयन फ़ाइल:

@interface NSDataAssetResourceLoaderDelegate() 

@property (nonatomic) NSData *data; 
@property (nonatomic) NSString *contentType; 

@end 

@implementation NSDataAssetResourceLoaderDelegate 

- (instancetype)initWithData:(NSData *)data contentType:(NSString *)contentType { 
    if (self = [super init]) { 
     self.data = data; 
     self.contentType = contentType; 
    } 
    return self; 
} 

- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest { 
    AVAssetResourceLoadingContentInformationRequest* contentRequest = loadingRequest.contentInformationRequest; 

    // TODO: check that loadingRequest.request is actually our custom scheme   

    if (contentRequest) { 
     contentRequest.contentType = self.contentType; 
     contentRequest.contentLength = self.data.length; 
     contentRequest.byteRangeAccessSupported = YES; 
    } 

    AVAssetResourceLoadingDataRequest* dataRequest = loadingRequest.dataRequest; 

    if (dataRequest) { 
     // TODO: handle requestsAllDataToEndOfResource 
     NSRange range = NSMakeRange((NSUInteger)dataRequest.requestedOffset, (NSUInteger)dataRequest.requestedLength); 
     [dataRequest respondWithData:[self.data subdataWithRange:range]]; 
     [loadingRequest finishLoading]; 
    } 

    return YES; 
} 

@end 
+0

दो सवाल: 1) आप एक बंडल में एक wav फ़ाइल से डेटा लोड। आप इसका उपयोग केवल डेटा का स्रोत रखने के लिए करते हैं या मुझे उस वैव फ़ाइल का उपयोग करना चाहिए जिसमें मैं डेटा जोड़ूं? (ध्यान दें: मेरे पास पहले से ही स्मृति में डेटा है) और 2) यह लूप में हो रहा है क्योंकि नया डेटा लगातार आ रहा है। मुझे AVPlayer आवंटित करना होगा या मुझे कहीं हटाना चाहिए? – Pericles

+0

1) मैं कुछ स्रोत डेटा रखने के लिए Wav फ़ाइल का उपयोग करता हूं। 2) मेरे पास यह कहने के लिए पर्याप्त जानकारी नहीं है कि आपको अपने 'AVPlayer' को कब हटाना चाहिए। आपके द्वारा संलग्न फ़ाइल के लिए - मुझे नहीं पता कि यह आवश्यक है या नहीं, लेकिन आप या तो लोडर प्रतिनिधि फ़ाइल से या सीधे स्मृति में डिकंप्रेस्ड डेटा से पढ़ सकते हैं। लेकिन 'प्लेयरविथववदाता' सबसे अच्छा तरीका नहीं हो सकता है। मैंने केवल यही उदाहरण दिया क्योंकि आपने यही पूछा है। –

संबंधित मुद्दे