mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-11 05:31:51 +09:00
TAV-DT LDPC test
This commit is contained in:
@@ -36,6 +36,11 @@
|
||||
#include "decoder_tad.h"
|
||||
#include "reed_solomon.h"
|
||||
#include "ldpc.h"
|
||||
#include "ldpc_payload.h"
|
||||
|
||||
// FEC mode for payloads (must match encoder setting)
|
||||
#define FEC_MODE_RS 0 // Reed-Solomon (255,223) - default
|
||||
#define FEC_MODE_LDPC 1 // LDPC (255,223) - experimental
|
||||
|
||||
// =============================================================================
|
||||
// Constants
|
||||
@@ -187,6 +192,7 @@ typedef struct {
|
||||
// Options
|
||||
int verbose;
|
||||
int dump_mode; // Just dump packets, don't decode
|
||||
int fec_mode; // FEC_MODE_RS or FEC_MODE_LDPC (must match encoder)
|
||||
|
||||
// Multithreading
|
||||
int num_threads;
|
||||
@@ -226,11 +232,27 @@ static void print_usage(const char *program) {
|
||||
printf("\nOptions:\n");
|
||||
printf(" -t, --threads N Number of decoder threads (default: min(8, available CPUs))\n");
|
||||
printf(" 0 or 1 = single-threaded, 2-16 = multithreaded\n");
|
||||
printf(" --ldpc-payload Use LDPC(255,223) instead of RS(255,223) for payloads\n");
|
||||
printf(" (must match encoder setting)\n");
|
||||
printf(" --dump Dump packet info without decoding\n");
|
||||
printf(" -v, --verbose Verbose output\n");
|
||||
printf(" --help Show this help\n");
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// FEC Block Decoding (RS or LDPC based on mode)
|
||||
// =============================================================================
|
||||
|
||||
static int decode_fec_blocks(uint8_t *data, size_t total_len, uint8_t *output, size_t output_len, int fec_mode) {
|
||||
if (fec_mode == FEC_MODE_LDPC) {
|
||||
// Use LDPC(255,223) decoding
|
||||
return ldpc_p_decode_blocks(data, total_len, output, output_len);
|
||||
} else {
|
||||
// Use RS(255,223) decoding (default)
|
||||
return rs_decode_blocks(data, total_len, output, output_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void generate_random_filename(char *filename, size_t size) {
|
||||
static int seeded = 0;
|
||||
if (!seeded) {
|
||||
@@ -763,17 +785,17 @@ static int decode_audio_subpacket(dt_decoder_t *dec, const uint8_t *data, size_t
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rs_result = rs_decode_blocks(rs_data, rs_total, decoded_payload, compressed_size);
|
||||
if (rs_result < 0) {
|
||||
int fec_result = decode_fec_blocks(rs_data, rs_total, decoded_payload, compressed_size, dec->fec_mode);
|
||||
if (fec_result < 0) {
|
||||
if (dec->verbose) {
|
||||
fprintf(stderr, "Warning: RS decode failed for audio - UNRECOVERABLE\n");
|
||||
fprintf(stderr, "Warning: FEC decode failed for audio - UNRECOVERABLE\n");
|
||||
}
|
||||
free(rs_data);
|
||||
free(decoded_payload);
|
||||
*consumed = offset + rs_total;
|
||||
return -1; // Unrecoverable - RS failed
|
||||
} else if (rs_result > 0) {
|
||||
dec->fec_corrections += rs_result;
|
||||
return -1; // Unrecoverable - FEC failed
|
||||
} else if (fec_result > 0) {
|
||||
dec->fec_corrections += fec_result;
|
||||
}
|
||||
|
||||
// decoded_payload already contains the full TAD chunk format:
|
||||
@@ -876,17 +898,17 @@ static int decode_video_subpacket_mt(dt_decoder_t *dec, const uint8_t *data, siz
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rs_result = rs_decode_blocks(rs_data, rs_total, decoded_payload, compressed_size);
|
||||
if (rs_result < 0) {
|
||||
int fec_result = decode_fec_blocks(rs_data, rs_total, decoded_payload, compressed_size, dec->fec_mode);
|
||||
if (fec_result < 0) {
|
||||
if (dec->verbose) {
|
||||
fprintf(stderr, "Warning: RS decode failed for video (MT) - UNRECOVERABLE\n");
|
||||
fprintf(stderr, "Warning: FEC decode failed for video (MT) - UNRECOVERABLE\n");
|
||||
}
|
||||
free(rs_data);
|
||||
free(decoded_payload);
|
||||
*consumed = offset + rs_total;
|
||||
return -1; // Unrecoverable - RS failed
|
||||
} else if (rs_result > 0) {
|
||||
dec->fec_corrections += rs_result;
|
||||
return -1; // Unrecoverable - FEC failed
|
||||
} else if (fec_result > 0) {
|
||||
dec->fec_corrections += fec_result;
|
||||
}
|
||||
free(rs_data);
|
||||
|
||||
@@ -1050,17 +1072,17 @@ static int decode_video_subpacket(dt_decoder_t *dec, const uint8_t *data, size_t
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rs_result = rs_decode_blocks(rs_data, rs_total, decoded_payload, compressed_size);
|
||||
if (rs_result < 0) {
|
||||
int fec_result = decode_fec_blocks(rs_data, rs_total, decoded_payload, compressed_size, dec->fec_mode);
|
||||
if (fec_result < 0) {
|
||||
if (dec->verbose) {
|
||||
fprintf(stderr, "Warning: RS decode failed for video - UNRECOVERABLE\n");
|
||||
fprintf(stderr, "Warning: FEC decode failed for video - UNRECOVERABLE\n");
|
||||
}
|
||||
free(rs_data);
|
||||
free(decoded_payload);
|
||||
*consumed = offset + rs_total;
|
||||
return -1; // Unrecoverable - RS failed
|
||||
} else if (rs_result > 0) {
|
||||
dec->fec_corrections += rs_result;
|
||||
return -1; // Unrecoverable - FEC failed
|
||||
} else if (fec_result > 0) {
|
||||
dec->fec_corrections += fec_result;
|
||||
}
|
||||
|
||||
// Initialize video decoder if needed
|
||||
@@ -1680,14 +1702,16 @@ int main(int argc, char **argv) {
|
||||
// Initialize FEC libraries
|
||||
rs_init();
|
||||
ldpc_init();
|
||||
ldpc_p_init(); // LDPC payload codec
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"input", required_argument, 0, 'i'},
|
||||
{"output", required_argument, 0, 'o'},
|
||||
{"threads", required_argument, 0, 't'},
|
||||
{"dump", no_argument, 0, 'd'},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"input", required_argument, 0, 'i'},
|
||||
{"output", required_argument, 0, 'o'},
|
||||
{"threads", required_argument, 0, 't'},
|
||||
{"ldpc-payload", no_argument, 0, 'D'},
|
||||
{"dump", no_argument, 0, 'd'},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@@ -1711,6 +1735,9 @@ int main(int argc, char **argv) {
|
||||
if (dec.num_threads > MAX_DECODE_THREADS) dec.num_threads = MAX_DECODE_THREADS;
|
||||
break;
|
||||
}
|
||||
case 'D':
|
||||
dec.fec_mode = FEC_MODE_LDPC;
|
||||
break;
|
||||
case 'd':
|
||||
dec.dump_mode = 1;
|
||||
break;
|
||||
|
||||
@@ -36,6 +36,11 @@
|
||||
#include "encoder_tad.h"
|
||||
#include "reed_solomon.h"
|
||||
#include "ldpc.h"
|
||||
#include "ldpc_payload.h"
|
||||
|
||||
// FEC mode for payloads (stored in flags byte bit 2)
|
||||
#define FEC_MODE_RS 0 // Reed-Solomon (255,223) - default
|
||||
#define FEC_MODE_LDPC 1 // LDPC (255,223) - experimental
|
||||
|
||||
// =============================================================================
|
||||
// Constants
|
||||
@@ -197,6 +202,7 @@ typedef struct {
|
||||
// Options
|
||||
int verbose;
|
||||
int encode_limit;
|
||||
int fec_mode; // FEC_MODE_RS or FEC_MODE_LDPC for payloads
|
||||
|
||||
// Multithreading
|
||||
int num_threads; // 0 = single-threaded, 1+ = num worker threads
|
||||
@@ -226,6 +232,8 @@ static void print_usage(const char *program) {
|
||||
printf(" --ntsc Force NTSC format (720x480, default)\n");
|
||||
printf(" --pal Force PAL format (720x576)\n");
|
||||
printf(" --interlaced Interlaced output\n");
|
||||
printf(" --ldpc-payload Use LDPC(255,223) instead of RS(255,223) for payloads\n");
|
||||
printf(" (experimental: better at high error rates)\n");
|
||||
printf(" --encode-limit N Encode only N frames (for testing)\n");
|
||||
printf(" -t, --threads N Parallel encoding threads (default: min(8, available CPUs))\n");
|
||||
printf(" 0 or 1 = single-threaded, 2-16 = multithreaded\n");
|
||||
@@ -234,31 +242,37 @@ static void print_usage(const char *program) {
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// RS Block Encoding
|
||||
// FEC Block Encoding (RS or LDPC based on mode)
|
||||
// =============================================================================
|
||||
|
||||
static size_t encode_rs_blocks(const uint8_t *data, size_t data_len, uint8_t *output) {
|
||||
size_t output_len = 0;
|
||||
size_t remaining = data_len;
|
||||
const uint8_t *src = data;
|
||||
uint8_t *dst = output;
|
||||
static size_t encode_fec_blocks(const uint8_t *data, size_t data_len, uint8_t *output, int fec_mode) {
|
||||
if (fec_mode == FEC_MODE_LDPC) {
|
||||
// Use LDPC(255,223) encoding
|
||||
return ldpc_p_encode_blocks(data, data_len, output);
|
||||
} else {
|
||||
// Use RS(255,223) encoding (default)
|
||||
size_t output_len = 0;
|
||||
size_t remaining = data_len;
|
||||
const uint8_t *src = data;
|
||||
uint8_t *dst = output;
|
||||
|
||||
while (remaining > 0) {
|
||||
size_t block_data = (remaining > RS_DATA_SIZE) ? RS_DATA_SIZE : remaining;
|
||||
size_t encoded_len = rs_encode(src, block_data, dst);
|
||||
while (remaining > 0) {
|
||||
size_t block_data = (remaining > RS_DATA_SIZE) ? RS_DATA_SIZE : remaining;
|
||||
size_t encoded_len = rs_encode(src, block_data, dst);
|
||||
|
||||
// Pad to full block size for consistent block boundaries
|
||||
if (encoded_len < RS_BLOCK_SIZE) {
|
||||
memset(dst + encoded_len, 0, RS_BLOCK_SIZE - encoded_len);
|
||||
// Pad to full block size for consistent block boundaries
|
||||
if (encoded_len < RS_BLOCK_SIZE) {
|
||||
memset(dst + encoded_len, 0, RS_BLOCK_SIZE - encoded_len);
|
||||
}
|
||||
|
||||
src += block_data;
|
||||
dst += RS_BLOCK_SIZE;
|
||||
output_len += RS_BLOCK_SIZE;
|
||||
remaining -= block_data;
|
||||
}
|
||||
|
||||
src += block_data;
|
||||
dst += RS_BLOCK_SIZE;
|
||||
output_len += RS_BLOCK_SIZE;
|
||||
remaining -= block_data;
|
||||
return output_len;
|
||||
}
|
||||
|
||||
return output_len;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -355,12 +369,12 @@ static int write_packet(dt_encoder_t *enc, uint64_t timecode_ns,
|
||||
uint8_t ldpc_tav_header[DT_TAV_HEADER_SIZE * 2];
|
||||
ldpc_encode(tav_header, DT_TAV_HEADER_SIZE, ldpc_tav_header);
|
||||
|
||||
// RS encode payloads
|
||||
// FEC encode payloads (RS or LDPC based on mode)
|
||||
uint8_t *tad_rs_data = malloc(tad_rs_size);
|
||||
uint8_t *tav_rs_data = malloc(tav_rs_size);
|
||||
|
||||
encode_rs_blocks(tad_data, tad_size, tad_rs_data);
|
||||
encode_rs_blocks(tav_data, tav_size, tav_rs_data);
|
||||
encode_fec_blocks(tad_data, tad_size, tad_rs_data, enc->fec_mode);
|
||||
encode_fec_blocks(tav_data, tav_size, tav_rs_data, enc->fec_mode);
|
||||
|
||||
// Write everything
|
||||
fwrite(ldpc_header, 1, DT_MAIN_HEADER_SIZE * 2, enc->output_fp);
|
||||
@@ -1268,6 +1282,7 @@ int main(int argc, char **argv) {
|
||||
// Initialize FEC libraries
|
||||
rs_init();
|
||||
ldpc_init();
|
||||
ldpc_p_init(); // LDPC payload codec
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"input", required_argument, 0, 'i'},
|
||||
@@ -1277,6 +1292,7 @@ int main(int argc, char **argv) {
|
||||
{"ntsc", no_argument, 0, 'N'},
|
||||
{"pal", no_argument, 0, 'P'},
|
||||
{"interlaced", no_argument, 0, 'I'},
|
||||
{"ldpc-payload", no_argument, 0, 'D'},
|
||||
{"encode-limit", required_argument, 0, 'L'},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
@@ -1319,6 +1335,9 @@ int main(int argc, char **argv) {
|
||||
case 'I':
|
||||
enc.is_interlaced = 1;
|
||||
break;
|
||||
case 'D':
|
||||
enc.fec_mode = FEC_MODE_LDPC;
|
||||
break;
|
||||
case 'L':
|
||||
enc.encode_limit = atoi(optarg);
|
||||
break;
|
||||
@@ -1366,6 +1385,7 @@ int main(int argc, char **argv) {
|
||||
printf(" Framerate: %d/%d\n", enc.fps_num, enc.fps_den);
|
||||
printf(" Quality: %d\n", enc.quality_index);
|
||||
printf(" GOP size: %d\n", DT_GOP_SIZE);
|
||||
printf(" Payload FEC: %s\n", enc.fec_mode == FEC_MODE_LDPC ? "LDPC(255,223)" : "RS(255,223)");
|
||||
printf(" Threads: %d%s\n", enc.num_threads > 0 ? enc.num_threads : 1,
|
||||
enc.num_threads > 0 ? " (multithreaded)" : " (single-threaded)");
|
||||
printf(" Header sizes: main=%dB tad=%dB tav=%dB (after LDPC)\n",
|
||||
|
||||
Reference in New Issue
Block a user