Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: How does LAME actually work? (Read 7656 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

How does LAME actually work?

Greetings.

I am doing some experiments with audio encoding. I am right now studying sources of the LAME encoder (lastest stable).
So far, i've read every available documentation and i still wonder:

Lame encoding process goes like this:
- init
- pass parameters
- encode some frames
- close

Frames are encoded in a loop where we get values from (for example) wav file and pass them to a function that looks like this:

lame_encode_buffer_int(lame_global_flags * gfp,
                      const int buffer_l[],
                      const int buffer_r[],
                      const int nsamples, unsigned char *mp3buf, const int mp3buf_size)

Then we write the contents of mp3buf to disc and get values again until we get EOF.

Question: From what i've read, MP3 is supposed to have:
a) Bit reservoir
b) Consequently, Data that "overlaps" into other "frames", meaning that after the frame X header may come data of a frame from the future (for example data of X+1)

Therefore, how can we actually encode MP3 file in such fashion? I mean, say frame1 is all silence and it takes less than our bitrate (for example 128) to encode. Then we should end with a frame 1 header, then some data, and some not yet used space now allocated to bit reservoir. Then, encoding frame 2, we would first fill the unused space in frame 1's data part, and then start filling frame 2.
If we output frames one-by-one, what happens? How is this actually processed? Does LAME actually store the bit reservoir data somewhere in the GFP structure and outputs only the part of the frame that contains data of the frame, meaning say header of the frame 2 might only get put into buffer when we output frame 4 (which used bit reservoir and thus occupies space before and after frame 3 header)?

What happens at the end? For example, we end our encoding with bit reservoir bigger than a frame, this means we didnt ouput last frame header yet, however there is no more data to encode. From what i see in the frontend code, we just read wav file until we read 0 bytes, and then we stop. Or does calling encode_buffer function with nsamples=0 trigger "finalisation" of the encoding? It doesnt look like since the function contains:
if (nsamples == 0)
        return 0;
Which means supplying 0 samples will make it do nothing, presumably. So how do those headers end up in the stream, or are they... dropped? But then this would mean we are loosing up to max_bit_reservoir/frame_size frames? Or is max_bit_reservoir smaller than minimum possible frame size?

I know this might be very narrow / specific question to those who have knowledge of the code, or it might even be a stupid question cos i am blind, but please if you have knowledge and time, help me.

Thanks!

How does LAME actually work?

Reply #1
LAME always outputs complete frames, but each call to lame_encode_buffer can return 0..n frames. So if the first block of data to encode does not fill a complete frame, you simply get no data back from the first call. Then if the second block fills the rest of frame 1 and the complete frame 2, you will get both frames returned at once.

At the end of an encoder run, lame_encode_flush is called to flush the internal buffers and possibly return one last frame that is not completely filled (padded with zeros / silence).

So it's actually:

- init
- pass parameters
- encode some frames
- flush
- close

How does LAME actually work?

Reply #2
Aah, thats it. Thanks! I missed that the flush part is part of lame, not usual "flush" that you use before closing files.

Could you please explain then, where exactly are the unfinished frames stored between lame_encode_buffer runs? Where are all the mp3 "intermediate" parameters stored like previous frame information (as we need it for MDCT)?
I looked at lame_global_flags and i only see floats, ints and function pointers for data report.. What am i missing?

How does LAME actually work?

Reply #3
I think one of the key functions that answers your questions is function 'VBR_new_iteration_loop' (in the case of VBR new) in quantize.c.
Here is the decision which output frame bitrate to use, and bit reservoir status is updated here.
lame3995o -Q1.7 --lowpass 17

How does LAME actually work?

Reply #4
Internal variables and buffers are kept in the lame_internal_flags structure defined in util.h and pointed to by the internal_flags member of lame_global_flags.

How does LAME actually work?

Reply #5
Thanks, i see now, thats what i've been lookign for.

How does LAME actually work?

Reply #6
Ah, cannot edit my first post, but i dont want to make a new one for a simple small question either.

How does the DLL version work, generally? The gfp (and lame internal flags etc) structure are stored in this program memory, that calls the dll, right? Do i understand correctly that the structure is created when beInitStream is called and pointer to it is then passed under the name of HBE_STREAM hbeStream to other functions?
So to use the dll, i will first call beInitStream, supplying a PBE_CONFIG pbeConfig structure, and then receive pointer to lame global flags structure and later pass pointer to that to all the other dll functions, right?

Also, is there any documentation on error codes for LAME? I mean, there are different places in code of functions like encode_buffer_int that return -1, or -3, etc. Is there any known table of error codes that LAME returns on various stages? I googled and found absolutely not a single hint!

How does LAME actually work?

Reply #7
Do you want to use lame_enc.dll or libmp3lame.dll?

How does LAME actually work?

Reply #8
Erm, what is the difference?
I downloaded the lastest source and i have a project that generates a dll, project is called LameDLL_vc8 and it makes lame_enc.dll... what is libmp3lame.dll and how does it differ and where does it come from?

 

How does LAME actually work?

Reply #9
Erm, what is the difference?
I downloaded the lastest source and i have a project that generates a dll, project is called LameDLL_vc8 and it makes lame_enc.dll... what is libmp3lame.dll and how does it differ and where does it come from?

I'm too looking for the same answer 

How does LAME actually work?

Reply #10
Open vc_solution\vc9_lame.sln. Build libmp3lameDLL project.