Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / audio

AAC Encode

3.80/5 (9 votes)
17 Feb 2012CPOL3 min read 68.7K   5K  
Raw Audio data is encoded to AAC compression using ffmmpeg library.

Introduction

This article is 2nd article of audio capturing, encoding and streaming. It describes to how to encode capture PCM data to AAC encoding and write to audio file.

Back Ground.

It is for software developers who are interested in audio related applications. Mostly suits for Audio software developers who are interested in encoding and decoding audio files to AAC encoding using FFMPEG libraries in windows platform. It is not required to know AAC encoding and decoding details unless one wants to decode captured data manually.

Total application is written in "C" language consists of simple functions and simple port audio library and ffmpeg library calls. It uses ffmpeg libraries calls intensively it is better have some ffmpeg knowledge.

Port-Audio

Port-Audio is a free, cross-platform, open-source, audio I/O library. It lets you write simple audio programs in 'C' or C++ that will compile and run on many platforms including Windows, Macintosh OS X, and Unix (OSS/ALSA). It is intended to promote the exchange of audio software between developers on different platforms. Port Audio software many useful examples.

Official web site http://www.portaudio.com.

FFMPEG

ffmpeg is a very fast video and audio converter that can also grab from a live audio/video source. It can also convert between arbitrary sample rates and resize video on the fly with a high quality polyphase filter.

ffmpeg reads from an arbitrary number of input "files" (which can be regular files, pipes, network streams, grabbing devices, etc.), specified by the -i option, and writes to an arbitrary number of output "files", which are specified by a plain output filename. Anything found on the command line which cannot be interpreted as an option is considered to be an output filename.

Official ffmpeg web site http://ffmpeg.org/

AAC Audio Encoding Data flow Diagram.

Data flow diagram is as follows

AACEncode

Software details

For more details on port audio calls see the port-audio documentation, and AMR narrow band see opencore-amr documentation.

Step1: Initialize port audio and register record callback function.

Initialize the port audio and open port audio stream with record call back function with following configurations 8000 sampling rate, 16 bit signed PCM data, frame size of 80 samples mean 10 milliseconds audio data in one frame. After stream is started, record call back is called for every 10 ms with one frame of audio data.

C++
static PaError
yakAudioStreamOpen(paTestData *yakData)
static PaError yakAudioStreamOpen(paTestData *yakData)
{ 
PaStreamParametersinputParameters;
PaStream*stream;
PaErrorerr = paNoError;
 
// register signal SIGINT and signal handler
signal(SIGINT, signalHandler);
 
err = Pa_Initialize();
if( err != paNoError ) goto done;
 
inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
if (inputParameters.device == paNoDevice) {
fprintf(stderr,"Error: No default input device.\n");
goto done;
}
inputParameters.channelCount = NUM_CHANNELS;/* stereo input */
inputParameters.sampleFormat = PA_SAMPLE_TYPE;
inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
inputParameters.hostApiSpecificStreamInfo = NULL;

/* Record some audio. -------------------------------------------- */
err = Pa_OpenStream(
&stream,
&inputParameters,
NULL,/* &outputParameters, */
SAMPLE_RATE,
SAMPLES_PER_FRAME,
paClipOff,/* we won't output out of range samples so don't bother clipping them */
yakAudioRecordCallback,
yakData );
if( err != paNoError ) goto done;
 
yakData->recordStream = stream; 
return paNoError;
 
done:
Pa_Terminate();
if( err != paNoError )
{
fprintf( stderr, "An error occured while using the portaudio stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
err = 1;/* Always return 0 or 1, but no other return codes. */
}
return err;
}

Step 2: Initialize FFMPEG library.

Initialize opencore-amr library to with proper configuration parameters to match port-audio capture configuration.

Code snippet as follows

C++
AVCodecContext*audioCodec;
AVCodec *codec;

avcodec_register_all();


//Set up audio encoder
codec = avcodec_find_encoder(CODEC_ID_AAC);
if (codec == NULL) 
{
printf("avcodec_find_encoder: ERROR\n");
return NULL;
}
audioCodec = avcodec_alloc_context();
audioCodec->bit_rate = audioBitrate;
audioCodec->sample_fmt = SAMPLE_FMT_S16;
audioCodec->sample_rate = sampleRate;
audioCodec->channels = channels;
audioCodec->profile = FF_PROFILE_AAC_MAIN;
//audioCodec->time_base = (AVRational){1, sampleRate};
audioCodec->time_base.num= 1;
audioCodec->time_base.den= sampleRate;
 
audioCodec->codec_type = AVMEDIA_TYPE_AUDIO;
if (avcodec_open(audioCodec, codec) < 0) 
{
printf("avcodec_open: ERROR\n");
return NULL;
}
 
return audioCodec;
}

Step 3: Encode Raw Audio Frame.

When port-audio record callback is called, raw audio data is stored input buffer, pass the buffer and length to amr encoder, amr encoder returns encoded data.

C++
static void yakAudioEncode(paTestData *yakData, uint8_t *rawData, int rawDataSize)
{
int frameBytes;

frameBytes = yakData->c->frame_size * yakData->c->channels * sizeof(SAMPLE);

// Note: revisit the while loop
// BUG-1
while (rawDataSize >= frameBytes) 
{
int packetSize;
 
packetSize = avcodec_encode_audio(yakData->c, yakData->encoderOutput, 
yakData->allocOutputSize, (short *)rawData);
//printf("EncodePaData (%d-%d-%d)\n",packetSize,audioSize,frameBytes);
 
yakData->encoderOutputSize+= packetSize;
rawData += frameBytes;
rawDataSize -= frameBytes;
} 
}

Step 4: write to file.

C++
static void EncodePaData(paTestData *yakData, uint8_t *rawData, int rawDataSize)
{
yakAudioEncode(yakData, rawData, rawDataSize);
fwrite(yakData->encoderOutput, sizeof(uint8_t), yakData->encoderOutputSize, 
yakData->recFileStream);
yakData->encoderOutputSize = 0;
}

Step 6: close ffmpeg library

Close all resources related ffmpeg AvCodecContext and AvCodec libraries.

Step 7: Stop, close audio stream and close port audio.

C++
static PaError yakCloseAudioStream(paTestData *yakData) 

{ 

return Pa_CloseStream( yakData->recordStream); 

}

Required software

The following software are required to execute and listen captured audio file.

VC++, portaudio library/dll, ffmpeg library/dll and ant AAC capable audio player (VLC).

NOTE:

FFMPEG development release software is required to run this application. please download ffmpeg development version. and specificy required paths for include and libraries.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)