5

我对编程比较陌生,虽然我对正常功能没问题,但我对视频编辑完全陌生

所以我设法在网上找到了一些代码来完成如下所示的工作:

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

但是我遇到的问题是视频的输出有些损坏(它确实可以播放,尽管它​​有如下所示的有趣的线条: 在此处输入图像描述

我会很感激任何帮助

非常感谢

托马斯

4

1 回答 1

10

我一直看到 H264 视频编码硬件存在问题,它可能会破坏与已知宽高比不匹配的输入。例如,我的测试表明,如果一个视频尺寸小于 128 像素,则视频不会编码。

我所看到的工作是 128x128、192x128、240x160、480x320 等。

请参阅此页面的纵横比

PS 您可能会想要使用 ,AVAssetWriterInputPixelBufferAdaptor因为它包含一个像素缓冲池,您可以通过CVPixelBufferPoolCreatePixelBuffer(). 此外,您需要assert(adaptor.pixelBufferPool);在调用startSessionAtSourceTime后确保您的适配器可以写入作者。

于 2012-07-19T09:24:45.197 回答