2012-07-14 7 views
5

Jestem stosunkowo nowy w programowaniu i chociaż jestem ok z normalnych funkcji, jestem jednak zupełnie nowe do edycji wideoNSArray od UIImages do błędu wideo ma zniekształceń na wyjściu

Więc udało mi się znaleźć trochę kodu w Internecie zrobić zadania przedstawiono poniżej:

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

Ale problem, że ja mam to, że wyjście wideo jest jakiś sposób uszkodzony (to nie grać choć to śmieszne wiersze poniżej: enter image description here

Byłbym bardzo wdzięczny za wszelką pomoc

Wiele Dzięki

Thomas

Odpowiedz

10

byłem widząc problemy ze sprzętem kodowania wideo H264 gdzie można wejście uszkodzony, że nie zgadza się znany proporcji. Na przykład moje testy pokazują, że jeśli jeden wymiar wideo jest mniejszy niż 128 pikseli, wideo nie będzie kodować.

Co Widziałem pracy wynosi 128x128, 192x128, 240x160, 480x320 i inne.

Zobacz ten page on aspect ratios

PS: Najprawdopodobniej będziesz chciał użyć AVAssetWriterInputPixelBufferAdaptor, ponieważ zawiera on pulę buforów pikseli, z której możesz korzystać za pośrednictwem CVPixelBufferPoolCreatePixelBuffer(). Ponadto, po wywołaniu startSessionAtSourceTime użytkownik będzie chciał, aby adapter mógł pisać do programu piszącego.

+0

Dziękuję bardzo, działało idealnie! –

+0

Bardzo pomocny. Czy możesz zaktualizować link lub udostępnić więcej informacji dotyczących obsługiwanych współczynników proporcji? Zauważyłem, że chociaż obsługiwane jest 960x540, 540x960 nie jest; czy formaty portretów nie są zazwyczaj obsługiwane przez h264? – Morrowless

+0

Nie ma żadnej dokumentacji na ten temat, szukałem. Trzeba go wypróbować w określonym rozmiarze i sprawdzić, czy działa. Możliwe, że nie otrzymasz kodu błędu o określonej wielkości, ale sprzęt może nadal szyfrować dane obrazu. H.264 powinien działać z większością rozmiarów (zakładając, że obie strony są zdarzeniami), ale sprzęt do kodowania do h.264, który jest dołączany do systemu iOS, jest znacznie bardziej wybredny i trudny w obsłudze. – MoDJ

Powiązane problemy