-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
139 lines (109 loc) · 3.97 KB
/
main.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package main
import (
"flag"
"fmt"
"log"
"os"
"github.com/janeczku/go-spinner"
ffmpeg "github.com/u2takey/ffmpeg-go"
)
type Input struct {
startTime string
endTime string
videoPath string
outputPath string
defaultPath string
}
func getInputs() *Input {
defaultPath, err := os.Getwd()
errorHandler(err, "Could not get the current directory")
startTime := flag.String("start", "00:00:00", "Start time")
endTime := flag.String("end", "", "End time")
videoPath := flag.String("path", "", "URL / The path to a video file on your local machine.")
outputPath := flag.String("out", defaultPath, "The path for the generated GIF.")
flag.Parse()
if len(*videoPath) < 1 {
log.Fatal("Err: The path to video file is required")
}
if *endTime == "" {
log.Fatal("Err: End time is required")
}
return &Input{
startTime: *startTime,
endTime: *endTime,
videoPath: *videoPath,
outputPath: *outputPath,
defaultPath: defaultPath,
}
}
func cropVideo(videoPath string, startTime string, endTime string) string {
// Get directory to create the cropped video
croppedDir, err := os.Getwd()
errorHandler(err, "Could not read current directory")
croppedVideoOutputPath := fmt.Sprintf("%s/cropped.mp4", croppedDir)
// ffmpeg -ss 00:01:00 -to 00:02:00 -i input.mp4 -c copy output.mp4
stream := ffmpeg.Input(videoPath, ffmpeg.KwArgs{"ss": startTime, "to": endTime})
err = stream.Output(croppedVideoOutputPath, ffmpeg.KwArgs{"c": "copy", "v": "quiet"}).OverWriteOutput().ErrorToStdOut().Silent(true).Run()
errorHandler(err, "Could not crop the video")
return croppedVideoOutputPath
}
func videoToFrames(videoPath string) string {
currentDir, err := os.Getwd()
errorHandler(err, "Could not read current directory")
framesDir := fmt.Sprintf("%s/frames", currentDir)
if _, err := os.Stat(framesDir); os.IsNotExist(err) {
err = os.Mkdir(framesDir, 0755)
errorHandler(err, fmt.Sprintf("Could not create frames directory at %s", framesDir))
}
framesOutputImgPath := fmt.Sprintf("%s/img%%03d.png", framesDir)
stream := ffmpeg.Input(videoPath)
err = stream.Output(framesOutputImgPath, ffmpeg.KwArgs{"vf": "fps=15", "v": "quiet"}).OverWriteOutput().ErrorToStdOut().Silent(true).Run()
errorHandler(err, "Could not convert cropped video to frames")
return framesDir
}
func framesToGIF(framesPath string, outputPath string) string {
framesImgPath := fmt.Sprintf("%s/img%%03d.png", framesPath)
outputFilePath := fmt.Sprintf("%s/output.gif", outputPath)
stream := ffmpeg.Input(framesImgPath, ffmpeg.KwArgs{"f": "image2", "framerate": "15", "loop": "0"})
err := stream.Output(outputFilePath, ffmpeg.KwArgs{"v": "quiet"}).OverWriteOutput().ErrorToStdOut().Silent(true).Run()
errorHandler(err, "Could not create GIF using frames")
return outputFilePath
}
func cleanUp(dir string, filePath string) {
err := os.RemoveAll(dir)
errorHandler(err, fmt.Sprintf("Could not delete %s", dir))
err = os.Remove(filePath)
errorHandler(err, fmt.Sprintf("Could not delete %s", filePath))
}
func main() {
// Get inputs from the command line
inputData := getInputs()
videoPath := inputData.videoPath
s := spinner.NewSpinner("Fetching video from URL...")
if isUrl(inputData.videoPath) {
// Check for youtube
videoId, err := isYoutubeUrl(inputData.videoPath)
if err != nil {
errorHandler(err, "Error fetching resource")
}
s.Start()
if len(videoId) > 1 {
videoPath = fetchYoutubeVideo(videoId, inputData.defaultPath)
} else {
videoPath = fetchVideo(inputData.videoPath, inputData.defaultPath)
}
s.Stop()
fmt.Println("✓ Video fetched")
}
s = spinner.NewSpinner("Cooking up the GIF...")
s.SetCharset([]string{"⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"})
s.Start()
// FFMPEG work
croppedOutput := cropVideo(videoPath, inputData.startTime, inputData.endTime)
framesOutput := videoToFrames(croppedOutput)
gifPath := framesToGIF(framesOutput, inputData.outputPath)
// Cleanup
cleanUp(framesOutput, croppedOutput)
s.Stop()
fmt.Println("✓ Your GIF: ", gifPath)
}