2014-10-09 567 views
0

我有一個圖像數組可以轉換爲MP4文件。從我所知道的情況來看,似乎並沒有將圖像添加到視頻的視頻幀中,導致視頻中出現零幀。我如何解決這個錯誤,以正確地將圖像轉換爲視頻文件?以下是轉換器的所有代碼和錯誤消息的圖像。將圖像陣列轉換爲MP4文件時遇到問題

- (void) createVideoPlayer:(NSArray *)imagesArray { 

    NSError *error = nil; 


    // set up file manager, and file videoOutputPath, remove "test_output.mp4" if it exists... 
    //NSString *videoOutputPath = @"/Users/someuser/Desktop/test_output.mp4"; 
    NSFileManager *fileMgr = [NSFileManager defaultManager]; 
    NSString *documentsDirectory = [NSHomeDirectory() 
           stringByAppendingPathComponent:@"Documents"]; 
    NSString *videoOutputPath = [documentsDirectory stringByAppendingPathComponent:@"test_output.mp4"]; 
    //NSLog(@"-->videoOutputPath= %@", videoOutputPath); 
    // get rid of existing mp4 if exists... 
    if ([fileMgr removeItemAtPath:videoOutputPath error:&error] != YES) 
     NSLog(@"Unable to delete file: %@", [error localizedDescription]); 


    CGSize imageSize = CGSizeMake(640, 853); 


//////////////  end setup /////////////////////////////////// 

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

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



    NSDictionary* compression = @{ 
           AVVideoAverageBitRateKey:[NSNumber numberWithInt:(960000 * 2)], 
           AVVideoMaxKeyFrameIntervalKey:[NSNumber numberWithInt:1] 
           }; 
    AVAssetWriterInput* videoWriterInput = [AVAssetWriterInput 
             assetWriterInputWithMediaType:AVMediaTypeVideo 
             outputSettings:@{ 
                 AVVideoCodecKey:AVVideoCodecH264, 
                 AVVideoCompressionPropertiesKey:compression, 
                 AVVideoWidthKey:[NSNumber numberWithInt:imageSize.width], 
                 AVVideoHeightKey:[NSNumber numberWithInt:imageSize.height] 
                 }]; 


    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 = 0; 

    // double FPS = self.numberOfImages/10; 

    //for(VideoFrame * frm in imageArray) 
    NSLog(@"**************************************************"); 
    for(UIImage * img in imagesArray) 
    { 
     //UIImage * img = frm._imageFrame; 
     buffer = [self pixelBufferFromCGImage:[img CGImage]]; 

     BOOL append_ok = NO; 
     int j = 0; 
     while (!append_ok && j < 30) { 
      if (adaptor.assetWriterInput.readyForMoreMediaData) { 
       //print out status: 
       NSLog(@"Processing video frame (%d,%lu)",frameCount,(unsigned long)[imagesArray count]); 

       CMTime frameTime = CMTimeMake(frameCount,(int32_t) 10); 
       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(@"**************************************************"); 

    //Finish the session: 
    [videoWriterInput markAsFinished]; 
    [videoWriter finishWritingWithCompletionHandler:^{ 

    }]; 
    NSLog(@"Write Ended"); 




    AVMutableComposition* mixComposition = [AVMutableComposition composition]; 



    // this is the video file that was just written above, full path to file is in --> videoOutputPath 
    NSURL *video_inputFileUrl = [NSURL fileURLWithPath:videoOutputPath]; 
    NSLog(@"%@", video_inputFileUrl); 
    // create the final video output file as MP4 
    NSString *outputFilePath = [documentsDirectory stringByAppendingPathComponent:@"final_video.mp4"]; 
    NSURL *outputFileUrl = [NSURL fileURLWithPath:outputFilePath]; 
    NSLog(@"%@", outputFileUrl); 
    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, 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"; 
    //NSLog(@"support file types= %@", [_assetExport supportedFileTypes]); 
    _assetExport.outputURL = outputFileUrl; 
    theURL = _assetExport.outputURL; 
    [_assetExport exportAsynchronouslyWithCompletionHandler: 
    ^(void) { 


     dispatch_async(dispatch_get_main_queue(), ^{ 

      [spinner stopAnimating]; 

     moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:_assetExport.outputURL]; 
     [moviePlayer.view setFrame:CGRectMake(0, 100, 320, 320)]; 
     [moviePlayer prepareToPlay]; 
     [moviePlayer repeatMode]; 
      moviePlayer.backgroundView.backgroundColor = [UIColor whiteColor]; 
     // And other options you can look through the documentation. 
     [self.view addSubview:moviePlayer.view]; 
     [moviePlayer play]; 



     }); 
    } 
    ]; 

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


     //////////////////////////////////////////////////////////////////////////// 
     //////////////////////////////////////////////////////////////////////////// 

} 


//////////////////////// 
- (CVPixelBufferRef) pixelBufferFromCGImage: (CGImageRef) image { 


    CGSize size = CGSizeMake(640, 853); 

    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, 
              kCGImageAlphaNoneSkipFirst); 


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

    CGColorSpaceRelease(rgbColorSpace); 
    CGContextRelease(context); 

    CVPixelBufferUnlockBaseAddress(pxbuffer, 0); 

    return pxbuffer; 

} 

console Log

error

回答

1

AssetWriter的寫作永遠不會結束。 AVAssetWriterStatus是AVAssetWriterStatusWriting,嘗試完成文件寫入之前通過結束其會話訪問它:

CMTime frameTime = CMTimeMake(frameCount, 1);  
[videoWriter endSessionAtSourceTime:frameTime];