forked from bakape/thumbnailer
-
Notifications
You must be signed in to change notification settings - Fork 2
/
thumbnailer.go
114 lines (106 loc) · 2.07 KB
/
thumbnailer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package thumbnailer
// #include "thumbnailer.h"
// #include <libavutil/log.h>
import "C"
import (
"image"
"io"
"unsafe"
)
func init() {
C.av_log_set_level(C.AV_LOG_ERROR)
}
// Thumbnail generates a thumbnail from a representative frame of the media.
// Images count as one frame media.
func (c *FFContext) Thumbnail(dims Dims) (thumb image.Image, err error) {
ci, err := c.codecContext(FFVideo)
if err != nil {
return
}
var img C.struct_Buffer
defer func() {
if img.data != nil {
C.free(unsafe.Pointer(img.data))
}
}()
ret := C.generate_thumbnail(&img, c.avFormatCtx, ci.ctx, ci.stream,
C.struct_Dims{
width: C.uint64_t(dims.Width),
height: C.uint64_t(dims.Height),
})
switch {
case ret != 0:
err = castError(ret)
case img.data == nil:
err = ErrGetFrame
default:
thumb = &image.RGBA{
Pix: copyCBuffer(img),
Stride: 4 * int(img.width),
Rect: image.Rectangle{
Max: image.Point{
X: int(img.width),
Y: int(img.height),
},
},
}
}
return
}
func processMedia(rs io.ReadSeeker, src *Source, opts Options,
) (
thumb image.Image, err error,
) {
c, err := newFFContextWithFormat(rs, inputFormats[src.Mime])
if err != nil {
return
}
defer c.Close()
src.Length = c.Length()
src.Meta = c.Meta()
src.HasAudio, err = c.HasStream(FFAudio)
if err != nil {
return
}
src.HasVideo, err = c.HasStream(FFVideo)
if err != nil {
return
}
if src.HasVideo {
src.Dims, err = c.Dims()
if err != nil {
return
}
}
if c.HasCoverArt() {
thumb, err = processCoverArt(c.CoverArt(), opts)
switch err {
case nil:
return
case ErrCantThumbnail:
// Try again on the container itself, if cover art thumbnailing
// fails
default:
return
}
}
if src.HasVideo {
max := opts.MaxSourceDims
if max.Width != 0 && src.Width > max.Width {
err = ErrTooWide
return
}
if max.Height != 0 && src.Height > max.Height {
err = ErrTooTall
return
}
src.Codec, err = c.CodecName(FFVideo)
if err != nil {
return
}
thumb, err = c.Thumbnail(opts.ThumbDims)
} else {
err = ErrCantThumbnail
}
return
}