Проблема при создании видео из массива изображения - PullRequest
0 голосов
/ 01 марта 2012

Я использовал следующий код для генерации видео из массива изображений и аудио (предварительно записанных) ..

- (void)viewDidLoad
{
    imagearray=[[NSMutableArray alloc]initWithObjects:@"Quiz pic1.jpg",@"Quiz pic2.jpg",@"Quiz pic3.jpg",@"Quiz pic6.jpg",@"Quiz pic7.jpg",nil];
    image1array=[[NSMutableArray alloc]init];
    for (int i=0; i<[imagearray count]; i++)
    {
        UIImage *aimage=[UIImage imageNamed:[imagearray objectAtIndex:i]];
        [image1array addObject:aimage];
    }
    NSLog(@"%@",image1array);
    ImageVideoPath=@"/Users/image/Library/Application Support/iPhone Simulator/4.3/Applications/6CC91208-5819-4BFF-B868-6605887861EB/Output";
    FinalVideoPath=@"/Users/image/Library/Application Support/iPhone Simulator/4.3/Applications/6CC91208-5819-4BFF-B868-6605887861EB/VideoOutput";
    CGSize size;
    UIImage *image=[UIImage imageNamed:[imagearray objectAtIndex:0]];
    size=image.size;
    NSString *audioFilePath;
    int duration=10;
    //[self pixelBufferFromCGImage:[[image1array objectAtIndex:0] CGImage]];
    [self writeImageAndAudioAsMovie:image andAudio:audioFilePath duration:duration];

    //[self pixelBufferFromCGImage:[image CGImage] andSize:size];
    [super viewDidLoad];
}

- (void)writeImageAndAudioAsMovie:(UIImage*)image andAudio:(NSString *)audioFilePath duration:(int)duration {
    NSLog(@"start make movie: length:%d",duration);
    NSError *error = nil;
    AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:ImageVideoPath] fileType:AVFileTypeQuickTimeMovie
                                                              error:&error];
    NSParameterAssert(videoWriter);
    if ([[NSFileManager defaultManager] fileExistsAtPath:ImageVideoPath]) 
        [[NSFileManager defaultManager] removeItemAtPath:ImageVideoPath error:nil];

    NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:AVVideoCodecH264, AVVideoCodecKey,
                                   [NSNumber numberWithInt:image.size.width],AVVideoWidthKey,[NSNumber numberWithInt:image.size.height], AVVideoHeightKey,nil];
    AVAssetWriterInput* writerInput = [[AVAssetWriterInput
                                        assetWriterInputWithMediaType:AVMediaTypeVideo
                                        outputSettings:videoSettings] retain];

    AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput sourcePixelBufferAttributes:nil];
    NSParameterAssert(writerInput);
    NSParameterAssert([videoWriter canAddInput:writerInput]);
    writerInput.expectsMediaDataInRealTime = YES;
    [videoWriter setShouldOptimizeForNetworkUse:YES];
    [videoWriter addInput:writerInput];

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

    //Write samples:
    CVPixelBufferRef buffer = [self pixelBufferFromCGImage:image.CGImage];
    [adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero];

    //Finish the session:
    [videoWriter endSessionAtSourceTime:CMTimeMake(duration, 1)];
    [writerInput markAsFinished];
    [videoWriter finishWriting];

    CVPixelBufferPoolRelease(adaptor.pixelBufferPool);
    [videoWriter release];
    [writerInput release];
    audioFilePath=[[NSBundle mainBundle]pathForResource:@"Video" ofType:@"mp3"];
    NSLog(@"%@",audioFilePath);
    [self addAudioToFileAtPath:ImageVideoPath andAudioPath:audioFilePath];
}

-(CVPixelBufferRef)pixelBufferFromCGImage: (CGImageRef) image{
    float width = CGImageGetWidth(image);
    float height = CGImageGetHeight(image);

    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
                             nil];
    CVPixelBufferRef pxbuffer = NULL;
    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, width,height, kCVPixelFormatType_32ARGB,(CFDictionaryRef)options,&pxbuffer);

    NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);

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

    NSParameterAssert(pxdata != NULL);

    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pxdata,width,height,8,4*width,rgbColorSpace,kCGImageAlphaNoneSkipFirst);

    NSParameterAssert(context);
    CGContextDrawImage(context, CGRectMake(0, 0,width, height), image);

    CGColorSpaceRelease(rgbColorSpace);
    CGContextRelease(context);

    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);

    return pxbuffer;
}

-(void) addAudioToFileAtPath:(NSString *)vidoPath andAudioPath:(NSString *)audioFilePath{
    AVMutableComposition* mixComposition = [AVMutableComposition composition];
    NSLog(@"%@ %@",ImageVideoPath,audioFilePath);
    NSURL* audio_inputFileUrl = [NSURL fileURLWithPath:audioFilePath];
    NSURL* video_inputFileUrl = [NSURL fileURLWithPath:ImageVideoPath];
    NSLog(@"%@",video_inputFileUrl);
    NSString *outputFilePath = FinalVideoPath;
    NSURL* outputFileUrl = [NSURL fileURLWithPath:outputFilePath];

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

   AVURLAsset* audioAsset = [[AVURLAsset alloc]initWithURL:audio_inputFileUrl options:nil];
AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:video_inputFileUrl options:nil];
NSLog(@"asset:%@",videoAsset);
NSArray *tracks1=[videoAsset tracksWithMediaType:AVMediaTypeVideo];
if ([tracks1 count]>0)
{
    //CMTimeRange video_timeRange = CMTimeRangeMake(kCMTimeZero,videoAsset.duration);
    AVAssetTrack *videoAssetTrack=[tracks1 objectAtIndex:0];
    AVMutableCompositionTrack *a_compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];

    [a_compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,videoAsset.duration) ofTrack:videoAssetTrack atTime:kCMTimeZero error:nil];  

}

NSArray *tracks = [audioAsset tracksWithMediaType:AVMediaTypeAudio];
if([tracks count]>0)
{
    AVAssetTrack * audioAssetTrack = [tracks objectAtIndex:0];
    AVMutableCompositionTrack *compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio 
                                                                                   preferredTrackID: kCMPersistentTrackID_Invalid];

    [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,audioAsset.duration) ofTrack:audioAssetTrack atTime:kCMTimeZero error:nil];  


    //nextClipStartTime = CMTimeAdd(nextClipStartTime, a_timeRange.duration);
    [audioAsset release];audioAsset = nil;
}


    AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];   
    _assetExport.outputFileType = AVFileTypeMPEG4;
    _assetExport.outputURL = outputFileUrl;

    [_assetExport exportAsynchronouslyWithCompletionHandler:
     ^(void ) {
         switch (_assetExport.status) 
         {
             case AVAssetExportSessionStatusCompleted:
                 //export complete 
                 NSLog(@"Export Complete");
                 break;
             case AVAssetExportSessionStatusFailed:
                 NSLog(@"Export Failed");
                 NSLog(@"ExportSessionError: %@", [_assetExport.error localizedDescription]);
                 //export error (see exportSession.error)  
                 break;
             case AVAssetExportSessionStatusCancelled:
                 NSLog(@"Export Failed");
                 NSLog(@"ExportSessionError: %@", [_assetExport.error localizedDescription]);
                 //export cancelled  
                 break;
         }
     }];    
}

Я обнаружил, что один из видеофайлов создан методом writeImageAndAudioAsMovie, но он не поддерживает любой плеер на моей машине ... Я не знаю, что я скучаю? Любые предложения плз ....

Ответы [ 2 ]

0 голосов
/ 28 сентября 2012

Одна вещь, которая привлекла мое внимание, это то, что вы вызываете CVPixelBufferPoolRelease(adaptor.pixelBufferPool); в своем writeImageAndAudioAsMovie:andAudio:duration: методе, но, поскольку вы не создали adaptor.pixelBufferPool, вы не владеете им и, следовательно, не должны его выпускать,право?Мне кажется подозрительным.

0 голосов
/ 01 марта 2012

Проблема заключается в двух местах:

1.Путь, который вы указываете, должен быть таким, чтобы вы могли писать как каталог документов.И это должно иметь определенное расширение.Когда вы создаете HighestQualityVideo, оно должно быть .mov.

2.Вы должны предоставить правильный outputFileType, соответствующий расширению и presetType.так что в вашем случае это должно быть _assetExport.outputFileType = AVFileTypeQuickTimeMovie;.

Попробуйте с этими изменениями.

Обновление: Чтобы удалить ошибку, вам нужно заменить код для AVAssetTrack наследующий код в методе addAudioToFileAtPath:

NSArray *tracks = [videoAsset tracksWithMediaType:AVMediaTypeAudio];
if([tracks count]>0)
{
AVAssetTrack * audioAssetTrack = [tracks objectAtIndex:0];
    AVMutableCompositionTrack *compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio 
                                                                                preferredTrackID: kCMPersistentTrackID_Invalid];

    [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,videoAsset.duration) ofTrack:audioAssetTrack atTime:kCMTimeZero error:nil];  


    //nextClipStartTime = CMTimeAdd(nextClipStartTime, a_timeRange.duration);
    [audioAsset release];audioAsset = nil;
}

Относительно типов видео:

Facebook поддерживает QuickTimeVideo (mov / qt), см. http://www.facebook.com/help/?faq=218673814818907

Для поддержки другого типавидео, которые вам нужно будет изменить presetName при создании объекта AVAssetExportSession и расширения выходного файла, для этого, пожалуйста, просмотрите этот документ.

http://www.google.co.in/url?sa=t&rct=j&q=AVAssetExportSession++class&source=web&cd=1&ved=0CCYQFjAA&url=http%3A%2F%2Fdeveloper.apple.com%2Flibrary%2Fios%2FDOCUMENTATION%2FAVFoundation%2FReference%2FAVAssetExportSession_Class%2FReference%2FReference.html&ei=xXxPT5akDsG8rAeck5XUDQ&usg=AFQjCNH1HqxIiT1kYJom6kZ82NS-qjVSyQ&cad=rja

Обновление 1:

Здесь мы получаем доступ к каждому изображению и добавляем его в буфер после отображения некоторого времени (я разделил продолжительность.

for (int i=0; i<[image1array count]; i++)
    {
        int time = (int)i*(duration/[image1array count]);
        CVPixelBufferRef buffer = [self pixelBufferFromCGImage:[[image1array objectAtIndex:i] CGImage]];
        [adaptor appendPixelBuffer:buffer withPresentationTime:CMTimeMake(time, 1)];
    }

Обновление 2:

Вот код, в котором я внес несколько изменений в состав смешанного актива.

-(void) addAudioToFileAtPath:(NSString *)vidoPath andAudioPath:(NSString *)audioFilePath{

    NSURL* audio_inputFileUrl = [NSURL fileURLWithPath:audioFilePath];
    NSURL* video_inputFileUrl = [NSURL fileURLWithPath:ImageVideoPath];
     NSURL* outputFileUrl = [NSURL fileURLWithPath:FinalVideoPath];
    AVMutableComposition *composition = [AVMutableComposition composition];
    AVAsset * audioAsset = [AVURLAsset URLAssetWithURL:audio_inputFileUrl options:nil];;
    AVAsset * videoAsset = [AVURLAsset URLAssetWithURL:video_inputFileUrl options:nil];

    AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo
                                                                                preferredTrackID:kCMPersistentTrackID_Invalid];
    AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio
                                                                                preferredTrackID:kCMPersistentTrackID_Invalid];

    NSError *error = nil;
    BOOL ok = NO;

    CMTimeRange video_timeRange = CMTimeRangeMake(kCMTimeZero,videoAsset.duration);
    AVAssetTrack *sourceVideoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
    ok = [compositionVideoTrack insertTimeRange:video_timeRange ofTrack:sourceVideoTrack atTime:kCMTimeZero error:&error];
    if (!ok) {
        // Deal with the error.
        NSLog(@"Error : %@ : %d",error,videoAsset.duration.value);
    }
    CMTimeRange audio_timeRange = CMTimeRangeMake(kCMTimeZero, audioAsset.duration);
    AVAssetTrack *sourceAudioTrack = [[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
    ok = [compositionAudioTrack insertTimeRange:audio_timeRange ofTrack:sourceAudioTrack atTime:kCMTimeZero error:&error];
    if (!ok) {
        // Deal with the error.
        NSLog(@"Error : %@ : %d",error,audioAsset.duration.value);
    }

    AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetHighestQuality];   
    _assetExport.outputFileType = AVFileTypeQuickTimeMovie;
    _assetExport.outputURL = outputFileUrl;

    [_assetExport exportAsynchronouslyWithCompletionHandler:
     ^(void ) {
         switch (_assetExport.status) 
         {
             case AVAssetExportSessionStatusCompleted:
                 //export complete 
                 NSLog(@"Export Complete");
                 break;
             case AVAssetExportSessionStatusFailed:
                 NSLog(@"Export Failed");
                 NSLog(@"ExportSessionError: %@", [_assetExport.error localizedDescription]);
                 //export error (see exportSession.error)  
                 break;
             case AVAssetExportSessionStatusCancelled:
                 NSLog(@"Export Failed");
                 NSLog(@"ExportSessionError: %@", [_assetExport.error localizedDescription]);
                 //export cancelled  
                 break;
         }
         NSLog(@"Error : %@",_assetExport.error);
     }];    
}

Спасибо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...