Example #1
0
        // fetch and process a packet. Handles the case where we're at a
        // bitstream boundary and dumps the decoding machine. If the decoding
        // machine is unloaded, it loads it. It also keeps pcm_offset up to
        // date (seek and read both use this. seek uses a special hack with
        // readp).
        //
        // return: -1) hole in the data (lost packet)
        // 0) need more date (only if readp==0)/eof
        // 1) got a packet

        private int process_packet(int readp)
        {
            Page og = new Page();

            // handle one packet. Try to fetch it from current stream state
            // extract packets from page
            while (true)
            {
                // process a packet if we can. If the machine isn't loaded,
                // neither is a page
                if (decode_ready)
                {
                    Packet op     = new Packet();
                    int    result = os.packetout(op);
                    long   granulepos;
                    // if(result==-1)return(-1); // hole in the data. For now, swallow
                    // and go. We'll need to add a real
                    // error code in a bit.
                    if (result > 0)
                    {
                        // got a packet. process it
                        granulepos = op.granulepos;
                        if (vb.synthesis(op) == 0)
                        {
                            // lazy check for lazy
                            // header handling. The
                            // header packets aren't
                            // audio, so if/when we
                            // submit them,
                            // vorbis_synthesis will
                            // reject them
                            // suck in the synthesis data and track bitrate
                            {
                                int oldsamples = vd.synthesis_pcmout(null, null);
                                vd.synthesis_blockin(vb);
                                samptrack += vd.synthesis_pcmout(null, null) - oldsamples;
                                bittrack  += op.bytes * 8;
                            }

                            // update the pcm offset.
                            if (granulepos != -1 && op.e_o_s == 0)
                            {
                                int link = current_link;
                                int samples;
                                // this packet has a pcm_offset on it (the last packet
                                // completed on a page carries the offset) After processing
                                // (above), we know the pcm position of the *last* sample
                                // ready to be returned. Find the offset of the *first*
                                //
                                // As an aside, this trick is inaccurate if we begin
                                // reading anew right at the last page; the end-of-stream
                                // granulepos declares the last frame in the stream, and the
                                // last packet of the last page may be a partial frame.
                                // So, we need a previous granulepos from an in-sequence page
                                // to have a reference point. Thus the !op.e_o_s clause above

                                samples     = vd.synthesis_pcmout(null, null);
                                granulepos -= samples;
                                for (int i = 0; i < link; i++)
                                {
                                    granulepos += pcmlengths[i];
                                }
                                pcm_offset = granulepos;
                            }
                            return(1);
                        }
                    }
                }

                if (readp == 0)
                {
                    return(0);
                }
                if (get_next_page(og, -1) < 0)
                {
                    return(0);
                }                                              // eof. leave unitialized

                // bitrate tracking; add the header's bytes here, the body bytes
                // are done by packet above
                bittrack += og.header_len * 8;

                // has our decoding just traversed a bitstream boundary?
                if (decode_ready)
                {
                    if (current_serialno != og.serialno())
                    {
                        decode_clear();
                    }
                }

                // Do we need to load a new machine before submitting the page?
                // This is different in the seekable and non-seekable cases.
                //
                // In the seekable case, we already have all the header
                // information loaded and cached; we just initialize the machine
                // with it and continue on our merry way.
                //
                // In the non-seekable (streaming) case, we'll only be at a
                // boundary if we just left the previous logical bitstream and
                // we're now nominally at the header of the next bitstream

                if (!decode_ready)
                {
                    int i;
                    current_serialno = og.serialno();

                    // match the serialno to bitstream section. We use this rather than
                    // offset positions to avoid problems near logical bitstream
                    // boundaries
                    for (i = 0; i < links; i++)
                    {
                        if (serialnos[i] == current_serialno)
                        {
                            break;
                        }
                    }
                    if (i == links)
                    {
                        return(-1);
                    }                                // sign of a bogus stream. error out,
                    // leave machine uninitialized
                    current_link = i;

                    os.init(current_serialno);
                    os.reset();

                    make_decode_ready();
                }
                os.pagein(og);
            }
        }