Now splittable into segments with variable intervals, and more Cli options
This commit is contained in:
@@ -3,6 +3,8 @@ package main
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
thumbnailgen "github.com/pablu23/thumbnail-gen"
|
thumbnailgen "github.com/pablu23/thumbnail-gen"
|
||||||
)
|
)
|
||||||
@@ -11,37 +13,27 @@ var (
|
|||||||
pathFlag = flag.String("path", "", "path to video")
|
pathFlag = flag.String("path", "", "path to video")
|
||||||
intervalFlag = flag.Int("interval", 20, "Interval in seconds between thumbnails")
|
intervalFlag = flag.Int("interval", 20, "Interval in seconds between thumbnails")
|
||||||
maxThumbnailsFlag = flag.Int("max", 0, "Max Thumbnails, default as much as possible with interval")
|
maxThumbnailsFlag = flag.Int("max", 0, "Max Thumbnails, default as much as possible with interval")
|
||||||
|
blackFilterFlag = flag.Bool("filter", true, "Try to filter out black frames, might be an expensive operation")
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if *pathFlag != "" {
|
if *pathFlag != "" {
|
||||||
_, err := thumbnailgen.GetFramerate(*pathFlag)
|
// thumbnails, num, err := thumbnailgen.GetThumbnail(*pathFlag, *intervalFlag, *maxThumbnailsFlag, *blackFilterFlag)
|
||||||
|
thumbnails, num, err := thumbnailgen.GetThumbnailSegments(*pathFlag, 12, *blackFilterFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Framerate: %s\n", err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = thumbnailgen.GetVideoLength(*pathFlag)
|
fmt.Printf("Extracted %d thumbnails\n", num)
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Video Length: %s\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = thumbnailgen.GetFilter(*pathFlag)
|
name := filepath.Base(*pathFlag)
|
||||||
if err != nil {
|
for i, thumbnail := range thumbnails[:num] {
|
||||||
fmt.Printf("Filter: %s\n", err)
|
err := os.WriteFile(fmt.Sprintf("%s-%d.png", name, i), thumbnail, 0600)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// thumbnails, err := thumbnailgen.GetThumbnail(*pathFlag, *intervalFlag, *maxThumbnailsFlag)
|
|
||||||
// if err != nil {
|
|
||||||
// panic(err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// name := filepath.Base(*pathFlag)
|
|
||||||
// for i, thumbnail := range thumbnails {
|
|
||||||
// err := os.WriteFile(fmt.Sprintf("%s-%d.png", name, i), thumbnail, 0600)
|
|
||||||
// if err != nil {
|
|
||||||
// panic(err)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
53
generator.go
53
generator.go
@@ -16,6 +16,26 @@ type TimeFilter struct {
|
|||||||
End float64
|
End float64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetThumbnailSegments(path string, segments int, enableFilter bool) ([][]byte, int, error) {
|
||||||
|
var filters []TimeFilter
|
||||||
|
if enableFilter {
|
||||||
|
f, err := GetFilter(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
filters = f
|
||||||
|
}
|
||||||
|
|
||||||
|
length, err := GetVideoLength(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
interval := length / float64(segments)
|
||||||
|
|
||||||
|
return getThumbnailUnderlying(path, 0, filters, length, int(interval), enableFilter)
|
||||||
|
}
|
||||||
|
|
||||||
func GetThumbnail(path string, intervalSeconds int, maxThumbnails int, enableFilter bool) ([][]byte, int, error) {
|
func GetThumbnail(path string, intervalSeconds int, maxThumbnails int, enableFilter bool) ([][]byte, int, error) {
|
||||||
var filters []TimeFilter
|
var filters []TimeFilter
|
||||||
if enableFilter {
|
if enableFilter {
|
||||||
@@ -26,18 +46,16 @@ func GetThumbnail(path string, intervalSeconds int, maxThumbnails int, enableFil
|
|||||||
filters = f
|
filters = f
|
||||||
}
|
}
|
||||||
|
|
||||||
fps, err := GetFramerate(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
length, err := GetVideoLength(path)
|
length, err := GetVideoLength(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return getThumbnailUnderlying(path, maxThumbnails, filters, length, intervalSeconds, enableFilter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getThumbnailUnderlying(path string, maxThumbnails int, filters []TimeFilter, length float64, intervalSeconds int, enableFilter bool) ([][]byte, int, error) {
|
||||||
buf := bytes.NewBuffer(nil)
|
buf := bytes.NewBuffer(nil)
|
||||||
currFrame := 0
|
|
||||||
framesExtracted := 0
|
framesExtracted := 0
|
||||||
|
|
||||||
var out [][]byte
|
var out [][]byte
|
||||||
@@ -47,15 +65,21 @@ func GetThumbnail(path string, intervalSeconds int, maxThumbnails int, enableFil
|
|||||||
out = make([][]byte, 0)
|
out = make([][]byte, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fmt.Printf("FPS: %f, Lenght: %f, Interval: %d, Filters: %t\n", fps, length, intervalSeconds, enableFilter)
|
||||||
|
|
||||||
|
var time float64 = 1
|
||||||
for {
|
for {
|
||||||
time := float64(currFrame) / fps
|
fmt.Printf("Time: %f\n", time)
|
||||||
if (maxThumbnails > 0 && framesExtracted >= maxThumbnails) || time >= length {
|
if (maxThumbnails > 0 && framesExtracted >= maxThumbnails) || time >= length {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
currFrame += int(fps) * intervalSeconds
|
if enableFilter {
|
||||||
if enableFilter && FrameLiesWithinFilter(time, filters) {
|
if ok, next := FrameLiesWithinFilter(time, filters); ok {
|
||||||
continue
|
fmt.Printf("Black Frame, skipping to: %f\n", next)
|
||||||
|
time = next
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := GetImage(buf, path, int(time), "png")
|
err := GetImage(buf, path, int(time), "png")
|
||||||
@@ -71,20 +95,23 @@ func GetThumbnail(path string, intervalSeconds int, maxThumbnails int, enableFil
|
|||||||
out = append(out, b)
|
out = append(out, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time += float64(intervalSeconds)
|
||||||
framesExtracted += 1
|
framesExtracted += 1
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
}
|
}
|
||||||
return out, framesExtracted, nil
|
return out, framesExtracted, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func FrameLiesWithinFilter(time float64, filters []TimeFilter) bool {
|
// Return true, if time is inside filter, also returns next time, when not in filter anymore.
|
||||||
|
// If False it returns input time
|
||||||
|
func FrameLiesWithinFilter(time float64, filters []TimeFilter) (bool, float64) {
|
||||||
for _, filter := range filters {
|
for _, filter := range filters {
|
||||||
if time >= filter.Start && time <= filter.End {
|
if time >= filter.Start && time <= filter.End {
|
||||||
return true
|
return true, filter.End
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return false
|
return false, time
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetImage(buf *bytes.Buffer, path string, timestamp int, format string) error {
|
func GetImage(buf *bytes.Buffer, path string, timestamp int, format string) error {
|
||||||
|
|||||||
Reference in New Issue
Block a user