I was trying to clone discord and i found out they use ogg formats for audio (i think), im trying to get the audio duration to store in the database.
A stackoverflow solution about getting the OGG audio duration, i found fascinating. The approach involves seeking to the end of the file, finding the last Ogg page header, and reading its granule position.
func getOggDurationMs(reader io.Reader) (int64, error) {
// For simplicity, we read the entire Ogg file into a byte slice
data, err := io.ReadAll(reader)
if err != nil {
return 0, fmt.Errorf("error reading Ogg file: %w", err)
}
// Search for the "OggS" signature and calculate the length
var length int64
for i := len(data) - 14; i >= 0 && length == 0; i-- {
if data[i] == 'O' && data[i+1] == 'g' && data[i+2] == 'g' && data[i+3] == 'S' {
length = int64(readLittleEndianInt(data[i+6 : i+14]))
}
}
// Search for the "vorbis" signature and calculate the rate
var rate int64
for i := 0; i < len(data)-14 && rate == 0; i++ {
if data[i] == 'v' && data[i+1] == 'o' && data[i+2] == 'r' && data[i+3] == 'b' && data[i+4] == 'i' && data[i+5] == 's' {
rate = int64(readLittleEndianInt(data[i+11 : i+15]))
}
}
if length == 0 || rate == 0 {
return 0, fmt.Errorf("could not find necessary information in Ogg file")
}
durationMs := length * 1000 / rate
return durationMs, nil
}
func readLittleEndianInt(data []byte) int64 {
return int64(uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16 | uint32(data[3])<<24)
}
I decided to share it here, i just found the implementation very cool and maybe help some other people out
Top comments (0)