Skip to content

Latest commit

 

History

History
225 lines (171 loc) · 6 KB

File metadata and controls

225 lines (171 loc) · 6 KB

V2A Specification - True Color Quadrant Rendering

Overview

V2A (Video to ANSI) is a video format optimized for terminal playback using Unicode Quadrant Block characters with 24-bit true color.

Technical Design

Quadrant Blocks

Quadrant blocks are solid rectangular Unicode characters (U+2596 to U+259F) that fully occupy the character cell. Combined with ANSI true color (24-bit RGB), each quadrant displays its actual pixel color:

  • Clean, sharp edges
  • Full coverage of character space
  • True color per pixel (24-bit)

Quadrant Character Encoding

Unicode Range: U+2596 to U+259F (10 characters)

Quadrant layout (2×2 grid):

┌───┬───┐
│ TL│ TR│
├───┼───┤
│ BL│ BR│
└───┴───┘

Data Format

Frame Structure

V2AFrame {
    width: u16,                    // Number of quadrant cells horizontally
    height: u16,                   // Number of quadrant cells vertically
    pixel_cells: Vec<Cell>        // Per-cell data
}

Cell {
    quadrant_index: u8,            // 0-9, which quadrant character to use
    colors: [RGB; 4]               // 4 RGB colors, one per quadrant position
}

RGB {
    r: u8,                         // Red (0-255)
    g: u8,                         // Green (0-255)
    b: u8,                         // Blue (0-255)
}

Cell Layout

Each 2×2 pixel block from source video maps to 1 Quadrant cell:

[px1][px2]  →  TL, TR
[px3][px4]  →  BL, BR

The quadrant_index determines which quadrants are filled (show fg color) vs empty (show bg color).

Filled quadrants show the average color of their respective pixels. Empty quadrants show the background color.

Downsampling Algorithm

For each 2×2 pixel block:

  1. Read 4 source pixels (RGB)
  2. Store the 4 RGB colors directly in the cell
  3. Determine quadrant_index based on luminance threshold:
    • If pixel luminance > block average: quadrant is filled
    • If pixel luminance <= block average: quadrant is empty
  4. Calculate fill/empty colors:
    • Filled quadrants: average color of filled pixels
    • Empty quadrants: average color of empty pixels (or transparent)

True Color ANSI Codes

Foreground (24-bit RGB):

\x1b[38;2;R;G;Bm

Background (24-bit RGB):

\x1b[48;2;R;G;Bm

Reset:

\x1b[0m

Example:

\x1b[38;2;255;128;0m\x1b[48;2;0;0;255m▚\x1b[0m

File Format

File Layout

┌─────────────────────────────────────┐
│            Header (32 bytes)        │
├─────────────────────────────────────┤
│         Audio Data (N bytes)        │
├─────────────────────────────────────┤
│      Frame 1 (gzip compressed)      │
├─────────────────────────────────────┤
│      Frame 2 (gzip compressed)      │
├─────────────────────────────────────┤
│              ...                    │
├─────────────────────────────────────┤
│      Frame N (gzip compressed)      │
└─────────────────────────────────────┘

Header (32 bytes)

Offset Type Description
0-3 bytes Magic: "V2A\0"
4-5 u16 Version: 2
6-9 u32 Frame count
10-13 u32 Original video width
14-17 u32 Original video height
18-21 float FPS
22-29 u64 Audio data size
30-31 bytes Padding

Audio Data

Raw audio bytes immediately following the header. Size is specified in audio_data_size.

Frame Data

Each frame is individually gzip compressed.

Offset Type Description
0-1 u16 Frame width (cells)
2-3 u16 Frame height (cells)
4+ bytes pixel_cells as 13-byte tuples

Cell Format (13 bytes)

Offset Size Description
0 1 quadrant_index (0-9)
1 3 TL RGB (r,g,b)
4 3 TR RGB (r,g,b)
7 3 BL RGB (r,g,b)
10 3 BR RGB (r,g,b)

Frame Buffer

The player uses a prefetch buffer to prevent I/O lag:

Setting Value
Buffer size 300 frames
Prefetch thread Background thread continuously reads frames
Buffer type Thread-safe queue
Sync mechanism Condition variable for producer/consumer

Buffer Flow

[Disk] → [Prefetch Thread] → [Buffer] → [Playback Thread] → [Terminal]

Terminal Rendering

Quadrant Character Mapping

Characters indexed 0-9, mapped to Unicode U+2596-U+259F:

Index 0: U+2596 (▖) - Lower-left
Index 1: U+2597 (▗) - Lower-right
Index 2: U+2598 (▘) - Upper-left
Index 3: U+2599 (▙) - Three quadrants (UL+LL+LR)
Index 4: U+259A (▚) - Diagonal (UL+LR)
Index 5: U+259B (▛) - Three quadrants (UL+LL+UR)
Index 6: U+259C (▜) - Three quadrants (UL+UR+LR)
Index 7: U+259D (▝) - Upper-right
Index 8: U+259E (▞) - Diagonal (UR+LL)
Index 9: U+259F (▟) - Three quadrants (UR+LL+LR)

Cell Rendering

  1. Get quadrant_index and 4 RGB colors
  2. Calculate foreground color (average of filled quadrants)
  3. Calculate background color (average of empty quadrants)
  4. Output: \x1b[38;2;R;G;Bm\x1b[48;2;R;G;Bm<quadrant_char>\x1b[0m

Scaling Calculations

scaled_width = floor(term_cols * 2 * scale)
scaled_height = floor(term_rows * 2 * scale)

Pause/Resume Behavior

When paused:

  1. Video playback freezes (no frames advance)
  2. Audio playback freezes
  3. Internal timing pauses

When resumed:

  1. Video continues from exact pause point
  2. Audio continues from exact pause point
  3. Timing compensates for pause duration

Version

Format Version: 2