gpt4 book ai didi

iphone - 如何在 iOS 上使用 ExtAudioFile 使 AAC 编码正常工作?

转载 作者:技术小花猫 更新时间:2023-10-29 11:19:49 24 4
gpt4 key购买 nike

我需要在 iOS 上将 WAVE 文件转换为 AAC 编码的 M4A 文件。我知道旧设备或模拟器不支持 AAC 编码。我在运行代码之前正在测试它。但我仍然无法让它工作。

我查看了 Apple 自己的 iPhoneExtAudioFileConvertTest例子,我想我完全按照它做了,但还是不走运!

目前,我在尝试在目标文件上设置客户端格式时收到 -50(= 用户参数列表中的错误)。在源文件上,它有效。

下面是我的代码。非常感谢任何帮助,谢谢!

UInt32 size;

// Open a source audio file.
ExtAudioFileRef sourceAudioFile;
ExtAudioFileOpenURL( (CFURLRef)sourceURL, &sourceAudioFile );

// Get the source data format
AudioStreamBasicDescription sourceFormat;
size = sizeof( sourceFormat );
result = ExtAudioFileGetProperty( sourceAudioFile, kExtAudioFileProperty_FileDataFormat, &size, &sourceFormat );

// Define the output format (AAC).
AudioStreamBasicDescription outputFormat;
outputFormat.mFormatID = kAudioFormatMPEG4AAC;
outputFormat.mSampleRate = 44100;
outputFormat.mChannelsPerFrame = 2;

// Use AudioFormat API to fill out the rest of the description.
size = sizeof( outputFormat );
AudioFormatGetProperty( kAudioFormatProperty_FormatInfo, 0, NULL, &size, &outputFormat);

// Make a destination audio file with this output format.
ExtAudioFileRef destAudioFile;
ExtAudioFileCreateWithURL( (CFURLRef)destURL, kAudioFileM4AType, &outputFormat, NULL, kAudioFileFlags_EraseFile, &destAudioFile );

// Create canonical PCM client format.
AudioStreamBasicDescription clientFormat;
clientFormat.mSampleRate = sourceFormat.mSampleRate;
clientFormat.mFormatID = kAudioFormatLinearPCM;
clientFormat.mFormatFlags = kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
clientFormat.mChannelsPerFrame = 2;
clientFormat.mBitsPerChannel = 16;
clientFormat.mBytesPerFrame = 4;
clientFormat.mBytesPerPacket = 4;
clientFormat.mFramesPerPacket = 1;

// Set the client format in source and destination file.
size = sizeof( clientFormat );
ExtAudioFileSetProperty( sourceAudioFile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat );
size = sizeof( clientFormat );
ExtAudioFileSetProperty( destAudioFile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat );

// Make a buffer
int bufferSizeInFrames = 8000;
int bufferSize = ( bufferSizeInFrames * sourceFormat.mBytesPerFrame );
UInt8 * buffer = (UInt8 *)malloc( bufferSize );
AudioBufferList bufferList;
bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0].mNumberChannels = clientFormat.mChannelsPerFrame;
bufferList.mBuffers[0].mData = buffer;
bufferList.mBuffers[0].mDataByteSize = ( bufferSize );

while( TRUE )
{
// Try to fill the buffer to capacity.
UInt32 framesRead = bufferSizeInFrames;
ExtAudioFileRead( sourceAudioFile, &framesRead, &bufferList );

// 0 frames read means EOF.
if( framesRead == 0 )
break;

// Write.
ExtAudioFileWrite( destAudioFile, framesRead, &bufferList );
}

free( buffer );

// Close the files.
ExtAudioFileDispose( sourceAudioFile );
ExtAudioFileDispose( destAudioFile );

最佳答案

回答了我自己的问题:我不得不将这个问题转交给我的同事,他解决了这个问题!我从来没有机会分析我原来的问题,但我想,为了完整起见,我会把它贴在这里。从 NSThread 中调用以下方法。参数是通过“threadDictionary”设置的,他创建了一个自定义委托(delegate)来传输进度反馈(抱歉,SO 没有正确理解格式,下面应该是方法实现的一个 block ):

- (void)encodeToAAC
{
RXAudioEncoderStatusType encoderStatus;
OSStatus result = noErr;
BOOL success = NO;
BOOL cancelled = NO;
UInt32 size;

ExtAudioFileRef sourceAudioFile,destAudioFile;
AudioStreamBasicDescription sourceFormat,outputFormat, clientFormat;

SInt64 totalFrames;
unsigned long long encodedBytes, totalBytes;

int bufferSizeInFrames, bufferSize;
UInt8 * buffer;
AudioBufferList bufferList;

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

NSFileManager * fileManager = [[[NSFileManager alloc] init] autorelease];

NSMutableDictionary * threadDict = [[NSThread currentThread] threadDictionary];

NSObject<RXAudioEncodingDelegate> * delegate = (NSObject<RXAudioEncodingDelegate> *)[threadDict objectForKey:@"Delegate"];

NSString *sourcePath = (NSString *)[threadDict objectForKey:@"SourcePath"];
NSString *destPath = (NSString *)[threadDict objectForKey:@"DestinationPath"];

NSURL * sourceURL = [NSURL fileURLWithPath:sourcePath];
NSURL * destURL = [NSURL fileURLWithPath:destPath];

// Open a source audio file.
result = ExtAudioFileOpenURL( (CFURLRef)sourceURL, &sourceAudioFile );
if( result != noErr )
{
DLog( @"Error in ExtAudioFileOpenURL: %ld", result );
goto bailout;
}

// Get the source data format
size = sizeof( sourceFormat );
result = ExtAudioFileGetProperty( sourceAudioFile, kExtAudioFileProperty_FileDataFormat, &size, &sourceFormat );
if( result != noErr )
{
DLog( @"Error in ExtAudioFileGetProperty: %ld", result );
goto bailout;
}

// Define the output format (AAC).
memset(&outputFormat, 0, sizeof(outputFormat));
outputFormat.mFormatID = kAudioFormatMPEG4AAC;
outputFormat.mSampleRate = 44100;
outputFormat.mFormatFlags = kMPEG4Object_AAC_Main;
outputFormat.mChannelsPerFrame = 2;
outputFormat.mBitsPerChannel = 0;
outputFormat.mBytesPerFrame = 0;
outputFormat.mBytesPerPacket = 0;
outputFormat.mFramesPerPacket = 1024;


// Use AudioFormat API to fill out the rest of the description.
//size = sizeof( outputFormat );
//AudioFormatGetProperty( kAudioFormatProperty_FormatInfo, 0, NULL, &size, &outputFormat);

// Make a destination audio file with this output format.
result = ExtAudioFileCreateWithURL( (CFURLRef)destURL, kAudioFileM4AType, &outputFormat, NULL, kAudioFileFlags_EraseFile, &destAudioFile );
if( result != noErr )
{
DLog( @"Error creating destination file: %ld", result );
goto bailout;
}

// Create the canonical PCM client format.
memset(&clientFormat, 0, sizeof(clientFormat));
clientFormat.mSampleRate = sourceFormat.mSampleRate;
clientFormat.mFormatID = kAudioFormatLinearPCM;
clientFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; //kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
clientFormat.mChannelsPerFrame = 2;
clientFormat.mBitsPerChannel = 16;
clientFormat.mBytesPerFrame = 4;
clientFormat.mBytesPerPacket = 4;
clientFormat.mFramesPerPacket = 1;

// Set the client format in source and destination file.
size = sizeof( clientFormat );
result = ExtAudioFileSetProperty( sourceAudioFile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat );
if( result != noErr )
{
DLog( @"Error while setting client format in source file: %ld", result );
goto bailout;
}
size = sizeof( clientFormat );
result = ExtAudioFileSetProperty( destAudioFile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat );
if( result != noErr )
{
DLog( @"Error while setting client format in destination file: %ld", result );
goto bailout;
}

// Make a buffer
bufferSizeInFrames = 8000;
bufferSize = ( bufferSizeInFrames * sourceFormat.mBytesPerFrame );
buffer = (UInt8 *)malloc( bufferSize );

bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0].mNumberChannels = clientFormat.mChannelsPerFrame;
bufferList.mBuffers[0].mData = buffer;
bufferList.mBuffers[0].mDataByteSize = ( bufferSize );

// Obtain total number of audio frames to encode
size = sizeof( totalFrames );
result = ExtAudioFileGetProperty( sourceAudioFile, kExtAudioFileProperty_FileLengthFrames, &size, &totalFrames );
if( result != noErr )
{
DLog( @"Error in ExtAudioFileGetProperty, could not get kExtAudioFileProperty_FileLengthFrames from sourceFile: %ld", result );
goto bailout;
}

encodedBytes = 0;
totalBytes = totalFrames * sourceFormat.mBytesPerFrame;
[threadDict setValue:[NSValue value:&totalBytes withObjCType:@encode(unsigned long long)] forKey:@"TotalBytes"];

if (delegate != nil)
[self performSelectorOnMainThread:@selector(didStartEncoding) withObject:nil waitUntilDone:NO];

while( TRUE )
{
// Try to fill the buffer to capacity.
UInt32 framesRead = bufferSizeInFrames;
result = ExtAudioFileRead( sourceAudioFile, &framesRead, &bufferList );
if( result != noErr )
{
DLog( @"Error in ExtAudioFileRead: %ld", result );
success = NO;
break;
}

// 0 frames read means EOF.
if( framesRead == 0 ) {
success = YES;
break;
}

// Write.
result = ExtAudioFileWrite( destAudioFile, framesRead, &bufferList );
if( result != noErr )
{
DLog( @"Error in ExtAudioFileWrite: %ld", result );
success = NO;
break;
}

encodedBytes += framesRead * sourceFormat.mBytesPerFrame;

if (delegate != nil)
[self performSelectorOnMainThread:@selector(didEncodeBytes:) withObject:[NSValue value:&encodedBytes withObjCType:@encode(unsigned long long)] waitUntilDone:NO];

if ([[NSThread currentThread] isCancelled]) {
cancelled = YES;
DLog( @"Encoding was cancelled." );
success = NO;
break;
}
}

free( buffer );

// Close the files.
ExtAudioFileDispose( sourceAudioFile );
ExtAudioFileDispose( destAudioFile );

bailout:
encoderStatus.result = result;
[threadDict setValue:[NSValue value:&encoderStatus withObjCType:@encode(RXAudioEncoderStatusType)] forKey:@"EncodingError"];

// Report to the delegate if one exists
if (delegate != nil)
if (success)
[self performSelectorOnMainThread:@selector(didEncodeFile) withObject:nil waitUntilDone:YES];
else if (cancelled)
[self performSelectorOnMainThread:@selector(encodingCancelled) withObject:nil waitUntilDone:YES];
else
[self performSelectorOnMainThread:@selector(failedToEncodeFile) withObject:nil waitUntilDone:YES];

// Clear the partially encoded file if encoding failed or is cancelled midway
if ((cancelled || !success) && [fileManager fileExistsAtPath:destPath])
[fileManager removeItemAtURL:destURL error:NULL];

[threadDict setValue:[NSNumber numberWithBool:NO] forKey:@"isEncoding"];

[pool release];
}

关于iphone - 如何在 iOS 上使用 ExtAudioFile 使 AAC 编码正常工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4956338/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com