-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscanner.rb
More file actions
executable file
·152 lines (137 loc) · 4.88 KB
/
scanner.rb
File metadata and controls
executable file
·152 lines (137 loc) · 4.88 KB
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
145
146
147
148
149
150
151
#!/usr/bin/env ruby
class Callback
def initialize()
end
def callback(input_file, frames)
end
def needs_processing(input_file)
end
end
class DirectoryCallback
def initialize()
end
def callback(input_folder)
end
def needs_processing(input_file)
end
end
class Scanner
def initialize(directory, input_extension, callback_list, directory_callback_list)
@directory = File.expand_path(directory)
@input_extension = input_extension
@callback_list = Array.new
@callback_list.push(callback_list)
@callback_list.flatten!
@directory_callback_list = Array.new
@directory_callback_list.push(directory_callback_list)
@directory_callback_list.flatten!
throw "ffmpeg is required" if !is_ffmpeg_present()
end
def is_ffmpeg_present()
result = `which ffmpeg`
return false if nil == result || result.empty?
return true
end
private :is_ffmpeg_present
def timecode_string(seconds)
hours = (seconds / (60 * 60)).to_i
seconds = seconds % (60 * 60)
minutes = (seconds / 60).to_i
seconds = seconds % 60
return sprintf("%02u:%02u:%02u.000", hours, minutes, seconds)
end
private :timecode_string
def extract_frames(video_filename, extract_period, tmp_location)
seconds = 0
counter = 0
print("Extracting frames from #{video_filename}\n")
while true
timecode = timecode_string(seconds)
filename = sprintf("%s/img%05d.jpg", tmp_location, counter)
cmd = "ffmpeg -loglevel 16 -ss #{timecode} -i \"#{video_filename}\" -frames:v 1 \"#{filename}\""
print("#{timecode}\r")
rc = Kernel.system(cmd)
break if (true != rc)
break if (!File.exists?(filename))
seconds += extract_period
counter += 1
end
end
private :extract_frames
def load_frames(folder, frames)
Dir.new(folder).each { |filename|
if (0 == filename.index('img') && filename.end_with?('.jpg'))
frames << File.expand_path(folder + '/' + filename);
end
}
end
private :load_frames
def scan()
# First process all files recursively.
scan_dir_for_files(@directory)
# After all of the artifacts have been generated, scan all folders recursively.
scan_dir_for_folders(@directory)
end
def scan_dir_for_files(directory_name)
Dir.open(directory_name) { |dir|
file_list = []
dir.each { |item|
next if item.empty? || '.' == item[0]
full_path = File.expand_path(directory_name + "/" + item)
if File.directory?(full_path)
scan_dir_for_files(full_path)
next
end
next if !full_path.end_with?(@input_extension)
any_need_processing = false
@callback_list.each { |obj|
any_need_processing = any_need_processing | obj.needs_processing(full_path)
}
if any_need_processing
file_list << full_path
end
}
if !file_list.empty?
file_list.sort!
file_list.each { |full_path|
temp_folder = "/tmp/tagger/"
`rm -rf #{temp_folder}`
Dir.mkdir(temp_folder)
frames = Array.new
extract_frames(full_path, 1, temp_folder)
load_frames(temp_folder, frames)
@callback_list.each { |obj|
obj.callback(full_path, frames)
}
}
end
}
end
private :scan_dir_for_files
def scan_dir_for_folders(directory_name)
directory_name = File.expand_path(directory_name)
Dir.open(directory_name) { |dir|
dir.each { |item|
next if item.empty? || '.' == item[0]
full_path = File.expand_path(directory_name + "/" + item)
if File.directory?(full_path)
# Depth-first scan.
scan_dir_for_folders(full_path)
# Check if we need to do the thing.
@directory_callback_list.each { |obj|
if obj.needs_processing(full_path)
obj.callback(full_path)
end
}
end
}
}
# Finally, process the outtermost folder
@directory_callback_list.each { |obj|
if obj.needs_processing(directory_name)
obj.callback(directory_name)
end
}
end
private :scan_dir_for_folders
end