Пример #1
0
/**
 * 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
}
Пример #2
0
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
}