[Vorbis] encoder_example.c Questions
Ian Malone
ibm21 at cam.ac.uk
Mon Sep 26 13:35:11 PDT 2005
Daniel Mikusa wrote:
> I've been trying to piece my way through the encoder_example.c program
> to better understand how to encode files as ogg/vorbis. I'm stuck on
> two sections of the code.
>
Well, I can't claim to know anything about the internals of Ogg or
Vorbis, but I can tell what what's happening here.
> This is the first
>
> /* uninterleave samples */
> for(i=0;i<bytes/4;i++){
> buffer[0][i]=((readbuffer[i*4+1]<<8)|
> (0x00ff&(int)readbuffer[i*4]))/32768.f;
> buffer[1][i]=((readbuffer[i*4+3]<<8)|
> (0x00ff&(int)readbuffer[i*4+2]))/32768.f;
> }
>
readbuffer is a signed char type (8 bits, never repeat that on
comp.lang.c), it has been used to read in values for alternate
stereo channels, which are 16bits wide. They are in little-endian
format, so the first octet is the _least_ significant, hence
readbuffer[i*4] is promoted to an int and bitmasked with 0x00ff
to get the 8 least significant bits of the int (note: C doesn't
care about underyling endianess, its representations of unsigned
numbers are straightforward binary). The second octet of the pair
---readbuffer[i*4+1]---is then bit-shifted 8 bits up (this implies
promotion to int), they are ORed to get the resulting reformed int,
and divided by a floating point number to get a floating point
result normalised to +/-1.0. The same is done for the next int,
but it is put in buffer[1][i] instead of buffer[0][i].
My one piece of knowledge on Vorbis itself is that it uses floating
point values internally. Here you are converting interleaved 16bit
signed integer values to floating point ones.
>
> This is the second.
>
This is the point where my lack of knowledge shows, but if you know
what these functions do then the comments are probably fairly
informative. I should caution that I don't have function
documentation in front of me, so I'm going by names, comments and
their position in the flow.
> /* vorbis does some data preanalysis, then divvies up blocks for
> more involved (potentially parallel) processing. Get a single
> block for encoding now */
> while(vorbis_analysis_blockout(&vd,&vb)==1){
>
My understanding is that vd stores the current 'state' of the encoder.
You have already loaded the raw audio into it. Now, while there is
still processing to be done, you follow this loop. My guess is that
vb will be loaded with the next block in the series each time round.
> /* analysis, assume we want to use bitrate management */
> vorbis_analysis(&vb,NULL);
> vorbis_bitrate_addblock(&vb);
>
Do the encode and push the new block onto an internal stack which
controls the number of blocks in a packet to maintain the bitrate.
> while(vorbis_bitrate_flushpacket(&vd,&op)){
>
This (and the nested while) comprise an output loop within the encoder
loop. If we have accumulated blocks to fill a packet, do so.
> /* weld the packet into the bitstream */
> ogg_stream_packetin(&os,&op);
>
> /* write out pages (if any) */
> while(!eos){
> int result=ogg_stream_pageout(&os,&og);
If we haven't come to the end of the stream then see if we have enough
packets to fill a page.
> if(result==0)break;
If we haven't, break the loop (we'll then continue until we do have
enough).
> fwrite(og.header,1,og.header_len,stdout);
> fwrite(og.body,1,og.body_len,stdout);
>
If we do then push the header and body onto stdout (which is where the
resulting ogg/vorbis encoded stuff is going).
> /* this could be set above, but for illustrative purposes, I do
> it here (to show that vorbis does know where the stream
> ends) */
>
> if(ogg_page_eos(&og))eos=1;
I'm not certain, but if(result==0)break; is probably the equivalent to
the while(vorbis_bitrate_flushpacket(&vd,&op)), I think eos will only be
encountered once all input data is finished.
> }
> }
>
>
> Can anyone elaborate on what is happening in these two sections of
> code? Also if anyone has more / better examples for libvorbis please
> let me know.
>
Hope the above isn't totally misleading.
--
imalone
More information about the Vorbis
mailing list