mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-07 11:51:49 +09:00
280x224 macrotile
This commit is contained in:
@@ -92,7 +92,7 @@ if (fullFilePathStr.startsWith('$:/TAPE') || fullFilePathStr.startsWith('$:\\\\T
|
||||
|
||||
con.clear()
|
||||
con.curs_set(0)
|
||||
graphics.setGraphicsMode(4) // 4096-color mode
|
||||
graphics.setGraphicsMode(4) // 4096-colour mode
|
||||
graphics.clearPixels(0)
|
||||
graphics.clearPixels2(0)
|
||||
|
||||
@@ -106,8 +106,8 @@ audio.setMasterVolume(0, 255)
|
||||
function clearSubtitleArea() {
|
||||
// Clear the subtitle area at the bottom of the screen
|
||||
// Text mode is 80x32, so clear the bottom few lines
|
||||
let oldFgColor = con.get_color_fore()
|
||||
let oldBgColor = con.get_color_back()
|
||||
let oldFgColour = con.get_color_fore()
|
||||
let oldBgColour = con.get_color_back()
|
||||
|
||||
con.color_pair(255, 255) // transparent to clear
|
||||
|
||||
@@ -119,7 +119,7 @@ function clearSubtitleArea() {
|
||||
}
|
||||
}
|
||||
|
||||
con.color_pair(oldFgColor, oldBgColor)
|
||||
con.color_pair(oldFgColour, oldBgColour)
|
||||
}
|
||||
|
||||
function getVisualLength(line) {
|
||||
@@ -153,8 +153,8 @@ function getVisualLength(line) {
|
||||
}
|
||||
|
||||
function displayFormattedLine(line) {
|
||||
// Parse line and handle <b> and <i> tags with color changes
|
||||
// Default subtitle color: yellow (231), formatted text: white (254)
|
||||
// Parse line and handle <b> and <i> tags with colour changes
|
||||
// Default subtitle colour: yellow (231), formatted text: white (254)
|
||||
|
||||
let i = 0
|
||||
let inBoldOrItalic = false
|
||||
@@ -202,9 +202,9 @@ function displaySubtitle(text, position = 0) {
|
||||
return
|
||||
}
|
||||
|
||||
// Set subtitle colors: yellow (231) on black (0)
|
||||
let oldFgColor = con.get_color_fore()
|
||||
let oldBgColor = con.get_color_back()
|
||||
// Set subtitle colours: yellow (231) on black (0)
|
||||
let oldFgColour = con.get_color_fore()
|
||||
let oldBgColour = con.get_color_back()
|
||||
con.color_pair(231, 0)
|
||||
|
||||
// Split text into lines
|
||||
@@ -270,7 +270,7 @@ function displaySubtitle(text, position = 0) {
|
||||
displayFormattedLine(line)
|
||||
}
|
||||
|
||||
con.color_pair(oldFgColor, oldBgColor)
|
||||
con.color_pair(oldFgColour, oldBgColour)
|
||||
}
|
||||
|
||||
function processSubtitlePacket(packetSize) {
|
||||
@@ -454,7 +454,7 @@ console.log(`Wavelet filter: ${header.waveletFilter === WAVELET_5_3_REVERSIBLE ?
|
||||
console.log(`Decomposition levels: ${header.decompLevels}`)
|
||||
console.log(`Quality: Y=${header.qualityY}, Co=${header.qualityCo}, Cg=${header.qualityCg}`)
|
||||
console.log(`Tiles: ${tilesX}x${tilesY} (${numTiles} total)`)
|
||||
console.log(`Color space: ${header.version === 2 ? "ICtCp" : "YCoCg-R"}`)
|
||||
console.log(`Colour space: ${header.version === 2 ? "ICtCp" : "YCoCg-R"}`)
|
||||
console.log(`Features: ${hasAudio ? "Audio " : ""}${hasSubtitles ? "Subtitles " : ""}${progressiveTransmission ? "Progressive " : ""}${roiCoding ? "ROI " : ""}`)
|
||||
|
||||
// Frame buffer addresses - same as TEV
|
||||
@@ -559,7 +559,7 @@ let stopPlay = false
|
||||
let akku = FRAME_TIME
|
||||
let akku2 = 0.0
|
||||
|
||||
let blockDataPtr = sys.malloc(560*448*3)
|
||||
let blockDataPtr = sys.malloc(2377764)
|
||||
|
||||
// Playback loop - properly adapted from TEV
|
||||
try {
|
||||
@@ -613,6 +613,7 @@ try {
|
||||
}
|
||||
|
||||
try {
|
||||
// serial.println(actualSize)
|
||||
// Duplicate every 1000th frame if NTSC (same as TEV)
|
||||
if (!isNTSC || frameCount % 1000 != 501 || frameDuped) {
|
||||
frameDuped = false
|
||||
@@ -631,7 +632,7 @@ try {
|
||||
header.decompLevels, // TAV-specific parameter
|
||||
enableDeblocking,
|
||||
isLossless,
|
||||
header.version // TAV version for color space detection
|
||||
header.version // TAV version for colour space detection
|
||||
)
|
||||
|
||||
decodeTime = (sys.nanoTime() - decodeStart) / 1000000.0
|
||||
@@ -663,9 +664,10 @@ try {
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(`Frame ${frameCount}: decode failed: ${e}`)
|
||||
} finally {
|
||||
sys.free(compressedPtr)
|
||||
}
|
||||
|
||||
sys.free(compressedPtr)
|
||||
|
||||
let biasStart = sys.nanoTime()
|
||||
setBiasLighting()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,7 @@
|
||||
|
||||
// TSVM Advanced Video (TAV) format constants
|
||||
#define TAV_MAGIC "\x1F\x54\x53\x56\x4D\x54\x41\x56" // "\x1FTSVM TAV"
|
||||
// TAV version - dynamic based on color space mode
|
||||
// TAV version - dynamic based on colour space mode
|
||||
// Version 1: YCoCg-R (default)
|
||||
// Version 2: ICtCp (--ictcp flag)
|
||||
|
||||
@@ -40,15 +40,16 @@
|
||||
#define TAV_PACKET_SYNC 0xFF // Sync packet
|
||||
|
||||
// DWT settings
|
||||
#define TILE_SIZE 112 // 112x112 tiles - perfect fit for TSVM 560x448 (GCD = 112)
|
||||
#define MAX_DECOMP_LEVELS 6 // Can go deeper: 112→56→28→14→7→3→1
|
||||
#define DEFAULT_DECOMP_LEVELS 5 // Increased default for better compression
|
||||
#define TILE_SIZE_X 280 // 280x224 tiles - better compression efficiency
|
||||
#define TILE_SIZE_Y 224 // Optimized for TSVM 560x448 (2×2 tiles exactly)
|
||||
#define MAX_DECOMP_LEVELS 6 // Can go deeper: 280→140→70→35→17→8→4, 224→112→56→28→14→7→3
|
||||
|
||||
// Simulated overlapping tiles settings for seamless DWT processing
|
||||
#define DWT_FILTER_HALF_SUPPORT 4 // For 9/7 filter (filter lengths 9,7 → L=4)
|
||||
#define TILE_MARGIN_LEVELS 3 // Use margin for 3 levels: 4 * (2^3) = 4 * 8 = 32px
|
||||
#define TILE_MARGIN (DWT_FILTER_HALF_SUPPORT * (1 << TILE_MARGIN_LEVELS)) // 4 * 8 = 32px
|
||||
#define PADDED_TILE_SIZE (TILE_SIZE + 2 * TILE_MARGIN) // 112 + 64 = 176px
|
||||
#define PADDED_TILE_SIZE_X (TILE_SIZE_X + 2 * TILE_MARGIN) // 280 + 64 = 344px
|
||||
#define PADDED_TILE_SIZE_Y (TILE_SIZE_Y + 2 * TILE_MARGIN) // 224 + 64 = 288px
|
||||
|
||||
// Wavelet filter types
|
||||
#define WAVELET_5_3_REVERSIBLE 0 // Lossless capable
|
||||
@@ -166,7 +167,7 @@ typedef struct {
|
||||
int enable_roi;
|
||||
int verbose;
|
||||
int test_mode;
|
||||
int ictcp_mode; // 0 = YCoCg-R (default), 1 = ICtCp color space
|
||||
int ictcp_mode; // 0 = YCoCg-R (default), 1 = ICtCp colour space
|
||||
|
||||
// Frame buffers
|
||||
uint8_t *current_frame_rgb;
|
||||
@@ -216,7 +217,7 @@ static tav_encoder_t* create_encoder(void);
|
||||
static void cleanup_encoder(tav_encoder_t *enc);
|
||||
static int initialize_encoder(tav_encoder_t *enc);
|
||||
static void rgb_to_ycocg(const uint8_t *rgb, float *y, float *co, float *cg, int width, int height);
|
||||
static int estimate_motion_112x112(const float *current, const float *reference,
|
||||
static int estimate_motion_280x224(const float *current, const float *reference,
|
||||
int width, int height, int tile_x, int tile_y,
|
||||
motion_vector_t *mv);
|
||||
|
||||
@@ -246,7 +247,6 @@ static void show_usage(const char *program_name) {
|
||||
printf(" -q, --quality N Quality level 0-5 (default: 2)\n");
|
||||
printf(" -Q, --quantizer Y,Co,Cg Quantizer levels 0-100 for each channel\n");
|
||||
// printf(" -w, --wavelet N Wavelet filter: 0=5/3 reversible, 1=9/7 irreversible (default: 1)\n");
|
||||
// printf(" -d, --decomp N Decomposition levels 1-6 (default: %d)\n", DEFAULT_DECOMP_LEVELS);
|
||||
printf(" -b, --bitrate N Target bitrate in kbps (enables bitrate control mode)\n");
|
||||
printf(" -S, --subtitles FILE SubRip (.srt) or SAMI (.smi) subtitle file\n");
|
||||
printf(" -v, --verbose Verbose output\n");
|
||||
@@ -254,7 +254,7 @@ static void show_usage(const char *program_name) {
|
||||
printf(" --lossless Lossless mode: use 5/3 reversible wavelet\n");
|
||||
// printf(" --enable-progressive Enable progressive transmission\n");
|
||||
// printf(" --enable-roi Enable region-of-interest coding\n");
|
||||
printf(" --ictcp Use ICtCp color space instead of YCoCg-R (generates TAV version 2)\n");
|
||||
printf(" --ictcp Use ICtCp colour space instead of YCoCg-R (generates TAV version 2)\n");
|
||||
printf(" --help Show this help\n\n");
|
||||
|
||||
printf("Audio Rate by Quality:\n ");
|
||||
@@ -277,7 +277,7 @@ static void show_usage(const char *program_name) {
|
||||
|
||||
printf("\n\nFeatures:\n");
|
||||
printf(" - 112x112 DWT tiles with multi-resolution encoding\n");
|
||||
printf(" - Full resolution YCoCg-R/ICtCp color space\n");
|
||||
printf(" - Full resolution YCoCg-R/ICtCp colour space\n");
|
||||
// printf(" - Progressive transmission and ROI coding\n");
|
||||
// printf(" - Motion compensation with ±16 pixel search range\n");
|
||||
printf(" - Lossless and lossy compression modes\n");
|
||||
@@ -301,7 +301,7 @@ static tav_encoder_t* create_encoder(void) {
|
||||
enc->fps = DEFAULT_FPS;
|
||||
enc->quality_level = DEFAULT_QUALITY;
|
||||
enc->wavelet_filter = WAVELET_9_7_IRREVERSIBLE;
|
||||
enc->decomp_levels = DEFAULT_DECOMP_LEVELS;
|
||||
enc->decomp_levels = MAX_DECOMP_LEVELS;
|
||||
enc->quantizer_y = QUALITY_Y[DEFAULT_QUALITY];
|
||||
enc->quantizer_co = QUALITY_CO[DEFAULT_QUALITY];
|
||||
enc->quantizer_cg = QUALITY_CG[DEFAULT_QUALITY];
|
||||
@@ -314,8 +314,8 @@ static int initialize_encoder(tav_encoder_t *enc) {
|
||||
if (!enc) return -1;
|
||||
|
||||
// Calculate tile dimensions
|
||||
enc->tiles_x = (enc->width + TILE_SIZE - 1) / TILE_SIZE;
|
||||
enc->tiles_y = (enc->height + TILE_SIZE - 1) / TILE_SIZE;
|
||||
enc->tiles_x = (enc->width + TILE_SIZE_X - 1) / TILE_SIZE_X;
|
||||
enc->tiles_y = (enc->height + TILE_SIZE_Y - 1) / TILE_SIZE_Y;
|
||||
int num_tiles = enc->tiles_x * enc->tiles_y;
|
||||
|
||||
// Allocate frame buffers
|
||||
@@ -338,8 +338,8 @@ static int initialize_encoder(tav_encoder_t *enc) {
|
||||
enc->compressed_buffer_size = ZSTD_compressBound(1024 * 1024); // 1MB max
|
||||
enc->compressed_buffer = malloc(enc->compressed_buffer_size);
|
||||
|
||||
// OPTIMIZATION: Allocate reusable quantization buffers for padded tiles (176x176)
|
||||
const int padded_coeff_count = PADDED_TILE_SIZE * PADDED_TILE_SIZE;
|
||||
// OPTIMIZATION: Allocate reusable quantization buffers for padded tiles (344x288)
|
||||
const int padded_coeff_count = PADDED_TILE_SIZE_X * PADDED_TILE_SIZE_Y;
|
||||
enc->reusable_quantized_y = malloc(padded_coeff_count * sizeof(int16_t));
|
||||
enc->reusable_quantized_co = malloc(padded_coeff_count * sizeof(int16_t));
|
||||
enc->reusable_quantized_cg = malloc(padded_coeff_count * sizeof(int16_t));
|
||||
@@ -459,11 +459,11 @@ static void dwt_97_forward_1d(float *data, int length) {
|
||||
// Extract padded tile with margins for seamless DWT processing (correct implementation)
|
||||
static void extract_padded_tile(tav_encoder_t *enc, int tile_x, int tile_y,
|
||||
float *padded_y, float *padded_co, float *padded_cg) {
|
||||
const int core_start_x = tile_x * TILE_SIZE;
|
||||
const int core_start_y = tile_y * TILE_SIZE;
|
||||
const int core_start_x = tile_x * TILE_SIZE_X;
|
||||
const int core_start_y = tile_y * TILE_SIZE_Y;
|
||||
|
||||
// OPTIMIZATION: Process row by row with bulk copying for core region
|
||||
for (int py = 0; py < PADDED_TILE_SIZE; py++) {
|
||||
for (int py = 0; py < PADDED_TILE_SIZE_Y; py++) {
|
||||
// Map padded row to source image row
|
||||
int src_y = core_start_y + py - TILE_MARGIN;
|
||||
|
||||
@@ -473,30 +473,30 @@ static void extract_padded_tile(tav_encoder_t *enc, int tile_x, int tile_y,
|
||||
src_y = CLAMP(src_y, 0, enc->height - 1);
|
||||
|
||||
// Calculate source and destination row offsets
|
||||
const int padded_row_offset = py * PADDED_TILE_SIZE;
|
||||
const int padded_row_offset = py * PADDED_TILE_SIZE_X;
|
||||
const int src_row_offset = src_y * enc->width;
|
||||
|
||||
// Check if we can do bulk copying for the core region
|
||||
int core_start_px = TILE_MARGIN;
|
||||
int core_end_px = TILE_MARGIN + TILE_SIZE;
|
||||
int core_end_px = TILE_MARGIN + TILE_SIZE_X;
|
||||
|
||||
// Check if core region is entirely within frame bounds
|
||||
int core_src_start_x = core_start_x;
|
||||
int core_src_end_x = core_start_x + TILE_SIZE;
|
||||
int core_src_end_x = core_start_x + TILE_SIZE_X;
|
||||
|
||||
if (core_src_start_x >= 0 && core_src_end_x <= enc->width) {
|
||||
// OPTIMIZATION: Bulk copy core region (112 pixels) in one operation
|
||||
// OPTIMIZATION: Bulk copy core region (280 pixels) in one operation
|
||||
const int src_core_offset = src_row_offset + core_src_start_x;
|
||||
|
||||
memcpy(&padded_y[padded_row_offset + core_start_px],
|
||||
&enc->current_frame_y[src_core_offset],
|
||||
TILE_SIZE * sizeof(float));
|
||||
TILE_SIZE_X * sizeof(float));
|
||||
memcpy(&padded_co[padded_row_offset + core_start_px],
|
||||
&enc->current_frame_co[src_core_offset],
|
||||
TILE_SIZE * sizeof(float));
|
||||
TILE_SIZE_X * sizeof(float));
|
||||
memcpy(&padded_cg[padded_row_offset + core_start_px],
|
||||
&enc->current_frame_cg[src_core_offset],
|
||||
TILE_SIZE * sizeof(float));
|
||||
TILE_SIZE_X * sizeof(float));
|
||||
|
||||
// Handle margin pixels individually (left and right margins)
|
||||
for (int px = 0; px < core_start_px; px++) {
|
||||
@@ -512,7 +512,7 @@ static void extract_padded_tile(tav_encoder_t *enc, int tile_x, int tile_y,
|
||||
padded_cg[padded_idx] = enc->current_frame_cg[src_idx];
|
||||
}
|
||||
|
||||
for (int px = core_end_px; px < PADDED_TILE_SIZE; px++) {
|
||||
for (int px = core_end_px; px < PADDED_TILE_SIZE_X; px++) {
|
||||
int src_x = core_start_x + px - TILE_MARGIN;
|
||||
if (src_x >= enc->width) src_x = enc->width - 1 - (src_x - enc->width);
|
||||
src_x = CLAMP(src_x, 0, enc->width - 1);
|
||||
@@ -526,7 +526,7 @@ static void extract_padded_tile(tav_encoder_t *enc, int tile_x, int tile_y,
|
||||
}
|
||||
} else {
|
||||
// Fallback: process entire row pixel by pixel (for edge tiles)
|
||||
for (int px = 0; px < PADDED_TILE_SIZE; px++) {
|
||||
for (int px = 0; px < PADDED_TILE_SIZE_X; px++) {
|
||||
int src_x = core_start_x + px - TILE_MARGIN;
|
||||
|
||||
// Handle horizontal boundary conditions with mirroring
|
||||
@@ -546,47 +546,50 @@ static void extract_padded_tile(tav_encoder_t *enc, int tile_x, int tile_y,
|
||||
}
|
||||
|
||||
|
||||
// 2D DWT forward transform for padded tile
|
||||
// 2D DWT forward transform for rectangular padded tile (344x288)
|
||||
static void dwt_2d_forward_padded(float *tile_data, int levels, int filter_type) {
|
||||
const int size = PADDED_TILE_SIZE;
|
||||
float *temp_row = malloc(size * sizeof(float));
|
||||
float *temp_col = malloc(size * sizeof(float));
|
||||
const int width = PADDED_TILE_SIZE_X; // 344
|
||||
const int height = PADDED_TILE_SIZE_Y; // 288
|
||||
const int max_size = (width > height) ? width : height;
|
||||
float *temp_row = malloc(max_size * sizeof(float));
|
||||
float *temp_col = malloc(max_size * sizeof(float));
|
||||
|
||||
for (int level = 0; level < levels; level++) {
|
||||
int current_size = size >> level;
|
||||
if (current_size < 1) break;
|
||||
int current_width = width >> level;
|
||||
int current_height = height >> level;
|
||||
if (current_width < 1 || current_height < 1) break;
|
||||
|
||||
// Row transform
|
||||
for (int y = 0; y < current_size; y++) {
|
||||
for (int x = 0; x < current_size; x++) {
|
||||
temp_row[x] = tile_data[y * size + x];
|
||||
// Row transform (horizontal)
|
||||
for (int y = 0; y < current_height; y++) {
|
||||
for (int x = 0; x < current_width; x++) {
|
||||
temp_row[x] = tile_data[y * width + x];
|
||||
}
|
||||
|
||||
if (filter_type == WAVELET_5_3_REVERSIBLE) {
|
||||
dwt_53_forward_1d(temp_row, current_size);
|
||||
dwt_53_forward_1d(temp_row, current_width);
|
||||
} else {
|
||||
dwt_97_forward_1d(temp_row, current_size);
|
||||
dwt_97_forward_1d(temp_row, current_width);
|
||||
}
|
||||
|
||||
for (int x = 0; x < current_size; x++) {
|
||||
tile_data[y * size + x] = temp_row[x];
|
||||
for (int x = 0; x < current_width; x++) {
|
||||
tile_data[y * width + x] = temp_row[x];
|
||||
}
|
||||
}
|
||||
|
||||
// Column transform
|
||||
for (int x = 0; x < current_size; x++) {
|
||||
for (int y = 0; y < current_size; y++) {
|
||||
temp_col[y] = tile_data[y * size + x];
|
||||
// Column transform (vertical)
|
||||
for (int x = 0; x < current_width; x++) {
|
||||
for (int y = 0; y < current_height; y++) {
|
||||
temp_col[y] = tile_data[y * width + x];
|
||||
}
|
||||
|
||||
if (filter_type == WAVELET_5_3_REVERSIBLE) {
|
||||
dwt_53_forward_1d(temp_col, current_size);
|
||||
dwt_53_forward_1d(temp_col, current_height);
|
||||
} else {
|
||||
dwt_97_forward_1d(temp_col, current_size);
|
||||
dwt_97_forward_1d(temp_col, current_height);
|
||||
}
|
||||
|
||||
for (int y = 0; y < current_size; y++) {
|
||||
tile_data[y * size + x] = temp_col[y];
|
||||
for (int y = 0; y < current_height; y++) {
|
||||
tile_data[y * width + x] = temp_col[y];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -626,8 +629,8 @@ static size_t serialize_tile_data(tav_encoder_t *enc, int tile_x, int tile_y,
|
||||
return offset;
|
||||
}
|
||||
|
||||
// Quantize and serialize DWT coefficients (full padded tile: 176x176)
|
||||
const int tile_size = PADDED_TILE_SIZE * PADDED_TILE_SIZE;
|
||||
// Quantize and serialize DWT coefficients (full padded tile: 344x288)
|
||||
const int tile_size = PADDED_TILE_SIZE_X * PADDED_TILE_SIZE_Y;
|
||||
// OPTIMIZATION: Use pre-allocated buffers instead of malloc/free per tile
|
||||
int16_t *quantized_y = enc->reusable_quantized_y;
|
||||
int16_t *quantized_co = enc->reusable_quantized_co;
|
||||
@@ -669,8 +672,8 @@ static size_t serialize_tile_data(tav_encoder_t *enc, int tile_x, int tile_y,
|
||||
|
||||
// Compress and write frame data
|
||||
static size_t compress_and_write_frame(tav_encoder_t *enc, uint8_t packet_type) {
|
||||
// Calculate total uncompressed size (for padded tile coefficients: 176x176)
|
||||
const size_t max_tile_size = 9 + (PADDED_TILE_SIZE * PADDED_TILE_SIZE * 3 * sizeof(int16_t)); // header + 3 channels of coefficients
|
||||
// Calculate total uncompressed size (for padded tile coefficients: 344x288)
|
||||
const size_t max_tile_size = 9 + (PADDED_TILE_SIZE_X * PADDED_TILE_SIZE_Y * 3 * sizeof(int16_t)); // header + 3 channels of coefficients
|
||||
const size_t total_uncompressed_size = enc->tiles_x * enc->tiles_y * max_tile_size;
|
||||
|
||||
// Allocate buffer for uncompressed tile data
|
||||
@@ -685,12 +688,12 @@ static size_t compress_and_write_frame(tav_encoder_t *enc, uint8_t packet_type)
|
||||
// Determine tile mode (simplified)
|
||||
uint8_t mode = TAV_MODE_INTRA; // For now, all tiles are INTRA
|
||||
|
||||
// Extract padded tile data (176x176) with neighbor context for overlapping tiles
|
||||
float tile_y_data[PADDED_TILE_SIZE * PADDED_TILE_SIZE];
|
||||
float tile_co_data[PADDED_TILE_SIZE * PADDED_TILE_SIZE];
|
||||
float tile_cg_data[PADDED_TILE_SIZE * PADDED_TILE_SIZE];
|
||||
// Extract padded tile data (344x288) with neighbour context for overlapping tiles
|
||||
float tile_y_data[PADDED_TILE_SIZE_X * PADDED_TILE_SIZE_Y];
|
||||
float tile_co_data[PADDED_TILE_SIZE_X * PADDED_TILE_SIZE_Y];
|
||||
float tile_cg_data[PADDED_TILE_SIZE_X * PADDED_TILE_SIZE_Y];
|
||||
|
||||
// Extract padded tiles using context from neighbors
|
||||
// Extract padded tiles using context from neighbours
|
||||
extract_padded_tile(enc, tile_x, tile_y, tile_y_data, tile_co_data, tile_cg_data);
|
||||
|
||||
// Debug: check input data before DWT
|
||||
@@ -742,13 +745,14 @@ static size_t compress_and_write_frame(tav_encoder_t *enc, uint8_t packet_type)
|
||||
}
|
||||
|
||||
// Motion estimation for 112x112 tiles using SAD
|
||||
static int estimate_motion_112x112(const float *current, const float *reference,
|
||||
static int estimate_motion_280x224(const float *current, const float *reference,
|
||||
int width, int height, int tile_x, int tile_y,
|
||||
motion_vector_t *mv) {
|
||||
const int tile_size = TILE_SIZE;
|
||||
const int search_range = 28; // ±28 pixels (increased proportionally: 16 * 112/64 = 28)
|
||||
const int start_x = tile_x * tile_size;
|
||||
const int start_y = tile_y * tile_size;
|
||||
const int tile_size_x = TILE_SIZE_X;
|
||||
const int tile_size_y = TILE_SIZE_Y;
|
||||
const int search_range = 32; // ±32 pixels (scaled for larger tiles)
|
||||
const int start_x = tile_x * tile_size_x;
|
||||
const int start_y = tile_y * tile_size_y;
|
||||
|
||||
int best_mv_x = 0, best_mv_y = 0;
|
||||
int min_sad = INT_MAX;
|
||||
@@ -761,14 +765,14 @@ static int estimate_motion_112x112(const float *current, const float *reference,
|
||||
|
||||
// Check bounds
|
||||
if (ref_x < 0 || ref_y < 0 ||
|
||||
ref_x + tile_size > width || ref_y + tile_size > height) {
|
||||
ref_x + tile_size_x > width || ref_y + tile_size_y > height) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Calculate SAD
|
||||
int sad = 0;
|
||||
for (int y = 0; y < tile_size; y++) {
|
||||
for (int x = 0; x < tile_size; x++) {
|
||||
for (int y = 0; y < tile_size_y; y++) {
|
||||
for (int x = 0; x < tile_size_x; x++) {
|
||||
int curr_idx = (start_y + y) * width + (start_x + x);
|
||||
int ref_idx = (ref_y + y) * width + (ref_x + x);
|
||||
|
||||
@@ -795,7 +799,7 @@ static int estimate_motion_112x112(const float *current, const float *reference,
|
||||
return min_sad;
|
||||
}
|
||||
|
||||
// RGB to YCoCg color space conversion
|
||||
// RGB to YCoCg colour space conversion
|
||||
static void rgb_to_ycocg(const uint8_t *rgb, float *y, float *co, float *cg, int width, int height) {
|
||||
const int total_pixels = width * height;
|
||||
|
||||
@@ -815,7 +819,7 @@ static void rgb_to_ycocg(const uint8_t *rgb, float *y, float *co, float *cg, int
|
||||
const float g = rgb_ptr[j * 3 + 1];
|
||||
const float b = rgb_ptr[j * 3 + 2];
|
||||
|
||||
// YCoCg-R transform (optimized with fewer temporary variables)
|
||||
// YCoCg-R transform (optimised with fewer temporary variables)
|
||||
co[idx] = r - b;
|
||||
const float tmp = b + co[idx] * 0.5f;
|
||||
cg[idx] = g - tmp;
|
||||
@@ -963,16 +967,16 @@ void ictcp_hlg_to_srgb8(double I8, double Ct8, double Cp8,
|
||||
*b8 = (uint8_t)iround(FCLAMP(b * 255.0, 0.0, 255.0));
|
||||
}
|
||||
|
||||
// ---------------------- Color Space Switching Functions ----------------------
|
||||
// ---------------------- Colour Space Switching Functions ----------------------
|
||||
// Wrapper functions that choose between YCoCg-R and ICtCp based on encoder mode
|
||||
|
||||
static void rgb_to_color_space(tav_encoder_t *enc, uint8_t r, uint8_t g, uint8_t b,
|
||||
static void rgb_to_colour_space(tav_encoder_t *enc, uint8_t r, uint8_t g, uint8_t b,
|
||||
double *c1, double *c2, double *c3) {
|
||||
if (enc->ictcp_mode) {
|
||||
// Use ICtCp color space
|
||||
// Use ICtCp colour space
|
||||
srgb8_to_ictcp_hlg(r, g, b, c1, c2, c3);
|
||||
} else {
|
||||
// Use YCoCg-R color space (convert from existing function)
|
||||
// Use YCoCg-R colour space (convert from existing function)
|
||||
float rf = r, gf = g, bf = b;
|
||||
float co = rf - bf;
|
||||
float tmp = bf + co / 2;
|
||||
@@ -984,13 +988,13 @@ static void rgb_to_color_space(tav_encoder_t *enc, uint8_t r, uint8_t g, uint8_t
|
||||
}
|
||||
}
|
||||
|
||||
static void color_space_to_rgb(tav_encoder_t *enc, double c1, double c2, double c3,
|
||||
static void colour_space_to_rgb(tav_encoder_t *enc, double c1, double c2, double c3,
|
||||
uint8_t *r, uint8_t *g, uint8_t *b) {
|
||||
if (enc->ictcp_mode) {
|
||||
// Use ICtCp color space
|
||||
// Use ICtCp colour space
|
||||
ictcp_hlg_to_srgb8(c1, c2, c3, r, g, b);
|
||||
} else {
|
||||
// Use YCoCg-R color space (inverse of rgb_to_ycocg)
|
||||
// Use YCoCg-R colour space (inverse of rgb_to_ycocg)
|
||||
float y = (float)c1;
|
||||
float co = (float)c2;
|
||||
float cg = (float)c3;
|
||||
@@ -1004,8 +1008,8 @@ static void color_space_to_rgb(tav_encoder_t *enc, double c1, double c2, double
|
||||
}
|
||||
}
|
||||
|
||||
// RGB to color space conversion for full frames
|
||||
static void rgb_to_color_space_frame(tav_encoder_t *enc, const uint8_t *rgb,
|
||||
// RGB to colour space conversion for full frames
|
||||
static void rgb_to_colour_space_frame(tav_encoder_t *enc, const uint8_t *rgb,
|
||||
float *c1, float *c2, float *c3, int width, int height) {
|
||||
if (enc->ictcp_mode) {
|
||||
// ICtCp mode
|
||||
@@ -1029,7 +1033,7 @@ static int write_tav_header(tav_encoder_t *enc) {
|
||||
// Magic number
|
||||
fwrite(TAV_MAGIC, 1, 8, enc->output_fp);
|
||||
|
||||
// Version (dynamic based on color space)
|
||||
// Version (dynamic based on colour space)
|
||||
uint8_t version = enc->ictcp_mode ? 2 : 1; // Version 2 for ICtCp, 1 for YCoCg-R
|
||||
fputc(version, enc->output_fp);
|
||||
|
||||
@@ -1731,7 +1735,7 @@ int main(int argc, char *argv[]) {
|
||||
printf("Wavelet: %s\n", enc->wavelet_filter ? "9/7 irreversible" : "5/3 reversible");
|
||||
printf("Decomposition levels: %d\n", enc->decomp_levels);
|
||||
printf("Quality: Y=%d, Co=%d, Cg=%d\n", enc->quantizer_y, enc->quantizer_co, enc->quantizer_cg);
|
||||
printf("Color space: %s\n", enc->ictcp_mode ? "ICtCp" : "YCoCg-R");
|
||||
printf("Colour space: %s\n", enc->ictcp_mode ? "ICtCp" : "YCoCg-R");
|
||||
|
||||
// Open output file
|
||||
if (strcmp(enc->output_file, "-") == 0) {
|
||||
@@ -1747,7 +1751,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// Start FFmpeg process for video input (using TEV-compatible filtergraphs)
|
||||
if (enc->test_mode) {
|
||||
// Test mode - generate solid color frames
|
||||
// Test mode - generate solid colour frames
|
||||
enc->total_frames = 15; // Fixed 15 test frames like TEV
|
||||
printf("Test mode: Generating %d solid colour frames\n", enc->total_frames);
|
||||
} else {
|
||||
@@ -1877,8 +1881,8 @@ int main(int argc, char *argv[]) {
|
||||
printf("\n");
|
||||
}*/
|
||||
|
||||
// Convert RGB to color space (YCoCg-R or ICtCp)
|
||||
rgb_to_color_space_frame(enc, enc->current_frame_rgb,
|
||||
// Convert RGB to colour space (YCoCg-R or ICtCp)
|
||||
rgb_to_colour_space_frame(enc, enc->current_frame_rgb,
|
||||
enc->current_frame_y, enc->current_frame_co, enc->current_frame_cg,
|
||||
enc->width, enc->height);
|
||||
|
||||
@@ -1899,7 +1903,7 @@ int main(int argc, char *argv[]) {
|
||||
int tile_y = tile_idx / enc->tiles_x;
|
||||
|
||||
if (!is_keyframe && frame_count > 0) {
|
||||
estimate_motion_112x112(enc->current_frame_y, enc->previous_frame_y,
|
||||
estimate_motion_280x224(enc->current_frame_y, enc->previous_frame_y,
|
||||
enc->width, enc->height, tile_x, tile_y,
|
||||
&enc->motion_vectors[tile_idx]);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user