SQLite Metadata Format¶
In order for all tools in the ld-decode tool-chain to communicate metadata about video and non-video capture content, the tools use an SQLite database to store and process information.
Please note that this metadata format is internal to the ld-decode project and should not be used by external tools (as the metadata format is subject to change without notice).
SQLite Schema¶
------------------------------------------------------------------
-- Schema Versioning
------------------------------------------------------------------
PRAGMA user_version = 1;
------------------------------------------------------------------
-- 1. Capture-level metadata (one per JSON file)
------------------------------------------------------------------
CREATE TABLE capture (
capture_id INTEGER PRIMARY KEY,
system TEXT NOT NULL
CHECK (system IN ('NTSC','PAL','PAL_M')),
decoder TEXT NOT NULL
CHECK (decoder IN ('ld-decode','vhs-decode')),
git_branch TEXT,
git_commit TEXT,
video_sample_rate REAL,
active_video_start INTEGER,
active_video_end INTEGER,
field_width INTEGER,
field_height INTEGER,
number_of_sequential_fields INTEGER,
colour_burst_start INTEGER,
colour_burst_end INTEGER,
is_mapped INTEGER
CHECK (is_mapped IN (0,1)),
is_subcarrier_locked INTEGER
CHECK (is_subcarrier_locked IN (0,1)),
is_widescreen INTEGER
CHECK (is_widescreen IN (0,1)),
white_16b_ire INTEGER,
black_16b_ire INTEGER,
blanking_16b_ire INTEGER,
capture_notes TEXT -- was JSON tape_format
);
------------------------------------------------------------------
-- 2. PCM Audio Parameters (one per capture)
------------------------------------------------------------------
CREATE TABLE pcm_audio_parameters (
capture_id INTEGER PRIMARY KEY
REFERENCES capture(capture_id) ON DELETE CASCADE,
bits INTEGER,
is_signed INTEGER
CHECK (is_signed IN (0,1)),
is_little_endian INTEGER
CHECK (is_little_endian IN (0,1)),
sample_rate REAL
);
------------------------------------------------------------------
-- 3. Field metadata
------------------------------------------------------------------
CREATE TABLE field_record (
capture_id INTEGER NOT NULL
REFERENCES capture(capture_id) ON DELETE CASCADE,
-- Note: Original JSON seqNo was indexed from 1, the field_id
-- will be the original seqNo - 1 to zero-index the ID
field_id INTEGER NOT NULL,
audio_samples INTEGER,
decode_faults INTEGER,
disk_loc REAL,
efm_t_values INTEGER,
field_phase_id INTEGER,
file_loc INTEGER,
is_first_field INTEGER
CHECK (is_first_field IN (0,1)),
median_burst_ire REAL,
pad INTEGER
CHECK (pad IN (0,1)),
sync_conf INTEGER,
-- NTSC specific fields (NULL for other formats)
ntsc_is_fm_code_data_valid INTEGER
CHECK (ntsc_is_fm_code_data_valid IN (0,1)),
ntsc_fm_code_data INTEGER,
ntsc_field_flag INTEGER
CHECK (ntsc_field_flag IN (0,1)),
ntsc_is_video_id_data_valid INTEGER
CHECK (ntsc_is_video_id_data_valid IN (0,1)),
ntsc_video_id_data INTEGER,
ntsc_white_flag INTEGER
CHECK (ntsc_white_flag IN (0,1)),
PRIMARY KEY (capture_id, field_id)
);
------------------------------------------------------------------
-- 4. VITS metrics (optional) - one per field
------------------------------------------------------------------
CREATE TABLE vits_metrics (
capture_id INTEGER NOT NULL,
field_id INTEGER NOT NULL,
b_psnr REAL,
w_snr REAL,
FOREIGN KEY (capture_id, field_id)
REFERENCES field_record(capture_id, field_id)
ON DELETE CASCADE,
PRIMARY KEY (capture_id, field_id)
);
------------------------------------------------------------------
-- 5. VBI data (optional) - stores 3 VBI data values per field
------------------------------------------------------------------
CREATE TABLE vbi (
capture_id INTEGER NOT NULL,
field_id INTEGER NOT NULL,
vbi0 INTEGER NOT NULL, -- VBI line 16 data
vbi1 INTEGER NOT NULL, -- VBI line 17 data
vbi2 INTEGER NOT NULL, -- VBI line 18 data
FOREIGN KEY (capture_id, field_id)
REFERENCES field_record(capture_id, field_id)
ON DELETE CASCADE,
PRIMARY KEY (capture_id, field_id)
);
------------------------------------------------------------------
-- 6. Drop-out elements (optional)
------------------------------------------------------------------
CREATE TABLE drop_outs (
capture_id INTEGER NOT NULL,
field_id INTEGER NOT NULL,
field_line INTEGER NOT NULL,
startx INTEGER NOT NULL,
endx INTEGER NOT NULL,
PRIMARY KEY (capture_id, field_id, field_line, startx, endx),
FOREIGN KEY (capture_id, field_id)
REFERENCES field_record(capture_id, field_id)
ON DELETE CASCADE
);
------------------------------------------------------------------
-- 7. VITC data (optional) - stores 8 VITC data values per field
------------------------------------------------------------------
CREATE TABLE vitc (
capture_id INTEGER NOT NULL,
field_id INTEGER NOT NULL,
vitc0 INTEGER NOT NULL, -- VITC data element 0
vitc1 INTEGER NOT NULL, -- VITC data element 1
vitc2 INTEGER NOT NULL, -- VITC data element 2
vitc3 INTEGER NOT NULL, -- VITC data element 3
vitc4 INTEGER NOT NULL, -- VITC data element 4
vitc5 INTEGER NOT NULL, -- VITC data element 5
vitc6 INTEGER NOT NULL, -- VITC data element 6
vitc7 INTEGER NOT NULL, -- VITC data element 7
FOREIGN KEY (capture_id, field_id)
REFERENCES field_record(capture_id, field_id)
ON DELETE CASCADE,
PRIMARY KEY (capture_id, field_id)
);
------------------------------------------------------------------
-- 8. Closed Caption data (optional) - one per field
------------------------------------------------------------------
CREATE TABLE closed_caption (
capture_id INTEGER NOT NULL,
field_id INTEGER NOT NULL,
data0 INTEGER, -- First closed caption byte (-1 if invalid)
data1 INTEGER, -- Second closed caption byte (-1 if invalid)
FOREIGN KEY (capture_id, field_id)
REFERENCES field_record(capture_id, field_id)
ON DELETE CASCADE,
PRIMARY KEY (capture_id, field_id)
);
Field Descriptions¶
This section provides detailed descriptions of each field in the SQLite schema tables.
Table: capture¶
Contains capture-level metadata (one record per capture/JSON file).
| Field | Type | Description |
|---|---|---|
capture_id |
INTEGER | Primary key identifier for the capture |
system |
TEXT | Video system in use: "PAL", "NTSC", or "PAL_M". PAL is standard 625-line PAL, NTSC is standard 525-line NTSC (as used on LaserDisc), and PAL_M is the 525-line PAL system used in Brazil |
decoder |
TEXT | The decoder used: "ld-decode" or "vhs-decode" |
git_branch |
TEXT | The git branch ID of the decoder used to decode the TBC (optional) |
git_commit |
TEXT | The git commit ID of the decoder used to decode the TBC (optional) |
video_sample_rate |
REAL | The sample rate in Hz (usually 4 × fSC for ld-decode) |
active_video_start |
INTEGER | Position (in pixels) of the start of the active video line |
active_video_end |
INTEGER | Position (in pixels) of the end of the active video line |
field_width |
INTEGER | The width of each field in pixels |
field_height |
INTEGER | The height of each field in field-lines (represents the taller of the two video fields; the shorter field is padded to match) |
number_of_sequential_fields |
INTEGER | The total number of fields decoded |
colour_burst_start |
INTEGER | Position (in pixels) of the colour-burst start |
colour_burst_end |
INTEGER | Position (in pixels) of the colour-burst end |
is_mapped |
INTEGER | Boolean: 1 if the video has been mapped by ld-discmap, 0 otherwise |
is_subcarrier_locked |
INTEGER | Boolean: 1 if samples are subcarrier-locked (aligned to colour subcarrier rather than line-locked), 0 otherwise |
is_widescreen |
INTEGER | Boolean: 1 if the video is 16:9 anamorphic, 0 if 4:3 |
white_16b_ire |
INTEGER | The white level IRE in a 16-bit scale |
black_16b_ire |
INTEGER | The black level IRE in a 16-bit scale |
blanking_16b_ire |
INTEGER | The blanking level IRE in a 16-bit scale |
capture_notes |
TEXT | Notes about the capture (was JSON tapeFormat field describing tape media format like VHS, Betamax, Video8) |
Table: pcm_audio_parameters¶
PCM audio configuration when audio data is present (one record per capture).
| Field | Type | Description |
|---|---|---|
capture_id |
INTEGER | Foreign key referencing capture.capture_id |
bits |
INTEGER | The number of bits used per sample (e.g., 16) |
is_signed |
INTEGER | Boolean: 1 if sample data is signed, 0 if unsigned |
is_little_endian |
INTEGER | Boolean: 1 if sample is little endian, 0 if big endian |
sample_rate |
REAL | The audio sample rate in Hz |
Table: field_record¶
Field-level metadata (one record per video field).
| Field | Type | Description |
|---|---|---|
capture_id |
INTEGER | Foreign key referencing capture.capture_id |
field_id |
INTEGER | Zero-indexed unique sequential field number (original JSON seqNo was 1-indexed; this is seqNo - 1) |
audio_samples |
INTEGER | The number of (stereo, signed 16-bit) audio samples corresponding to the video field |
decode_faults |
INTEGER | Bit flags for decode faults: bit 1 = first-field detection failure, bit 2 = field phase ID mismatch, bit 3 = skipped field (likely a player skip) |
disk_loc |
REAL | The location in the file (in fields) where the field is located |
efm_t_values |
INTEGER | The number of .efm T-Values (in bytes) corresponding to the video field |
field_phase_id |
INTEGER | The position of this field in the 4-field (NTSC) or 8-field (PAL) sequence |
file_loc |
INTEGER | The sample number in the file where the field is located |
is_first_field |
INTEGER | Boolean: 1 if first field, 0 if second field |
median_burst_ire |
REAL | The median point of the colour burst (in IRE) |
pad |
INTEGER | Boolean: 1 if field is padded (contains no valid video data), 0 if normal field |
sync_conf |
INTEGER | Sync confidence: 0 = poor, 100 = perfect (percentage confidence of the sync point determination) |
ntsc_is_fm_code_data_valid |
INTEGER | Boolean (NTSC only): 1 if FM code data is valid, 0 if invalid, NULL for non-NTSC |
ntsc_fm_code_data |
INTEGER | The 20-bit FM code data payload (X5 to X1) (NTSC only, NULL for non-NTSC) |
ntsc_field_flag |
INTEGER | Boolean (NTSC only): 1 if first video field, 0 if not first video field, NULL for non-NTSC |
ntsc_is_video_id_data_valid |
INTEGER | Boolean (NTSC only): 1 if VIDEO ID data is valid, 0 if invalid, NULL for non-NTSC |
ntsc_video_id_data |
INTEGER | The 14-bit VIDEO ID code data payload (IEC 61880) (NTSC only, NULL for non-NTSC) |
ntsc_white_flag |
INTEGER | Boolean (NTSC only): 1 if white flag present, 0 if not present, NULL for non-NTSC |
Table: vits_metrics¶
Video Insert Test Signal metrics (optional, one record per field when available).
| Field | Type | Description |
|---|---|---|
capture_id |
INTEGER | Foreign key referencing field_record.capture_id |
field_id |
INTEGER | Foreign key referencing field_record.field_id |
b_psnr |
REAL | Black line PSNR (not conventional SNR) |
w_snr |
REAL | The Signal to Noise ratio of a white (100 IRE) area of the field |
Table: vbi¶
Vertical Blanking Interval data (optional, one record per field when available).
| Field | Type | Description |
|---|---|---|
capture_id |
INTEGER | Foreign key referencing field_record.capture_id |
field_id |
INTEGER | Foreign key referencing field_record.field_id |
vbi0 |
INTEGER | VBI line 16 raw data (see IEC 60857-1986 and IEC 60856-1986 for details) |
vbi1 |
INTEGER | VBI line 17 raw data |
vbi2 |
INTEGER | VBI line 18 raw data |
Table: drop_outs¶
RF dropout detection data (optional, multiple records per field possible).
| Field | Type | Description |
|---|---|---|
capture_id |
INTEGER | Foreign key referencing field_record.capture_id |
field_id |
INTEGER | Foreign key referencing field_record.field_id |
field_line |
INTEGER | Field line number on which the dropout occurs |
startx |
INTEGER | Start pixel position of the detected dropout |
endx |
INTEGER | End pixel position of the detected dropout |
Table: vitc¶
Vertical Interval Timecode data (optional, one record per field when available).
| Field | Type | Description |
|---|---|---|
capture_id |
INTEGER | Foreign key referencing field_record.capture_id |
field_id |
INTEGER | Foreign key referencing field_record.field_id |
vitc0 |
INTEGER | VITC data element 0 (8 bits of raw VITC data without framing bits or CRC) |
vitc1 |
INTEGER | VITC data element 1 (8 bits of raw VITC data) |
vitc2 |
INTEGER | VITC data element 2 (8 bits of raw VITC data) |
vitc3 |
INTEGER | VITC data element 3 (8 bits of raw VITC data) |
vitc4 |
INTEGER | VITC data element 4 (8 bits of raw VITC data) |
vitc5 |
INTEGER | VITC data element 5 (8 bits of raw VITC data) |
vitc6 |
INTEGER | VITC data element 6 (8 bits of raw VITC data) |
vitc7 |
INTEGER | VITC data element 7 (8 bits of raw VITC data) |
Note: Each value represents 8 bits of the raw VITC data. The LSB of vitc0 is VITC bit 2 (the LSB of the frame number), and the MSB of vitc7 is VITC bit 79.
Table: closed_caption¶
Closed Caption data (optional, one record per field when available).
| Field | Type | Description |
|---|---|---|
capture_id |
INTEGER | Foreign key referencing field_record.capture_id |
field_id |
INTEGER | Foreign key referencing field_record.field_id |
data0 |
INTEGER | First closed caption byte (-1 if invalid, 0 indicates CC is present but no data is being transferred) |
data1 |
INTEGER | Second closed caption byte (-1 if invalid, 0 indicates CC is present but no data is being transferred) |
Note: See ANSI/CTA-608 for details on closed caption data format.