Подтвердить что ты не робот

Кодирование видео с использованием AVAssetWriter - Сбой

У меня есть функция, которая должна перекодировать видео на управляемый битрейт на iphone/ipad. Вот он: * ОБНОВЛЕННЫЙ РАБОЧИЙ КОД, ТЕПЕРЬ С АУДИОМ!:) *

    -(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");
}

К сожалению, если я передаю видео более 2 секунд, приложение всасывает память, как сумасшедший, и падает! Код кажется довольно простым, но я не могу заставить его работать!
Должен ли я освободить буфер там где-то после его написания? Я был бы очень любезным для всех, кто имеет какие-либо данные.

4b9b3361

Ответ 1

-copyNextSampleBuffer возвращает CMSampleBufferRef с сохранением +1 (методы копирования делают это). Это означает, что вы должны освободить объект. Поскольку вы этого не делаете, вы будете пропускать копию каждый проход через цикл while().

Кроме того, вы работаете с этим циклом, не управляя пулом автозапуска. Если есть объекты, которые автореализовываются в любой из подпрограмм, которые вы вызываете, они не будут выпущены до тех пор, пока пул автоопределения выше вас не будет истощен. Поскольку длительность цикла while() основана на вводе, это хороший кандидат на добавление ручного пула автозапуска.

Еще одна вещь, которую следует учитывать: поскольку вы выполняете это синхронно с циклом while(), вы будете блокировать поток и, возможно, несколько раз вращаться над своим продолжением. AVAssetWriterInput предоставляет альтернативный механизм использования libdispatch для обработки данных асинхронно по мере поступления ресурсов: -requestMediaDataWhenReadyOnQueue: usingBlock: