frames.rs

crates/veilvoice-video/src/frames.rs

veilvoice-video · 686 lines · read the source here · or on GitHub

The video's pictures, and how many of them there really are.

What this finishes

crate::ffmpeg::command has always known how to turn a directory of pictures into a video file. Nothing filled the directory, so what a render produced was veiled audio over a black picture, and the roadmap row said so rather than letting somebody find out by playing the file.

This fills it, with crate::raster for the pixels and crate::font for the names.

A frame is written when the picture changes, not thirty times a second

An hour at thirty frames a second is 108,000 pictures. Written out at 1080p that is gigabytes of intermediate files to make one video, and almost all of them are identical to the one before.

So the frame rate decides when the picture is looked at, and a new file is written only when what it would contain has actually changed. Three things can change it, and Signature is exactly those three:

  • the playhead, which moves one pixel at a time and not one frame at a time,
  • the level bars, which move when the envelope column changes,
  • who is lit, which changes at a turn boundary.

On a 1920-wide waveform over an hour the playhead moves a pixel about every two seconds, so runs of fifty-odd identical frames collapse into one file held for the length of the run. That is not a guess: plan reports how many pictures it actually produced against how many frames the video has, and a caller can show the ratio.

A short recording saves nothing, and should not. The playhead crosses the whole waveform however long the recording is, so under about forty seconds it moves more than a pixel per frame and every frame is genuinely a different picture. The saving arrives with length, which is exactly where it was needed.

This is why the ffmpeg command is a concat list rather than a numbered sequence. image2 gives every file the same duration; a held frame needs its own. See crate::ffmpeg::concat_command.

What the video cannot draw that the page can

Names outside printable ASCII. The page is markup and uses whatever face the reader's machine has; this has one face, written here, for the reasons crate::font gives. A name it cannot draw comes out as open boxes and is named in the notes, because a person who typed a name in Cyrillic should be told before they render an hour of video rather than after.

In plain words

This draws the pictures the video is made of.

It only draws a new one when something on screen has actually moved, which for a long recording is a tiny fraction of the frames the video has, so a render writes hundreds of pictures rather than hundreds of thousands.

WHAT THIS FILE CONTAINS

686 lines defining 7 functions (4 public), 5 types and 0 constants. Everything below is read out of the source, so it cannot disagree with the code.

The types it owns.

  • struct Signature line 76 · What decides whether two moments look the same.
  • struct Frame line 109 · One picture, and how long the video shows it for.
  • struct Plan line 118 · The pictures a render will write, worked out without drawing any of them.
  • struct Notes line 187 · What a drawn frame carried with it.
  • struct Written line 375 · What a written sequence produced.

What happens when it runs. These are the ways in: public, and nothing else in this file calls them, so they are what an outside caller reaches first.

  • Plan::saving line 133 · How many pictures were saved by holding the ones that did not change.
  • write line 394 · Draw and write the whole sequence into directory.
    reaches draw, plan, dim, draw_wave, at

WHAT CALLS WHAT

Signature::at line 86 Plan::saving line 133 plan line 146 draw line 200 dim line 336 draw_wave line 349 write line 394 entry: a way in: public, and nothing in this file calls it api: public, and also used inside this file helper: private to this file dashed: a call that goes back up, or across a wrapped rank The functions this file defines, and the calls between them. An edge means the callee's name appears, called, inside the caller's body. This is a syntactic reading, not a type-resolved one.

The functions this file defines, and the calls between them. An edge means the callee's name appears, called, inside the caller's body. This is a syntactic reading, not a type-resolved one.

The same graph as Mermaid source
%%{init: {"theme":"base","themeVariables":{"background":"#1a1b26","primaryColor":"#1f2335","primaryTextColor":"#c0caf5","primaryBorderColor":"#7aa2f7","secondaryColor":"#16161e","tertiaryColor":"#16161e","lineColor":"#737aa2","textColor":"#c0caf5","mainBkg":"#1f2335","nodeBorder":"#7aa2f7","clusterBkg":"#16161e","clusterBorder":"#2f3549","fontFamily":"ui-monospace, SFMono-Regular, Consolas, monospace","fontSize":"14px"}}}%%
flowchart TD
    n_at["Signature::at<br/>line 86"]
    n_saving(["Plan::saving<br/>line 133"])
    n_plan["plan<br/>line 146"]
    n_draw["draw<br/>line 200"]
    n_dim["dim<br/>line 336"]
    n_draw_wave["draw_wave<br/>line 349"]
    n_write(["write<br/>line 394"])
    n_draw --> n_dim
    n_draw --> n_draw_wave
    n_plan --> n_at
    n_write --> n_draw
    n_write --> n_plan
    click n_at href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-video/src/frames.rs#L86" "open the source"
    click n_saving href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-video/src/frames.rs#L133" "open the source"
    click n_plan href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-video/src/frames.rs#L146" "open the source"
    click n_draw href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-video/src/frames.rs#L200" "open the source"
    click n_dim href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-video/src/frames.rs#L336" "open the source"
    click n_draw_wave href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-video/src/frames.rs#L349" "open the source"
    click n_write href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-video/src/frames.rs#L394" "open the source"
    classDef entry fill:#1f2335,stroke:#7aa2f7,color:#c0caf5
    class n_saving,n_write entry
    classDef api fill:#1f2335,stroke:#7dcfff,color:#c0caf5
    class n_plan,n_draw api
    classDef helper fill:#1f2335,stroke:#bb9af7,color:#c0caf5
    class n_at,n_dim,n_draw_wave helper

This site loads no third-party script, so it cannot run Mermaid; the diagram above is the same nodes and edges drawn by the generator instead. GitHub renders the source below directly.

ITEMS

ItemLineDocumentation
Signature struct76What decides whether two moments look the same.
Signature::at fn86
Frame pub struct109One picture, and how long the video shows it for.
Plan pub struct118The pictures a render will write, worked out without drawing any of them.
Plan::saving pub fn133How many pictures were saved by holding the ones that did not change.
plan pub fn146Work out which moments need a picture.
Notes pub struct187What a drawn frame carried with it.
draw pub fn200Draw the picture at at_secs.
dim fn336Mix colour towards background, keeping amount of it.
draw_wave fn349The envelope as filled columns inside the waveform's box.
Written pub struct375What a written sequence produced.
write pub fn394Draw and write the whole sequence into directory.