-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathExportingMediaHandler.go
144 lines (116 loc) · 4.04 KB
/
ExportingMediaHandler.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
144
package main
import (
"fmt"
"image"
"image/png"
"io"
"os"
"github.com/inkyblackness/res/audio/mem"
"github.com/inkyblackness/res/movi"
"github.com/inkyblackness/chunkie/convert/wav"
)
var subtitleLanguages = map[movi.SubtitleControl]string{
movi.SubtitleTextStd: "en",
movi.SubtitleTextFrn: "fr",
movi.SubtitleTextGer: "de"}
type subtitleEntry struct {
file io.WriteCloser
counter int
timestamp float32
text string
}
type exportingMediaHandler struct {
mediaDuration float32
fileBaseName string
sampleRate float32
audio []byte
subtitles map[movi.SubtitleControl]*subtitleEntry
frameCounter int
lastFrameTimestamp float32
lastFrame *image.Paletted
framesPerSecond float32
}
func newExportingMediaHandler(fileBaseName string, mediaDuration float32, framesPerSecond float32, sampleRate float32) *exportingMediaHandler {
return &exportingMediaHandler{
mediaDuration: mediaDuration,
fileBaseName: fileBaseName,
subtitles: make(map[movi.SubtitleControl]*subtitleEntry),
framesPerSecond: framesPerSecond,
sampleRate: sampleRate}
}
func (handler *exportingMediaHandler) finish() {
handler.writeLastFramesUntil(handler.mediaDuration)
for _, entry := range handler.subtitles {
handler.finishSubtitle(entry, handler.mediaDuration)
_ = entry.file.Close()
}
if len(handler.audio) > 0 {
soundData := mem.NewL8SoundData(handler.sampleRate, handler.audio)
wav.ExportToWav(handler.fileBaseName+".wav", soundData)
}
}
func (handler *exportingMediaHandler) OnAudio(timestamp float32, samples []byte) {
handler.audio = append(handler.audio, samples...)
}
func (handler *exportingMediaHandler) OnSubtitle(timestamp float32, control movi.SubtitleControl, text string) {
if control != movi.SubtitleArea {
entry := handler.subtitles[control]
if entry == nil {
file, _ := os.Create(handler.fileBaseName + "_" + subtitleLanguages[control] + ".srt")
entry = &subtitleEntry{file: file}
handler.subtitles[control] = entry
}
handler.finishSubtitle(entry, timestamp)
entry.timestamp = timestamp
entry.text = text
entry.counter++
}
}
func (handler *exportingMediaHandler) OnVideo(timestamp float32, frame *image.Paletted) {
handler.writeLastFramesUntil(timestamp)
handler.lastFrameTimestamp = timestamp
handler.lastFrame = image.NewPaletted(frame.Bounds(), frame.Palette)
copy(handler.lastFrame.Pix, frame.Pix)
}
func (handler *exportingMediaHandler) finishSubtitle(entry *subtitleEntry, endTime float32) {
if entry.counter > 0 {
fmt.Fprintf(entry.file, "%d\n", entry.counter)
fmt.Fprintf(entry.file, "%s --> %s\n", handler.formatTimestamp(entry.timestamp), handler.formatTimestamp(endTime))
fmt.Fprintf(entry.file, "%s\n", entry.text)
fmt.Fprint(entry.file, "\n")
}
}
func (handler *exportingMediaHandler) formatTimestamp(timestamp float32) string {
inMillis := uint64(timestamp * 1000)
inSeconds := inMillis / 1000
inMinutes := inSeconds / 60
inHours := inMinutes / 60
return fmt.Sprintf("%02d:%02d:%02d,%03d", inHours, inMinutes%60, inSeconds%60, inMillis%1000)
}
func (handler *exportingMediaHandler) writeLastFramesUntil(timestamp float32) {
if handler.lastFrame != nil {
if handler.framesPerSecond > 0 {
limitFrameID := int((timestamp * handler.framesPerSecond) + 0.5)
lastFrameID := int((handler.lastFrameTimestamp * handler.framesPerSecond) + 0.5)
for lastFrameID < limitFrameID {
name := fmt.Sprintf("%s_%04d.png", handler.fileBaseName, handler.frameCounter)
handler.frameCounter++
handler.writeFrame(handler.lastFrame, name)
lastFrameID++
}
} else {
name := handler.timedFileName(handler.lastFrameTimestamp)
handler.writeFrame(handler.lastFrame, name)
}
}
}
func (handler *exportingMediaHandler) writeFrame(frame *image.Paletted, name string) {
file, _ := os.Create(name)
png.Encode(file, frame)
file.Close()
}
func (handler *exportingMediaHandler) timedFileName(timestamp float32) string {
inMillis := uint64(timestamp * 1000)
inSeconds := inMillis / 1000
return fmt.Sprintf("%s_%03d.%03d.png", handler.fileBaseName, inSeconds, inMillis%1000)
}