【问题标题】:AVAssetWriter How to write down-sampled/compressed m4a/mp3 filesAVAssetWriter 如何写下采样/压缩的 m4a/mp3 文件
【发布时间】:2012-10-24 20:14:49
【问题描述】:

我正在尝试获取本地 m4a 或 mp3 文件并压缩/向下采样此文件(为了制作更小的文件)。

最初,我使用 AVAssetExportSession 将 AVAsset 导出到临时目录,但我无法控制压缩/下采样(您只能使用预设,其中仅支持 .wav 文件格式质量下降)。

然后,按照 SO 上的几个示例,我尝试使用 AVAssetReader/AVAssetWriter 来执行此“导出”。

我这样创建我的阅读器/作者:

NSString *exportPath = [NSHomeDirectory() stringByAppendingPathComponent:@"out.m4a"];

NSURL *exportURL = [NSURL fileURLWithPath:outPath];

// reader
NSError *readerError = nil;
AVAssetReader *reader = [[AVAssetReader alloc] initWithAsset:asset
                                                       error:&readerError];

AVAssetTrack *track = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];    
AVAssetReaderTrackOutput *readerOutput = [[AVAssetReaderTrackOutput alloc] initWithTrack:track
                                                                          outputSettings:nil];
[reader addOutput:readerOutput];

// writer
NSError *writerError = nil;
AVAssetWriter *writer = [[AVAssetWriter alloc] initWithURL:exportURL
                                                  fileType:AVFileTypeAppleM4A
                                                     error:&writerError];

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

// use different values to affect the downsampling/compression
NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                [NSNumber numberWithInt: kAudioFormatMPEG4AAC], AVFormatIDKey,
                                [NSNumber numberWithFloat:44100.0], AVSampleRateKey,
                                [NSNumber numberWithInt:2], AVNumberOfChannelsKey,
                                [NSNumber numberWithInt:128000], AVEncoderBitRateKey,
                                [NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)], AVChannelLayoutKey,
                                nil];

AVAssetWriterInput *writerInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeAudio
                                                                 outputSettings:outputSettings];
[writerInput setExpectsMediaDataInRealTime:NO];
[writer addInput:writerInput];

然后我开始写...

[writer startWriting];
[writer startSessionAtSourceTime:kCMTimeZero];

[reader startReading];
dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL);
[writerInput requestMediaDataWhenReadyOnQueue:mediaInputQueue usingBlock:^{

    NSLog(@"Asset Writer ready : %d", writerInput.readyForMoreMediaData);
    while (writerInput.readyForMoreMediaData) {
        CMSampleBufferRef nextBuffer;
        if ([reader status] == AVAssetReaderStatusReading && (nextBuffer = [readerOutput copyNextSampleBuffer])) {
            if (nextBuffer) {
                NSLog(@"Adding buffer");
                [writerInput appendSampleBuffer:nextBuffer];
            }
        } else {
            [writerInput markAsFinished];

            switch ([reader status]) {
                case AVAssetReaderStatusReading:
                    break;
                case AVAssetReaderStatusFailed:
                    [writer cancelWriting];
                    break;
                case AVAssetReaderStatusCompleted:
                    NSLog(@"Writer completed");
                    [writer endSessionAtSourceTime:asset.duration];
                    [writer finishWriting];

                    NSData *data = [NSData dataWithContentsOfFile:exportPath];
                    NSLog(@"Data: %@", data);
                    break;
            }
            break;
        }
    }
}];

当我写完后,我应该写入到 exportURL 的数据是空的,并且作者报告成功完成。有什么想法可能出了什么问题?

更新 调用appendSampleBuffer:后的writer状态是AVAssetWriterStatusFailed,虽然reader状态是成功的,而且好像是读完了整个文件。

【问题讨论】:

  • 它有没有尝试写任何东西?第一次尝试附加样本缓冲区时,阅读器的状态是什么?
  • 啊哈,每次调用[writerInput appendSampleBuffer:]的时候都会出现,writer状态是3,看枚举,好像是AVAssetWriterStatusFailed。看起来读者正在从我的资产中复制所有样本缓冲区 - appendSampleBuffer 被调用 many
  • 可以添加这个以避免内存泄漏:CMSampleBufferInvalidate(nextBuffer); CFRelease(nextBuffer); nextBuffer = NULL;

标签: ios avfoundation avassetwriter avassetreader


【解决方案1】:

我遇到了解决方案:

NSString *exportPath = [NSHomeDirectory() stringByAppendingPathComponent:@"out.m4a"] 中使用 NSHomeDirectory() 导致编写器无法创建文件。不完全确定为什么,或者我需要做什么才能让它工作,但同时将NSHomeDirectiory() 更改为NSTemporaryDirectory() 解决了我的问题。

【讨论】:

  • 您无法写入 iOS 中的主目录。临时目录没问题,还有Documents目录
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-21
  • 2018-08-25
  • 2016-05-31
  • 2017-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多