2015-10-14 86 views
0

我需要減少使用混合應用拍攝的視頻的尺寸而不降低分辨率,因此我試圖修改cordova video editor plugin以通過更改比特率來減少視頻的尺寸。 我試圖使用SDAVAssetExportSession沒有任何成功,並獲得噸的CVPixel錯誤。 插件代碼爲:在AVAsset修改cordova的比特率視頻編輯器

- (void) transcodeVideo:(CDVInvokedUrlCommand*)command 
{ 
    NSDictionary* options = [command.arguments objectAtIndex:0]; 

    if ([options isKindOfClass:[NSNull class]]) { 
     options = [NSDictionary dictionary]; 
    } 

    NSString *assetPath = [options objectForKey:@"fileUri"]; 
    NSString *videoFileName = [options objectForKey:@"outputFileName"]; 

    CDVQualityType qualityType = ([options objectForKey:@"quality"]) ? [[options objectForKey:@"quality"] intValue] : LowQuality; 

    NSString *presetName = Nil; 

    switch(qualityType) { 
     case HighQuality: 
      presetName = AVAssetExportPresetHighestQuality; 
      break; 
     case MediumQuality: 
     default: 
      presetName = AVAssetExportPresetMediumQuality; 
      break; 
     case LowQuality: 
      presetName = AVAssetExportPresetLowQuality; 
    } 

    CDVOutputFileType outputFileType = ([options objectForKey:@"outputFileType"]) ? [[options objectForKey:@"outputFileType"] intValue] : MPEG4; 

    BOOL optimizeForNetworkUse = ([options objectForKey:@"optimizeForNetworkUse"]) ? [[options objectForKey:@"optimizeForNetworkUse"] intValue] : NO; 

    float videoDuration = [[options objectForKey:@"duration"] floatValue]; 

    BOOL saveToPhotoAlbum = [options objectForKey:@"saveToLibrary"] ? [[options objectForKey:@"saveToLibrary"] boolValue] : YES; 

    NSString *stringOutputFileType = Nil; 
    NSString *outputExtension = Nil; 

    switch (outputFileType) { 
     case QUICK_TIME: 
      stringOutputFileType = AVFileTypeQuickTimeMovie; 
      outputExtension = @".mov"; 
      break; 
     case M4A: 
      stringOutputFileType = AVFileTypeAppleM4A; 
      outputExtension = @".m4a"; 
      break; 
     case M4V: 
      stringOutputFileType = AVFileTypeAppleM4V; 
      outputExtension = @".m4v"; 
      break; 
     case MPEG4: 
     default: 
      stringOutputFileType = AVFileTypeMPEG4; 
      outputExtension = @".mp4"; 
      break; 
    } 

    // remove file:// from the assetPath if it is there 
    assetPath = [[assetPath stringByReplacingOccurrencesOfString:@"file://" withString:@""] mutableCopy]; 

    // check if the video can be saved to photo album before going further 
    if (saveToPhotoAlbum && !UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(assetPath)) 
    { 
     NSString *error = @"Video cannot be saved to photo album"; 
     [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:error ] callbackId:command.callbackId]; 
     return; 
    } 

    NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 
    NSString *tempVideoPath =[NSString stringWithFormat:@"%@/%@%@", docDir, videoFileName, @".mov"]; 
    NSData *videoData = [NSData dataWithContentsOfFile:assetPath]; 
    [videoData writeToFile:tempVideoPath atomically:NO]; 

    AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:tempVideoPath] options:nil]; 
    NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset]; 

    if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality]) 
    { 
     AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:avAsset presetName: presetName]; 
     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
     NSString *videoPath = [NSString stringWithFormat:@"%@/%@%@", [paths objectAtIndex:0], videoFileName, outputExtension]; 

     exportSession.outputURL = [NSURL fileURLWithPath:videoPath]; 
     exportSession.outputFileType = stringOutputFileType; 
     exportSession.shouldOptimizeForNetworkUse = optimizeForNetworkUse; 

     NSLog(@"videopath of your file: %@", videoPath); 

     if (videoDuration) 
     { 
      int32_t preferredTimeScale = 600; 
      CMTime startTime = CMTimeMakeWithSeconds(0, preferredTimeScale); 
      CMTime stopTime = CMTimeMakeWithSeconds(videoDuration, preferredTimeScale); 
      CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime); 
      exportSession.timeRange = exportTimeRange; 
     } 

     [exportSession exportAsynchronouslyWithCompletionHandler:^{ 
      switch ([exportSession status]) { 
       case AVAssetExportSessionStatusCompleted: 
        if (saveToPhotoAlbum) { 
         UISaveVideoAtPathToSavedPhotosAlbum(videoPath, self, nil, nil); 
        } 
        NSLog(@"Export Complete %d %@", exportSession.status, exportSession.error); 
        [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:videoPath] callbackId:command.callbackId]; 
        break; 
       case AVAssetExportSessionStatusFailed: 
        NSLog(@"Export failed: %@", [[exportSession error] localizedDescription]); 
        [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[[exportSession error] localizedDescription]] callbackId:command.callbackId]; 
        break; 
       case AVAssetExportSessionStatusCancelled: 
        NSLog(@"Export canceled"); 
        break; 
       default: 
        NSLog(@"Export default in switch"); 
        break; 
      } 
     }]; 
    } 

} 

我怎麼能實現科爾多瓦插件裏面AVAssetWriter?

NSDictionary *settings = @{AVVideoCodecKey:AVVideoCodecH264, 
          AVVideoWidthKey:@(video_width), 
          AVVideoHeightKey:@(video_height), 
          AVVideoCompressionPropertiesKey: 
           @{AVVideoAverageBitRateKey:@(desired_bitrate), 
           AVVideoProfileLevelKey:AVVideoProfileLevelH264Main31, /* Or whatever profile & level you wish to use */ 
           AVVideoMaxKeyFrameIntervalKey:@(desired_keyframe_interval)}}; 

AVAssetWriterInput* writer_input = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:settings]; 

我真的不需要靈活的解決方案,硬編碼很好。 我不是一個真正的Object-C專家(我發現它是一個相當晦澀的語言)

+0

你爲什麼不問作者做出改變?其他人也有可能需要這種靈活性。 – JesseMonroy650

回答

0

我設法解決了SDAVAssetExportSession的問題。接下來,我正在聯繫作者進行更改。下面是代碼(MUST添加的CoreVideo.framework):

- (void) transcodeVideo:(CDVInvokedUrlCommand*)command 
{ 
    NSDictionary* options = [command.arguments objectAtIndex:0]; 

    if ([options isKindOfClass:[NSNull class]]) { 
     options = [NSDictionary dictionary]; 
    } 

    NSString *assetPath = [options objectForKey:@"fileUri"]; 
    NSString *videoFileName = [options objectForKey:@"outputFileName"]; 

    CDVQualityType qualityType = ([options objectForKey:@"quality"]) ? [[options objectForKey:@"quality"] intValue] : LowQuality; 

    NSString *presetName = Nil; 

    switch(qualityType) { 
     case HighQuality: 
      presetName = AVAssetExportPresetHighestQuality; 
      break; 
     case MediumQuality: 
     default: 
      presetName = AVAssetExportPresetMediumQuality; 
      break; 
     case LowQuality: 
      presetName = AVAssetExportPresetLowQuality; 
    } 

    CDVOutputFileType outputFileType = ([options objectForKey:@"outputFileType"]) ? [[options objectForKey:@"outputFileType"] intValue] : MPEG4; 

    BOOL optimizeForNetworkUse = ([options objectForKey:@"optimizeForNetworkUse"]) ? [[options objectForKey:@"optimizeForNetworkUse"] intValue] : NO; 

    float videoDuration = [[options objectForKey:@"duration"] floatValue]; 

    BOOL saveToPhotoAlbum = [options objectForKey:@"saveToLibrary"] ? [[options objectForKey:@"saveToLibrary"] boolValue] : YES; 

    NSString *stringOutputFileType = Nil; 
    NSString *outputExtension = Nil; 

    switch (outputFileType) { 
     case QUICK_TIME: 
      stringOutputFileType = AVFileTypeQuickTimeMovie; 
      outputExtension = @".mov"; 
      break; 
     case M4A: 
      stringOutputFileType = AVFileTypeAppleM4A; 
      outputExtension = @".m4a"; 
      break; 
     case M4V: 
      stringOutputFileType = AVFileTypeAppleM4V; 
      outputExtension = @".m4v"; 
      break; 
     case MPEG4: 
     default: 
      stringOutputFileType = AVFileTypeMPEG4; 
      outputExtension = @".mp4"; 
      break; 
    } 

    // remove file:// from the assetPath if it is there 
    assetPath = [[assetPath stringByReplacingOccurrencesOfString:@"file://" withString:@""] mutableCopy]; 

    // check if the video can be saved to photo album before going further 
    if (saveToPhotoAlbum && !UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(assetPath)) 
    { 
     NSString *error = @"Video cannot be saved to photo album"; 
     [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:error ] callbackId:command.callbackId]; 
     return; 
    } 

    NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 
    NSString *tempVideoPath =[NSString stringWithFormat:@"%@/%@%@", docDir, videoFileName, @".mov"]; 
    NSData *videoData = [NSData dataWithContentsOfFile:assetPath]; 
    [videoData writeToFile:tempVideoPath atomically:NO]; 

    AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:tempVideoPath] options:nil]; 
    NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset]; 

    SDAVAssetExportSession *encoder = [SDAVAssetExportSession.alloc initWithAsset:avAsset]; 

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *videoPath = [NSString stringWithFormat:@"%@/%@%@", [paths objectAtIndex:0], videoFileName, outputExtension]; 

    encoder.outputFileType = stringOutputFileType; 
    encoder.outputURL = [NSURL fileURLWithPath:videoPath]; 
    encoder.shouldOptimizeForNetworkUse = optimizeForNetworkUse; 
    encoder.videoSettings = @ 
    { 
    AVVideoCodecKey: AVVideoCodecH264, 
    AVVideoWidthKey: @1280, 
    AVVideoHeightKey: @720, 
    AVVideoCompressionPropertiesKey: @ 
     { 
     AVVideoAverageBitRateKey: @1200000, 
     AVVideoProfileLevelKey: AVVideoProfileLevelH264High40, 
     }, 
    }; 
    encoder.audioSettings = @ 
    { 
    AVFormatIDKey: @(kAudioFormatMPEG4AAC), 
    AVNumberOfChannelsKey: @2, 
    AVSampleRateKey: @44100, 
    AVEncoderBitRateKey: @128000, 
    }; 

    [encoder exportAsynchronouslyWithCompletionHandler:^ 
    { 
     if (encoder.status == AVAssetExportSessionStatusCompleted) 
     { 
      if (saveToPhotoAlbum) { 
       UISaveVideoAtPathToSavedPhotosAlbum(videoPath, self, nil, nil); 
      } 
      NSLog(@"Export Complete %d %@", encoder.status, encoder.error); 
      [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:videoPath] callbackId:command.callbackId]; 
     } 
     else if (encoder.status == AVAssetExportSessionStatusCancelled) 
     { 
      NSLog(@"Video export cancelled"); 
     } 
     else 
     { 
      NSLog(@"Export failed: %@", [[encoder error] localizedDescription]); 
      [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[[encoder error] localizedDescription]] callbackId:command.callbackId]; 
     } 
     /*switch ([encoder status]) { 
      case AVAssetExportSessionStatusCompleted: 

      break; 
      case AVAssetExportSessionStatusFailed: 

      break; 
      case AVAssetExportSessionStatusCancelled: 
      NSLog(@"Export canceled"); 
      break; 
      default: 
      NSLog(@"Export default in switch"); 
      break; 
      }*/ 

    }]; 
    /*if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality]) 
    { 
    AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:avAsset presetName: presetName]; 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *videoPath = [NSString stringWithFormat:@"%@/%@%@", [paths objectAtIndex:0], videoFileName, outputExtension]; 

    exportSession.outputURL = [NSURL fileURLWithPath:videoPath]; 
    exportSession.outputFileType = stringOutputFileType; 
    exportSession.shouldOptimizeForNetworkUse = optimizeForNetworkUse; 

    NSLog(@"videopath of your file: %@", videoPath); 

    if (videoDuration) 
    { 
    int32_t preferredTimeScale = 600; 
    CMTime startTime = CMTimeMakeWithSeconds(0, preferredTimeScale); 
    CMTime stopTime = CMTimeMakeWithSeconds(videoDuration, preferredTimeScale); 
    CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime); 
    exportSession.timeRange = exportTimeRange; 
    } 

    [exportSession exportAsynchronouslyWithCompletionHandler:^{ 
    switch ([exportSession status]) { 
    case AVAssetExportSessionStatusCompleted: 
    if (saveToPhotoAlbum) { 
    UISaveVideoAtPathToSavedPhotosAlbum(videoPath, self, nil, nil); 
    } 
    NSLog(@"Export Complete %d %@", exportSession.status, exportSession.error); 
    [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:videoPath] callbackId:command.callbackId]; 
    break; 
    case AVAssetExportSessionStatusFailed: 
    NSLog(@"Export failed: %@", [[exportSession error] localizedDescription]); 
    [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[[exportSession error] localizedDescription]] callbackId:command.callbackId]; 
    break; 
    case AVAssetExportSessionStatusCancelled: 
    NSLog(@"Export canceled"); 
    break; 
    default: 
    NSLog(@"Export default in switch"); 
    break; 
    } 
    }]; 
    }*/ 

}