Example #1
0
func (d *Decoder) readNextPage(frame *[][]float32, pcm [][][]float32) (n int, err error) {
	if ret := vorbis.OggSyncPageout(&d.syncState, &d.page); ret < 0 {
		d.onError(errors.New("vorbis: corrupt or missing data in bitstream"))
		return 0, nil // non-fatal
	} else if ret == 0 {
		// need more data
		return d.readChunk(d.input)
	}

	// page is synced at this point
	vorbis.OggStreamPagein(&d.streamState, &d.page)

	for !d.stopRequested() {
		if ret := vorbis.OggStreamPacketout(&d.streamState, &d.packet); ret < 0 {
			continue // skip packet
		} else if ret == 0 {
			// no packets left on the page, go to the new one
			return 0, nil
		}
		if vorbis.Synthesis(&d.block, &d.packet) == 0 {
			vorbis.SynthesisBlockin(&d.dspState, &d.block)
		}
		samples := vorbis.SynthesisPcmout(&d.dspState, pcm)
		for ; samples > 0; samples = vorbis.SynthesisPcmout(&d.dspState, pcm) {
			space := int32(d.samplesPerChannel - len(*frame))
			if samples > space {
				samples = space
			}
			for i := 0; i < int(samples); i++ {
				sample := make([]float32, d.info.Channels)
				for j := 0; j < int(d.info.Channels); j++ {
					sample[j] = pcm[0][j][:samples][i]
				}
				*frame = append(*frame, sample)
			}
			if len(*frame) == d.samplesPerChannel {
				d.sendFrame(*frame)
				*frame = make([][]float32, 0, d.samplesPerChannel)
			}
			vorbis.SynthesisRead(&d.dspState, samples)
		}
	}
	if d.stopRequested() || vorbis.OggPageEos(&d.page) == 1 {
		return 0, io.EOF
	}
	return 0, nil
}
Example #2
0
func (d *Decoder) readStreamHeaders(r io.Reader) error {
	d.readChunk(r)

	// Read the first page
	if ret := vorbis.OggSyncPageout(&d.syncState, &d.page); ret != 1 {
		return errors.New("vorbis: not a valid Ogg bitstream")
	}

	// Init the logical bitstream with serial number stored in the page
	vorbis.OggStreamInit(&d.streamState, vorbis.OggPageSerialno(&d.page))

	vorbis.InfoInit(&d.info)
	vorbis.CommentInit(&d.comment)

	// Add a complete page to the bitstream
	if ret := vorbis.OggStreamPagein(&d.streamState, &d.page); ret < 0 {
		return errors.New("vorbis: the supplied page does not belong this Vorbis stream")
	}
	// Get the first packet
	if ret := vorbis.OggStreamPacketout(&d.streamState, &d.packet); ret != 1 {
		return errors.New("vorbis: unable to fetch initial Vorbis packet from the first page")
	}
	// Finally decode the header packet
	if ret := vorbis.SynthesisHeaderin(&d.info, &d.comment, &d.packet); ret < 0 {
		return fmt.Errorf("vorbis: unable to decode the initial Vorbis header: %d", ret)
	}

	var headersRead int
forPage:
	for headersRead < 2 {
		if res := vorbis.OggSyncPageout(&d.syncState, &d.page); res < 0 {
			// bytes have been skipped, try to sync again
			continue forPage
		} else if res == 0 {
			// go get more data
			if _, err := d.readChunk(r); err != nil {
				return errors.New("vorbis: got EOF while reading Vorbis headers")
			}
			continue forPage
		}
		// page is synced at this point
		vorbis.OggStreamPagein(&d.streamState, &d.page)
		for headersRead < 2 {
			if ret := vorbis.OggStreamPacketout(&d.streamState, &d.packet); ret < 0 {
				return errors.New("vorbis: data is missing near the secondary Vorbis header")
			} else if ret == 0 {
				// no packets left on the page, go get a new one
				continue forPage
			}
			if ret := vorbis.SynthesisHeaderin(&d.info, &d.comment, &d.packet); ret < 0 {
				return errors.New("vorbis: unable to read the secondary Vorbis header")
			}
			headersRead++
		}
	}

	d.info.Deref()
	d.comment.Deref()
	d.comment.UserComments = make([][]byte, d.comment.Comments)
	d.comment.Deref()
	return nil
}