/** * tries to find the next MPEG Audio Frame, loads it into the destination * buffer (including 32bit header) and returns a FrameHeader object. (If * destFH is non-null, that object will be used to store the header infos) * will block until data is available. will throw EOFException of any other * IOException created by the InputStream object. set filter to 0 or to any * other value using the FILTER_xxx flags to force a specific frame type. */ func (p *mpaFrameParser) getNextFrame(filter uint32, destBuffer []byte, destFH *mp3agic.FrameHeader) (*mp3agic.FrameHeader, os.Error) { p.setupFilter(filter) fill(p.headBuff[:], 0) hbPos := 0 fh := destFH if fh == nil { fh = new(mp3agic.FrameHeader) } var tmp [1]byte skipped := -4 for { readn, err := p.ips.Read(tmp[:]) if readn == 0 && err == os.EOF { // EOF ? if p.junkh != nil { for i := 0; i < 4; i++ { // flush headBuff if skipped >= 0 { p.junkh.Write(p.headBuff[(hbPos+i)&3]) } skipped++ } p.junkh.EndOfJunkBlock() } return nil, os.EOF } else if err != os.EOF { return nil, err } if p.junkh != nil && skipped >= 0 { p.junkh.Write(p.headBuff[hbPos]) } p.headBuff[hbPos] = tmp[0] skipped++ hbPos = (hbPos + 1) & 3 if p.headBuff[hbPos] != 0xFF { continue // not the beginning of a sync-word } header32 := uint32(p.headBuff[hbPos]) for z := 1; z < 4; z++ { header32 <<= 8 header32 |= uint32(p.headBuff[(hbPos+z)&3]) } if header32&p.masker != p.masked { continue // not a frame header } *fh = mp3agic.FrameHeader(header32) if fh.Verify() != nil { // doesn't look like a proper header continue } if filter&FILTER_STEREO != 0 && fh.Channels() != 2 { continue } offs := 0 for ; offs < 4; offs++ { destBuffer[offs] = p.headBuff[(hbPos+offs)&3] } tmp2 := fh.LengthInBytes() - offs //tmp2 := fh.getFrameSize() - offs; // FIXME: behaviour when not enough data read (different from Java) readn, err = p.ips.Read(destBuffer[offs : offs+tmp2]) if readn != tmp2 { if err != os.EOF { panic(err) } if p.junkh != nil { readn += 4 // inklusive header for z := 0; z < readn; z++ { p.junkh.Write(destBuffer[z] & 0xFF) } p.junkh.EndOfJunkBlock() } return nil, err } if p.junkh != nil { p.junkh.EndOfJunkBlock() } break } return fh, nil }
func createHeaderFrame(toBeSimilar mp3agic.FrameHeader, vbr bool, kbps float32, frameCount, musicBytes, vbrScale int, seektable []byte, encDelay, encPadding int, srcTag *XingInfoLameTagFrame, dest []byte, dofs int, maskATH int) int { fh32 := toBeSimilar | 0x00010000 // disable CRC if any frameSize := 0 tagOffset := 0 { // calculate optimal header frame size tmp := mp3agic.FrameHeader() minDist := float32(9999) for i := 1; i < 15; i++ { var th32 int = (fh32 & 0xFFFF0FFF) | (i << 12) tmp.setHeader32(th32) if tmp.getFrameSize() >= 0xC0 { var ikbps int = tmp.BitrateInKbps() var dist float32 = Math.abs(kbps - ikbps) if dist < minDist { minDist = dist fh32 = th32 frameSize = tmp.getFrameSize() tagOffset = tmp.getSideInfoSize() + 4 } } } } tagOffset += dofs fill(dest[dofs:dofs+frameSize], 0) //Arrays.fill(dest, dofs, dofs + frameSize, (byte) 0); dest[dofs] = byte(fh32 >> 24) dest[dofs+1] = byte(fh32 >> 16) dest[dofs+2] = byte(fh32 >> 8) dest[dofs+3] = byte(fh32) if vbr { copy(dest, "Xing") } else { copy(dest, "Info") } tagOffset += 4 copy(dest, []byte{0, 0, 0, 0x0f}) tagOffset += 4 add := func(b byte) { dest[tagOffset] = b tagOffset++ } add32 := func(i uint32) { add(byte(i >> 24)) add(byte(i >> 16)) add(byte(i >> 8)) add(byte(i)) } add32(uint32(frameCount)) add32(uint32(frameSize + musicBytes)) copy(dest[tagOffset:tagOffset+100], seektable) //System.arraycopy(seektable, 0, dest, tagOffset, 100); tagOffset += 100 add32(uint32(vbrScale)) if srcTag != nil && srcTag.Verify() == nil && srcTag.hasLameTag { copy(dest[tagOffset-4:], srcTag.bb[srcTag.lameTagOfs:srcTag.lameTagOfs+40]) //System.arraycopy(srcTag.bb, srcTag.lameTagOfs, dest, tagOffset - 4, 40); tagOffset += 4 // delete LAME's replaygain tag for i := 0; i < 8; i++ { dest[tagOffset+0x07+i] = 0 } // deleting no-gap flags ... dest[tagOffset+0x0F] &= maskATH } else { copy(dest, "LAME") tagOffset += 4 } encDelay = max(0, min(encDelay, 4095)) encPadding = max(0, min(encPadding, 4095)) tagOffset += 0x11 // write encDelay / encPadding ... add(byte(uint32(encDelay) >> 4)) add(byte(((encDelay & 0xF) << 4) | (uint32(encPadding) >> 8))) add(byte(encPadding)) tagOffset += 4 add32(uint32(frameSize + musicBytes)) crc = uint16(0) for i := 0; i < 190; i++ { crc = CRC16.updateLAME(crc, dest[dofs+i]) } tagOffset += 6 add(byte(crc >> 8)) add(byte(crc)) return frameSize }