xcode中图像数组的视频

Posted

技术标签:

【中文标题】xcode中图像数组的视频【英文标题】:video of image array in xcode 【发布时间】:2014-08-14 12:45:51 【问题描述】:

我已经对图像进行了屏幕截图并将其文档目录路径存储到了一个数组中。 我想通过传递这个数组来创建一个视频。这是我创建视频的代码

-(void)writeImagesAsMovie:(NSArray *)array toPath:(NSString *)path


    NSError *error1 = nil;
    NSFileManager *fileMgr = [NSFileManager defaultManager];

    if ([fileMgr removeItemAtURL:[NSURL fileURLWithPath:path] error:&error1]!=YES)
    
        NSLog(@"Unable to delete file: %@", [error1 localizedDescription]);
    

    UIImage *first = [UIImage imageWithContentsOfFile:[array objectAtIndex:0]];


    CGSize frameSize = first.size;

    NSError *error = nil;
    AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:
                                  [NSURL fileURLWithPath:path] fileType:AVFileTypeMPEG4
                                                              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_32RGBA] 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;

    int fps = 25;


    int cnt = 0;
    for (NSString *filename in array)
    
        if (adaptor.assetWriterInput.readyForMoreMediaData)
        

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

            UIImage *imgFrame=[UIImage imageWithContentsOfFile:filename];

            buffer = [self pixelBufferFromCGImage:[imgFrame CGImage]];
            BOOL result = [adaptor appendPixelBuffer:buffer withPresentationTime:presentTime];

            if (result == NO) 
                NSLog(@"failed to append buffer");
                NSLog(@"The error is %@", [videoWriter error]);
            

            if(buffer) 
                CVBufferRelease(buffer);
            
        

        else 
            NSLog(@"error");
            cnt--;
        
    

    // finish the session
    [writerInput markAsFinished];
    [videoWriter finishWritingWithCompletionHandler:^

    ];

    CVPixelBufferPoolRelease(adaptor.pixelBufferPool);

        UIAlertView *saveAlert = [[UIAlertView alloc] initWithTitle:@"Complete" message:@"Finished making movie" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
    [saveAlert show];


- (CVPixelBufferRef) pixelBufferFromCGImage: (CGImageRef) cgiImage 



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

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

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

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



    CGContextConcatCTM(context, CGAffineTransformMakeRotation(0));

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



    CGAffineTransform flipHorizontal = CGAffineTransformMake(
                                                             -1.0, 0.0, 0.0, 1.0, CGImageGetWidth(cgiImage), 0.0
                                                             );

    CGContextConcatCTM(context, flipHorizontal);


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

    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);

    return pxbuffer;

此代码帮助我创建视频,但视频不正确,所有像素都模糊了......

【问题讨论】:

你为什么要标记android 【参考方案1】:

在 .m 文件中。

导入“ViewController.h”

@interface ViewController()

@结束

@implementation 视图控制器

-(void)viewDidLoad

[超级viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

-(void)didReceiveMemoryWarning

[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.

-(IBAction)createVideo:(id)sender

NSError *error = nil;

NSFileManager *fileMgr = [NSFileManager defaultManager];

NSString *documentsDirectory = [NSHomeDirectory()
                                stringByAppendingPathComponent:@"Documents"];
NSString *videoOutputPath = [documentsDirectory stringByAppendingPathComponent:@"test_output.mp4"];

if ([fileMgr removeItemAtPath:videoOutputPath error:&error] != YES)

    NSLog(@"Unable to delete file: %@", [error localizedDescription]);


CGSize imageSize = CGSizeMake(400, 200);
NSUInteger fps = 30;



NSMutableArray *imageArray;
imageArray = [[NSMutableArray alloc] initWithObjects:@"photo1.png",@"photo2.png",@"photo3.png",@"photo4.png",@"photo5.png", nil];

NSArray* imagePaths = [[NSBundle mainBundle] pathsForResourcesOfType:@"png" inDirectory:nil];
imageArray = [[NSMutableArray alloc] initWithCapacity:imagePaths.count];
NSLog(@"-->imageArray.count= %lu", (unsigned long)imageArray.count);
for (NSString* path in imagePaths)

    [imageArray addObject:[UIImage imageWithContentsOfFile:path]];



NSLog(@"Start building video from defined frames.");

AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:
                              [NSURL fileURLWithPath:videoOutputPath] fileType:AVFileTypeQuickTimeMovie
                                                          error:&error];
NSParameterAssert(videoWriter);

NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                               AVVideoCodecH264, AVVideoCodecKey,
                               [NSNumber numberWithInt:imageSize.width], AVVideoWidthKey,
                               [NSNumber numberWithInt:imageSize.height], AVVideoHeightKey,
                               nil];

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


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

NSParameterAssert(videoWriterInput);
NSParameterAssert([videoWriter canAddInput:videoWriterInput]);
videoWriterInput.expectsMediaDataInRealTime = YES;
[videoWriter addInput:videoWriterInput];


[videoWriter startWriting];
[videoWriter startSessionAtSourceTime:kCMTimeZero];

CVPixelBufferRef buffer = NULL;


int frameCount = 0;
double numberOfSecondsPerFrame = 6;
double frameDuration = fps * numberOfSecondsPerFrame;


NSLog(@"**************************************************");
for(UIImage * img in imageArray)


    buffer = [self pixelBufferFromCGImage:[img CGImage]];

    BOOL append_ok = NO;
    int j = 0;
    while (!append_ok && j < 30) 
        if (adaptor.assetWriterInput.readyForMoreMediaData)  

            NSLog(@"Processing video frame (%d,%d)",frameCount,[imageArray count]);

            CMTime frameTime = CMTimeMake(frameCount*frameDuration,(int32_t) fps);
            append_ok = [adaptor appendPixelBuffer:buffer withPresentationTime:frameTime];
            if(!append_ok)
                NSError *error = videoWriter.error;
                if(error!=nil) 
                    NSLog(@"Unresolved error %@,%@.", error, [error userInfo]);
                
            
        
        else 
            printf("adaptor not ready %d, %d\n", frameCount, j);
            [NSThread sleepForTimeInterval:0.1];
        
        j++;
    
    if (!append_ok) 
        printf("error appending image %d times %d\n, with error.", frameCount, j);
    
    frameCount++;

NSLog(@"**************************************************");

[videoWriterInput markAsFinished];
[videoWriter finishWriting];


AVMutableComposition* mixComposition = [AVMutableComposition composition];

NSString *bundleDirectory = [[NSBundle mainBundle] bundlePath];

NSString *audio_inputFilePath = [bundleDirectory stringByAppendingPathComponent:@"30secs.mp3"];
NSURL    *audio_inputFileUrl = [NSURL fileURLWithPath:audio_inputFilePath];


NSURL    *video_inputFileUrl = [NSURL fileURLWithPath:videoOutputPath];


NSString *outputFilePath = [documentsDirectory stringByAppendingPathComponent:@"final_video.mp4"];
NSURL    *outputFileUrl = [NSURL fileURLWithPath:outputFilePath];

if ([[NSFileManager defaultManager] fileExistsAtPath:outputFilePath])
    [[NSFileManager defaultManager] removeItemAtPath:outputFilePath error:nil];

CMTime nextClipStartTime = kCMTimeZero;

AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:video_inputFileUrl options:nil];
CMTimeRange video_timeRange = CMTimeRangeMake(kCMTimeZero,videoAsset.duration);
AVMutableCompositionTrack *a_compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[a_compositionVideoTrack insertTimeRange:video_timeRange ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:nextClipStartTime error:nil];




AVURLAsset* audioAsset = [[AVURLAsset alloc]initWithURL:audio_inputFileUrl options:nil];
CMTimeRange audio_timeRange = CMTimeRangeMake(kCMTimeZero, audioAsset.duration);
AVMutableCompositionTrack *b_compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[b_compositionAudioTrack insertTimeRange:audio_timeRange ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:nextClipStartTime error:nil];



AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];

_assetExport.outputFileType = @"public.mpeg-4";

_assetExport.outputURL = outputFileUrl;


[_assetExport exportAsynchronouslyWithCompletionHandler:
 ^(void ) 
    //[self saveVideoToAlbum:outputFilePath];
 
 ];

NSLog(@"DONE.....outputFilePath--->%@", outputFilePath);

-(CVPixelBufferRef) pixelBufferFromCGImage: (CGImageRef) 图像

CGSize size = CGSizeMake(400, 200);

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,
                                      (__bridge CFDictionaryRef) options,
                                      &pxbuffer);
if (status != kCVReturnSuccess)
    NSLog(@"Failed to create pixel buffer");


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

CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pxdata, size.width,
                                             size.height, 8, 4*size.width, rgbColorSpace,(CGBitmapInfo)
                                             kCGImageAlphaNoneSkipLast);

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

CVPixelBufferUnlockBaseAddress(pxbuffer, 0);

return pxbuffer;

@结束

在 .h 文件中...

导入

导入 Foundation/Foundation.h

导入CoreMedia/CoreMedia.h

导入CoreVideo/CoreVideo.h

导入 CoreGraphics/CoreGraphics.h

导入 AVFoundation/AVFoundation.h

导入 QuartzCore/QuartzCore.h

@interface ViewController : UIViewController

-(IBAction)createVideo:(id)sender;

@结束

并添加以下框架.. CoreMedia.framework

CoreVideo.framework

CoreGraphics.framework

AVFoundation.framework

QuartzCore.framework

【讨论】:

以上是关于xcode中图像数组的视频的主要内容,如果未能解决你的问题,请参考以下文章

java中图像与数组转换

Python-OpenCV中图像合并显示

如何获取相册中图像的图像文件名和标签?

matlab中图像显示函数

无法读取 C 中图像的所有字节 [重复]

css 在nuvo-express上更改主页视频块中图像的背景位置。不幸的是!因为内联风格很重要......