IPB

Welcome Guest ( Log In | Register )

 
Reply to this topicStart new topic
How does LAME actually work?, I dont understand how the lib itsef functions
Istrebitel
post Aug 1 2011, 12:12
Post #1





Group: Members
Posts: 54
Joined: 20-October 10
Member No.: 84756



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!

This post has been edited by Istrebitel: Aug 1 2011, 12:15
Go to the top of the page
+Quote Post
enzo
post Aug 1 2011, 14:04
Post #2


BonkEnc developer


Group: Developer
Posts: 70
Joined: 17-January 03
From: Hamburg
Member No.: 4611



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
Go to the top of the page
+Quote Post
Istrebitel
post Aug 1 2011, 15:06
Post #3





Group: Members
Posts: 54
Joined: 20-October 10
Member No.: 84756



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?
Go to the top of the page
+Quote Post
halb27
post Aug 1 2011, 17:52
Post #4





Group: Members
Posts: 2446
Joined: 9-October 05
From: Dormagen, Germany
Member No.: 25015



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.

This post has been edited by halb27: Aug 1 2011, 17:55


--------------------
lame3100m -V1 --insane-factor 0.75
Go to the top of the page
+Quote Post
enzo
post Aug 1 2011, 20:09
Post #5


BonkEnc developer


Group: Developer
Posts: 70
Joined: 17-January 03
From: Hamburg
Member No.: 4611



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.

This post has been edited by enzo: Aug 1 2011, 20:10
Go to the top of the page
+Quote Post
Istrebitel
post Aug 2 2011, 14:03
Post #6





Group: Members
Posts: 54
Joined: 20-October 10
Member No.: 84756



Thanks, i see now, thats what i've been lookign for.
Go to the top of the page
+Quote Post
Istrebitel
post Aug 2 2011, 14:22
Post #7





Group: Members
Posts: 54
Joined: 20-October 10
Member No.: 84756



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!

This post has been edited by Istrebitel: Aug 2 2011, 14:34
Go to the top of the page
+Quote Post
lvqcl
post Aug 2 2011, 14:59
Post #8





Group: Developer
Posts: 3467
Joined: 2-December 07
Member No.: 49183



Do you want to use lame_enc.dll or libmp3lame.dll?
Go to the top of the page
+Quote Post
Istrebitel
post Aug 2 2011, 15:13
Post #9





Group: Members
Posts: 54
Joined: 20-October 10
Member No.: 84756



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?
Go to the top of the page
+Quote Post
FiFo
post Aug 14 2011, 10:03
Post #10





Group: Members
Posts: 1
Joined: 13-June 08
Member No.: 54297



QUOTE (Istrebitel @ Aug 2 2011, 18:13) *
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 rolleyes.gif
Go to the top of the page
+Quote Post
lvqcl
post Aug 14 2011, 10:26
Post #11





Group: Developer
Posts: 3467
Joined: 2-December 07
Member No.: 49183



Open vc_solution\vc9_lame.sln. Build libmp3lameDLL project.
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 User(s) are reading this topic (1 Guests and 0 Anonymous Users)
0 Members:

 



RSS Lo-Fi Version Time is now: 21st December 2014 - 14:43