Skip to content

Commit 8254930

Browse files
committed
Move to integer based thumbnail state list, fix indices
Also, adjust progress block rendering to display the proper size, so that the last block will be partial. This way thumbnail ranges are displayed more accurately, useful for development.
1 parent 90b1b69 commit 8254930

File tree

3 files changed

+65
-24
lines changed

3 files changed

+65
-24
lines changed

src/patched_osc.lua

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,16 +163,17 @@ function display_thumbnail(pos, value, ass)
163163
ass:append(("%d%% - %d/%d"):format(perc, thumbs_ready, thumbs_total))
164164

165165
-- Draw the generation progress
166-
local block_w = (thumb_size.w / thumbs_total) * msy
166+
local block_w = thumb_size.w * (Thumbnailer.state.thumbnail_delta / duration) * msy
167+
local block_max_x = thumb_size.w * msy
167168

168169
-- Draw finished thumbnail blocks (white)
169170
ass:new_event()
170171
ass:pos(bg_left, framegraph_top)
171172
ass:append(("{\\bord0\\1c&HFFFFFF&\\1a&H%X&"):format(0))
172173
ass:draw_start(2)
173174
for i, v in pairs(Thumbnailer.state.thumbnails) do
174-
if i ~= closest_index and v then
175-
ass:rect_cw(i*block_w, 0, (i+1)*block_w, framegraph_h)
175+
if i ~= closest_index and v > 0 then
176+
ass:rect_cw((i-1)*block_w, 0, math.min(block_max_x, i*block_w), framegraph_h)
176177
end
177178
end
178179
ass:draw_stop()
@@ -183,8 +184,8 @@ function display_thumbnail(pos, value, ass)
183184
ass:append(("{\\bord0\\1c&H44AA44&\\1a&H%X&"):format(0))
184185
ass:draw_start(2)
185186
for i, v in pairs(Thumbnailer.state.thumbnails) do
186-
if i ~= closest_index and v == false then
187-
ass:rect_cw(i*block_w, 0, (i+1)*block_w, framegraph_h)
187+
if i ~= closest_index and v == 0 then
188+
ass:rect_cw((i-1)*block_w, 0, math.min(block_max_x, i*block_w), framegraph_h)
188189
end
189190
end
190191
ass:draw_stop()
@@ -194,7 +195,7 @@ function display_thumbnail(pos, value, ass)
194195
ass:pos(bg_left, framegraph_top)
195196
ass:append(("{\\bord0\\1c&H4444FF&\\1a&H%X&"):format(0))
196197
ass:draw_start(2)
197-
ass:rect_cw(closest_index*block_w, 0, (closest_index+1)*block_w, framegraph_h)
198+
ass:rect_cw((closest_index-1)*block_w, 0, math.min(block_max_x, closest_index*block_w), framegraph_h)
198199
ass:draw_stop()
199200
end
200201
end

src/thumbnailer_server.lua

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,10 @@ function do_worker_job(state_json_string, frames_json_string)
175175
end
176176

177177
local generate_thumbnail_for_index = function(thumbnail_index)
178-
local thumbnail_path = thumb_state.thumbnail_template:format(thumbnail_index)
179-
local timestamp = math.min(file_duration, thumbnail_index * thumb_state.thumbnail_delta)
178+
-- Given a 1-based thumbnail index, generate a thumbnail for it based on the thumbnailer state
179+
180+
local thumbnail_path = thumb_state.thumbnail_template:format(thumbnail_index - 1)
181+
local timestamp = math.min(file_duration, (thumbnail_index - 1) * thumb_state.thumbnail_delta)
180182

181183
mp.commandv("script-message", "mpv_thumbnail_script-progress", tostring(thumbnail_index))
182184

@@ -193,7 +195,7 @@ function do_worker_job(state_json_string, frames_json_string)
193195
local existing_thumbnail_filesize = thumbnail_file:seek("end")
194196
if existing_thumbnail_filesize ~= thumbnail_raw_size then
195197
-- Size doesn't match, so (re)generate
196-
msg.warn("Thumbnail", thumbnail_index, "did not match expected size, regenerating")
198+
msg.warn("Thumbnail", thumbnail_index-1, "did not match expected size, regenerating")
197199
need_thumbnail_generation = true
198200
end
199201
thumbnail_file:close()

src/thumbnailer_shared.lua

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ local Thumbnailer = {
1414
thumbnail_size = nil,
1515

1616
finished_thumbnails = 0,
17+
18+
-- List of thumbnail states (from 1 to thumbnail_count)
19+
-- ready: 1
20+
-- in progress: 0
21+
-- not ready: -1
1722
thumbnails = {}
1823
},
1924
workers = {}
@@ -33,17 +38,19 @@ function Thumbnailer:on_file_loaded()
3338
end
3439

3540
function Thumbnailer:on_thumb_ready(index)
36-
self.state.thumbnails[index] = true
41+
self.state.thumbnails[index] = 1
3742

38-
-- Recount (just in case)
43+
-- Full recount instead of a naive increment (let's be safe!)
3944
self.state.finished_thumbnails = 0
40-
for i in pairs(self.state.thumbnails) do
41-
self.state.finished_thumbnails = self.state.finished_thumbnails + 1
45+
for i, v in pairs(self.state.thumbnails) do
46+
if v > 0 then
47+
self.state.finished_thumbnails = self.state.finished_thumbnails + 1
48+
end
4249
end
4350
end
4451

4552
function Thumbnailer:on_thumb_progress(index)
46-
self.state.thumbnails[index] = self.state.thumbnails[index] or false
53+
self.state.thumbnails[index] = math.max(self.state.thumbnails[index], 0)
4754
end
4855

4956
function Thumbnailer:on_video_change(params)
@@ -58,7 +65,12 @@ end
5865

5966
function Thumbnailer:update_state()
6067
self.state.thumbnail_delta = self:get_delta()
61-
self.state.thumbnail_count = self:get_thumbnail_count()
68+
self.state.thumbnail_count = self:get_thumbnail_count(self.state.thumbnail_delta)
69+
70+
-- Prefill individual thumbnail states
71+
for i = 1, self.state.thumbnail_count do
72+
self.state.thumbnails[i] = -1
73+
end
6274

6375
self.state.thumbnail_template = self:get_thumbnail_template()
6476
self.state.thumbnail_size = self:get_thumbnail_size()
@@ -165,8 +177,7 @@ function Thumbnailer:get_delta()
165177
end
166178

167179

168-
function Thumbnailer:get_thumbnail_count()
169-
local delta = self:get_delta()
180+
function Thumbnailer:get_thumbnail_count(delta)
170181
if delta == nil then
171182
return 0
172183
end
@@ -176,26 +187,50 @@ function Thumbnailer:get_thumbnail_count()
176187
end
177188

178189
function Thumbnailer:get_closest(thumbnail_index)
179-
local min_distance = self.state.thumbnail_count+1
190+
-- Given a 1-based index, find the closest available thumbnail and return it's 1-based index
191+
192+
-- Check the direct thumbnail index first
193+
if self.state.thumbnails[thumbnail_index] > 0 then
194+
return thumbnail_index
195+
end
196+
197+
local min_distance = self.state.thumbnail_count + 1
180198
local closest = nil
181199

200+
-- Naive, inefficient, lazy. But functional.
182201
for index, value in pairs(self.state.thumbnails) do
183202
local distance = math.abs(index - thumbnail_index)
184-
if distance < min_distance and value then
203+
if distance < min_distance and value > 0 then
185204
min_distance = distance
186205
closest = index
187206
end
188207
end
189-
return closest, min_distance
208+
return closest
209+
end
210+
211+
function Thumbnailer:get_thumbnail_index(time_position)
212+
-- Returns a 1-based thumbnail index for the given timestamp (between 1 and thumbnail_count, inclusive)
213+
if self.state.thumbnail_delta and (self.state.thumbnail_count and self.state.thumbnail_count > 0) then
214+
return math.min(math.floor(time_position / self.state.thumbnail_delta) + 1, self.state.thumbnail_count)
215+
else
216+
return nil
217+
end
190218
end
191219

192220
function Thumbnailer:get_thumbnail_path(time_position)
193-
local thumbnail_index = math.min(math.floor(time_position / self.state.thumbnail_delta), self.state.thumbnail_count-1)
221+
-- Given a timestamp, return:
222+
-- the closest available thumbnail path (if any)
223+
-- the 1-based thumbnail index calculated from the timestamp
224+
-- the 1-based thumbnail index of the closest available (and used) thumbnail
225+
-- OR nil if thumbnails are not available.
226+
227+
local thumbnail_index = self:get_thumbnail_index(time_position)
228+
if not thumbnail_index then return nil end
194229

195-
local closest, distance = self:get_closest(thumbnail_index)
230+
local closest = self:get_closest(thumbnail_index)
196231

197232
if closest ~= nil then
198-
return self.state.thumbnail_template:format(closest), thumbnail_index, closest
233+
return self.state.thumbnail_template:format(closest-1), thumbnail_index, closest
199234
else
200235
return nil, thumbnail_index, nil
201236
end
@@ -243,13 +278,16 @@ function Thumbnailer:register_client()
243278
end
244279

245280
function Thumbnailer:_create_thumbnail_job_order()
281+
-- Returns a list of 1-based thumbnail indices in a job order
246282
local used_frames = {}
247283
local work_frames = {}
248284

285+
-- Pick frames in increasing frequency.
286+
-- This way we can do a quick few passes over the video and then fill in the gaps.
249287
for x = 6, 0, -1 do
250288
local nth = (2^x)
251289

252-
for thi = 0, self.state.thumbnail_count-1, nth do
290+
for thi = 1, self.state.thumbnail_count, nth do
253291
if not used_frames[thi] then
254292
table.insert(work_frames, thi)
255293
used_frames[thi] = true

0 commit comments

Comments
 (0)