iOS

2015-07-29 25 views
9

çalışırken HLS akışından (video) Ses Çıkarma/Kaydetme AVPlayer kullanarak HLS akışlarını oynuyorum. Ayrıca bu akışları kullanıcı presleri kayıt düğmesi olarak kaydetmem gerekiyor. Kullandığım yaklaşım, ses ve videoyu ayrı ayrı kaydetmek ve ardından son videoyu yapmak için bu dosyayı birleştirmek. Ve uzak mp4 dosyaları ile başarılı.iOS

Ancak şimdi HLS (.m3u8) dosyaları için AVAssetWriter kullanarak video kaydedebiliyorum ancak ses kaydıyla ilgili sorunlarım var.

Ham ses verilerini işlemek ve bir dosyaya yazmak için MTAudioProccessingTap kullanıyorum. this makalesini takip ettim. Uzak mp4 sesini kaydedebiliyorum ancak HLS akışlarıyla çalışmaz. Başlangıçta ses parçalarını AVAssetTrack * audioTrack = [asset tracksWithMediaType: AVMediaTypeAudio] [0] kullanarak akıtamıyordum;

Ancak MTAudioProcessingTap'ı başlatmak için KVO'yu kullanarak audioTracks'ı ayıklayabildim.

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ 
AVPlayer *player = (AVPlayer*) object; 

if (player.status == AVPlayerStatusReadyToPlay) 
{ 
    NSLog(@"Ready to play"); 
    self.previousAudioTrackID = 0; 


     __weak typeof (self) weakself = self; 

     timeObserverForTrack = [player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(1, 100) queue:nil usingBlock:^(CMTime time) 
       { 

        @try { 

          for(AVPlayerItemTrack* track in [weakself.avPlayer.currentItem tracks]) { 
           if([track.assetTrack.mediaType isEqualToString:AVMediaTypeAudio]) 
            weakself.currentAudioPlayerItemTrack = track; 

          } 

          AVAssetTrack* audioAssetTrack = weakself.currentAudioPlayerItemTrack.assetTrack; 


          weakself.currentAudioTrackID = audioAssetTrack.trackID; 

          if(weakself.previousAudioTrackID != weakself.currentAudioTrackID) { 

           NSLog(@":::::::::::::::::::::::::: Audio track changed : %d",weakself.currentAudioTrackID); 
           weakself.previousAudioTrackID = weakself.currentAudioTrackID; 
           weakself.audioTrack = audioAssetTrack; 
           /// Use this audio track to initialize MTAudioProcessingTap 
          } 
         } 
         @catch (NSException *exception) { 
          NSLog(@"Exception Trap ::::: Audio tracks not found!"); 
         } 

       }]; 


    } 
} 

Ben de iz değiştirilirse kontrol etmek TrackID takip ediyorum.

MTAudioProcessingTap'ı bu şekilde başlatıyorum.

-(void)beginRecordingAudioFromTrack:(AVAssetTrack *)audioTrack{ 
// Configure an MTAudioProcessingTap to handle things. 
MTAudioProcessingTapRef tap; 
MTAudioProcessingTapCallbacks callbacks; 
callbacks.version = kMTAudioProcessingTapCallbacksVersion_0; 
callbacks.clientInfo = (__bridge void *)(self); 
callbacks.init = init; 
callbacks.prepare = prepare; 
callbacks.process = process; 
callbacks.unprepare = unprepare; 
callbacks.finalize = finalize; 

OSStatus err = MTAudioProcessingTapCreate(
    kCFAllocatorDefault, 
    &callbacks, 
    kMTAudioProcessingTapCreationFlag_PostEffects, 
    &tap 
); 

if(err) { 
    NSLog(@"Unable to create the Audio Processing Tap %d", (int)err); 
    NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain 
             code:err 
            userInfo:nil]; 
    NSLog(@"Error: %@", [error description]);; 
    return; 
} 

// Create an AudioMix and assign it to our currently playing "item", which 
// is just the stream itself. 


AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix]; 
AVMutableAudioMixInputParameters *inputParams = [AVMutableAudioMixInputParameters 
    audioMixInputParametersWithTrack:audioTrack]; 

inputParams.audioTapProcessor = tap; 
audioMix.inputParameters = @[inputParams]; 
_audioPlayer.currentItem.audioMix = audioMix; 
} 

Ama Şimdi bu ses parçasına MTAudioProcessingTap geri aramaları "hazırlayın" ve "Süreç" ile adlandırılan asla.

AudioTrack ile ilgili sorun KVO'dan geçiyor muyum?

Şimdi, birisinin bana bu konuda yardımcı olması için gerçekten minnettar olurum. Ya da HLS Akımlarını kaydetmek için yazma yaklaşımını kullandığımı söyleyebilir miyim?

+0

m3u8 dosyasını kullanarak mp4 dosyası oluşturmayı başardınız mı? –

+1

@Milan Bunun için cevabı gönderdim. lütfen kontrol edin. –

+0

Çok teşekkürler Sajad. –

cevap

8

Bunun için bir çözüm buldum ve onu uygulamamda kullanıyorum. Daha önce yayınlamak istedim ama zaman almadı.

HLS ile oynamak için tam olarak ne olduklarına dair bilgi sahibi olmalısınız. Bunun için lütfen burada Apple Web Sitesinde bakın. HLS Apple

İzlediğim adımlar. 1. İlk olarak m3u8'i alın ve ayrıştırın. Bu faydalı seti M3U8Kit kullanarak ayrıştırabilirsiniz. Bu kitin kullanılması alabilirsiniz M3U8MediaPlaylist veya M3U8MasterPlaylist (bir usta çalma listesi ise) master çalma listesi alırsanız da Sen bağlantıları alacak görebilirsiniz M3U8MediaPlaylist

(void) parseM3u8 
{ 
NSString *plainString = [self.url m3u8PlanString]; 
BOOL isMasterPlaylist = [plainString isMasterPlaylist]; 


NSError *error; 
NSURL *baseURL; 

if(isMasterPlaylist) 
{ 

    M3U8MasterPlaylist *masterList = [[M3U8MasterPlaylist alloc] initWithContentOfURL:self.url error:&error]; 
    self.masterPlaylist = masterList; 

    M3U8ExtXStreamInfList *xStreamInfList = masterList.xStreamList; 
    M3U8ExtXStreamInf *StreamInfo = [xStreamInfList extXStreamInfAtIndex:0]; 

    NSString *URI = StreamInfo.URI; 
    NSRange range = [URI rangeOfString:@"dailymotion.com"]; 
    NSString *baseURLString = [URI substringToIndex:(range.location+range.length)]; 
    baseURL = [NSURL URLWithString:baseURLString]; 

    plainString = [[NSURL URLWithString:URI] m3u8PlanString]; 
} 



M3U8MediaPlaylist *mediaPlaylist = [[M3U8MediaPlaylist alloc] initWithContent:plainString baseURL:baseURL]; 
self.mediaPlaylist = mediaPlaylist; 

M3U8SegmentInfoList *segmentInfoList = mediaPlaylist.segmentList; 

NSMutableArray *segmentUrls = [[NSMutableArray alloc] init]; 

for (int i = 0; i < segmentInfoList.count; i++) 
{ 
    M3U8SegmentInfo *segmentInfo = [segmentInfoList segmentInfoAtIndex:i]; 

    NSString *segmentURI = segmentInfo.URI; 
    NSURL *mediaURL = [baseURL URLByAppendingPathComponent:segmentURI]; 

    [segmentUrls addObject:mediaURL]; 
    if(!self.segmentDuration) 
     self.segmentDuration = segmentInfo.duration; 
} 

self.segmentFilesURLs = segmentUrls; 



} 

almak için ayrıştırmak olabilir m3u8 gelen .ts dosyaları ayrıştırmak için.

  1. Artık tüm ts yerel bir klasöre dosya indirmek.
  2. bir mp4 dosya ve İhracat için bu ts dosyaları birleştirme. Sen yapabileceği bu harika C kütüphanesini TS2MP4

kullanarak ve sonra ts dosyaları silmek veya bunları gerekirse tutabilirsiniz.

+1

Bu m3u8 ts segmentlerinin statik bir listesi ise yararlıdır. Ancak canlı bir akış kaydetmek istiyorsanız, bu işlem işe yaramayacaktır çünkü düzenli aralıklarla sunucuyu vurarak çoğaltmaları yönetmelisiniz. Danışmanı işe almak demek olsa bile bu kadar umutsuzca ihtiyacım var. –

+0

Evet Carlos F, oyuncuyu sunucuya ilk vurduğunda bir karmaşa yaratacağından ve sonra ayrıştırmaya çalıştığınız için, bunu yönetmek zorunda olduğunuz konusunda haklısınız. Ancak bu yaklaşımı kullanarak canlı yayınları kaydetmeyi başardım. –

2

Bu, M3U8 bağlantısını ayrıştırmak için yapabileceğiniz iyi bir yaklaşım değildir. Daha sonra segment dosyalarını (.ts) karşıdan yüklemeyi deneyin. Bu dosyayı alırsanız, mp4 dosyası oluşturmak için onları birleştirebilirsiniz.