// ReadHeaders allows to init info and comment from a private codec data payload // when no Ogg stream is available. Info and comment must be initialised beforehand. func ReadHeaders(codecPriv []byte, info *vorbis.Info, comment *vorbis.Comment) error { if len(codecPriv) == 0 { return errors.New("vorbis decoder: no codec private data") } headerSizes := make([]int, 3) headers := make([][]byte, 3) p := codecPriv if p[0] == 0x00 && p[1] == 0x30 { for i := 0; i < 3; i++ { headerSizes[i] = int(uint16(p[0])<<8 | uint16(p[1])) headers[i] = p p = p[headerSizes[i]:] } } else if p[0] == 0x02 { offset := 1 p = p[1:] for i := 0; i < 2; i++ { headerSizes[i] = 0 for (p[0] == 0xFF) && offset < len(codecPriv) { headerSizes[i] += 0xFF offset++ p = p[1:] } if offset >= len(codecPriv)-1 { return errors.New("vorbis decoder: header sizes damaged") } headerSizes[i] += int(p[0]) offset++ p = p[1:] } headerSizes[2] = len(codecPriv) - headerSizes[0] - headerSizes[1] - offset headers[0] = codecPriv[offset:] headers[1] = codecPriv[offset+headerSizes[0]:] headers[2] = codecPriv[offset+headerSizes[0]+headerSizes[1]:] } else { return fmt.Errorf("vorbis decoder: initial header len is wrong: %d", p[0]) } for i := 0; i < 3; i++ { packet := vorbis.OggPacket{ BOS: b(i == 0), Bytes: headerSizes[i], Packet: headers[i], } if ret := vorbis.SynthesisHeaderin(info, comment, &packet); ret < 0 { return fmt.Errorf("vorbis decoder: %d. header damaged", i+1) } } return nil }
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 }