从图像创建视频并保存到相册

Posted

技术标签:

【中文标题】从图像创建视频并保存到相册【英文标题】:create video from images and save to photo album 【发布时间】:2012-10-31 21:54:12 【问题描述】:

我正在用一组图像和一个音频文件制作视频

但我似乎无法将其保存到相机胶卷

有时它会保存,但有时它不会并给我一个奇怪的错误

outputFile.mp4 无法保存到已保存的相册中:Error Domain=NSOSStatusErrorDomain Code=-12848 “电影无法播放。” UserInfo=0x7bd7370 NSLocalizedDescription=电影无法播放。

此函数从图像数组创建视频:

-(void) writeImagesToMovieAtPath:(NSString *) path withSize:(CGSize) size

    NSLog(@"Write Started");

    NSError *error = nil;

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

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

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


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

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

    //Start a session:
    [videoWriter startWriting];
    [videoWriter startSessionAtSourceTime:kCMTimeZero];

    CVPixelBufferRef buffer = NULL;

    //convert uiimage to CGImage.

    int frameCount = 16;
    int kRecordingFPS = 30;
    UIImage * im = [UIImage imageNamed:@"IMG_0103.JPG"];

    NSArray * imageArray = [[NSArray alloc]initWithObjects:im,im,im,im,im,im,im,im,im,im,im,im,im,im,im,im, nil];

    for(UIImage * img in imageArray)
    
        buffer = [self pixelBufferFromCGImage:[img CGImage] andSize:size];

        BOOL append_ok = NO;
        int j = 0;
        while (!append_ok && j < 30)
        
            if (adaptor.assetWriterInput.readyForMoreMediaData)
            
                printf("appending %d attemp %d\n", frameCount, j);

                CMTime frameTime = CMTimeMake(frameCount,(int32_t) kRecordingFPS);
                append_ok = [adaptor appendPixelBuffer:buffer withPresentationTime:frameTime];

                if(buffer)
                    CVBufferRelease(buffer);
                [NSThread sleepForTimeInterval:0.05];
            
            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", frameCount, j);
        
        frameCount++;
    


    //Finish the session:
    [videoWriterInput markAsFinished];
    [videoWriter finishWriting];
    NSLog(@"Write Ended");
    [videoWriterInput release];
    [videoWriter release];
    [imageArray release];

此函数添加音频:

    -(void)CompileFilesToMakeMovie
        AVMutableComposition* mixComposition = [AVMutableComposition composition];

        NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];

        NSString* audio_inputFileName = @"Rihanna-Take a Bow.mp3";

        NSString* audio_inputFilePath = [NSString stringWithFormat:@"%@/%@",documentsDirectoryPath,audio_inputFileName];

        NSURL*    audio_inputFileUrl = [NSURL fileURLWithPath:audio_inputFilePath];

        NSString* video_inputFileName = @"a.mp4";
        NSString* video_inputFilePath = [NSString stringWithFormat:@"%@/%@",documentsDirectoryPath,video_inputFileName];
        NSURL*    video_inputFileUrl = [NSURL fileURLWithPath:video_inputFilePath];

        NSString* outputFileName = @"outputFile.mp4";
        NSString* outputFilePath = [NSString stringWithFormat:@"%@/%@",documentsDirectoryPath,outputFileName];

        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];

        //nextClipStartTime = CMTimeAdd(nextClipStartTime, a_timeRange.duration);

        AVURLAsset* audioAsset = [[AVURLAsset alloc]initWithURL:audio_inputFileUrl options:nil];
        CMTimeRange audio_timeRange = CMTimeRangeMake(kCMTimeZero, videoAsset.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:AVAssetExportPresetMediumQuality];
        _assetExport.outputFileType = AVFileTypeMPEG4;
        _assetExport.outputURL = outputFileUrl;
        [_assetExport setTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)];
        [_assetExport exportAsynchronouslyWithCompletionHandler:nil];

        [audioAsset release];
        [videoAsset release];


        [_assetExport release];
    

函数调用:

- (void)viewDidLoad

    [super viewDidLoad];
    NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];

    UIImage * i = [UIImage imageNamed:@"IMG_0103.JPG"];

    [self writeImagesToMovieAtPath:[NSString stringWithFormat:@"%@/%@",documentsDirectoryPath,@"a.mp4"] withSize:CGSizeMake(i.size.width, i.size.height)];

    NSString* exportVideoPath1 = [NSString stringWithFormat:@"%@/%@",documentsDirectoryPath,@"a.mp4"];


    NSString* exportVideoPath = [NSString stringWithFormat:@"%@/%@",documentsDirectoryPath,@"outputFile.mp4"];

    UISaveVideoAtPathToSavedPhotosAlbum (exportVideoPath,self, @selector(video:didFinishSavingWithError: contextInfo:), nil);


【问题讨论】:

你能再清楚一点。你做了一个应用程序,将图片转换为视频,然后保存视频?有时它并没有拯救他们?你有什么代码可以分享一下你的 dong 方法吗? 我添加的代码主要是我在这篇文章中使用的代码:***.com/a/6094407/1708270 这正是发生的事情,有时它会保存,有时它也不会自行将错误代码更改为 (Code=-12893) 不确定这是否有帮助。但是在将图像保存到 ALAssetsGroup 时我遇到了类似的问题(图像到画廊,类似于你正在做的事情),它有时会起作用,但有时会不起作用。问题似乎是操作系统在一段时间内阻止了调用。我通过添加代码以在等待(例如 0.1 秒)后再次尝试失败来解决这个问题。这解决了我的问题。如果遇到错误,请尝试添加呼叫以在延迟一段时间后重试。 我让它休眠 1 秒然后尝试保存增益,但它一直在尝试并给出相同的错误@Bergasms THX 任何方式:D 【参考方案1】:

就我而言,原因是 AVAssetWriter 尚未完成写入。使用以下代码解决了它:

__block BOOL _finished = NO;

[assetWriter finishWritingWithCompletionHandler:^
    _finished = YES;
];

while (!_finished) 
    [NSThread sleepForTimeInterval:0.1];

【讨论】:

以上是关于从图像创建视频并保存到相册的主要内容,如果未能解决你的问题,请参考以下文章

iOS之保存图片到系统相册和从系统相册选取一张或者多张照片

如何将图像保存到具有来自先前视图控制器的 id 的单独相册中

如何使用 PHPhotoLibrary 将视频/图像写入保存的相册?

将图像保存在 iOS 相册(我的文件夹)中并存储图像 url

如何使用 angularjs 从 url 下载(保存)图像到我们的相册中?

在 iOS 应用中保存和显示视频。