-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathffmpeg.go
143 lines (123 loc) · 3.19 KB
/
ffmpeg.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
140
141
142
143
package radikocast
import (
"context"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
)
type ffmpeg struct {
*exec.Cmd
}
func newFfmpeg(ctx context.Context) (*ffmpeg, error) {
cmdPath, err := exec.LookPath("ffmpeg")
if err != nil {
return nil, err
}
return &ffmpeg{exec.CommandContext(
ctx,
cmdPath,
)}, nil
}
func (f *ffmpeg) setDir(dir string) {
f.Dir = dir
}
func (f *ffmpeg) setArgs(args ...string) {
f.Args = append(f.Args, args...)
}
func (f *ffmpeg) setInput(input string) {
f.setArgs("-i", input)
}
func (f *ffmpeg) run(output string) error {
f.setArgs(output)
return f.Run()
}
func (f *ffmpeg) start(output string) error {
f.setArgs(output)
return f.Start()
}
func (f *ffmpeg) wait() error {
return f.Wait()
}
func (f *ffmpeg) stdinPipe() (io.WriteCloser, error) {
return f.StdinPipe()
}
func (f *ffmpeg) stderrPipe() (io.ReadCloser, error) {
return f.StderrPipe()
}
// ConcatAACFilesFromList concatenates files from the list of resources.
func ConcatAACFilesFromList(ctx context.Context, resourcesDir string) (string, error) {
files, err := ioutil.ReadDir(resourcesDir)
if err != nil {
return "", err
}
allFilePaths := []string{}
for _, f := range files {
p := filepath.Join(resourcesDir, f.Name())
allFilePaths = append(allFilePaths, p)
}
concatedFile := filepath.Join(resourcesDir, "concated.aac")
if err := ConcatAACFilesAll(ctx, allFilePaths, resourcesDir, concatedFile); err != nil {
return "", err
}
return concatedFile, nil
}
// ConcatAACFiles concatenate files of the same type.
func ConcatAACFilesAll(ctx context.Context, files []string, resourcesDir string, output string) error {
// input is a path to a file which lists all the aac files.
// it may include a lot of aac file and exceed max number of file descriptor.
oneConcatNum := 100
if len(files) > oneConcatNum {
reducedFiles := files[:oneConcatNum]
restFiles := files[oneConcatNum:]
// reducedFiles -> reducedFiles[0]
tmpOutputFile, err := ioutil.TempFile(resourcesDir, "tmp-concatenated-*.aac")
if err != nil {
fmt.Println("Failed to call ioutil.TempFile")
return err
}
err = ConcatAACFiles(ctx, reducedFiles, resourcesDir, tmpOutputFile.Name())
if err != nil {
fmt.Println("Failed to ConcatAACFiles")
return err
}
err = ConcatAACFilesAll(ctx, append([]string{tmpOutputFile.Name()}, restFiles...), resourcesDir, output)
defer os.Remove(tmpOutputFile.Name())
return err
} else {
return ConcatAACFiles(ctx, files, resourcesDir, output)
}
}
func ConcatAACFiles(ctx context.Context, input []string, resourcesDir string, output string) error {
listFile, err0 := ioutil.TempFile(resourcesDir, "aac_resources")
if err0 != nil {
return err0
}
defer os.Remove(listFile.Name())
for _, f := range input {
p := fmt.Sprintf("file '%s'\n", f)
if _, err := listFile.WriteString(p); err != nil {
return err
}
}
f, err := newFfmpeg(ctx)
if err != nil {
return err
}
f.setArgs(
"-f", "concat",
"-safe", "0",
"-y",
)
f.setInput(listFile.Name())
f.setArgs("-c", "copy")
// TODO: Collect log
err = f.run(output)
// Remove the intermediate files right after they are concatenated into one file
for _, f := range input {
defer os.Remove(f)
}
return err
}