无法正确反转AVAssetaudio。 唯一的结果是白噪音

我试图扭转AVAssetaudio并将其保存到文件。 为了清楚起见,我已经使用https://github.com/ksenia-lyagusha/AudioReverse.git

该应用程序从软件包中获取mp4video文件,将其作为单个m4a文件导出到沙箱中的临时文件夹,然后尝试从那里读取,反转并将结果文件保存回。 临时m4a文件是可以的。

我的反向部分唯一的结果是Sandboxaudio文件,有白噪声。

下面有一部分代码,负责反转AVAsset 。 这是基于相关的问题

  • 如何反转audio文件?
  • iOSaudio操作 – 向后播放本地.caf文件

但是,它不适合我。

 OSStatus theErr = noErr; UInt64 fileDataSize = 0; AudioFileID inputAudioFile; AudioStreamBasicDescription theFileFormat; UInt32 thePropertySize = sizeof(theFileFormat); theErr = AudioFileOpenURL((__bridge CFURLRef)[NSURL URLWithString:inputPath], kAudioFileReadPermission, 0, &inputAudioFile); thePropertySize = sizeof(fileDataSize); theErr = AudioFileGetProperty(inputAudioFile, kAudioFilePropertyAudioDataByteCount, &thePropertySize, &fileDataSize); UInt32 ps = sizeof(AudioStreamBasicDescription) ; AudioFileGetProperty(inputAudioFile, kAudioFilePropertyDataFormat, &ps, &theFileFormat); UInt64 dataSize = fileDataSize; void *theData = malloc(dataSize); // set up output file AudioFileID outputAudioFile; AudioStreamBasicDescription myPCMFormat; myPCMFormat.mSampleRate = 44100; myPCMFormat.mFormatID = kAudioFormatLinearPCM; // kAudioFormatFlagsCanonical is deprecated myPCMFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsNonInterleaved; myPCMFormat.mChannelsPerFrame = 1; myPCMFormat.mFramesPerPacket = 1; myPCMFormat.mBitsPerChannel = 32; myPCMFormat.mBytesPerPacket = (myPCMFormat.mBitsPerChannel / 8) * myPCMFormat.mChannelsPerFrame; myPCMFormat.mBytesPerFrame = myPCMFormat.mBytesPerPacket; NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"ReverseAudio.caf"]; NSURL *outputURL = [NSURL fileURLWithPath:exportPath]; theErr = AudioFileCreateWithURL((__bridge CFURLRef)outputURL, kAudioFileCAFType, &myPCMFormat, kAudioFileFlags_EraseFile, &outputAudioFile); //Read data into buffer //if readPoint = dataSize, then bytesToRead = 0 in while loop and //it is endless SInt64 readPoint = dataSize-1; UInt64 writePoint = 0; while(readPoint > 0) { UInt32 bytesToRead = 2; AudioFileReadBytes(inputAudioFile, false, readPoint, &bytesToRead, theData); // bytesToRead is now the amount of data actually read UInt32 bytesToWrite = bytesToRead; AudioFileWriteBytes(outputAudioFile, false, writePoint, &bytesToWrite, theData); // bytesToWrite is now the amount of data actually written writePoint += bytesToWrite; readPoint -= bytesToRead; } free(theData); AudioFileClose(inputAudioFile); AudioFileClose(outputAudioFile); 

如果将AudioFileCreateWithURL文件types从kAudioFileCAFType为另一个,则根本不会在Sandbox中创build结果文件。

谢谢你的帮助。

你会得到白色的噪音,因为你的文件格式是不兼容的。 你有不同的采样率和通道,可能还有其他的不同。 为了使这个工作,你需要有一个共同的(PCM)格式介于读写之间。 新(ish) AVAudio框架是一个合理的工作。 我们从文件读取PCM,洗牌缓冲区,然后从PCM写入文件。 这种方法并没有针对大文件进行优化,因为所有数据都是一次性读入缓冲区,但足以让您开始使用。

您可以从getAudioFromVideo完成块调用此方法。 error handling忽略清晰。

 - (void)readAudioFromURL:(NSURL*)inURL reverseToURL:(NSURL*)outURL { //prepare the in and outfiles AVAudioFile* inFile = [[AVAudioFile alloc] initForReading:inURL error:nil]; AVAudioFormat* format = inFile.processingFormat; AVAudioFrameCount frameCount =(UInt32)inFile.length; NSDictionary* outSettings = @{ AVNumberOfChannelsKey:@(format.channelCount) ,AVSampleRateKey:@(format.sampleRate)}; AVAudioFile* outFile = [[AVAudioFile alloc] initForWriting:outURL settings:outSettings error:nil]; //prepare the forward and reverse buffers self.forwaredBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:format frameCapacity:frameCount]; self.reverseBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:format frameCapacity:frameCount]; //read file into forwardBuffer [inFile readIntoBuffer:self.forwaredBuffer error:&error]; //set frameLength of reverseBuffer to forwardBuffer framelength AVAudioFrameCount frameLength = self.forwaredBuffer.frameLength; self.reverseBuffer.frameLength = frameLength; //iterate over channels //stride is 1 or 2 depending on interleave format NSInteger stride = self.forwaredBuffer.stride; for (AVAudioChannelCount channelIdx = 0; channelIdx < self.forwaredBuffer.format.channelCount; channelIdx++) { float* forwaredChannelData = self.forwaredBuffer.floatChannelData[channelIdx]; float* reverseChannelData = self.reverseBuffer.floatChannelData[channelIdx]; int32_t reverseIdx = 0; //iterate over samples, allocate to reverseBuffer in reverse order for (AVAudioFrameCount frameIdx = frameLength; frameIdx >0; frameIdx--) { float sample = forwaredChannelData[frameIdx*stride]; reverseChannelData[reverseIdx*stride] = sample; reverseIdx++; } } //write reverseBuffer to outFile [outFile writeFromBuffer:self.reverseBuffer error:nil]; } 

我无法在您的代码中find问题,但是我build议您使用AVAssetWriter反转AVAssetWriter 。 以下代码基于通过AVAssetWritet的iOS反向audio 。 我已经在那里添加了其他方法来使其工作。 最后我得到了反向文件。

 static NSMutableArray *samples; static OSStatus sampler(CMSampleBufferRef sampleBuffer, CMItemCount index, void *refcon) { [samples addObject:(__bridge id _Nonnull)(sampleBuffer)]; return noErr; } - (void)reversePlayAudio:(NSURL *)inputURL { AVAsset *asset = [AVAsset assetWithURL:inputURL]; AVAssetReader* reader = [[AVAssetReader alloc] initWithAsset:asset error:nil]; AVAssetTrack* audioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]; NSMutableDictionary* audioReadSettings = [NSMutableDictionary dictionary]; [audioReadSettings setValue:[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey]; AVAssetReaderTrackOutput* readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:audioTrack outputSettings:audioReadSettings]; [reader addOutput:readerOutput]; [reader startReading]; NSDictionary *outputSettings = @{AVFormatIDKey : @(kAudioFormatMPEG4AAC), AVSampleRateKey : @(44100.0), AVNumberOfChannelsKey : @(1), AVEncoderBitRateKey : @(128000), AVChannelLayoutKey : [NSData data]}; AVAssetWriterInput *writerInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeAudio outputSettings:outputSettings]; NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"reverseAudio.m4a"]; NSURL *exportURL = [NSURL fileURLWithPath:exportPath]; NSError *writerError = nil; AVAssetWriter *writer = [[AVAssetWriter alloc] initWithURL:exportURL fileType:AVFileTypeAppleM4A error:&writerError]; [writerInput setExpectsMediaDataInRealTime:NO]; writer.shouldOptimizeForNetworkUse = NO; [writer addInput:writerInput]; [writer startWriting]; [writer startSessionAtSourceTime:kCMTimeZero]; CMSampleBufferRef sample;// = [readerOutput copyNextSampleBuffer]; samples = [[NSMutableArray alloc] init]; while (sample != NULL) { sample = [readerOutput copyNextSampleBuffer]; if (sample == NULL) continue; CMSampleBufferCallForEachSample(sample, &sampler, NULL); CFRelease(sample); } NSArray* reversedSamples = [[samples reverseObjectEnumerator] allObjects]; for (id reversedSample in reversedSamples) { if (writerInput.readyForMoreMediaData) { [writerInput appendSampleBuffer:(__bridge CMSampleBufferRef)(reversedSample)]; } else { [NSThread sleepForTimeInterval:0.05]; } } [samples removeAllObjects]; [writerInput markAsFinished]; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); dispatch_async(queue, ^{ [writer finishWritingWithCompletionHandler:^{ // writing is finished // reversed audio file in TemporaryDirectory in the Sandbox }]; }); } 

已知的代码问题。

  1. 如果audio很长,内存可能会有一些问题。
  2. audio文件的持续时间比原来的长。 (作为一个快速解决scheme,你可以像平常一样把它剪掉)。
Interesting Posts