Skip to content

Commit ce753e4

Browse files
committed
feat: video2ascii player
1 parent df572d3 commit ce753e4

File tree

1 file changed

+179
-0
lines changed

1 file changed

+179
-0
lines changed
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
require "rainbow"
2+
require_relative "./terminal"
3+
4+
module Convert2Ascii
5+
class TerminalPlayer
6+
7+
SAFE_SLOW_DELTA = 0.9 # seconds
8+
SAFE_FAST_DELTA = 0.2 # seconds
9+
10+
attr_accessor :play_loop, :step_duration, :debug
11+
def initialize(**args)
12+
@debug = false
13+
@audio = args[:audio]
14+
@frames = args[:frames]
15+
@play_loop = args[:play_loop]
16+
@step_duration = args[:step_duration]
17+
18+
@first_frame = true
19+
@backspace_adjust = "\033[A" * (@frames.length + 1)
20+
21+
regist_hook
22+
end
23+
24+
def play
25+
begin
26+
init_screen
27+
render
28+
rescue => error
29+
raise error
30+
ensure
31+
clean_up
32+
end
33+
end
34+
35+
private
36+
37+
def regist_hook
38+
trap("INT") {
39+
clean_up
40+
exit 0
41+
}
42+
43+
# TODO ??? 改变会消失
44+
# # 窗口变化事件
45+
# trap("SIGWINCH") {
46+
# resize
47+
# }
48+
end
49+
50+
def resize
51+
clear_screen
52+
end
53+
54+
def clear_screen
55+
Terminal.clear_buffer
56+
end
57+
58+
def init_screen
59+
clear_screen
60+
setup
61+
end
62+
63+
def setup
64+
Terminal.open_buffer
65+
Terminal.hide_cursor
66+
Terminal.clear_screen
67+
end
68+
69+
def clean_up
70+
if !@debug
71+
Terminal.close_buffer
72+
Terminal.clear_screen
73+
Terminal.show_cursor
74+
end
75+
end
76+
77+
def debug_log(var_name)
78+
puts Rainbow('-- debug ----').yellow
79+
puts "class:"
80+
p var_name.class
81+
puts "value:"
82+
p var_name
83+
end
84+
85+
def full_screen(content)
86+
87+
if !content
88+
return content
89+
end
90+
# 补齐高度,没内容也要追加 \n 刷新,因为会拖拽 窗体尺寸会变化
91+
rows, _ = Terminal.winsize
92+
# content: pure text with "\n"
93+
content = content.split("\n")
94+
95+
rows_fill = []
96+
delta = rows - content.length
97+
98+
if delta > 0
99+
delta.times do
100+
rows_fill << "\n"
101+
end
102+
elsif delta < 0
103+
content = content[0..(rows - 1)]
104+
end
105+
106+
content.join("\n")
107+
end
108+
109+
def self_adaption_frame_play
110+
# 当偏移在-90ms(音频滞后于视频)到+20ms(音频超前视频)之间时,人感觉不到视听质量的变化,这个区域可以认为是同步区域
111+
# https://github.com/0voice/audio_video_streaming/blob/main/article/029-%E9%9F%B3%E8%A7%86%E9%A2%91%E5%90%8C%E6%AD%A5%E7%AE%97%E6%B3%95.md
112+
113+
start_time = Time.now
114+
if @audio
115+
Thread.new do
116+
start_time = Time.now # 以音频为准
117+
system("afplay #{@audio}")
118+
if @debug
119+
puts Rainbow("[info] audio time: #{Time.now - start_time} s").green
120+
end
121+
122+
# TODO control audio play
123+
# Open3.popen3("afplay #{@audio}") do |stdin, stdout, stderr, wait_thr|
124+
# # 可以在这里处理输出或错误信息
125+
# end
126+
end
127+
end
128+
frame_index = 0
129+
loop do
130+
if frame_index <= @frames.length
131+
content = @frames[frame_index]
132+
if !@first_frame
133+
$stdout.print @backspace_adjust
134+
end
135+
clear_screen
136+
$stdout.print(full_screen(content))
137+
@first_frame = false
138+
sleep(@step_duration)
139+
end
140+
141+
actual_time = Time.now - start_time
142+
video_play_time = frame_index * @step_duration
143+
144+
offset_time = actual_time - video_play_time
145+
if offset_time > SAFE_SLOW_DELTA
146+
offset = (offset_time / @step_duration).floor
147+
if @debug
148+
puts Rainbow("[+] #{offset}").green
149+
end
150+
elsif offset_time < -1 * SAFE_FAST_DELTA
151+
offset = 0
152+
else
153+
offset = 1
154+
end
155+
156+
frame_index += offset
157+
158+
if @debug
159+
puts ""
160+
real_time = Time.now - start_time
161+
frame_time = (frame_index + 1) * @step_duration
162+
puts Rainbow("RealTime: #{real_time} s").green
163+
puts Rainbow("FrameTime: #{frame_time} s").green
164+
puts Rainbow("Real - Frame: #{real_time - frame_time} s").green
165+
puts Rainbow("[+] #{offset}").green
166+
puts Rainbow("@step_duration #{@step_duration}").green
167+
end
168+
169+
if !@play_loop && frame_index > @frames.length
170+
break
171+
end
172+
end
173+
end
174+
175+
def render
176+
self_adaption_frame_play
177+
end
178+
end
179+
end

0 commit comments

Comments
 (0)