123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- package common
- import (
- "bytes"
- "encoding/binary"
- "io"
- "math"
- "mime/multipart"
- )
- import (
- "errors"
- )
- var (
- versions = []string{"2.5", "x", "2", "1"}
- layers = []string{"x", "3", "2", "1"}
- bitRates = map[string][]int{
- "V1Lx": []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- "V1L1": []int{0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448},
- "V1L2": []int{0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384},
- "V1L3": []int{0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320},
- "V2Lx": []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- "V2L1": []int{0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256},
- "V2L2": []int{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160},
- "V2L3": []int{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160},
- "VxLx": []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- "VxL1": []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- "VxL2": []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- "VxL3": []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- }
- sampleRates = map[string][]int{
- "x": []int{0, 0, 0},
- "1": []int{44100, 48000, 32000},
- "2": []int{22050, 24000, 16000},
- "2.5": []int{11025, 12000, 8000},
- }
- samples = map[string]map[string]int{
- "x": {
- "x": 0,
- "1": 0,
- "2": 0,
- "3": 0,
- },
- "1": { //MPEGv1, Layers 1,2,3
- "x": 0,
- "1": 384,
- "2": 1152,
- "3": 1152,
- },
- "2": { //MPEGv2/2.5, Layers 1,2,3
- "x": 0,
- "1": 384,
- "2": 1152,
- "3": 576,
- },
- }
- )
- type frame struct {
- bitRate int
- sampleRate int
- frameSize int
- sample int
- }
- func skipID3(buffer []byte) int {
- var id3v2Flags, z0, z1, z2, z3 byte
- var tagSize, footerSize int
- //http://id3.org/d3v2.3.0
- if buffer[0] == 0x49 && buffer[1] == 0x44 && buffer[2] == 0x33 { //'ID3'
- id3v2Flags = buffer[5]
- if (id3v2Flags & 0x10) != 0 {
- footerSize = 10
- } else {
- footerSize = 0
- }
- //ID3 size encoding is crazy (7 bits in each of 4 bytes)
- z0 = buffer[6]
- z1 = buffer[7]
- z2 = buffer[8]
- z3 = buffer[9]
- if ((z0 & 0x80) == 0) && ((z1 & 0x80) == 0) && ((z2 & 0x80) == 0) && ((z3 & 0x80) == 0) {
- tagSize = (((int)(z0 & 0x7f)) * 2097152) +
- (((int)(z1 & 0x7f)) * 16384) +
- (((int)(z2 & 0x7f)) * 128) +
- ((int)(z3 & 0x7f))
- return 10 + tagSize + footerSize
- }
- }
- return 0
- }
- func frameSize(samples int, layer string, bitRate, sampleRate, paddingBit int) int {
- if sampleRate == 0 {
- return 0
- } else if layer == "1" {
- return ((samples * bitRate * 125 / sampleRate) + paddingBit*4)
- } else { //layer 2, 3
- return (((samples * bitRate * 125) / sampleRate) + paddingBit)
- }
- }
- func parseFrameHeader(header []byte) *frame {
- b1 := header[1]
- b2 := header[2]
- versionBits := (b1 & 0x18) >> 3
- version := versions[versionBits]
- var simpleVersion string
- if version == "2.5" {
- simpleVersion = "2"
- } else {
- simpleVersion = version
- }
- layerBits := (b1 & 0x06) >> 1
- layer := layers[layerBits]
- bitRateKey := "V" + simpleVersion + "L" + layer
- bitRateIndex := (b2 & 0xf0) >> 4
- var bitRate int
- frameBitRates, exists := bitRates[bitRateKey]
- if exists && int(bitRateIndex) < len(frameBitRates) {
- bitRate = frameBitRates[bitRateIndex]
- } else {
- bitRate = 0
- }
- sampleRateIdx := (b2 & 0x0c) >> 2
- var sampleRate int
- frameSampleRates, exists := sampleRates[version]
- if exists && int(sampleRateIdx) < len(frameSampleRates) {
- sampleRate = frameSampleRates[sampleRateIdx]
- } else {
- sampleRate = 0
- }
- sample := samples[simpleVersion][layer]
- paddingBit := (b2 & 0x02) >> 1
- return &frame{
- bitRate: bitRate,
- sampleRate: sampleRate,
- frameSize: frameSize(sample, layer, bitRate, sampleRate, int(paddingBit)),
- sample: sample,
- }
- }
- func round(duration float64) float64 {
- return math.Round(duration*1000) / 1000 //round to nearest ms
- }
- // BoxHeader 信息头
- type BoxHeader2 struct {
- Size uint32
- FourccType [4]byte
- Size64 uint64
- }
- func getHeaderBoxInfo2(data []byte) (boxHeader BoxHeader2) {
- buf := bytes.NewBuffer(data)
- binary.Read(buf, binary.BigEndian, &boxHeader)
- return
- }
- // Calculate returns the duration of an mp3 file
- func GetMP3PlayDuration(file multipart.File) (duration float64, err error) {
- var size int64
- var info = make([]byte, 0x10)
- var boxHeader BoxHeader2
- file.ReadAt(info, 0)
- boxHeader = getHeaderBoxInfo2(info)
- size = int64(boxHeader.Size64)
- buffer := make([]byte, 100)
- if err != nil {
- return
- }
- var bytesRead int
- bytesRead, err = file.Read(buffer)
- if err != nil {
- return
- }
- if bytesRead < 100 {
- err = errors.New("Corrupt file")
- return
- }
- offset := int64(skipID3(buffer))
- buffer = make([]byte, 10)
- for offset < size {
- bytesRead, e := file.ReadAt(buffer, offset)
- if e != nil && e != io.EOF {
- err = e
- return
- }
- if bytesRead < 10 {
- duration = round(duration)
- return
- }
- if buffer[0] == 0xff && (buffer[1]&0xe0) == 0xe0 {
- info := parseFrameHeader(buffer)
- if info.frameSize > 0 && info.sample > 0 {
- offset += int64(info.frameSize)
- duration += (float64(info.sample) / float64(info.sampleRate))
- } else {
- offset++ //Corrupt file?
- }
- } else if buffer[0] == 0x54 && buffer[1] == 0x41 && buffer[2] == 0x47 { //'TAG'
- offset += 128 //Skip over id3v1 tag size
- } else {
- offset++ //Corrupt file?
- }
- }
- duration = round(duration)
- return
- }
|