2010-10-26 11 views
13

Mam pomyślnie utworzony film z obrazów przy użyciu następującego koduJak używać CVPixelBufferPool w połączeniu z AVAssetWriterInputPixelBufferAdaptor w iPhone?

-(void)writeImageAsMovie:(NSArray *)array toPath:(NSString*)path size:(CGSize)size duration:(int)duration 
{ 
    NSError *error = nil; 
    AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL: 
            [NSURL fileURLWithPath:path] fileType:AVFileTypeQuickTimeMovie 
                   error:&error]; 
    NSParameterAssert(videoWriter); 

    NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
            AVVideoCodecH264, AVVideoCodecKey, 
            [NSNumber numberWithInt:size.width], AVVideoWidthKey, 
            [NSNumber numberWithInt:size.height], AVVideoHeightKey, 
            nil]; 
    AVAssetWriterInput* writerInput = [[AVAssetWriterInput 
             assetWriterInputWithMediaType:AVMediaTypeVideo 
             outputSettings:videoSettings] retain]; 

    AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor 
                assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput 
                sourcePixelBufferAttributes:nil]; 
    NSParameterAssert(writerInput); 
    NSParameterAssert([videoWriter canAddInput:writerInput]); 
    [videoWriter addInput:writerInput]; 


    //Start a session: 
    [videoWriter startWriting]; 
    [videoWriter startSessionAtSourceTime:kCMTimeZero]; 

    CVPixelBufferRef buffer = NULL; 
    buffer = [self pixelBufferFromCGImage:[[array objectAtIndex:0] CGImage]]; 
    [adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero]; 

    //Write samples: 
    for (int i = 0;i<[array count]; i++) 
    { 
     if([writerInput isReadyForMoreMediaData]) 
     { 
      NSLog(@"inside for loop %d",i); 
      CMTime frameTime = CMTimeMake(1, 20); 

      CMTime lastTime=CMTimeMake(i, 20); //i is from 0 to 24 of the loop above 

      CMTime presentTime=CMTimeAdd(lastTime, frameTime); 

      buffer = [self pixelBufferFromCGImage:[[array objectAtIndex:i] CGImage]]; 

      [adaptor appendPixelBuffer:buffer withPresentationTime:presentTime]; 

     } 
     else 
     { 
      NSLog(@"error"); 
      i--; 
     } 
    } 
    NSLog(@"outside for loop"); 

    //Finish the session: 
    [writerInput markAsFinished]; 
    [videoWriter finishWriting]; 
} 

Tutaj użyłem CVPixelBufferRef. Zamiast tego chcę użyć CVPixelBufferPoolRef w połączeniu z AVAssetWriterInputPixelBufferAdaptor.

Czy ktoś może podać przykład, który mogę debugować i używać?

Odpowiedz

14

są przechodzącą nil „sourcePixelBufferAttributes”, z powodu których pula buforów pikseli nie zostanie utworzona:

AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput sourcePixelBufferAttributes:nil]; 

Zamiast przechodzić pewne atrybuty, na przykład:

NSDictionary *bufferAttributes = [NSDictionary dictionaryWithObjectsAndKeys: 
[NSNumber numberWithInt:kCVPixelFormatType_32ARGB], kCVPixelBufferPixelFormatTypeKey, nil]; 

Następnie można użyć puli, aby utworzyć bufory pikseli, takie jak:

CVPixelBufferPoolCreatePixelBuffer (NULL, adaptor.pixelBufferPool, &pixelBuffer); 
+0

Dzięki za odpowiedź, ale mam już rozwiązał ten problem w taki sam sposób, jak powiedział ... –

+3

Czy wydajność wyraźnie (lub wymiernie) jest lepsza przy użyciu puli buforów i adaptera? – kevlar

+1

@kevlar mówiąc z własnego doświadczenia, korzystanie z basenu to różnica nocy i dnia. Dosłownie 1 LOC naprawił wyciek pamięci: D – jakenberg

4

Zamiast używać "f" lub "użyj tego kodu:

dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL); 
[writerInput requestMediaDataWhenReadyOnQueue:mediaInputQueue usingBlock:^{ 

    CVPixelBufferRef buffer = NULL; 
    buffer = [self pixelBufferFromCGImage:[[array objectAtIndex:0] CGImage]]; 
    CVPixelBufferPoolCreatePixelBuffer (NULL, adaptor.pixelBufferPool, &buffer); 

    [adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero]; 
    int i = 1; 
    while (writerInput.readyForMoreMediaData) { 
     NSLog(@"inside for loop %d",i); 
     CMTime frameTime = CMTimeMake(1, 20); 

     CMTime lastTime=CMTimeMake(i, 20); //i is from 0 to 19 of the loop above 

     CMTime presentTime=CMTimeAdd(lastTime, frameTime); 

     if (i >= [array count]) { 
      buffer = NULL; 
     }else { 
       buffer = [self pixelBufferFromCGImage:[[array objectAtIndex:i] CGImage]]; 
     }   
     //CVBufferRetain(buffer); 

     if (buffer) { 
      // append buffer 
      [adaptor appendPixelBuffer:buffer withPresentationTime:presentTime]; 
      i++; 
     } else { 
      // done! 

      //Finish the session: 
      [writerInput markAsFinished]; 
      [videoWriter finishWriting];     

      CVPixelBufferPoolRelease(adaptor.pixelBufferPool); 
      [videoWriter release]; 
      [writerInput release]; 
      NSLog (@"Done"); 
      [imageArray removeAllObjects];    
      break; 
     } 
    } 
}]; 
+0

thanx za pomoc, ale już rozwiązałem problem, a także ukończyłem projekt ... –

+1

Istnieje również błąd w tej procedurze, ponieważ pisarz może stać się "niegotowy" przed tobą iteruj po twojej tablicy. Jeśli wyniesiesz swój licznik z bloku i wyczyścisz wpis pętli do klucza dowolnego indeksu, powinieneś być w porządku. –

6

@Atulkumar V. Jain: świetnie! powodzenia ^^ @Brian: masz rację, dzięki, ja go poprawić i jestem coraz to działa teraz tutaj jest kod roboczych (jeśli ktoś go potrzebują :-))

CVPixelBufferRef buffer = NULL; 
buffer = [self pixelBufferFromCGImage:[[imagesArray objectAtIndex:0] CGImage]]; 
CVPixelBufferPoolCreatePixelBuffer (NULL, adaptor_.pixelBufferPool, &buffer); 

[adaptor_ appendPixelBuffer:buffer withPresentationTime:kCMTimeZero]; 

__block UInt64 convertedByteCount = 0; 
dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL); 
static int i = 1; 
int frameNumber = [imagesArray count]; 

[writerInput requestMediaDataWhenReadyOnQueue:mediaInputQueue usingBlock:^{ 
    while (1){ 
     if (i == frameNumber) { 
      break; 
     } 
     if ([writerInput isReadyForMoreMediaData]) { 

      CVPixelBufferRef sampleBuffer = [self pixelBufferFromCGImage:[[imagesArray objectAtIndex:i] CGImage]]; 
      NSLog(@"inside for loop %d",i); 
      CMTime frameTime = CMTimeMake(1, 20); 

      CMTime lastTime=CMTimeMake(i, 20); //i is from 0 to 19 of the loop above 

      CMTime presentTime=CMTimeAdd(lastTime, frameTime);  

     if (sampleBuffer) { 
       [adaptor_ appendPixelBuffer:sampleBuffer withPresentationTime:presentTime]; 
       i++; 
       CFRelease(sampleBuffer); 
      } else { 
       break; 
      } 
     } 
    } 
    NSLog (@"done"); 
    [writerInput markAsFinished]; 
    [videoWriter finishWriting];  

    CVPixelBufferPoolRelease(adaptor_.pixelBufferPool); 
    [videoWriter release]; 
    [writerInput release];  
    [imagesArray removeAllObjects]; 


}]; 
4

mam to wszystko działa !

Oto przykładowy link code: [email protected]: RudyAramayo/AVAssetWriterInputPixelBufferAdaptorSample.git

Oto kod trzeba:

- (void) testCompressionSession 
{ 
    CGSize size = CGSizeMake(480, 320); 

    NSString *betaCompressionDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/Movie.m4v"]; 

    NSError *error = nil; 

    unlink([betaCompressionDirectory UTF8String]); 

    //----initialize compression engine 
    AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:betaCompressionDirectory] 
                  fileType:AVFileTypeQuickTimeMovie 
                   error:&error]; 
    NSParameterAssert(videoWriter); 
    if(error) 
     NSLog(@"error = %@", [error localizedDescription]); 

    NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:AVVideoCodecH264, AVVideoCodecKey, 
             [NSNumber numberWithInt:size.width], AVVideoWidthKey, 
             [NSNumber numberWithInt:size.height], AVVideoHeightKey, nil]; 
    AVAssetWriterInput *writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings]; 

    NSDictionary *sourcePixelBufferAttributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys: 
                   [NSNumber numberWithInt:kCVPixelFormatType_32ARGB], kCVPixelBufferPixelFormatTypeKey, nil]; 

    AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput 
                                 sourcePixelBufferAttributes:sourcePixelBufferAttributesDictionary]; 
    NSParameterAssert(writerInput); 
    NSParameterAssert([videoWriter canAddInput:writerInput]); 

    if ([videoWriter canAddInput:writerInput]) 
     NSLog(@"I can add this input"); 
    else 
     NSLog(@"i can't add this input"); 

    [videoWriter addInput:writerInput]; 
    [videoWriter startWriting]; 
    [videoWriter startSessionAtSourceTime:kCMTimeZero]; 

    //--- 
    // insert demo debugging code to write the same image repeated as a movie 

    CGImageRef theImage = [[UIImage imageNamed:@"Lotus.png"] CGImage]; 

    dispatch_queue_t dispatchQueue = dispatch_queue_create("mediaInputQueue", NULL); 
    int __block frame = 0; 

    [writerInput requestMediaDataWhenReadyOnQueue:dispatchQueue usingBlock:^{ 
     while ([writerInput isReadyForMoreMediaData]) 
     { 
      if(++frame >= 120) 
      { 
       [writerInput markAsFinished]; 
       [videoWriter finishWriting]; 
       [videoWriter release]; 
       break; 
      } 

      CVPixelBufferRef buffer = (CVPixelBufferRef)[self pixelBufferFromCGImage:theImage size:size]; 
      if (buffer) 
      { 
       if(![adaptor appendPixelBuffer:buffer withPresentationTime:CMTimeMake(frame, 20)]) 
        NSLog(@"FAIL"); 
       else 
        NSLog(@"Success:%d", frame); 
       CFRelease(buffer); 
      } 
     } 
    }]; 

    NSLog(@"outside for loop"); 

} 

- (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image size:(CGSize)size 
{ 
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: 
          [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey, 
          [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, nil]; 
    CVPixelBufferRef pxbuffer = NULL; 
    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, size.width, size.height, kCVPixelFormatType_32ARGB, (CFDictionaryRef) options, &pxbuffer); 
    // CVReturn status = CVPixelBufferPoolCreatePixelBuffer(NULL, adaptor.pixelBufferPool, &pxbuffer); 

    NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL); 

    CVPixelBufferLockBaseAddress(pxbuffer, 0); 
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer); 
    NSParameterAssert(pxdata != NULL); 

    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef context = CGBitmapContextCreate(pxdata, size.width, size.height, 8, 4*size.width, rgbColorSpace, kCGImageAlphaPremultipliedFirst); 
    NSParameterAssert(context); 

    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image); 

    CGColorSpaceRelease(rgbColorSpace); 
    CGContextRelease(context); 

    CVPixelBufferUnlockBaseAddress(pxbuffer, 0); 

    return pxbuffer; 
} 
+0

Czy chcesz odkomentować linię 'CVPixelBufferPoolCreatePixelBuffer' wewnątrz' pixelBufferFromCGImage'? Czy zdecydowałeś się nie używać 'CVPixelBufferPoolCreatePixelBuffer'? – taber

+0

Byłem tak zagubiony, kiedy to napisałem, to była kompilacja wielu różnych zestawów kodu, które próbowałem przerobić ... proszę, nie przejmuj się niektórymi kwarkami, tak jak komentowane rzeczy, wciąż się uczyłem/testowanie ... Będę musiał poprawić próbkę i wkrótce dostarczyć więcej kodu AVFoundation. – Orbitus007

+1

Nie używaj tego kodu - jest źle. Aby użyć puli, musisz zadzwonić tylko do CVPixelBufferPoolCreatePixelBuffer. – AlexeyVMP

Powiązane problemy