【问题标题】:ios - Convert video's audio to AACios - 将视频音频转换为 AAC
【发布时间】:2017-10-17 04:08:43
【问题描述】:

我正在尝试将任何音频格式编码为 AAC 格式,采样率为 44100Hz。

所以基本上:输入(mp3、aac?等,任何采样率)-> AAC (44100Hz)

源音频来自视频 (mp4),但我可以将其提取为 m4a (AAC)。问题是我还想将采样率更改为 44100Hz。

我正在尝试使用 AVAssetReader 和 AVAssetWriter 来实现这一点,但不确定它是否可能或者它是否是最佳解决方案。任何其他解决方案将不胜感激!

到目前为止,这是我的代码:

    // Input video audio (.mp4)
    AVAsset *videoAsset = <mp4 video asset>;
    NSArray<AVAssetTrack *> *videoAudioTracks = [videoAsset tracksWithMediaType:AVMediaTypeAudio];
    AVAssetTrack *videoAudioTrack = [videoAudioTracks objectAtIndex:0];

    // Output audio (.m4a AAC)
    NSURL *exportUrl = <m4a, aac output file URL>;

    // ASSET READER
    NSError *error;
    AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:videoAsset
                                                               error:&error];
    if(error) {
        NSLog(@"error:%@",error);
        return;
    }

    // Asset reader output
    AVAssetReaderOutput *assetReaderOutput =[AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:videoAudioTrack
                                                                                       outputSettings:nil];
    if(![assetReader canAddOutput:assetReaderOutput]) {
        NSLog(@"Can't add output!");
        return;
    }

    [assetReader addOutput:assetReaderOutput];

    // ASSET WRITER
    AVAssetWriter *assetWriter = [AVAssetWriter assetWriterWithURL:exportUrl
                                                          fileType:AVFileTypeAppleM4A
                                                             error:&error];
    if(error) {
        NSLog(@"error:%@",error);
        return;
    }

    AudioChannelLayout channelLayout;
    memset(&channelLayout, 0, sizeof(AudioChannelLayout));
    channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;

    NSDictionary *outputSettings = @{AVFormatIDKey: @(kAudioFormatMPEG4AAC),
            AVNumberOfChannelsKey: @2,
            AVSampleRateKey: @44100.0F,
            AVChannelLayoutKey: [NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)],
            AVEncoderBitRateKey: @64000};

    /*NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                    [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,
                                    [NSNumber numberWithFloat:44100.f], AVSampleRateKey,
                                    [NSNumber numberWithInt:2], AVNumberOfChannelsKey,
                                    [NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)], AVChannelLayoutKey,
                                    [NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,
                                    [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved,
                                    [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,
                                    [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,
                                    nil];*/

    // Asset writer input
    AVAssetWriterInput *assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio
                                                                              outputSettings:outputSettings];
    if ([assetWriter canAddInput:assetWriterInput])
        [assetWriter addInput:assetWriterInput];
    else {
        NSLog(@"can't add asset writer input... die!");
        return;
    }

    assetWriterInput.expectsMediaDataInRealTime = NO;

    [assetWriter startWriting];
    [assetReader startReading];

    CMTime startTime = CMTimeMake (0, videoAudioTrack.naturalTimeScale);
    [assetWriter startSessionAtSourceTime: startTime];

    __block UInt64 convertedByteCount = 0;
    dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL);

    [assetWriterInput requestMediaDataWhenReadyOnQueue:mediaInputQueue
                                            usingBlock: ^
                                            {
                                                while (assetWriterInput.readyForMoreMediaData)
                                                {
                                                    CMSampleBufferRef nextBuffer = [assetReaderOutput copyNextSampleBuffer];
                                                    if (nextBuffer)
                                                    {
                                                        // append buffer
                                                        [assetWriterInput appendSampleBuffer: nextBuffer];
                                                        convertedByteCount += CMSampleBufferGetTotalSampleSize (nextBuffer);

                                                        CMSampleBufferInvalidate(nextBuffer);
                                                        CFRelease(nextBuffer);
                                                        nextBuffer = NULL;
                                                    }
                                                    else
                                                    {
                                                        [assetWriterInput markAsFinished];
                                                        //              [assetWriter finishWriting];
                                                        [assetReader cancelReading];

                                                        break;
                                                    }
                                                }
                                            }]; 

这是我在包含 mp3 音轨的视频中遇到的错误:

Terminating app due to uncaught exception 
'NSInvalidArgumentException', reason: '*** -[AVAssetWriterInput 
appendSampleBuffer:] Cannot append sample buffer: Input buffer must 
be in an uncompressed format when outputSettings is not nil'

任何帮助将不胜感激,谢谢!

【问题讨论】:

  • PCM 是原始音频 - 未压缩 - 它是音频曲线上的一系列点...首先将输入音频文件转换为 PCM,然后从 PCM 转换为选择的输出格式 (aac) ...这种模式简化了转换器逻辑

标签: ios audio avfoundation file-conversion avassetwriter


【解决方案1】:

您应该能够通过配置AVAssetReaderOutput 输出设置来实现此目的:

NSDictionary *readerOutputSettings = @{ AVSampleRateKey: @44100, AVFormatIDKey: @(kAudioFormatLinearPCM) };

AVAssetReaderOutput *assetReaderOutput =[AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:videoAudioTrack
                                                                                   outputSettings:readerOutputSettings];

【讨论】:

    【解决方案2】:

    我不是 Obj-C 的本地人,我不得不四处搜索以找出 Swift 中的 accepted answer

    这里是 Swift 版本:

    let audioSettings: [String : Any] = [
                    AVFormatIDKey: kAudioFormatLinearPCM,
                    AVSampleRateKey: 44100
                ]
    
    let assetReaderAudioOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: audioSettings)
    

    【讨论】:

      猜你喜欢
      • 2012-01-16
      • 2016-01-31
      • 2012-05-30
      • 1970-01-01
      • 2013-09-19
      • 2010-12-22
      • 2020-08-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多