【问题标题】:AVAssetExportSession exporting too slowAVAssetExportSession 导出太慢
【发布时间】:2015-07-24 12:06:27
【问题描述】:

我正在尝试使用AVAssetExportSession 导出AVMutableComposition

AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mutableComposition presetName:AVAssetExportPresetHighestQuality];
    exporter.outputURL=url;
    exporter.outputFileType = AVFileTypeQuickTimeMovie;
    exporter.videoComposition = mainCompositionInst;
    exporter.shouldOptimizeForNetworkUse = YES;

    [exporter exportAsynchronouslyWithCompletionHandler:^
     {
         switch (exporter.status)
         {
             case AVAssetExportSessionStatusCompleted:
             {
                 NSLog(@"Video Merge SuccessFullt");
             }
                 break;
             case AVAssetExportSessionStatusFailed:
                 NSLog(@"Failed:%@", exporter.error.description);
                 break;
             case AVAssetExportSessionStatusCancelled:
                 NSLog(@"Canceled:%@", exporter.error);
                 break;
             case AVAssetExportSessionStatusExporting:
                 NSLog(@"Exporting!");
                 break;
             case AVAssetExportSessionStatusWaiting:
                 NSLog(@"Waiting");
                 break;
             default:
                 break;
         }
     }];

但即使导出 1 分钟的视频也需要大约 30 秒,考虑到 iPad 内置的相机应用程序需要不到 2 秒,这太长了。

此外,如果我从导出器中删除 videoComposition,时间会减少到 7 秒,考虑到视频长度只有 1 分钟,这仍然很糟糕。 那么,我想知道如何将导出时间减少到最短?

另外,我想知道,AVAssetExportSession 通常需要这么多时间还是只是我的情况?

更新: 合并代码:

AVMutableComposition *mutableComposition = [AVMutableComposition 合成];

AVMutableCompositionTrack *videoCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo
                                                                                   preferredTrackID:kCMPersistentTrackID_Invalid];

AVMutableCompositionTrack *audioCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio
                                                                                   preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableVideoCompositionLayerInstruction *videoTrackLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoCompositionTrack];


NSMutableArray *instructions = [NSMutableArray new];
CGSize size = CGSizeZero;

CMTime time = kCMTimeZero;
for (AVURLAsset *asset in assets)
{
    AVAssetTrack *assetTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
    AVAssetTrack *audioAssetTrack = [asset tracksWithMediaType:AVMediaTypeAudio].firstObject;



    NSError *error;
    [videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, assetTrack.timeRange.duration )
                                       ofTrack:assetTrack
                                        atTime:time
                                         error:&error];

    [videoTrackLayerInstruction setTransform:assetTrack.preferredTransform atTime:time];

    if (error) {
        NSLog(@"asset url :: %@",assetTrack.asset);
        NSLog(@"Error1 - %@", error.debugDescription);
    }

    [audioCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAssetTrack.timeRange.duration)
                                       ofTrack:audioAssetTrack
                                        atTime:time
                                         error:&error];
    if (error) {
        NSLog(@"Error2 - %@", error.debugDescription);
    }

    time = CMTimeAdd(time, assetTrack.timeRange.duration);

    if (CGSizeEqualToSize(size, CGSizeZero)) {
        size = assetTrack.naturalSize;
    }
}

AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, time);
mainInstruction.layerInstructions = [NSArray arrayWithObject:videoTrackLayerInstruction];
AVMutableVideoComposition *mainCompositionInst = [AVMutableVideoComposition videoComposition];
mainCompositionInst.instructions = [NSArray arrayWithObject:mainInstruction];
mainCompositionInst.frameDuration = CMTimeMake(1, 30);
mainCompositionInst.renderSize = size;

【问题讨论】:

    标签: ios objective-c video avfoundation avassetexportsession


    【解决方案1】:

    我构建了一个将不同视频片段合并在一起的应用,我可以肯定地说这是你的情况。我的视频文件有大约 10 mb,所以它们可能会小一点,但即使有 10、20 个片段,也只需不到一秒的时间就可以将它们合并在一起。

    现在实际发生了,我已经对照你的配置检查了我的配置,区别如下:

    • 我用export.outputFileType = AVFileTypeMPEG4
    • 我已禁用网络优化,如果您不打算从您的设备流式传输视频,您也应该禁用它

    除此之外,它应该是相同的,我无法真正比​​较它,因为您必须提供有关您如何实际创建组合的代码。不过有一些事情需要检查:

    • 如果您在创建 AVURLAsset 时使用 AVURLAssetPreferPreciseDurationAndTimingKey 并且没有足够的关键帧,则实际上可能需要相当长的时间才能找到关键帧,因此会减慢速度
    • 考虑一下您是否真的需要最高质量的视频
    • 考虑视频的分辨率并可能降低它

    如果您提供更多信息,我应该能够为您提供更多帮助,但也许其中一些内容会起作用。试一试,然后回来报告。

    希望对你有所帮助!

    编辑 1: 我忘了提到,如果你没有选择,你应该尝试使用FFmpeg 库,因为它的性能非常高,尽管由于许可可能不适合你。

    【讨论】:

    • 我尝试了您提到的所有方法,但没有注意到导出时间有任何变化(至少不显着)。我也发布了我的合并代码。正如我所说,如果我通过 AVVideoComposition 添加指令,导出时间会非常长。所以只是想让你特别检查那部分。
    • 如果您的代码不包含 AVVideoComposition 那么请您添加一个空指令并检查是否有任何区别。
    • 删除任何指令痕迹,除非你使用它(AVMutableVideoCompositionInstruction)——因为看起来你不是;它应该有很大帮助,我认为转换和其他东西使它工作缓慢。此外,删除帧持续时间和渲染大小,其中之一也会有所作为。只是为了测试:) 因为组合不需要任何这些,它都是可选的。
    • 我需要说明以保留视频的方向。这就是为什么我需要应用这些帧持续时间和渲染大小。
    • 所以您合并的视频大小不同?如果是这样,那么我怀疑您应该研究 FFmpeg,因为此操作将非常昂贵,并且是为此而构建的
    【解决方案2】:

    我认为这里的问题是AVAssetExportPresetHighestQuality 这将导致转换或上采样,并且会减慢速度。尝试改用AVAssetExportPresetPassthrough。将我的导出时间从大约 35 多秒缩短到不到一秒

    我还禁用了网络使用优化,因为我们所有的视频都只在应用内使用,从未通过网络流式传输或传递

    【讨论】:

    • 我尝试将它用于导出音频,但如果我一次又一次地将音频附加到同一个文件,AVAssetExportPresetPassthrough 不起作用。有什么猜测吗?
    【解决方案3】:

    请记住,您尝试导出的资产可能未存储在本地,首先是下载内容,然后导出您的资产。

    如果您不想下载任何内容

    let videoRequestOptions: PHVideoRequestOptions = PHVideoRequestOptions()
    videoRequestOptions.isNetworkAccessAllowed = true
    

    您还将在requestExportSession 完成处理程序中收到一条消息,其中包含几个有用的信息值。 https://developer.apple.com/documentation/photokit/phimagemanager/image_result_info_keys

    否则,如果您想从 iCloud 下载资产并使其尽可能快,您可以使用以下参数

    let videoRequestOptions: PHVideoRequestOptions = PHVideoRequestOptions()
    // highQualityFormat, highQualityFormat, fastFormat, automatic
    videoRequestOptions.deliveryMode = .fastFormat 
    videoRequestOptions.isNetworkAccessAllowed = true
    

    另一个重要的属性是导出预设,有一堆可用的预设

    let lowQualityPreset1 = AVAssetExportPresetLowQuality
    let lowQualityPreset2 = AVAssetExportPreset640x480
    let lowQualityPreset3 = AVAssetExportPreset960x540
    let lowQualityPreset4 = AVAssetExportPreset1280x720
    
    let manager = PHImageManager()
    manager.requestExportSession(forVideo: asset, 
                                  options: videoRequestOptions, 
                             exportPreset: lowQualityPreset1) { (session, info) in
      session?.outputURL = outputUrl
      session?.outputFileType = .mp4
      session?.shouldOptimizeForNetworkUse = true
    
      session?.exportAsynchronously {
    
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-03
      • 2019-03-21
      • 1970-01-01
      相关资源
      最近更新 更多