LAME: Asynchronous frame processing
Uncompressed frames pass several stages during the encoding process. They are shown
in the following picture:
The processing of one frame depends on the results of his predecessor.
The pseudo code (imperative) is as follows:
MP3EncodeFrames(frames)
{
frames[0] = InitializeFirstFrame();
for (f = 1; f < frames.count; ++f) {
SampleConverter(frames[f], frames[f - 1]);
ReplayGain(frames[f], frames[f - 1]);
PsychoAcoustics(frames[f], frames[f - 1]);
MDCT(frames[f], frames[f - 1]);
Quantizer(frames[f], frames[f - 1]);
BitStream(frames[f], frames[f - 1]);
}
}
The search for parallelizable elements in this code is hardly reasonable, because one frame
is processed in less than 1 msec on current processors.
Also the loop cannot be parallelized because of the dependencies.
It looks different if an asynchronous programming language is used: In this case, the
function "MP3EncodeFrames" can be written in a way, where the potential for
parallelization becomes visible – even if finally no parallelization is possible:
MP3EncodeFrames(frames)
{
frames[0] = InitializeFirstFrame();
SampleConverter(frames);
ReplayGain(frames);
PsychoAcoustics(frames);
MDCT(frames);
Quantizer(frames);
BitStream(frames);
}
And representative for the other asynchronous tasks:
SampleConverter(frames)
{
for (f = 1; f < frames.count; ++f)
SampleConverter(frames[f], frames[f - 1]);
}
The processing times of the particular tasks are in the range of seconds, thus, a
possible parallelization may lead to a significant performance gain.
Implementation in fpMP3:
"MP3EncodeFrames" was implemented as C++ class "LAMEEncoder".
Parts of the function were moved to the class "MP3EncodingTask" for organizational reasons.
|