Skip to content

Commit 5e96709

Browse files
committed
Added fingerprinting
1 parent 027b328 commit 5e96709

File tree

9 files changed

+200
-254
lines changed

9 files changed

+200
-254
lines changed

README.md

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ import (
6666
)
6767

6868
func main() {
69-
manager := media.NewManager()
69+
manager, err := media.NewManager()
70+
if err != nil {
71+
log.Fatal(err)
72+
}
7073

7174
// Open a media file for reading. The format of the file is guessed.
7275
// Alteratively, you can pass a format as the second argument. Further optional
@@ -111,7 +114,11 @@ import (
111114
)
112115

113116
func main() {
114-
manager := NewManager()
117+
manager, err := media.NewManager()
118+
if err != nil {
119+
log.Fatal(err)
120+
}
121+
115122
media, err := manager.Open("etc/test/sample.mp4", nil)
116123
if err != nil {
117124
log.Fatal(err)
@@ -159,7 +166,53 @@ TODO
159166

160167
### Retrieving Metadata and Artwork from a media file
161168

162-
TODO
169+
Here is an example of opening a media file and retrieving metadata and artwork.
170+
171+
```go
172+
package main
173+
174+
import (
175+
"log"
176+
"os"
177+
178+
media "github.com/mutablelogic/go-media"
179+
file "github.com/mutablelogic/go-media/pkg/file"
180+
)
181+
182+
func main() {
183+
manager, err := media.NewManager()
184+
if err != nil {
185+
log.Fatal(err)
186+
}
187+
188+
// Open a media file for reading. The format of the file is guessed.
189+
// Alteratively, you can pass a format as the second argument. Further optional
190+
// arguments can be used to set the format options.
191+
reader, err := manager.Open(os.Args[1], nil)
192+
if err != nil {
193+
log.Fatal(err)
194+
}
195+
defer reader.Close()
196+
197+
// Retrieve all the metadata from the file, and display it. If you pass
198+
// keys to the Metadata function, then only entries with those keys will be
199+
// returned.
200+
for _, metadata := range reader.Metadata() {
201+
log.Print(metadata.Key(), " => ", metadata.Value())
202+
}
203+
204+
// Retrieve artwork by using the MetaArtwork key. The value is of type []byte.
205+
// which needs to be converted to an image. There is a utility method to
206+
// detect the image type.
207+
for _, artwork := range reader.Metadata(media.MetaArtwork) {
208+
mimetype, ext, err := file.MimeType(artwork.Value().([]byte))
209+
if err != nil {
210+
log.Fatal(err)
211+
}
212+
log.Print("got artwork", mimetype, ext)
213+
}
214+
}
215+
```
163216

164217
### Audio Fingerprinting
165218

cmd/cli/fingerprint.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io/fs"
7+
"path/filepath"
8+
"time"
9+
10+
// Packages
11+
"github.com/mutablelogic/go-media"
12+
"github.com/mutablelogic/go-media/pkg/chromaprint"
13+
"github.com/mutablelogic/go-media/pkg/file"
14+
)
15+
16+
type FimgerprintCmd struct {
17+
Path string `arg:"" required:"" help:"Media file or path" type:"path"`
18+
}
19+
20+
func (cmd *FimgerprintCmd) Run(globals *Globals) error {
21+
// Create the walker with the processor callback
22+
walker := file.NewWalker(func(ctx context.Context, root, relpath string, info fs.FileInfo) error {
23+
if info.IsDir() || info.Size() == 0 {
24+
return nil
25+
}
26+
if err := cmd.mediaWalker(ctx, globals.manager, filepath.Join(root, relpath)); err != nil {
27+
if err == context.Canceled {
28+
globals.manager.Infof("Cancelled\n")
29+
} else {
30+
globals.manager.Errorf("Error processing %q: %v\n", relpath, err)
31+
}
32+
}
33+
return nil
34+
})
35+
36+
// Walk the filesystem
37+
return walker.Walk(globals.ctx, cmd.Path)
38+
}
39+
40+
func (cmd *FimgerprintCmd) mediaWalker(ctx context.Context, manager media.Manager, path string) error {
41+
reader, err := manager.Open(path, nil)
42+
if err != nil {
43+
return err
44+
}
45+
defer reader.Close()
46+
47+
// Create a decoder for audio - needs to be s16 pcm for chromaprint
48+
decoder, err := reader.Decoder(func(stream media.Stream) (media.Parameters, error) {
49+
if stream.Type().Is(media.AUDIO) {
50+
return manager.AudioParameters("mono", "s16", 22050)
51+
} else {
52+
return nil, nil
53+
}
54+
})
55+
if err != nil {
56+
return err
57+
}
58+
59+
// Create a fingerprinter
60+
fingerprint := chromaprint.New(22050, 1, time.Minute)
61+
defer fingerprint.Close()
62+
63+
// Decode the frames
64+
if err := decoder.Decode(ctx, func(frame media.Frame) error {
65+
_, err := fingerprint.Write(frame.Int16(0))
66+
if err != nil {
67+
return err
68+
}
69+
return nil
70+
}); err != nil {
71+
return err
72+
}
73+
74+
if hash, err := fingerprint.Finish(); err != nil {
75+
return err
76+
} else {
77+
fmt.Println(path, "=>", hash)
78+
}
79+
80+
// Return success
81+
return nil
82+
}

cmd/cli/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ type CLI struct {
3333
PixelFormats PixelFormatsCmd `cmd:"pixelfmts" help:"List video pixel formats"`
3434
Metadata MetadataCmd `cmd:"metadata" help:"Display media metadata information"`
3535
Artwork ArtworkCmd `cmd:"artwork" help:"Save artwork from media file"`
36+
Fingerprint FimgerprintCmd `cmd:"fingerprint" help:"Fingerprint an audio file"`
3637
Probe ProbeCmd `cmd:"probe" help:"Probe media file or device"`
3738
Decode DecodeCmd `cmd:"decode" help:"Decode media"`
3839
Thumbnails ThumbnailsCmd `cmd:"thumbnails" help:"Generate thumbnails from media file"`

cmd/examples/decode/main.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import (
99
)
1010

1111
func main() {
12-
manager := media.NewManager()
12+
manager, err := media.NewManager()
13+
if err != nil {
14+
log.Fatal(err)
15+
}
1316

1417
// Open a media file for reading. The format of the file is guessed.
1518
// Alteratively, you can pass a format as the second argument. Further optional

cmd/examples/demux/main.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import (
99
)
1010

1111
func main() {
12-
manager := media.NewManager()
12+
manager, err := media.NewManager()
13+
if err != nil {
14+
log.Fatal(err)
15+
}
1316

1417
// Open a media file for reading. The format of the file is guessed.
1518
// Alteratively, you can pass a format as the second argument. Further optional

cmd/examples/metadata/main.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"os"
6+
7+
media "github.com/mutablelogic/go-media"
8+
file "github.com/mutablelogic/go-media/pkg/file"
9+
)
10+
11+
func main() {
12+
manager, err := media.NewManager()
13+
if err != nil {
14+
log.Fatal(err)
15+
}
16+
17+
// Open a media file for reading. The format of the file is guessed.
18+
// Alteratively, you can pass a format as the second argument. Further optional
19+
// arguments can be used to set the format options.
20+
reader, err := manager.Open(os.Args[1], nil)
21+
if err != nil {
22+
log.Fatal(err)
23+
}
24+
defer reader.Close()
25+
26+
// Retrieve all the metadata from the file, and display it. If you pass
27+
// keys to the Metadata function, then only entries with those keys will be
28+
// returned.
29+
for _, metadata := range reader.Metadata() {
30+
log.Print(metadata.Key(), " => ", metadata.Value())
31+
}
32+
33+
// Retrieve artwork by using the MetaArtwork key. The value is of type []byte.
34+
// which needs to be converted to an image. There is a utility method to
35+
// detect the image type.
36+
for _, artwork := range reader.Metadata(media.MetaArtwork) {
37+
mimetype, ext, err := file.MimeType(artwork.Value().([]byte))
38+
if err != nil {
39+
log.Fatal(err)
40+
}
41+
log.Print("got artwork", mimetype, ext)
42+
}
43+
44+
}

0 commit comments

Comments
 (0)