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
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.
static PaError
yakAudioStreamOpen(paTestData *yakData)
static PaError yakAudioStreamOpen(paTestData *yakData)
{
PaStreamParametersinputParameters;
PaStream*stream;
PaErrorerr = paNoError;
signal(SIGINT, signalHandler);
err = Pa_Initialize();
if( err != paNoError ) goto done;
inputParameters.device = Pa_GetDefaultInputDevice();
if (inputParameters.device == paNoDevice) {
fprintf(stderr,"Error: No default input device.\n");
goto done;
}
inputParameters.channelCount = NUM_CHANNELS;
inputParameters.sampleFormat = PA_SAMPLE_TYPE;
inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
inputParameters.hostApiSpecificStreamInfo = NULL;
err = Pa_OpenStream(
&stream,
&inputParameters,
NULL,
SAMPLE_RATE,
SAMPLES_PER_FRAME,
paClipOff,
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;
}
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
AVCodecContext*audioCodec;
AVCodec *codec;
avcodec_register_all();
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.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.
static void yakAudioEncode(paTestData *yakData, uint8_t *rawData, int rawDataSize)
{
int frameBytes;
frameBytes = yakData->c->frame_size * yakData->c->channels * sizeof(SAMPLE);
while (rawDataSize >= frameBytes)
{
int packetSize;
packetSize = avcodec_encode_audio(yakData->c, yakData->encoderOutput,
yakData->allocOutputSize, (short *)rawData);
yakData->encoderOutputSize+= packetSize;
rawData += frameBytes;
rawDataSize -= frameBytes;
}
}
Step 4: write to file.
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.
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.