Compare commits
2 commits
84faf19303
...
2f8ffb318f
Author | SHA1 | Date | |
---|---|---|---|
DataHoarder | 2f8ffb318f | ||
DataHoarder | a7ca061d6c |
141
cmd/decode/decode.go
Normal file
141
cmd/decode/decode.go
Normal file
|
@ -0,0 +1,141 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"git.gammaspectra.live/S.O.N.G/Kirika/audio"
|
||||
"git.gammaspectra.live/S.O.N.G/Kirika/audio/format"
|
||||
"git.gammaspectra.live/S.O.N.G/Kirika/audio/format/guess"
|
||||
"git.gammaspectra.live/S.O.N.G/Kirika/hasher"
|
||||
"hash"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
inputFile := flag.String("input", "", "Input file to decode")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
fp, err := os.Open(*inputFile)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
return
|
||||
}
|
||||
defer fp.Close()
|
||||
log.Printf("File: %s\n", *inputFile)
|
||||
|
||||
decoders, err := guess.GetDecoders(fp, *inputFile)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Print("Available decoders:\n")
|
||||
for _, d := range decoders {
|
||||
if ad, ok := d.(format.AnalyzerDecoder); ok {
|
||||
log.Printf("\t%s: %s (analyzer)", ad.Name(), ad.DecoderDescription())
|
||||
} else {
|
||||
log.Printf("\t%s: %s", d.Name(), d.DecoderDescription())
|
||||
}
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
|
||||
source, analyzer, err := guess.OpenAnalyzer(fp, decoders)
|
||||
if err != nil {
|
||||
source, err = guess.Open(fp, decoders)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
return
|
||||
}
|
||||
|
||||
var h *hasher.Hasher
|
||||
|
||||
if analyzer != nil {
|
||||
h = hasher.NewHasher(analyzer, hasher.HashtypeMd5)
|
||||
}
|
||||
|
||||
var rawFloat32Hasher hash.Hash
|
||||
|
||||
var sampleCount, blockCount uint64
|
||||
if f32Source, ok := source.(audio.TypedSource[float32]); ok {
|
||||
rawFloat32Hasher = md5.New()
|
||||
log.Printf("Decoding as float32 @ %dHz %d channel(s)", f32Source.GetSampleRate(), f32Source.GetChannels())
|
||||
for b := range f32Source.GetBlocks() {
|
||||
blockCount++
|
||||
sampleCount += uint64(len(b))
|
||||
|
||||
func() {
|
||||
defer runtime.KeepAlive(b)
|
||||
rawFloat32Hasher.Write(unsafe.Slice((*byte)(unsafe.Pointer(&b[0])), len(b)*int(unsafe.Sizeof(float32(0)))))
|
||||
}()
|
||||
}
|
||||
sampleCount /= uint64(f32Source.GetChannels())
|
||||
} else if i16Source, ok := source.(audio.TypedSource[int16]); ok {
|
||||
log.Printf("Decoding as int16 %d-bit @ %dHz %d channel(s)", i16Source.GetBitDepth(), i16Source.GetSampleRate(), i16Source.GetChannels())
|
||||
for b := range i16Source.GetBlocks() {
|
||||
blockCount++
|
||||
sampleCount += uint64(len(b))
|
||||
}
|
||||
sampleCount /= uint64(i16Source.GetChannels())
|
||||
} else if i32Source, ok := source.(audio.TypedSource[int32]); ok {
|
||||
log.Printf("Decoding as int32 %d-bit @ %dHz %d channel(s)", i32Source.GetBitDepth(), i32Source.GetSampleRate(), i32Source.GetChannels())
|
||||
for b := range i32Source.GetBlocks() {
|
||||
blockCount++
|
||||
sampleCount += uint64(len(b))
|
||||
}
|
||||
sampleCount /= uint64(i32Source.GetChannels())
|
||||
} else {
|
||||
rawFloat32Hasher = md5.New()
|
||||
f32Source = source.ToFloat32()
|
||||
log.Printf("Decoding as float32 (generic) %d-bit @ %dHz %d channel(s)", f32Source.GetBitDepth(), f32Source.GetSampleRate(), f32Source.GetChannels())
|
||||
for b := range f32Source.GetBlocks() {
|
||||
blockCount++
|
||||
sampleCount += uint64(len(b))
|
||||
|
||||
func() {
|
||||
defer runtime.KeepAlive(b)
|
||||
rawFloat32Hasher.Write(unsafe.Slice((*byte)(unsafe.Pointer(&b[0])), len(b)*int(unsafe.Sizeof(float32(0)))))
|
||||
}()
|
||||
}
|
||||
sampleCount /= uint64(f32Source.GetChannels())
|
||||
}
|
||||
|
||||
log.Printf("Decoded %d sample(s)", sampleCount)
|
||||
if blockCount > 0 {
|
||||
log.Printf("Processed %d blocks(s) (avg %0.2f sample(s) per block)", blockCount, float64(sampleCount)/float64(blockCount))
|
||||
}
|
||||
log.Printf("Duration %s", ((time.Duration(sampleCount) * time.Second) / time.Duration(source.GetSampleRate())).String())
|
||||
|
||||
if h != nil {
|
||||
h.Wait()
|
||||
log.Printf("MD5 hash: %s", hex.EncodeToString(h.GetResult()))
|
||||
if _, ok := source.(audio.TypedSource[float32]); ok {
|
||||
log.Printf("\tCheck via $ ffmpeg -hide_banner -loglevel error -i %s -vn -c:a pcm_f32le -f md5 -", strconv.Quote(*inputFile))
|
||||
} else {
|
||||
switch source.GetBitDepth() {
|
||||
case 8, 16, 24, 32:
|
||||
log.Printf("\tCheck via $ ffmpeg -hide_banner -loglevel error -i %s -vn -c:a pcm_s%dle -f md5 -", strconv.Quote(*inputFile), source.GetBitDepth())
|
||||
default:
|
||||
log.Printf("\tCheck via $ ffmpeg -hide_banner -loglevel error -i %s -vn -c:a pcm_s32le -f md5 -", strconv.Quote(*inputFile))
|
||||
}
|
||||
}
|
||||
} else if rawFloat32Hasher != nil {
|
||||
log.Printf("MD5 hash: %s", hex.EncodeToString(rawFloat32Hasher.Sum(nil)))
|
||||
if _, ok := source.(audio.TypedSource[float32]); ok {
|
||||
log.Printf("\tCheck via $ ffmpeg -hide_banner -loglevel error -i %s -vn -c:a pcm_f32le -f md5 -", strconv.Quote(*inputFile))
|
||||
log.Printf("\tNote that you might need to specify a decoder with -c:a before -i to perfectly match the hash on lossy decoders, for example, libopus instead of opus")
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("Took %s", time.Now().Sub(startTime).String())
|
||||
|
||||
}
|
2
go.mod
2
go.mod
|
@ -12,7 +12,7 @@ require (
|
|||
git.gammaspectra.live/S.O.N.G/go-tta v0.0.0-20220226150007-096de1072bd6
|
||||
git.gammaspectra.live/S.O.N.G/go-vorbis v0.0.0-20220728124510-303b3425eec0
|
||||
git.gammaspectra.live/S.O.N.G/goflac v0.0.0-20220515172202-6e490998d2a0
|
||||
git.gammaspectra.live/S.O.N.G/minimp3 v0.0.0-20221201085504-9103da68c320
|
||||
git.gammaspectra.live/S.O.N.G/minimp3 v0.0.0-20230128141646-872fc9482587
|
||||
git.gammaspectra.live/S.O.N.G/voaac-go v0.0.0-20221206094054-e088a49a96bc
|
||||
github.com/Eyevinn/mp4ff v0.33.2
|
||||
github.com/dh1tw/gosamplerate v0.1.2
|
||||
|
|
4
go.sum
4
go.sum
|
@ -16,8 +16,8 @@ git.gammaspectra.live/S.O.N.G/go-vorbis v0.0.0-20220728124510-303b3425eec0 h1:kZ
|
|||
git.gammaspectra.live/S.O.N.G/go-vorbis v0.0.0-20220728124510-303b3425eec0/go.mod h1:EZl7z0vfpaiu0ykpEkk6dh59XxBgWxAh4QPCCnkhICE=
|
||||
git.gammaspectra.live/S.O.N.G/goflac v0.0.0-20220515172202-6e490998d2a0 h1:imcnwHUqaAJzws41B8sCSp/sUmVranNjAX205Jr4Jc0=
|
||||
git.gammaspectra.live/S.O.N.G/goflac v0.0.0-20220515172202-6e490998d2a0/go.mod h1:/po1QgOh3xynbvi4sxdY6Iw8m5WPJfGGmry2boZD8fs=
|
||||
git.gammaspectra.live/S.O.N.G/minimp3 v0.0.0-20221201085504-9103da68c320 h1:rsu7pz3LvRFFMtruaYBUBhE/8ZCJU2Kx30xPUuQMIF0=
|
||||
git.gammaspectra.live/S.O.N.G/minimp3 v0.0.0-20221201085504-9103da68c320/go.mod h1:B34pwapfc0f6be6rJYg37xDeFPPB0bSyH0+DYM1lyEE=
|
||||
git.gammaspectra.live/S.O.N.G/minimp3 v0.0.0-20230128141646-872fc9482587 h1:yCfo8C7ANblOn5FEZLpkJZDl0v8OL/jOh3lIIe+v1fo=
|
||||
git.gammaspectra.live/S.O.N.G/minimp3 v0.0.0-20230128141646-872fc9482587/go.mod h1:B34pwapfc0f6be6rJYg37xDeFPPB0bSyH0+DYM1lyEE=
|
||||
git.gammaspectra.live/S.O.N.G/voaac-go v0.0.0-20221206094054-e088a49a96bc h1:57tqeyhK5ypviBHumVxdhiphsAX3nJXli6Ni/1+6Jn4=
|
||||
git.gammaspectra.live/S.O.N.G/voaac-go v0.0.0-20221206094054-e088a49a96bc/go.mod h1:y8tX6ZPpGKVO2uso29/q5XW4r8/lTc5QRjPOwDRVMNk=
|
||||
github.com/Eyevinn/mp4ff v0.33.2 h1:6b4OCWyBQim+VrL3bNYkqxumnqGdJEGnls2JBMWvKLs=
|
||||
|
|
Loading…
Reference in a new issue