2010-10-26 16 views
13

tôi đã tạo thành công video từ hình ảnh bằng cách sử dụng đoạn mã sauLàm thế nào để sử dụng CVPixelBufferPool kết hợp với AVAssetWriterInputPixelBufferAdaptor trong 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]; 
} 

Ở đây tôi đã sử dụng CVPixelBufferRef. Thay vào đó, tôi muốn sử dụng CVPixelBufferPoolRef kết hợp với AVAssetWriterInputPixelBufferAdaptor.

Ai cũng có thể cung cấp ví dụ mà tôi có thể gỡ lỗi và sử dụng?

Trả lời

14

Bạn đang đi qua nil 'sourcePixelBufferAttributes', bởi vì trong đó hồ điểm ảnh đệm sẽ không được tạo ra:

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

Thay vì vượt qua một số thuộc tính, ví dụ:

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

Sau đó, bạn có thể sử dụng hồ bơi để tạo bộ đệm pixel, như:

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

Thanx bạn đã trả lời nhưng tôi đã giải quyết vấn đề này theo cách tương tự mà bạn đã nói ... –

+3

Hiệu suất có đáng chú ý (hoặc đo được) tốt hơn khi sử dụng vùng đệm và bộ điều hợp không? – kevlar

+1

@kevlar nói từ kinh nghiệm cá nhân, sử dụng hồ bơi là sự khác biệt về đêm và ngày. Nghĩa là 1 LOC cố định rò rỉ bộ nhớ: D – jakenberg

4

Thay vì sử dụng "f hoặc "sử dụng mã này:

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 để được trợ giúp nhưng tôi đã giải quyết được vấn đề và cũng đã hoàn thành dự án ... –

+1

Ngoài ra còn có một lỗi trong thói quen này mà nhà văn có thể trở thành 'chưa sẵn sàng' trước bạn lặp qua mảng của bạn. Nếu bạn di chuyển truy cập của bạn ra khỏi khối, và làm sạch các mục vòng lặp để chìa khóa của bất kỳ chỉ số, bạn nên được tốt. –

6

@Atulkumar V. Jain: tuyệt! chúc may mắn ^^ @ Brian: bạn là đúng cảm ơn, tôi sửa nó và tôi nhận được nó làm việc tại đây là đoạn code làm việc (nếu ai đó cần nó :-))

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

tôi đã nhận nó làm việc tất cả !

Đây là đoạn mã liên kết mẫu: [email protected]: RudyAramayo/AVAssetWriterInputPixelBufferAdaptorSample.git

Đây là mã bạn cần:

- (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

Bạn có ý định bỏ ghi chú dòng 'CVPixelBufferPoolCreatePixelBuffer' bên trong' pixelBufferFromCGImage' không? Hay bạn quyết định không sử dụng 'CVPixelBufferPoolCreatePixelBuffer'? – taber

+0

Tôi đã rất lạc lối vào thời điểm tôi viết bài này, đó là một tập hợp nhiều bộ mã khác nhau mà tôi đã cố gắng tái kỹ sư ... xin đừng bận tâm một số quark như những thứ đã nhận xét, tôi vẫn đang học/testing ... Ill phải cải thiện mẫu và gửi thêm mã AVFoundation sớm. – Orbitus007

+1

Không sử dụng mã này - nó sai. Để sử dụng một nhóm, bạn chỉ cần gọi CVPixelBufferPoolCreatePixelBuffer. – AlexeyVMP

Các vấn đề liên quan