iOS 将 AVI 转换为 MP4

Posted

技术标签:

【中文标题】iOS 将 AVI 转换为 MP4【英文标题】:iOS Convert AVI to MP4 【发布时间】:2018-12-05 09:48:22 【问题描述】:

(请注意我已经看过this other SO post。)

问题

我正在尝试将 avi 视频转换为 mp4,以便我可以使用 Objective-C 在 ios 应用程序上本地播放它

我的尝试

我正在尝试使用以下代码进行转换:

- (void)convertVideoToLowQuailtyWithInputURL:(NSURL*)inputURL outputURL:(NSURL*)outputURL handler:(void (^)(AVAssetExportSession*))handler 
    [[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
    AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality];
    exportSession.outputURL = outputURL;
    exportSession.outputFileType = AVFileTypeMPEG4;
    [exportSession exportAsynchronouslyWithCompletionHandler:^(void) 
        handler(exportSession);
    ];

exportSession 返回的错误是Cannot Open

额外信息

当我运行我试图通过 Mediainfo 转换的视频时,我得到以下视频:

7 332kb/s, 1920*1080 (16:9), at 25.000 FPS, AVC (Baseline@L3.1) (CABAC / 1 Ref Frames)

这是音频:

128 kb/s, 8 000 Hz, 16 bits, 1 channel, PCM (Little / Signed)

我也在AVAssetExportSession上使用了exportPresetsCompatibleWithAsset:的方法,得到如下结果:

AVAssetExportPreset1920x1080,
AVAssetExportPresetLowQuality,
AVAssetExportPresetAppleM4A,
AVAssetExportPresetHEVCHighestQuality,
AVAssetExportPreset640x480,
AVAssetExportPreset3840x2160,
AVAssetExportPresetHEVC3840x2160,
AVAssetExportPresetHighestQuality,
AVAssetExportPreset1280x720,
AVAssetExportPresetMediumQuality,
AVAssetExportPreset960x540,
AVAssetExportPresetHEVC1920x1080

要注意的另一件事是,在使用预设和输出播放时,我设法获得了一个基本上是白噪声的纯音频文件。这是使用预设AVAssetExportPresetAppleM4A

我希望我已经记下了足够的信息。

更新

使用 Ashley 的评论,我创建了一个函数来返回与资产兼容的导出设置。

- (void)determineCompatibleExportForAsset:(AVURLAsset *)asset completion:(void(^)(NSArray<ExportSettings *> *exports))handler 
    NSArray<NSString *> *presets = @[
                                     AVAssetExportPresetLowQuality,
                                     AVAssetExportPresetMediumQuality,
                                     AVAssetExportPresetHighestQuality,
                                     AVAssetExportPresetHEVCHighestQuality,
                                     AVAssetExportPreset640x480,
                                     AVAssetExportPreset960x540,
                                     AVAssetExportPreset1280x720,
                                     AVAssetExportPreset1920x1080,
                                     AVAssetExportPreset3840x2160,
                                     AVAssetExportPresetHEVC1920x1080,
                                     AVAssetExportPresetHEVC3840x2160,
                                     AVAssetExportPresetAppleM4A,
                                     AVAssetExportPresetPassthrough
                                     ];

    NSArray<NSString *> *outputs = @[
                                     AVFileTypeQuickTimeMovie,
                                     AVFileTypeMPEG4,
                                     AVFileTypeAppleM4V,
                                     AVFileTypeAppleM4A,
                                     AVFileType3GPP,
                                     AVFileType3GPP2,
                                     AVFileTypeCoreAudioFormat,
                                     AVFileTypeWAVE,
                                     AVFileTypeAIFF,
                                     AVFileTypeAIFC,
                                     AVFileTypeAMR,
                                     AVFileTypeMPEGLayer3,
                                     AVFileTypeSunAU,
                                     AVFileTypeAC3,
                                     AVFileTypeEnhancedAC3,
                                     AVFileTypeJPEG,
                                     AVFileTypeDNG,
                                     AVFileTypeHEIC,
                                     AVFileTypeAVCI,
                                     AVFileTypeHEIF,
                                     AVFileTypeTIFF
                                     ];

    __block int counter = 0;
    int totalCount = (int)presets.count * (int)outputs.count;

    NSMutableArray<ExportSettings *> *exportSettingsArray = [@[] mutableCopy];

    for (NSString *preset in presets) 
        for (NSString *output in outputs) 
            [AVAssetExportSession determineCompatibilityOfExportPreset:preset withAsset:asset outputFileType:output completionHandler:^(BOOL compatible) 
                if (compatible) 
                    ExportSettings *exportSettings = [[ExportSettings alloc] initWithPreset:preset outputType:output];
                    [exportSettingsArray addObject:exportSettings];
                
                counter++;
                if (counter == totalCount) 
                    if (handler) 
                        handler([exportSettingsArray copy]);
                    
                
            ];
        
    

这样的结果如下:

"Preset: AVAssetExportPresetAppleM4A Output: com.apple.m4a-audio",
"Preset: AVAssetExportPresetPassthrough Output: com.microsoft.waveform-audio",
"Preset: AVAssetExportPresetPassthrough Output: public.aifc-audio",
"Preset: AVAssetExportPresetPassthrough Output: public.aiff-audio",
"Preset: AVAssetExportPresetPassthrough Output: com.apple.coreaudio-format",
"Preset: AVAssetExportPresetPassthrough Output: com.apple.quicktime-movie"

由此我推断使用预设AVAssetExportPresetPassthrough和输出类型AVFileTypeQuickTimeMovie会兼容。

但是,在运行以下代码时:(我尝试了 .mp4、.mov 和 .qt 作为文件类型)

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"MyVideo.mov"];
    NSURL *outputURL = [NSURL fileURLWithPath:filePath];
    NSURL *localURL = [NSBundle URLForResource:@"20180626_145233-v" withExtension:@"avi" subdirectory:nil inBundleWithURL:[NSBundle mainBundle].bundleURL];

    [self convertVideoToLowQuailtyWithInputURL:localURL outputURL:outputURL handler:^(AVAssetExportSession *exportSession) 
        switch ([exportSession status]) 
            case AVAssetExportSessionStatusFailed:
                NSLog(@"Export failed: %@", [exportSession error]);
                break;
            case AVAssetExportSessionStatusCancelled:
                NSLog(@"Export canceled");
                break;
            case AVAssetExportSessionStatusCompleted:
                NSLog(@"Successfully");
                 NSLog(@"OutputURL: %@", outputURL.absoluteString);
                break;
            default:
                break;
        

    ];

调用者:

- (void)convertVideoToLowQuailtyWithInputURL:(NSURL*)inputURL outputURL:(NSURL*)outputURL handler:(void (^)(AVAssetExportSession*))handler 
    [[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil];       

    AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetPassthrough];
    exportSession.outputURL = outputURL;
    exportSession.outputFileType = AVFileTypeQuickTimeMovie;

    [exportSession exportAsynchronouslyWithCompletionHandler:^(void) 
        handler(exportSession);
    ];

我收到此错误:

Export failed: Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo=NSLocalizedFailureReason=An unknown error occurred (-12842), NSLocalizedDescription=The operation could not be completed, NSUnderlyingError=0x60400024def0 Error Domain=NSOSStatusErrorDomain Code=-12842 "(null)"

【问题讨论】:

那么您的视频是本地的还是远程的?如果它是本地的,你如何生成你的inputURL?这些东西实际上对+[NSURL URLWithString:]+[NSURL fileURLWithPath:] 之间的差异非常敏感。我认为 Cannot Open 错误可能是编解码器或错误的 URL。 URL 是正确的,它是一个本地文件,我正在使用 NSBundle 将 URL 返回到该文件。这是为了测试功能,一旦完成,我会将其替换为实际的 URL 提取音频和视频轨道并使用 AVMutableVideoComposition 创建一个新电影。 问题是我无法使用导出会话提取视频 您是否尝试将扩展 mp4 放在输出 URL 中 【参考方案1】:

无法打开文件的原因是iOS不支持AVI文件。

这是AVFoundation 中的link to the Apple documentation on supported file types。

如果值发生变化,则为后代提供此图像:

最后,您只需在 XCode 中检查 AVFileType 的定义,即可亲自查看此列表。

对于它的价值,cursory inspection on AVI via Google 表示 AVI 容器存在一些限制,这些限制已在 iOS 支持的新格式中得到纠正,因此可能没有动力在以后添加支持。

虽然potential issue 也是 Microsoft 创建的 AVI,但我找不到任何会禁止某人使用它的限制性许可,但 IANAL。

【讨论】:

【参考方案2】:

您应该为此目的使用 FFmpeg 库。 这是一个基于 FFmpeg 的开源视频播放器:https://github.com/kolyvan/kxmovie 我不知道这个播放器是否仍然适用于最新的 iOS,但无论如何在源代码中,您可以发现许多可以帮助您解决问题的有趣东西(例如如何使用 FFmpeg 库)。

【讨论】:

我用 FFmeg 库做了一个秒杀,转换这些视频需要很长时间。另外关于 kxmovie,我不会对使用 4 年未更新且有 117 个问题的库感兴趣【参考方案3】:

MobileFFMpeg 很容易做到

https://***.com/a/59325680/1466453

拥有 MobileFFMpeg 后,请按如下方式拨打电话:

[MobileFFMpeg 执行:@"-i infile.avi youroutput.mp4"];

【讨论】:

以上是关于iOS 将 AVI 转换为 MP4的主要内容,如果未能解决你的问题,请参考以下文章

在 php 中通过 ffmpeg 命令将 avi 文件转换为 mp4 文件

如何将avi格式转化为gif

怎么转换dat文件

使用imageio包将mp4视频转换为avi视频

adv怎么转mp4

如何使用 python 将 .264 文件转换为 avi\wav