Пример #1
0
// HasID3V1Tag returns true if an ID3v1 tag is present at the end of r.
func HasID3v1Tag(r readerutil.SizeReaderAt) (bool, error) {
	if r.Size() < ID3v1TagLength {
		return false, nil
	}

	buf := make([]byte, len(id3v1Magic), len(id3v1Magic))
	if _, err := r.ReadAt(buf, r.Size()-ID3v1TagLength); err != nil {
		return false, fmt.Errorf("Failed to read ID3v1 data: %v", err)
	}
	if bytes.Equal(buf, id3v1Magic) {
		return true, nil
	}
	return false, nil
}
Пример #2
0
// GetMPEGAudioDuration reads the first frame in r and returns the audio length with millisecond precision.
// Format details are at http://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header.
func GetMPEGAudioDuration(r readerutil.SizeReaderAt) (time.Duration, error) {
	var header uint32
	if err := binary.Read(io.NewSectionReader(r, 0, r.Size()), binary.BigEndian, &header); err != nil {
		return 0, fmt.Errorf("Failed to read MPEG frame header: %v", err)
	}
	getBits := func(startBit, numBits uint) uint32 {
		return (header << startBit) >> (32 - numBits)
	}

	if getBits(0, 11) != 0x7ff {
		return 0, errors.New("Missing sync bits in MPEG frame header")
	}
	var version mpegVersion
	var ok bool
	if version, ok = mpegVersionsById[getBits(11, 2)]; !ok {
		return 0, errors.New("Invalid MPEG version index")
	}
	var layer mpegLayer
	if layer, ok = mpegLayersByIndex[getBits(13, 2)]; !ok {
		return 0, errors.New("Invalid MPEG layer index")
	}
	bitrate := mpegBitrates[version][layer][getBits(16, 4)]
	if bitrate == 0 {
		return 0, errors.New("Invalid MPEG bitrate")
	}
	samplingRate := mpegSamplingRates[version][getBits(20, 2)]
	if samplingRate == 0 {
		return 0, errors.New("Invalid MPEG sample rate")
	}
	samplesPerFrame := mpegSamplesPerFrame[version][layer]

	var xingHeaderStart int64 = 4
	// Skip "side information".
	if getBits(24, 2) == 0x3 { // Channel mode; 0x3 is mono.
		xingHeaderStart += 17
	} else {
		xingHeaderStart += 32
	}
	// Skip 16-bit CRC if present.
	if getBits(15, 1) == 0x0 { // 0x0 means "has protection".
		xingHeaderStart += 2
	}

	b := make([]byte, 12, 12)
	if _, err := r.ReadAt(b, xingHeaderStart); err != nil {
		return 0, fmt.Errorf("Unable to read Xing header at %d: %v", xingHeaderStart, err)
	}
	var ms int64
	if bytes.Equal(b[0:4], xingHeaderName) || bytes.Equal(b[0:4], infoHeaderName) {
		r := bytes.NewReader(b[4:])
		var xingFlags uint32
		binary.Read(r, binary.BigEndian, &xingFlags)
		if xingFlags&0x1 == 0x0 {
			return 0, fmt.Errorf("Xing header at %d lacks number of frames", xingHeaderStart)
		}
		var numFrames uint32
		binary.Read(r, binary.BigEndian, &numFrames)
		ms = int64(samplesPerFrame) * int64(numFrames) * 1000 / int64(samplingRate)
	} else {
		// Okay, no Xing VBR header. Assume that the file has a constant bitrate.
		// (The other alternative is to read the whole file and examine each frame.)
		ms = r.Size() / int64(bitrate) * 8
	}
	return time.Duration(ms) * time.Millisecond, nil
}