2012-07-14 23 views
5

Tôi tương đối mới để lập trình và mặc dù tôi ok với các chức năng bình thường, tôi tuy nhiên là hoàn toàn mới để chỉnh sửa videoNSArray của UIImages lỗi video có méo trong đầu ra

Vì vậy, tôi đã cố gắng tìm một số mã trực tuyến để làm các công việc dưới đây:

- (void)writeImagesAsMovie:(NSArray *)array { 
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDirectory, YES); 
NSString *documentDirectory = [paths objectAtIndex:0]; 
NSString *saveLocation = [documentDirectory stringByAppendingString:@"/temp.mov"]; 

if ([[NSFileManager defaultManager] fileExistsAtPath:saveLocation]) { 
    [[NSFileManager defaultManager] removeItemAtPath:saveLocation error:NULL]; 
} 

UIImage *first = [array objectAtIndex:0]; 

CGSize frameSize = first.size; 

NSError *error = nil; 
AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL: 
           [NSURL fileURLWithPath:saveLocation] fileType:AVFileTypeQuickTimeMovie 
                  error:&error]; 

if(error) { 
    NSLog(@"error creating AssetWriter: %@",[error description]); 
} 
NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
           AVVideoCodecH264, AVVideoCodecKey, 
           [NSNumber numberWithInt:frameSize.width], AVVideoWidthKey, 
           [NSNumber numberWithInt:frameSize.height], AVVideoHeightKey, 
           nil]; 



AVAssetWriterInput *writerInput = [AVAssetWriterInput 
            assetWriterInputWithMediaType:AVMediaTypeVideo 
            outputSettings:videoSettings]; 

NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init]; 
[attributes setObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32ARGB] forKey:(NSString*)kCVPixelBufferPixelFormatTypeKey]; 
[attributes setObject:[NSNumber numberWithUnsignedInt:frameSize.width] forKey:(NSString*)kCVPixelBufferWidthKey]; 
[attributes setObject:[NSNumber numberWithUnsignedInt:frameSize.height] forKey:(NSString*)kCVPixelBufferHeightKey]; 

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

[videoWriter addInput:writerInput]; 

// fixes all errors 
writerInput.expectsMediaDataInRealTime = YES; 

//Start a session: 
[videoWriter startWriting]; 

[videoWriter startSessionAtSourceTime:kCMTimeZero]; 

CVPixelBufferRef buffer = NULL; 
buffer = [self pixelBufferFromCGImage:[first CGImage]]; 
BOOL result = [adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero]; 

if (result == NO) //failes on 3GS, but works on iphone 4 
    NSLog(@"failed to append buffer"); 

if(buffer) { 
    CVBufferRelease(buffer); 
} 



//int reverseSort = NO; 
NSArray *newArray = array; 



int fps = 10; 


int i = 0; 
for (UIImage *image in newArray) 
{ 
    [NSThread sleepForTimeInterval:0.02]; 
    if (adaptor.assetWriterInput.readyForMoreMediaData) { 

     i++; 
     CMTime frameTime = CMTimeMake(1, fps); 
     CMTime lastTime = CMTimeMake(i, fps); 
     CMTime presentTime = CMTimeAdd(lastTime, frameTime); 

     UIImage *imgFrame = image;//[UIImage imageWithContentsOfFile:filePath] ; 
     buffer = [self pixelBufferFromCGImage:[imgFrame CGImage]]; 
     BOOL result = [adaptor appendPixelBuffer:buffer withPresentationTime:presentTime]; 

     if (result == NO) //failes on 3GS, but works on iphone 4 
     { 
      NSLog(@"failed to append buffer"); 
      NSLog(@"The error is %@", [videoWriter error]); 
      [NSThread sleepForTimeInterval:0.5]; 
     } 

     if(buffer) { 
      CVBufferRelease(buffer); 
     } 


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

//Finish the session: 
[writerInput markAsFinished]; 
[videoWriter finishWriting]; 
CVPixelBufferPoolRelease(adaptor.pixelBufferPool); 

NSLog(@"Movie created successfully"); 
} 

- (CVPixelBufferRef) pixelBufferFromCGImage: (CGImageRef) image 
{ 


    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: 
          [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey, 
          [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, 
          nil]; 
    CVPixelBufferRef pxbuffer = NULL; 

    CVPixelBufferCreate(kCFAllocatorDefault, CGImageGetWidth(image), 
         CGImageGetHeight(image), kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options, 
         &pxbuffer); 

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

    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef context = CGBitmapContextCreate(pxdata, CGImageGetWidth(image), 
               CGImageGetHeight(image), 8, 4*CGImageGetWidth(image), rgbColorSpace, 
               kCGImageAlphaNoneSkipFirst); 

    CGContextConcatCTM(context, CGAffineTransformMakeRotation(0)); 

    // CGAffineTransform flipVertical = CGAffineTransformMake(
    //               1, 0, 0, -1, 0, CGImageGetHeight(image) 
    //               ); 
    // CGContextConcatCTM(context, flipVertical); 



    // CGAffineTransform flipHorizontal = CGAffineTransformMake(
    //                -1.0, 0.0, 0.0, 1.0, CGImageGetWidth(image), 0.0 
    //               ); 
    // 
    // CGContextConcatCTM(context, flipHorizontal); 


    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), 
              CGImageGetHeight(image)), image); 
    CGColorSpaceRelease(rgbColorSpace); 
    CGContextRelease(context); 

    CVPixelBufferUnlockBaseAddress(pxbuffer, 0); 

    return pxbuffer; 
} 

Nhưng vấn đề mà tôi đang gặp là đầu ra của video là một số cách hỏng (nó chơi mặc dù nó đã dòng hài hước hình dưới đây: enter image description here

Tôi sẽ rất biết ơn sự giúp đỡ nào

Nhiều Cảm ơn

Thomas

Trả lời

10

Tôi đã nhìn thấy vấn đề với phần cứng mã hóa video H264 nơi nó có thể vào tham nhũng mà không phù hợp với tỷ lệ khung hình nổi tiếng. Ví dụ: thử nghiệm của tôi cho thấy rằng nếu một thứ nguyên video nhỏ hơn 128 pixel, video sẽ không mã hóa.

Điều tôi thấy là 128x128, 192x128, 240x160, 480x320 và các thiết bị khác.

Xem điều này page on aspect ratios

P.S. Bạn có thể muốn sử dụng AVAssetWriterInputPixelBufferAdaptor vì nó chứa một vùng đệm pixel mà bạn có thể sử dụng qua CVPixelBufferPoolCreatePixelBuffer(). Ngoài ra, bạn sẽ muốn assert(adaptor.pixelBufferPool); sau khi gọi startSessionAtSourceTime để đảm bảo rằng bộ điều hợp của bạn có thể viết cho người viết.

+0

Cảm ơn bạn rất nhiều, đã làm việc một cách hoàn hảo! –

+0

Rất hữu ích. Bạn có thể cập nhật liên kết hoặc chia sẻ thêm thông tin về tỷ lệ khung hình được hỗ trợ không? Tôi nhận thấy rằng mặc dù 960x540 được hỗ trợ nhưng 540x960 không được hỗ trợ; định dạng chân dung thường không được hỗ trợ bởi h264? – Morrowless

+0

Không có tài liệu nào về điều này ở bất cứ đâu, tôi đã xem. Bạn chỉ cần thử nó ở một kích thước cụ thể và xem nếu nó hoạt động. Bạn có thể không nhận được mã lỗi ở kích thước cụ thể, nhưng phần cứng vẫn có thể tranh giành dữ liệu hình ảnh của bạn. H.264 nên làm việc với hầu hết các kích cỡ (giả sử cả hai bên là sự kiện), nhưng phần cứng để mã hóa thành h.264 bao gồm với iOS là rất nhiều cầu kỳ và khó xử lý. – MoDJ

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