Hallo liebe Entwicklergemeinde,
ich befasse mich gerade mit dem Thema "Konvertierung einer Audio-Datei mit dem AudioToolbox-Framework".
Ziel soll es sein eine aiff-Audiodatei in eine mp3-Audiodatei zu konvertieren.
Um dies zu erreichen habe ich bereits eine Methode geschrieben die zumindest eine aiff-Audiodatei in eine aiff-Audiodatei "konvertieren" kann.
Die AudioStreamBasicDescription ist dann in beiden Fällen gleich.
Um eine mp3.Audiodatei erhalten zu können benötige ich folgende Informationen:
File: howarddean.mp3
File type ID: MPG3
Data format: 2 ch, 44100 Hz, '.mp3' (0x00000000) 0 bits/channel, 0 bytes/packet, 1152 frames/packet, 0 bytes/frame
no channel layout.
estimated duration: 22.000 sec
audio bytes: 357901
audio packets: 856
bit rate: 128000 bits per second
packet size upper bound: 1052
maximum packet size: 418
audio data file offset: 499
optimized
Nähere Erklärungen:
0 bytes per frame/packet means that each "packet" of audio data can have
a different size. A packet in this case is a frame of MP3 data, which
is a variable bit rate codec (the packets that it produces are of
different sizes).
Its called a vbr codec because each packet
represents the same length of time - 1152 samples worth. So while the
time represented in a packet of data remains constant, the number of
bytes used to encode that amount of time will vary. This is the most
common way that audio encoders work. Some common things you will see
here are:
Number of frames in each packet:MP3 - 1152 ALAC (Apple Lossless) - 4096AAC - 1024
The
bits / channel being zero is true for nearly all compressed
representations of audio. Once you have encoded the audio data in this
manner, it really doesn't have a notion of a bit depth anymore. The bit
depth it will be decoded to is often floating point or otherwise
dictated by the hardware the data is played back on.
With
uncompressed data, there is a direct representation of the audio data by
some number of bits for each channel of data in the file. 16 or 24 bits
are common for linear pcm for example.
Daraus leite ich folgende AudioStreamBasicDescription für das output-Format ab:
Alles anzeigen
Folgende Variablendeklarationen lege ich fest:
aiffFile = @"./input.aif";
mp3File = @"./output.mp3";
bitrate = 64000;
Somit erhalte ich folgenden Methodenaufruf:
Aufzurufende Methode:
Alles anzeigen
Wenn ich den Code ausführe erhalte ich folgende Fehlermeldung:
Die Exception wird von folgender Methode geworfen:
Wenn ich die Methode nutze um eine aiff-Audiodatei in eine aiff-Audiodatei zu "konvertieren" funktioniert das ohne Probleme - die AudioStreamBasicDescription ist in beiden Fällen identisch.
Wenn ich nun eine mp3-Audiodatei erhalten möchte und die AudioStreamBasicDescription entsprechen für das outputFileformat anpasse, so erhalte ich diese Exception.
Ich habe bereits viel Zeit mit der Internetrecherche verbracht und konnte zwar mit Hilfe dieser Recherche das Problem etwas umrahmen aber nicht den tatsächlichen Kern des Problemes erkennen.
In vielen Internetportalen wird dieses Problem zwar besprochen aber nicht sauber abgeschlossen.
Ich würde mich sehr freuen wenn wir dieses Thema gemeinsam besprechen um eine saubere Lösung für die Nachwelt zu erhalten.
Ich freue mich schon sehr auf die nachfolgende Diskussionsrunde mit euch!!!
Schönen Gruss, OsnaTiger
ich befasse mich gerade mit dem Thema "Konvertierung einer Audio-Datei mit dem AudioToolbox-Framework".
Ziel soll es sein eine aiff-Audiodatei in eine mp3-Audiodatei zu konvertieren.
Um dies zu erreichen habe ich bereits eine Methode geschrieben die zumindest eine aiff-Audiodatei in eine aiff-Audiodatei "konvertieren" kann.
Die AudioStreamBasicDescription ist dann in beiden Fällen gleich.
Um eine mp3.Audiodatei erhalten zu können benötige ich folgende Informationen:
File: howarddean.mp3
File type ID: MPG3
Data format: 2 ch, 44100 Hz, '.mp3' (0x00000000) 0 bits/channel, 0 bytes/packet, 1152 frames/packet, 0 bytes/frame
no channel layout.
estimated duration: 22.000 sec
audio bytes: 357901
audio packets: 856
bit rate: 128000 bits per second
packet size upper bound: 1052
maximum packet size: 418
audio data file offset: 499
optimized
Nähere Erklärungen:
0 bytes per frame/packet means that each "packet" of audio data can have
a different size. A packet in this case is a frame of MP3 data, which
is a variable bit rate codec (the packets that it produces are of
different sizes).
Its called a vbr codec because each packet
represents the same length of time - 1152 samples worth. So while the
time represented in a packet of data remains constant, the number of
bytes used to encode that amount of time will vary. This is the most
common way that audio encoders work. Some common things you will see
here are:
Number of frames in each packet:MP3 - 1152 ALAC (Apple Lossless) - 4096AAC - 1024
The
bits / channel being zero is true for nearly all compressed
representations of audio. Once you have encoded the audio data in this
manner, it really doesn't have a notion of a bit depth anymore. The bit
depth it will be decoded to is often floating point or otherwise
dictated by the hardware the data is played back on.
With
uncompressed data, there is a direct representation of the audio data by
some number of bits for each channel of data in the file. 16 or 24 bits
are common for linear pcm for example.
Daraus leite ich folgende AudioStreamBasicDescription für das output-Format ab:
PHP-Quellcode
- - (void) setOutputStreamDesc;
- {
- memset(&outputStreamDesc, 0, sizeof( AudioStreamBasicDescription ) );
- // OutputFormat
- outputStreamDesc.mSampleRate = inputStreamDesc.mSampleRate;
- outputStreamDesc.mFormatID = kAudioFormatMPEGLayer3;
- outputStreamDesc.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
- outputStreamDesc.mChannelsPerFrame = inputStreamDesc.mChannelsPerFrame;
- outputStreamDesc.mFramesPerPacket = 1152;
- outputStreamDesc.mBitsPerChannel = 0;
- outputStreamDesc.mBytesPerPacket = 0;
- outputStreamDesc.mBytesPerFrame = 0;
- }
Folgende Variablendeklarationen lege ich fest:
aiffFile = @"./input.aif";
mp3File = @"./output.mp3";
bitrate = 64000;
Somit erhalte ich folgenden Methodenaufruf:
PHP-Quellcode
Aufzurufende Methode:
PHP-Quellcode
- const UInt32 kSrcBufSize = 32768;
- - (int) convertFile:(CFURLRef*)_inputFileURL
- inputFormat:(AudioStreamBasicDescription)_inputFormat
- outputFileURL:(CFURLRef*)_outputFileURL
- outputFileType:(AudioFileTypeID)_outputFileType
- outputFormat:(AudioStreamBasicDescription)_outputFormat
- outputBitRate:(UInt32)_outputBitRate;
- {
- ExtAudioFileRef infile, outfile;
- // first open the input file
- OSStatus err = ExtAudioFileOpenURL (_inputFileURL, &infile);
- [self throwIfOSStatusIsErr:err
- fromFunction:@"ExtAudioFileOpen"];
- // if outputBitRate is specified, this can change the sample rate of the output file
- // so we let this "take care of itself"
- if (_outputBitRate)
- _outputFormat.mSampleRate = 0.;
- // create the output file (this will erase an exsiting file)
- err = ExtAudioFileCreateWithURL (_outputFileURL, _outputFileType, &_outputFormat, NULL, kAudioFileFlags_EraseFile, &outfile);
- //XThrowIfError (err, "ExtAudioFileCreateNew");
- [self throwIfOSStatusIsErr:err
- fromFunction:@"ExtAudioFileCreateNew"];
- // get and set the client format - it should be lpcm
- AudioStreamBasicDescription clientFormat = (_inputFormat.mFormatID == kAudioFormatLinearPCM ? _inputFormat : _outputFormat);
- UInt32 size = sizeof(clientFormat);
- err = ExtAudioFileSetProperty(infile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat);
- //XThrowIfError (err, "ExtAudioFileSetProperty inFile, kExtAudioFileProperty_ClientDataFormat");
- [self throwIfOSStatusIsErr:err
- fromFunction:@"ExtAudioFileSetProperty inFile, kExtAudioFileProperty_ClientDataFormat"];
- size = sizeof(clientFormat);
- err = ExtAudioFileSetProperty(outfile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat);
- //XThrowIfError (err, "ExtAudioFileSetProperty outFile, kExtAudioFileProperty_ClientDataFormat");
- [self throwIfOSStatusIsErr:err
- fromFunction:@"ExtAudioFileSetProperty outFile, kExtAudioFileProperty_ClientDataFormat"];
- if( _outputBitRate > 0 ) {
- printf ("Dest bit rate: %d\n", (int)_outputBitRate);
- AudioConverterRef outConverter;
- size = sizeof(outConverter);
- err = ExtAudioFileGetProperty(outfile, kExtAudioFileProperty_AudioConverter, &size, &outConverter);
- //XThrowIfError (err, "ExtAudioFileGetProperty outFile, kExtAudioFileProperty_AudioConverter");
- [self throwIfOSStatusIsErr:err
- fromFunction:@"ExtAudioFileGetProperty outFile, kExtAudioFileProperty_AudioConverter"];
- err = AudioConverterSetProperty(outConverter, kAudioConverterEncodeBitRate,
- sizeof(_outputBitRate), _outputBitRate);
- //XThrowIfError (err, "AudioConverterSetProperty, kAudioConverterEncodeBitRate");
- [self throwIfOSStatusIsErr:err
- fromFunction:@"AudioConverterSetProperty, kAudioConverterEncodeBitRate"];
- // we have changed the converter, so we should do this in case
- // setting a converter property changes the converter used by ExtAF in some manner
- CFArrayRef config = NULL;
- err = ExtAudioFileSetProperty(outfile, kExtAudioFileProperty_ConverterConfig, sizeof(config), &config);
- //XThrowIfError (err, "ExtAudioFileSetProperty outFile, kExtAudioFileProperty_ConverterConfig");
- [self throwIfOSStatusIsErr:err
- fromFunction:@"ExtAudioFileSetProperty outFile, kExtAudioFileProperty_ConverterConfig"];
- }
- // set up buffers
- char srcBuffer[kSrcBufSize];
- // do the read and write - the conversion is done on and by the write call
- while (1)
- {
- AudioBufferList fillBufList;
- fillBufList.mNumberBuffers = 1;
- fillBufList.mBuffers[0].mNumberChannels = _inputFormat.mChannelsPerFrame;
- fillBufList.mBuffers[0].mDataByteSize = kSrcBufSize;
- fillBufList.mBuffers[0].mData = srcBuffer;
- // client format is always linear PCM - so here we determine how many frames of lpcm
- // we can read/write given our buffer size
- UInt32 numFrames = (kSrcBufSize / clientFormat.mBytesPerFrame);
- // printf("test %d\n", numFrames);
- err = ExtAudioFileRead (infile, &numFrames, &fillBufList);
- //XThrowIfError (err, "ExtAudioFileRead");
- [self throwIfOSStatusIsErr:err
- fromFunction:@"ExtAudioFileRead"];
- if (!numFrames) {
- // this is our termination condition
- break;
- }
- err = ExtAudioFileWrite(outfile, numFrames, &fillBufList);
- //XThrowIfError (err, "ExtAudioFileWrite");
- [self throwIfOSStatusIsErr:err
- fromFunction:@"ExtAudioFileWrite"];
- }
- // close
- ExtAudioFileDispose(outfile);
- ExtAudioFileDispose(infile);
- return 0;
- }
Wenn ich den Code ausführe erhalte ich folgende Fehlermeldung:
Die Exception wird von folgender Methode geworfen:
PHP-Quellcode
- size = sizeof(clientFormat);
- err = ExtAudioFileSetProperty(outfile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat);
- //XThrowIfError (err, "ExtAudioFileSetProperty outFile, kExtAudioFileProperty_ClientDataFormat");
- [self throwIfOSStatusIsErr:err
- fromFunction:@"ExtAudioFileSetProperty outFile, kExtAudioFileProperty_ClientDataFormat"];
Wenn ich die Methode nutze um eine aiff-Audiodatei in eine aiff-Audiodatei zu "konvertieren" funktioniert das ohne Probleme - die AudioStreamBasicDescription ist in beiden Fällen identisch.
Wenn ich nun eine mp3-Audiodatei erhalten möchte und die AudioStreamBasicDescription entsprechen für das outputFileformat anpasse, so erhalte ich diese Exception.
Ich habe bereits viel Zeit mit der Internetrecherche verbracht und konnte zwar mit Hilfe dieser Recherche das Problem etwas umrahmen aber nicht den tatsächlichen Kern des Problemes erkennen.
In vielen Internetportalen wird dieses Problem zwar besprochen aber nicht sauber abgeschlossen.
Ich würde mich sehr freuen wenn wir dieses Thema gemeinsam besprechen um eine saubere Lösung für die Nachwelt zu erhalten.
Ich freue mich schon sehr auf die nachfolgende Diskussionsrunde mit euch!!!
Schönen Gruss, OsnaTiger