Class: TestRecorder::FrameWriter
- Inherits:
-
Object
- Object
- TestRecorder::FrameWriter
- Defined in:
- lib/test_recorder/frame_writer.rb
Constant Summary collapse
- MIN_LAST_FRAME_DURATION =
How long the last frame stays visible at the end of the video. A test usually fails some time after the last repaint, and that last screen is the one worth looking at.
1.0- MAX_LAST_FRAME_DURATION =
5.0
Instance Attribute Summary collapse
-
#duration ⇒ Object
readonly
How many seconds the finished video should run for.
-
#frame_count ⇒ Object
readonly
Chrome sends a frame as soon as the screencast starts, so a test that fails before it draws anything still leaves behind the one frame of the blank page it started on.
Instance Method Summary collapse
- #empty? ⇒ Boolean
-
#finish ⇒ Object
Repeats the last frame at the end of the recording so that it stays on screen, and so that the video covers the time between the last repaint and the end of the test.
-
#initialize(io) ⇒ FrameWriter
constructor
A new instance of FrameWriter.
- #write(frame, time) ⇒ Object
Constructor Details
#initialize(io) ⇒ FrameWriter
Returns a new instance of FrameWriter.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/test_recorder/frame_writer.rb', line 10 def initialize(io) @container = MatroskaWriter.new(io) @first_frame_time = nil @last_frame = nil @last_write_at = nil @last_timestamp_ms = 0 @duration = nil @frame_count = 0 @finished = false # CDP dispatches every screencast frame event on its own thread, and `finish` can run on the # main thread while a frame is still in flight, so all access to the state above and to the # container is serialized through this. @mutex = Mutex.new end |
Instance Attribute Details
#duration ⇒ Object (readonly)
How many seconds the finished video should run for. ffmpeg does not reliably infer this from
the container alone, so stop_and_save passes it to ffmpeg explicitly. Only meaningful after
finish has run.
32 33 34 |
# File 'lib/test_recorder/frame_writer.rb', line 32 def duration @duration end |
#frame_count ⇒ Object (readonly)
Chrome sends a frame as soon as the screencast starts, so a test that fails before it draws anything still leaves behind the one frame of the blank page it started on. Callers use this to tell that apart from a real recording.
37 38 39 |
# File 'lib/test_recorder/frame_writer.rb', line 37 def frame_count @frame_count end |
Instance Method Details
#empty? ⇒ Boolean
25 26 27 |
# File 'lib/test_recorder/frame_writer.rb', line 25 def empty? @last_frame.nil? end |
#finish ⇒ Object
Repeats the last frame at the end of the recording so that it stays on screen, and so that the video covers the time between the last repaint and the end of the test. That interval is measured with the monotonic clock, so a wall clock adjustment cannot stretch or shrink it.
54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/test_recorder/frame_writer.rb', line 54 def finish @mutex.synchronize do return if @finished @finished = true return if empty? elapsed = (monotonic_time - @last_write_at).clamp(MIN_LAST_FRAME_DURATION, MAX_LAST_FRAME_DURATION) write_ms(@last_frame, @last_timestamp_ms + (elapsed * 1000).round) @duration = @last_timestamp_ms / 1000.0 end end |
#write(frame, time) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/test_recorder/frame_writer.rb', line 39 def write(frame, time) @mutex.synchronize do return if @finished @first_frame_time ||= time write_at(frame, time) @last_frame = frame @last_write_at = monotonic_time @frame_count += 1 end end |