Class: TUITD::VideoRecorder

Inherits:
Object
  • Object
show all
Defined in:
lib/tui_td/video_recorder.rb

Overview

Records TUI sessions as video using ffmpeg.

Frames are captured via the existing Screenshot pipeline and piped directly to ffmpeg’s stdin as PNG images — no temporary frame files.

Usage:

recorder = VideoRecorder.new("session.mp4", driver: driver, framerate: 30)
recorder.start
# ... interact with TUI ...
recorder.stop  # => "session.mp4"

Constant Summary collapse

QUALITY_CRF =
{
  "high" => 18,
  "medium" => 23,
  "low" => 28,
}.freeze
DEFAULT_QUALITY =
"high"
DEFAULT_FRAMERATE =
30
DEFAULT_CODEC =
"libx264"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(output_path, driver:, framerate: DEFAULT_FRAMERATE, codec: DEFAULT_CODEC, quality: DEFAULT_QUALITY) ⇒ VideoRecorder

Returns a new instance of VideoRecorder.

Raises:



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/tui_td/video_recorder.rb', line 32

def initialize(output_path, driver:, framerate: DEFAULT_FRAMERATE,
               codec: DEFAULT_CODEC, quality: DEFAULT_QUALITY)
  raise Error, "ffmpeg not found. Install ffmpeg to use video recording." unless self.class.available?

  @output_path = File.expand_path(output_path)
  @driver = driver
  @framerate = framerate
  @codec = codec
  @quality = quality
  @ffmpeg_io = nil
  @capture_thread = nil
  @running = false
  @mutex = Mutex.new
  @frame_interval = 1.0 / framerate
end

Instance Attribute Details

#codecObject (readonly)

Returns the value of attribute codec.



30
31
32
# File 'lib/tui_td/video_recorder.rb', line 30

def codec
  @codec
end

#framerateObject (readonly)

Returns the value of attribute framerate.



30
31
32
# File 'lib/tui_td/video_recorder.rb', line 30

def framerate
  @framerate
end

#output_pathObject (readonly)

Returns the value of attribute output_path.



30
31
32
# File 'lib/tui_td/video_recorder.rb', line 30

def output_path
  @output_path
end

#qualityObject (readonly)

Returns the value of attribute quality.



30
31
32
# File 'lib/tui_td/video_recorder.rb', line 30

def quality
  @quality
end

Class Method Details

.available?Boolean

Check whether ffmpeg is available on the system.

Returns:

  • (Boolean)


49
50
51
# File 'lib/tui_td/video_recorder.rb', line 49

def self.available?
  system("which ffmpeg > /dev/null 2>&1")
end

Instance Method Details

#recording?Boolean

Is recording currently active?

Returns:

  • (Boolean)


94
95
96
# File 'lib/tui_td/video_recorder.rb', line 94

def recording?
  @mutex.synchronize { @running }
end

#startObject

Start recording. Spawns ffmpeg and begins frame capture.



54
55
56
57
58
59
60
61
62
63
64
# File 'lib/tui_td/video_recorder.rb', line 54

def start
  @mutex.synchronize do
    raise Error, "Recording already in progress" if @running

    @ffmpeg_io = IO.popen(ffmpeg_command, "w", err: File::NULL)
    @running = true
  end

  @capture_thread = Thread.new { capture_loop }
  true
end

#stopObject

Stop recording. Waits for ffmpeg to finalize and returns the output path.



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
# File 'lib/tui_td/video_recorder.rb', line 67

def stop
  @mutex.synchronize do
    return nil unless @running

    @running = false
  end

  @capture_thread&.join(5)
  begin
    @capture_thread&.kill
  rescue StandardError
    nil
  end
  @capture_thread = nil

  begin
    @ffmpeg_io&.close_write
    @ffmpeg_io&.close
  rescue StandardError
    nil
  end
  @ffmpeg_io = nil

  @output_path
end