2012-07-14 3 views
5

soy relativamente nuevo en la programación y aunque yo estoy bien con las funciones normales, i sin embargo soy totalmente nuevo en la edición de vídeoNSArray de UIImages a un error de vídeo tiene distorsión en la salida

así que he logrado encontrar algo de código en línea para hacer los trabajos muestran a continuación:

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

Pero el problema que estoy teniendo es que la salida del video es de alguna forma corrupta (sí juega aunque ha líneas divertidas se muestra a continuación: enter image description here

Yo estaría muy agradecido por cualquier ayuda

Muchas Gracias

Thomas

Respuesta

10

He estado viendo problemas con el hardware de codificación de vídeo H264 donde puede entrada corrupta que no coincide con una relación de aspecto conocido. Por ejemplo, mis pruebas muestran que si una dimensión de video es menor que 128 píxeles, el video no se codificará.

Lo que he visto trabajando es 128x128, 192x128, 240x160, 480x320, y otros.

ver este page on aspect ratios

P. S. Es probable que desee utilizar el AVAssetWriterInputPixelBufferAdaptor ya que contiene un grupo de búferes de píxeles que puede usar a través del CVPixelBufferPoolCreatePixelBuffer(). Además, deberá llamar al assert(adaptor.pixelBufferPool); después de llamar al startSessionAtSourceTime para asegurarse de que su adaptador pueda escribirle al escritor.

+0

¡Muchas gracias, funcionó a la perfección! –

+0

Muy útil. ¿Puede actualizar el enlace o compartir más información sobre las proporciones de aspecto compatibles? Noté que aunque 960x540 es compatible, 540x960 no; ¿los formatos de retrato generalmente no son compatibles con h264? – Morrowless

+0

No hay documentación sobre esto en ningún lado, lo busqué. Solo tienes que probarlo en un tamaño específico y ver si funciona. Es posible que no obtenga un código de error en un tamaño específico, pero el hardware aún podría codificar sus datos de imagen. H.264 debería funcionar con la mayoría de los tamaños (suponiendo que ambos lados son eventos), pero el hardware para codificar a h.264 incluye iOS con mucho más exigente y difícil de manejar. – MoDJ

Cuestiones relacionadas