2016-05-30 28 views
-1

你好傢伙需要在這裏快速幫助;我正嘗試使用在線教程將圖像轉換爲視頻。該過程在iphone/i-devices和quicktime上完成並正確播放,然而,當在任何其他播放器(如VLC realplayer,網絡播放器等)上播放時,它不會播放。看完最後生成的文件後,我可以看到視頻範圍在0到0.16之間的fps(理想情況下應該在24-30fps之間)。任何人都可以請建議一種方法來修復fps。我使用的代碼是下面:轉換圖像到視頻有錯誤的FPS ios

+ (void)createVideoWithImages:(NSArray <NSString *> *)images withDuration:(long int)duration completion:(void (^) (BOOL success, NSString *output, NSError *error))completion 
{ 
    __block BOOL success    = NO; 
    __block NSString *videoOutputPath = [ViewController newfNameWithPath]; 
    NSError *error      = nil; 

    double width     = 0; 
    double height     = 0; 
    CGSize imageSize    = CGSizeZero; 
    NSUInteger framesPerSecond  = 30; 
    NSMutableArray *imageArray  = [[NSMutableArray alloc] initWithCapacity:images.count]; 

    for (NSUInteger i = 0; i < [images count]; i++) 
    { 
     NSString *imagePath = [images objectAtIndex:i]; 
     [imageArray addObject:[UIImage imageWithContentsOfFile:imagePath]]; 

     UIImage *newImage = [ViewController createImage:((UIImage *)[imageArray objectAtIndex:i])]; 

     UIImage *img = [ViewController imageOrientation:newImage]; 
     [imageArray replaceObjectAtIndex:i withObject:img]; 

     width = (width > ((UIImage *)[imageArray lastObject]).size.width) ? width : ((UIImage *)[imageArray lastObject]).size.width; 
     height = (height > ((UIImage *)[imageArray lastObject]).size.height) ? height : ((UIImage *)[imageArray lastObject]).size.height; 
    } 

    imageSize = CGSizeMake(1280, 720); 

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

    NSDictionary *videoCleanApertureSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
               [NSNumber numberWithInt:1280], AVVideoCleanApertureWidthKey, 
               [NSNumber numberWithInt:720], AVVideoCleanApertureHeightKey, 
               [NSNumber numberWithInt:10], AVVideoCleanApertureHorizontalOffsetKey, 
               [NSNumber numberWithInt:10], AVVideoCleanApertureVerticalOffsetKey, 
               nil]; 

    NSDictionary *aspectRatioSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
             [NSNumber numberWithInt:3], AVVideoPixelAspectRatioHorizontalSpacingKey, 
             [NSNumber numberWithInt:3],AVVideoPixelAspectRatioVerticalSpacingKey, 
             nil]; 

    NSDictionary *codecSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
            [NSNumber numberWithInt:960000], AVVideoAverageBitRateKey, 
            [NSNumber numberWithInt:1],AVVideoMaxKeyFrameIntervalKey, 
            videoCleanApertureSettings, AVVideoCleanApertureKey, 
            aspectRatioSettings, AVVideoPixelAspectRatioKey, 
            //AVVideoProfileLevelH264Main30, AVVideoProfileLevelKey, 
            nil]; 

    NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
            AVVideoCodecH264, AVVideoCodecKey, 
            codecSettings,AVVideoCompressionPropertiesKey, 
            [NSNumber numberWithInt: 1280], AVVideoWidthKey, 
            [NSNumber numberWithInt: 720], 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]; 


    videoWriterInput.transform = CGAffineTransformMakeRotation(M_PI_2 * 2); 

    if (![videoWriter startWriting]) 
    { 
     completion(success, nil, videoWriter.error); 
    } 

    [videoWriter startSessionAtSourceTime:kCMTimeZero]; 

    CVPixelBufferRef buffer   = NULL; 
    int frameCount     = 0; 
    double numberOfSecondsPerFrame = duration/[imageArray count]; 
    double frameDuration   = framesPerSecond * numberOfSecondsPerFrame; 

    for(UIImage *image in imageArray) 
    { 
     buffer      = [ViewController pixelBufferFromCGImage:[image CGImage] withSize:imageSize]; 
     BOOL completeWitnNoError = NO; 
     int counter     = 0; 

     while (!completeWitnNoError && counter < 30) 
     { 

      NSLog(@"writing image: %ld at frame: %d",(long)frameCount, counter); 
      if (adaptor.assetWriterInput.readyForMoreMediaData) 
      { 

       CMTime frameTime  = CMTimeMake(frameCount*frameDuration, (int32_t)framesPerSecond); 
       CMTimeShow(frameTime); 
       completeWitnNoError  = [adaptor appendPixelBuffer:buffer withPresentationTime:frameTime]; 

       if(!completeWitnNoError) 
       { 
        if(buffer) 
         CVPixelBufferRelease(buffer); 

        completion(!completion, nil, videoWriter.error); 
       } 
      } 
      else 
      { 
       if(buffer) 
        CVPixelBufferRelease(buffer); 

       NSLog(@"adaptor not ready %d, %d\n", frameCount, counter); 
       [NSThread sleepForTimeInterval:0.1]; 
      } 

      counter++; 
     } 

     if(buffer) 
      CVPixelBufferRelease(buffer); 

     if (!completeWitnNoError) 
     { 
      NSDictionary *userInfo = @{ 
             NSLocalizedDescriptionKey:    NSLocalizedString(@"Error\n", nil), 
             NSLocalizedFailureReasonErrorKey:  NSLocalizedString(@"Images to video writing failed ", nil), 
             NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Images to video writing failed ", nil) 
             }; 

      NSError *error = [NSError errorWithDomain:@"Images to video error" code: -1005 userInfo:userInfo]; 
      completion(!completion, nil, error); 
     } 

     frameCount++; 
    } 

    [videoWriterInput markAsFinished]; 
    [videoWriter finishWritingWithCompletionHandler:^{ 

     switch ([videoWriter status]) 
     { 
      case AVAssetReaderStatusReading: 
       break; 

      case AVAssetReaderStatusCompleted: 
      { 
       NSLog(@"IMAGES TO VIDEO WRITE SUCCESS"); 
       success = !success; 
       completion(success, videoOutputPath, videoWriter.error); 
       break; 
      } 
      case AVAssetReaderStatusCancelled: 
      { 
       NSLog(@"IMAGES TO VIDEO WRITE FAILURE"); 
       completion(success, nil, videoWriter.error); 
       [videoWriter cancelWriting]; 
       break; 
      } 

      case AVAssetReaderStatusFailed: 
      { 
       NSLog(@"IMAGES TO VIDEO WRITE FAILURE"); 
       completion(success, nil, videoWriter.error); 
       [videoWriter cancelWriting]; 
       break; 
      } 

      case AVAssetReaderStatusUnknown: 
      { 
       NSLog(@"IMAGES TO VIDEO WRITE FAILURE"); 
       completion(success, nil, videoWriter.error); 
       [videoWriter cancelWriting]; 
       break; 
      } 
     } 
    }]; 

    return; 
} 

和緩衝液:

+ (CVPixelBufferRef) pixelBufferFromCGImage:(CGImageRef)image withSize:(CGSize)size 
{ 

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

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

    if (status != kCVReturnSuccess) 
    { 
     NSString *description = [NSString stringWithFormat:@"Failed to create pixel buffer."]; 
     NSDictionary *userInfo = @{ 
            NSLocalizedDescriptionKey:    NSLocalizedString(description, nil), 
            NSLocalizedFailureReasonErrorKey:  NSLocalizedString(@"Could create buffer", nil), 
            NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Try again", nil) 
            }; 

     NSError *error = [NSError errorWithDomain:@"CVPixelBufferRef" code: -1005 userInfo:userInfo]; 
     NSLog(@"ALERT: %@", [error localizedDescription]); 
    } 

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

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


    CGContextConcatCTM(context, CGAffineTransformMakeRotation(0)); 
    CGContextDrawImage(context, CGRectMake((size.width/(CGImageGetWidth(image)/2)), (size.height/(CGImageGetWidth(image)/2)), 1280, 720), image); 

    CGColorSpaceRelease(rgbColorSpace); 
    CGContextRelease(context); 
    CVPixelBufferUnlockBaseAddress(pxbuffer, 0); 

    return pxbuffer; 
} 

任何建議??

+0

我們知道您的'framesPerSecond'是'30',但.. 。'duration'的值是多少,[imageArray count]是多少?你也可能想要一個2500000的視頻比特率,因爲960k/b對於720p來說圖像質量很低。 –

+0

** _「......任何人都可以請建議一種方法來修復fps?」_ **。沒關係,我有一個愚蠢的想法,也許如果你分享這些數字,那麼一些志願者可以幫助你找出什麼是錯的。我懷疑你的輸入數字與你的分而號碼的問題。另外一個視頻總是有**一個FPS速率**,它不會做一個_「...視頻範圍在0到0.16之間的fps」_所以發生了什麼?提供重現問題所需的所有事實(不僅僅是具有未知神祕輸入的代碼轉儲)... –

回答

1

嘗試使用CEMovieMaker我之前使用它,就像魅力我覺得你的問題是在VIDEOCODEC

https://github.com/cameronehrlich/CEMovieMaker

@interface ViewController() 

@property (nonatomic, strong) CEMovieMaker *movieMaker; 

@end 

- (IBAction)process:(id)sender 
{ 
    NSMutableArray *frames = [[NSMutableArray alloc] init]; 

    UIImage *icon1 = [UIImage imageNamed:@"icon1"]; 
    UIImage *icon2 = [UIImage imageNamed:@"icon2"]; 
    UIImage *icon3 = [UIImage imageNamed:@"icon3"]; 

    NSDictionary *settings = [CEMovieMaker videoSettingsWithCodec:AVVideoCodecH264 withHeight:icon1.size.width andWidth:icon1.size.height]; 
    self.movieMaker = [[CEMovieMaker alloc] initWithSettings:settings]; 
    for (NSInteger i = 0; i < 10; i++) { 
     [frames addObject:icon1]; 
     [frames addObject:icon2]; 
     [frames addObject:icon3]; 
    } 

    [self.movieMaker createMovieFromImages:[frames copy] withCompletion:^(BOOL success, NSURL *fileURL){ 
     if (success) { 
      [self viewMovieAtUrl:fileURL]; 
     } 
    }]; 
} 

- (void)viewMovieAtUrl:(NSURL *)fileURL 
{ 
    MPMoviePlayerViewController *playerController = [[MPMoviePlayerViewController alloc] initWithContentURL:fileURL]; 
    [playerController.view setFrame:self.view.bounds]; 
    [self presentMoviePlayerViewControllerAnimated:playerController]; 
    [playerController.moviePlayer prepareToPlay]; 
    [playerController.moviePlayer play]; 
    [self.view addSubview:playerController.view]; 
} 
+0

感謝Mohamed這是非常有幫助的,但CEMovieMaker創建了一個10fps視頻的視頻,並且圖像之間切換非常迅速。任何原因? – user3355301

+0

他使用重複加入3幅圖像10次爲30倍的圖像 這裏使用您的圖像和避免(的UIImage *在imageArray圖像) { 的UIImageView * temptemp =開關 [[ALLOC的UIImageView] initWithImage:圖片]; [finalimgs addObject:temptemp]; } [self.movi​​eMaker createMovieFromImages:finalimgs ....... 改變幀速率10fps的你應該改變CEMovieMaker的 - (instancetype)initWithSettings:(NSDictionary的*)videoSettings; _frameTime = CMTimeMake(1,30); –