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. 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; } This is the second. /* 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){ /* analysis, assume we want to use bitrate management */ vorbis_analysis(&vb,NULL); vorbis_bitrate_addblock(&vb); while(vorbis_bitrate_flushpacket(&vd,&op)){ /* 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(result==0)break; fwrite(og.header,1,og.header_len,stdout); fwrite(og.body,1,og.body_len,stdout); /* 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; } } 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. Thanks in advance. Dan Mikusa dan@trz.cc -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.xiph.org/pipermail/vorbis/attachments/20050926/70007247/attachment.htm
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
On 9/26/05, Daniel Mikusa <dan@trz.cc> 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. > > 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; > }The encoder example assumes that the audio is stored as (interleaved) stereo, 16-bit signed little-endian samples (this is the most common format in WAV files, for example). The vorbis encoder library takes floating point samples in two seperate vectors (i.e. not interleaved). So this chunk of code is converting from 16-bit little-endian integer samples to floats (ranging from -1 to 1), then putting them into the buffers for the encoder.> > > This is the second. > > /* 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){At this point, we've already submitted raw (unencoded) data to the library. This call tells it to produce a 'block' to actually encode (this requires doing quite a bit of analysis to decide what size of block to use). The while loop makes us continue doing this until there's no longer enough data in the internal buffers (at which point we need to submit more data).> > /* analysis, assume we want to use bitrate management */ > vorbis_analysis(&vb,NULL); > vorbis_bitrate_addblock(&vb);This does the main analysis/encoding step.> > while(vorbis_bitrate_flushpacket(&vd,&op)){Then this actually produces a packet that we can write to our output file, based on the analysis that has been done. Again, we keep doing this until the encoder library has no further packets to produce.> > /* weld the packet into the bitstream */ > ogg_stream_packetin(&os,&op);At this point, we're no longer doing vorbis-specific things, we're just doing the work to write our packets into an ogg bitstream. This call gives the packet to libogg.> > /* write out pages (if any) */ > while(!eos){ > int result=ogg_stream_pageout(&os,&og); > if(result==0)break; > fwrite(og.header,1,og.header_len,stdout); > fwrite(og.body,1,og.body_len,stdout);And then we loop writing out ogg pages (if any) until we hit EOS or don't have any pages to write (in fact, most of the time we won't have any pages at all to write out here - there are multiple packets per page normally. Mike