2011-11-19 27 views
19

Ben iphone/ipad üzerinde yönetilebilir bir bit hızı için bir video yeniden kodlamak için beklenen bir işleve sahip CRASHES. İşte burada: * GÜNCELLEME ÇALIŞMA KOD, ŞİMDİ SES İLE! Ben artık 2 saniyeden daha bir videoda geçerse :) *Video Kodlama -

-(void)resizeVideo:(NSString*)pathy{ 
    NSString *newName = [pathy stringByAppendingString:@".down.mov"]; 
    NSURL *fullPath = [NSURL fileURLWithPath:newName]; 
    NSURL *path = [NSURL fileURLWithPath:pathy]; 


    NSLog(@"Write Started"); 

    NSError *error = nil; 

    AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:fullPath fileType:AVFileTypeQuickTimeMovie error:&error];  
    NSParameterAssert(videoWriter); 
    AVAsset *avAsset = [[[AVURLAsset alloc] initWithURL:path options:nil] autorelease]; 
    NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
            AVVideoCodecH264, AVVideoCodecKey, 
            [NSNumber numberWithInt:1280], AVVideoWidthKey, 
            [NSNumber numberWithInt:720], AVVideoHeightKey, 
            nil]; 

    AVAssetWriterInput* videoWriterInput = [[AVAssetWriterInput 
              assetWriterInputWithMediaType:AVMediaTypeVideo 
              outputSettings:videoSettings] retain]; 
    NSParameterAssert(videoWriterInput); 
    NSParameterAssert([videoWriter canAddInput:videoWriterInput]); 
    videoWriterInput.expectsMediaDataInRealTime = YES; 
    [videoWriter addInput:videoWriterInput]; 
    NSError *aerror = nil; 
    AVAssetReader *reader = [[AVAssetReader alloc] initWithAsset:avAsset error:&aerror]; 
    AVAssetTrack *videoTrack = [[avAsset tracksWithMediaType:AVMediaTypeVideo]objectAtIndex:0]; 
    videoWriterInput.transform = videoTrack.preferredTransform; 
    NSDictionary *videoOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange] forKey:(id)kCVPixelBufferPixelFormatTypeKey]; 
    AVAssetReaderTrackOutput *asset_reader_output = [[AVAssetReaderTrackOutput alloc] initWithTrack:videoTrack outputSettings:videoOptions];  
    [reader addOutput:asset_reader_output]; 
    //audio setup 

    AVAssetWriterInput* audioWriterInput = [[AVAssetWriterInput 
              assetWriterInputWithMediaType:AVMediaTypeAudio 
              outputSettings:nil] retain]; 
    AVAssetReader *audioReader = [[AVAssetReader assetReaderWithAsset:avAsset error:&error] retain]; 
    AVAssetTrack* audioTrack = [[avAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]; 
    AVAssetReaderOutput *readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:audioTrack outputSettings:nil]; 

    [audioReader addOutput:readerOutput]; 
    NSParameterAssert(audioWriterInput); 
    NSParameterAssert([videoWriter canAddInput:audioWriterInput]); 
    audioWriterInput.expectsMediaDataInRealTime = NO; 
    [videoWriter addInput:audioWriterInput]; 
    [videoWriter startWriting]; 
    [videoWriter startSessionAtSourceTime:kCMTimeZero]; 
    [reader startReading]; 
    dispatch_queue_t _processingQueue = dispatch_queue_create("assetAudioWriterQueue", NULL); 
    [videoWriterInput requestMediaDataWhenReadyOnQueue:_processingQueue usingBlock: 
    ^{ 
     [self retain]; 
     while ([videoWriterInput isReadyForMoreMediaData]) { 
      CMSampleBufferRef sampleBuffer; 
      if ([reader status] == AVAssetReaderStatusReading && 
       (sampleBuffer = [asset_reader_output copyNextSampleBuffer])) { 

       BOOL result = [videoWriterInput appendSampleBuffer:sampleBuffer]; 
       CFRelease(sampleBuffer); 

       if (!result) { 
        [reader cancelReading]; 
        break; 
       } 
      } else { 
       [videoWriterInput markAsFinished]; 

       switch ([reader status]) { 
        case AVAssetReaderStatusReading: 
         // the reader has more for other tracks, even if this one is done 
         break; 

        case AVAssetReaderStatusCompleted: 
         // your method for when the conversion is done 
         // should call finishWriting on the writer 
         //hook up audio track 
         [audioReader startReading]; 
         [videoWriter startSessionAtSourceTime:kCMTimeZero]; 
         dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL); 
         [audioWriterInput requestMediaDataWhenReadyOnQueue:mediaInputQueue usingBlock:^ 
          { 
           NSLog(@"Request"); 
           NSLog(@"Asset Writer ready :%d",audioWriterInput.readyForMoreMediaData); 
           while (audioWriterInput.readyForMoreMediaData) { 
            CMSampleBufferRef nextBuffer; 
            if ([audioReader status] == AVAssetReaderStatusReading && 
             (nextBuffer = [readerOutput copyNextSampleBuffer])) { 
             NSLog(@"Ready"); 
             if (nextBuffer) { 
              NSLog(@"NextBuffer"); 
              [audioWriterInput appendSampleBuffer:nextBuffer]; 
             } 
            }else{ 
             [audioWriterInput markAsFinished]; 
             switch ([audioReader status]) { 
              case AVAssetReaderStatusCompleted: 
               [videoWriter finishWriting]; 
               [self hookUpVideo:newName]; 
               break; 
             } 
            } 
           } 

          } 
          ]; 
         break; 

        case AVAssetReaderStatusFailed: 
         [videoWriter cancelWriting]; 
         break; 
       } 

       break; 
      } 
     } 
    } 
    ]; 
    NSLog(@"Write Ended"); 
} 

yazık ki, uygulama çılgın ve çöker gibi bellek berbat! Kod oldukça basit görünüyor, ama işe almak için görünmüyor olabilir!
Ben yazıldığı oralarda bir yerde sonra tampon serbest gerekiyor? Herhangi bir girdisi olan herkese en müthiş olurdum.

+0

Bültenlerinizi gösterir misiniz? Çok fazla şey saklıyorsun ama nerede serbest bırakıldığını göremiyorum. – nh32rg

+0

@ box86rowh Bit hızı nerede belirtirsiniz? Teşekkürler. – Ryan

+0

Uygulayabileceğiniz diğer ayarlar için bu dokümanı inceleyin: https://developer.apple.com/library/mac/#documentation/AVFoundation/Reference/AVFoundation_Constants/Reference/reference.html – box86rowh

cevap

8

-copyNextSampleBuffer 1 muhafaza ile CMSampleBufferRef (kopya yöntemleri bunu) dönüyor. Bu, nesneyi serbest bırakmanız gerektiği anlamına gelir. Bunu yapmadığınız için while() döngüsü boyunca her geçişte bir kopya sızdırıyor olacaksınız.

Ayrıca, otomatik salma havuzu yöneten olmadan sıkıca o döngü azalıyor. Aramakta olduğunuz rutinlerin herhangi birinde otomatik olarak yüklenen nesneler varsa, bunlar üstünüzdeki osiloskop havuzuna kadar tahliye edilmeyecektir. While() döngü süreniz girişe dayandığından, manuel otorizasyon havuzu eklemek için iyi bir adaydır.

bir diğer şey düşünün: Eğer bir süre() döngü ile eşzamanlı bu çalıştırıyorsanız, çünkü iplik engellemek ve muhtemelen devam koşulu birden fazla kez gereksiz yere dönüşünü gerekir. AVAssetWriterInput, kaynaklar kullanılabilir hale geldikçe zaman uyumsuz olarak verileri işlemek için libdispatch kullanmak için alternatif bir mekanizma sağlar: -requestMediaDataWhenReadyOnQueue: usingBlock:

+0

Çok detaylı girişler için, yarın fikirlerinizi denemek ve rapor etmek için yarın şansım olacak. – box86rowh

+0

Kod referanslarına bazı biçimlendirme eklemek isteyebilir. Kod olarak atamak istediğiniz metin işaretlerini kullanabilirsiniz. Bunun gibi: -copyNextSampleBuffer' –

+0

Bu, hiçbir çökme olmadan çalıştı! İlk yazımda kodumu güncelledim, bir sorun olsa da ses almıyorum? Bunu kodlamaya nasıl ekleyebilirim? – box86rowh