简体   繁体   English

ios - 将视频的音频转换为 AAC

[英]ios - Convert video's audio to AAC

I'm trying to encode any audio format to AAC format, with 44100Hz sample rate.我正在尝试将任何音频格式编码为 AAC 格式,采样率为 44100Hz。

So basically : input (mp3, aac? etc, any sample rate) -> AAC (44100Hz)所以基本上:输入(mp3,aac?等,任何采样率)-> AAC(44100Hz)

The source audio comes from a video (mp4), but I can extract it to m4a (AAC).源音频来自视频 (mp4),但我可以将其提取为 m4a (AAC)。 The thing is I also want to change the sample rate to 44100Hz.问题是我还想将采样率更改为 44100Hz。

I'm trying to achieve this with AVAssetReader and AVAssetWriter, but not sure if its possible or if it's the best solution.我正在尝试使用 AVAssetReader 和 AVAssetWriter 来实现这一点,但不确定它是否可能或者它是否是最佳解决方案。 Any other solution would be very much appreciated !任何其他解决方案将不胜感激!

Here's my code so far :到目前为止,这是我的代码:

    // 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;
                                                    }
                                                }
                                            }]; 

And here is the error I get with a video that contains an mp3 audio track :这是我在包含 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'

Any help would be much appreciated, thanks !任何帮助将不胜感激,谢谢!

You should be able to achieve this by configuring your AVAssetReaderOutput output settings:您应该能够通过配置AVAssetReaderOutput输出设置来实现这一点:

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

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

I'm not native to Obj-C and I had to google around to figure out the accepted answer in Swift.我不是 Obj-C 的本地人,我不得不四处谷歌以找出 Swift 中可接受的答案

Here is the Swift version:这是 Swift 版本:

let audioSettings: [String : Any] = [
                AVFormatIDKey: kAudioFormatLinearPCM,
                AVSampleRateKey: 44100
            ]

let assetReaderAudioOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: audioSettings)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM