removing obsolete files

This commit is contained in:
minjaesong
2025-10-23 10:09:11 +09:00
parent 53da0bfcee
commit e147072d03
3 changed files with 0 additions and 3085 deletions

View File

@@ -1,815 +0,0 @@
// Created by CuriousTorvald and Claude on 2025-08-17.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <math.h>
#include <zlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <getopt.h>
#include <sys/time.h>
// TSVM Enhanced Video (TEV) format constants
#define TEV_MAGIC "\x1F\x54\x53\x56\x4D\x54\x45\x56" // "\x1FTSVM TEV"
#define TEV_VERSION 1
// Block encoding modes (8x8 blocks)
#define TEV_MODE_SKIP 0x00 // Skip block (copy from reference)
#define TEV_MODE_INTRA 0x01 // Intra DCT coding (I-frame blocks)
#define TEV_MODE_INTER 0x02 // Inter DCT coding with motion compensation
#define TEV_MODE_MOTION 0x03 // Motion vector only (good prediction)
// Video packet types
#define TEV_PACKET_IFRAME 0x10 // Intra frame (keyframe)
#define TEV_PACKET_PFRAME 0x11 // Predicted frame
#define TEV_PACKET_AUDIO_MP2 0x20 // MP2 audio
#define TEV_PACKET_SYNC 0xFF // Sync packet
// Quality settings for quantization
static const uint8_t QUANT_TABLES[8][64] = {
// Quality 0 (lowest)
{80, 60, 50, 80, 120, 200, 255, 255,
55, 60, 70, 95, 130, 255, 255, 255,
70, 65, 80, 120, 200, 255, 255, 255,
70, 85, 110, 145, 255, 255, 255, 255,
90, 110, 185, 255, 255, 255, 255, 255,
120, 175, 255, 255, 255, 255, 255, 255,
245, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255},
// Quality 1-6 (intermediate)...
{40, 30, 25, 40, 60, 100, 128, 150,
28, 30, 35, 48, 65, 128, 150, 180,
35, 33, 40, 60, 100, 128, 150, 180,
35, 43, 55, 73, 128, 150, 180, 200,
45, 55, 93, 128, 150, 180, 200, 220,
60, 88, 128, 150, 180, 200, 220, 240,
123, 128, 150, 180, 200, 220, 240, 250,
128, 150, 180, 200, 220, 240, 250, 255},
// ... (simplified for example)
{20, 15, 13, 20, 30, 50, 64, 75,
14, 15, 18, 24, 33, 64, 75, 90,
18, 17, 20, 30, 50, 64, 75, 90,
18, 22, 28, 37, 64, 75, 90, 100,
23, 28, 47, 64, 75, 90, 100, 110,
30, 44, 64, 75, 90, 100, 110, 120,
62, 64, 75, 90, 100, 110, 120, 125,
64, 75, 90, 100, 110, 120, 125, 128},
{16, 12, 10, 16, 24, 40, 51, 60,
11, 12, 14, 19, 26, 51, 60, 72,
14, 13, 16, 24, 40, 51, 60, 72,
14, 17, 22, 29, 51, 60, 72, 80,
18, 22, 37, 51, 60, 72, 80, 88,
24, 35, 51, 60, 72, 80, 88, 96,
49, 51, 60, 72, 80, 88, 96, 100,
51, 60, 72, 80, 88, 96, 100, 102},
{12, 9, 8, 12, 18, 30, 38, 45,
8, 9, 11, 14, 20, 38, 45, 54,
11, 10, 12, 18, 30, 38, 45, 54,
11, 13, 17, 22, 38, 45, 54, 60,
14, 17, 28, 38, 45, 54, 60, 66,
18, 26, 38, 45, 54, 60, 66, 72,
37, 38, 45, 54, 60, 66, 72, 75,
38, 45, 54, 60, 66, 72, 75, 77},
{10, 7, 6, 10, 15, 25, 32, 38,
7, 7, 9, 12, 16, 32, 38, 45,
9, 8, 10, 15, 25, 32, 38, 45,
9, 11, 14, 18, 32, 38, 45, 50,
12, 14, 23, 32, 38, 45, 50, 55,
15, 22, 32, 38, 45, 50, 55, 60,
31, 32, 38, 45, 50, 55, 60, 63,
32, 38, 45, 50, 55, 60, 63, 65},
{8, 6, 5, 8, 12, 20, 26, 30,
6, 6, 7, 10, 13, 26, 30, 36,
7, 7, 8, 12, 20, 26, 30, 36,
7, 9, 11, 15, 26, 30, 36, 40,
10, 11, 19, 26, 30, 36, 40, 44,
12, 17, 26, 30, 36, 40, 44, 48,
25, 26, 30, 36, 40, 44, 48, 50,
26, 30, 36, 40, 44, 48, 50, 52},
// Quality 7 (highest)
{2, 1, 1, 2, 3, 5, 6, 7,
1, 1, 1, 2, 3, 6, 7, 9,
1, 1, 2, 3, 5, 6, 7, 9,
1, 2, 3, 4, 6, 7, 9, 10,
2, 3, 5, 6, 7, 9, 10, 11,
3, 4, 6, 7, 9, 10, 11, 12,
6, 6, 7, 9, 10, 11, 12, 13,
6, 7, 9, 10, 11, 12, 13, 13}
};
// Audio constants (reuse MP2 from existing system)
#define MP2_SAMPLE_RATE 32000
#define MP2_DEFAULT_PACKET_SIZE 0x240
// Encoding parameters
#define MAX_MOTION_SEARCH 16
#define KEYFRAME_INTERVAL 30
#define BLOCK_SIZE 8
// Default values
#define DEFAULT_WIDTH 560
#define DEFAULT_HEIGHT 448
#define TEMP_AUDIO_FILE "/tmp/tev_temp_audio.mp2"
typedef struct __attribute__((packed)) {
uint8_t mode; // Block encoding mode
int16_t mv_x, mv_y; // Motion vector (1/4 pixel precision)
uint16_t cbp; // Coded block pattern (which 8x8 have non-zero coeffs)
int16_t dct_coeffs[3][64]; // Quantized DCT coefficients (R,G,B)
} tev_block_t;
typedef struct {
char *input_file;
char *output_file;
int width;
int height;
int fps;
int total_frames;
double duration;
int has_audio;
int output_to_stdout;
int quality; // 0-7, higher = better quality
// Frame buffers (8-bit RGB format for encoding)
uint8_t *current_rgb, *previous_rgb, *reference_rgb;
// Encoding workspace
uint8_t *rgb_workspace; // 8x8 RGB blocks (192 bytes)
float *dct_workspace; // DCT coefficients (192 floats)
tev_block_t *block_data; // Encoded block data
uint8_t *compressed_buffer; // Zstd output
// Audio handling
FILE *mp2_file;
int mp2_packet_size;
size_t audio_remaining;
uint8_t *mp2_buffer;
// Compression context
z_stream gzip_stream;
// FFmpeg processes
FILE *ffmpeg_video_pipe;
// Progress tracking
struct timeval start_time;
size_t total_output_bytes;
// Statistics
int blocks_skip, blocks_intra, blocks_inter, blocks_motion;
} tev_encoder_t;
// Quantize DCT coefficient using quality table
static int16_t quantize_coeff(float coeff, uint8_t quant, int is_dc) {
if (is_dc) {
// DC coefficient uses fixed quantizer
return (int16_t)roundf(coeff / 8.0f);
} else {
// AC coefficients use quality table
return (int16_t)roundf(coeff / quant);
}
}
// These functions are reserved for future rate-distortion optimization
// Currently using simplified encoding logic
// Convert RGB to 4096-color format
static void copy_rgb_frame(uint8_t *rgb_input, uint8_t *rgb_frame, int pixels) {
// Copy input RGB data to frame buffer (preserving full 8-bit precision)
memcpy(rgb_frame, rgb_input, pixels * 3);
}
// Simple motion estimation (full search)
static void estimate_motion(tev_encoder_t *enc, int block_x, int block_y,
int16_t *best_mv_x, int16_t *best_mv_y) {
int best_sad = INT_MAX;
*best_mv_x = 0;
*best_mv_y = 0;
int start_x = block_x * BLOCK_SIZE;
int start_y = block_y * BLOCK_SIZE;
// Search in range [-16, +16] pixels
for (int mv_y = -MAX_MOTION_SEARCH; mv_y <= MAX_MOTION_SEARCH; mv_y++) {
for (int mv_x = -MAX_MOTION_SEARCH; mv_x <= MAX_MOTION_SEARCH; mv_x++) {
int ref_x = start_x + mv_x;
int ref_y = start_y + mv_y;
// Check bounds
if (ref_x >= 0 && ref_y >= 0 &&
ref_x + BLOCK_SIZE <= enc->width &&
ref_y + BLOCK_SIZE <= enc->height) {
int sad = 0;
// Calculate Sum of Absolute Differences
for (int dy = 0; dy < BLOCK_SIZE; dy++) {
for (int dx = 0; dx < BLOCK_SIZE; dx++) {
int cur_offset = (start_y + dy) * enc->width + (start_x + dx);
int ref_offset = (ref_y + dy) * enc->width + (ref_x + dx);
int cur_r = enc->current_rgb[cur_offset * 3];
int cur_g = enc->current_rgb[cur_offset * 3 + 1];
int cur_b = enc->current_rgb[cur_offset * 3 + 2];
int ref_r = enc->previous_rgb[ref_offset * 3];
int ref_g = enc->previous_rgb[ref_offset * 3 + 1];
int ref_b = enc->previous_rgb[ref_offset * 3 + 2];
// SAD on 8-bit RGB channels
sad += abs(cur_r - ref_r) + abs(cur_g - ref_g) + abs(cur_b - ref_b);
}
}
if (sad < best_sad) {
best_sad = sad;
*best_mv_x = mv_x * 4; // Convert to 1/4 pixel units
*best_mv_y = mv_y * 4;
}
}
}
}
}
// Encode an 8x8 block using the best mode
static void encode_block(tev_encoder_t *enc, int block_x, int block_y, int is_keyframe) {
int block_idx = block_y * ((enc->width + 7) / 8) + block_x;
tev_block_t *block = &enc->block_data[block_idx];
int start_x = block_x * BLOCK_SIZE;
int start_y = block_y * BLOCK_SIZE;
// Extract 8x8 RGB block from current frame
for (int y = 0; y < BLOCK_SIZE; y++) {
for (int x = 0; x < BLOCK_SIZE; x++) {
int pixel_x = block_x * BLOCK_SIZE + x;
int pixel_y = block_y * BLOCK_SIZE + y;
int offset = (y * BLOCK_SIZE + x) * 3;
if (pixel_x < enc->width && pixel_y < enc->height) {
int frame_offset = pixel_y * enc->width + pixel_x;
// Copy RGB data directly (preserving full 8-bit precision)
enc->rgb_workspace[offset] = enc->current_rgb[frame_offset * 3]; // R
enc->rgb_workspace[offset + 1] = enc->current_rgb[frame_offset * 3 + 1]; // G
enc->rgb_workspace[offset + 2] = enc->current_rgb[frame_offset * 3 + 2]; // B
} else {
// Pad with black
enc->rgb_workspace[offset] = 0;
enc->rgb_workspace[offset + 1] = 0;
enc->rgb_workspace[offset + 2] = 0;
}
}
}
// Initialize block
memset(block, 0, sizeof(tev_block_t));
if (is_keyframe) {
// Keyframes use INTRA mode
block->mode = TEV_MODE_INTRA;
enc->blocks_intra++;
} else {
// Try different modes and pick the best
// Try SKIP mode - compare with previous frame
int skip_sad = 0;
for (int dy = 0; dy < BLOCK_SIZE; dy++) {
for (int dx = 0; dx < BLOCK_SIZE; dx++) {
int pixel_x = start_x + dx;
int pixel_y = start_y + dy;
if (pixel_x < enc->width && pixel_y < enc->height) {
int offset = pixel_y * enc->width + pixel_x;
int cur_r = enc->current_rgb[offset * 3];
int cur_g = enc->current_rgb[offset * 3 + 1];
int cur_b = enc->current_rgb[offset * 3 + 2];
int prev_r = enc->previous_rgb[offset * 3];
int prev_g = enc->previous_rgb[offset * 3 + 1];
int prev_b = enc->previous_rgb[offset * 3 + 2];
skip_sad += abs(cur_r - prev_r) + abs(cur_g - prev_g) + abs(cur_b - prev_b);
}
}
}
if (skip_sad < 8) { // Much stricter threshold for SKIP
block->mode = TEV_MODE_SKIP;
enc->blocks_skip++;
return;
}
// Try MOTION mode
estimate_motion(enc, block_x, block_y, &block->mv_x, &block->mv_y);
// Calculate motion compensation SAD
int motion_sad = 0;
for (int y = 0; y < BLOCK_SIZE; y++) {
for (int x = 0; x < BLOCK_SIZE; x++) {
int cur_x = block_x * BLOCK_SIZE + x;
int cur_y = block_y * BLOCK_SIZE + y;
int ref_x = cur_x + block->mv_x;
int ref_y = cur_y + block->mv_y;
if (cur_x < enc->width && cur_y < enc->height &&
ref_x >= 0 && ref_x < enc->width && ref_y >= 0 && ref_y < enc->height) {
int cur_offset = cur_y * enc->width + cur_x;
int ref_offset = ref_y * enc->width + ref_x;
uint8_t cur_r = enc->current_rgb[cur_offset * 3];
uint8_t cur_g = enc->current_rgb[cur_offset * 3 + 1];
uint8_t cur_b = enc->current_rgb[cur_offset * 3 + 2];
uint8_t ref_r = enc->previous_rgb[ref_offset * 3];
uint8_t ref_g = enc->previous_rgb[ref_offset * 3 + 1];
uint8_t ref_b = enc->previous_rgb[ref_offset * 3 + 2];
motion_sad += abs(cur_r - ref_r) + abs(cur_g - ref_g) + abs(cur_b - ref_b);
} else {
motion_sad += 48; // Penalty for out-of-bounds reference
}
}
}
// Decide on encoding mode based on analysis
if (motion_sad < 32 && (abs(block->mv_x) > 0 || abs(block->mv_y) > 0)) {
// Good motion prediction
block->mode = TEV_MODE_MOTION;
enc->blocks_motion++;
return; // Motion blocks don't need DCT coefficients
} else if (motion_sad < 64) {
// Use INTER mode (motion compensation + DCT residual)
block->mode = TEV_MODE_INTER;
enc->blocks_inter++;
} else {
// Fall back to INTRA mode
block->mode = TEV_MODE_INTRA;
enc->blocks_intra++;
}
}
// Full 8x8 DCT implementation for all blocks (keyframe and P-frame)
const uint8_t *quant_table = QUANT_TABLES[enc->quality];
// DCT-II basis functions (precomputed for 8x8)
static double dct_basis[8][8];
static int basis_initialized = 0;
if (!basis_initialized) {
for (int u = 0; u < 8; u++) {
for (int x = 0; x < 8; x++) {
double cu = (u == 0) ? sqrt(1.0/8.0) : sqrt(2.0/8.0);
dct_basis[u][x] = cu * cos((2.0 * x + 1.0) * u * M_PI / 16.0);
}
}
basis_initialized = 1;
}
// Convert RGB block to DCT input format (subtract 128 to center around 0)
double rgb_block[3][8][8];
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) {
int offset = (y * 8 + x) * 3;
rgb_block[0][y][x] = enc->rgb_workspace[offset] - 128.0; // R: 0-255 -> -128 to +127
rgb_block[1][y][x] = enc->rgb_workspace[offset + 1] - 128.0; // G: 0-255 -> -128 to +127
rgb_block[2][y][x] = enc->rgb_workspace[offset + 2] - 128.0; // B: 0-255 -> -128 to +127
}
}
// Apply 2D DCT to each channel
double dct_coeffs[3][8][8];
for (int channel = 0; channel < 3; channel++) {
for (int u = 0; u < 8; u++) {
for (int v = 0; v < 8; v++) {
double sum = 0.0;
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
sum += dct_basis[u][x] * dct_basis[v][y] * rgb_block[channel][y][x];
}
}
dct_coeffs[channel][u][v] = sum;
}
}
}
// Quantize and store DCT coefficients
for (int channel = 0; channel < 3; channel++) {
for (int u = 0; u < 8; u++) {
for (int v = 0; v < 8; v++) {
int coeff_index = u * 8 + v;
int is_dc = (coeff_index == 0);
block->dct_coeffs[channel][coeff_index] =
quantize_coeff(dct_coeffs[channel][u][v], quant_table[coeff_index], is_dc);
// Debug DC coefficient for first block
if (block_x == 0 && block_y == 0 && channel < 3 && coeff_index == 0) {
fprintf(stderr, "Ch%d: DCT raw=%.2f, stored=%d, ",
channel, dct_coeffs[channel][u][v], (int)block->dct_coeffs[channel][coeff_index]);
// Show raw bytes in memory
uint8_t *bytes = (uint8_t*)&block->dct_coeffs[channel][coeff_index];
fprintf(stderr, "bytes=[%d,%d]\n", bytes[0], bytes[1]);
}
}
}
}
}
// Execute command and capture output
static char *execute_command(const char *command) {
FILE *pipe = popen(command, "r");
if (!pipe) return NULL;
char *result = malloc(4096);
size_t len = fread(result, 1, 4095, pipe);
result[len] = '\0';
pclose(pipe);
return result;
}
// Get video metadata using ffprobe
static int get_video_metadata(tev_encoder_t *enc) {
char command[1024];
char *output;
// Get frame count
snprintf(command, sizeof(command),
"ffprobe -v quiet -select_streams v:0 -count_frames -show_entries stream=nb_read_frames -of csv=p=0 \"%s\"",
enc->input_file);
output = execute_command(command);
if (!output) {
fprintf(stderr, "Failed to get frame count\n");
return 0;
}
enc->total_frames = atoi(output);
free(output);
// Get frame rate
snprintf(command, sizeof(command),
"ffprobe -v quiet -select_streams v:0 -show_entries stream=r_frame_rate -of csv=p=0 \"%s\"",
enc->input_file);
output = execute_command(command);
if (!output) {
fprintf(stderr, "Failed to get frame rate\n");
return 0;
}
int num, den;
if (sscanf(output, "%d/%d", &num, &den) == 2) {
enc->fps = (den > 0) ? (num / den) : 30;
} else {
enc->fps = (int)round(atof(output));
}
free(output);
// Get duration
snprintf(command, sizeof(command),
"ffprobe -v quiet -show_entries format=duration -of csv=p=0 \"%s\"",
enc->input_file);
output = execute_command(command);
if (output) {
enc->duration = atof(output);
free(output);
}
// Check if has audio
snprintf(command, sizeof(command),
"ffprobe -v quiet -select_streams a:0 -show_entries stream=index -of csv=p=0 \"%s\"",
enc->input_file);
output = execute_command(command);
enc->has_audio = (output && strlen(output) > 0 && atoi(output) >= 0);
if (output) free(output);
if (enc->total_frames <= 0 && enc->duration > 0) {
enc->total_frames = (int)(enc->duration * enc->fps);
}
fprintf(stderr, "Video metadata:\n");
fprintf(stderr, " Frames: %d\n", enc->total_frames);
fprintf(stderr, " FPS: %d\n", enc->fps);
fprintf(stderr, " Duration: %.2fs\n", enc->duration);
fprintf(stderr, " Audio: %s\n", enc->has_audio ? "Yes" : "No");
fprintf(stderr, " Resolution: %dx%d\n", enc->width, enc->height);
return (enc->total_frames > 0 && enc->fps > 0);
}
// Start FFmpeg process for video conversion
static int start_video_conversion(tev_encoder_t *enc) {
char command[2048];
snprintf(command, sizeof(command),
"ffmpeg -i \"%s\" -f rawvideo -pix_fmt rgb24 -vf scale=%d:%d:force_original_aspect_ratio=increase,crop=%d:%d -y - 2>/dev/null",
enc->input_file, enc->width, enc->height, enc->width, enc->height);
enc->ffmpeg_video_pipe = popen(command, "r");
return (enc->ffmpeg_video_pipe != NULL);
}
// Start audio conversion
static int start_audio_conversion(tev_encoder_t *enc) {
if (!enc->has_audio) return 1;
char command[2048];
snprintf(command, sizeof(command),
"ffmpeg -i \"%s\" -acodec libtwolame -psymodel 4 -b:a 192k -ar %d -ac 2 -y \"%s\" 2>/dev/null",
enc->input_file, MP2_SAMPLE_RATE, TEMP_AUDIO_FILE);
int result = system(command);
if (result == 0) {
enc->mp2_file = fopen(TEMP_AUDIO_FILE, "rb");
if (enc->mp2_file) {
fseek(enc->mp2_file, 0, SEEK_END);
enc->audio_remaining = ftell(enc->mp2_file);
fseek(enc->mp2_file, 0, SEEK_SET);
return 1;
}
}
fprintf(stderr, "Warning: Failed to convert audio\n");
enc->has_audio = 0;
return 1;
}
// Write TEV header
static void write_tev_header(tev_encoder_t *enc, FILE *output) {
fwrite(TEV_MAGIC, 1, 8, output);
uint8_t version = TEV_VERSION;
fwrite(&version, 1, 1, output);
uint8_t flags = enc->has_audio ? 0x01 : 0x00;
fwrite(&flags, 1, 1, output);
fwrite(&enc->width, 2, 1, output);
fwrite(&enc->height, 2, 1, output);
fwrite(&enc->fps, 2, 1, output);
fwrite(&enc->total_frames, 4, 1, output);
uint8_t quality = enc->quality;
fwrite(&quality, 1, 1, output);
uint8_t reserved[5] = {0};
fwrite(reserved, 1, 5, output);
}
// Process and encode one frame
static int process_frame(tev_encoder_t *enc, int frame_num, FILE *output) {
// Read RGB data
size_t rgb_size = enc->width * enc->height * 3;
uint8_t *rgb_buffer = malloc(rgb_size);
if (fread(rgb_buffer, 1, rgb_size, enc->ffmpeg_video_pipe) != rgb_size) {
free(rgb_buffer);
return 0; // End of video
}
// Convert to 4096-color format
copy_rgb_frame(rgb_buffer, enc->current_rgb, enc->width * enc->height);
free(rgb_buffer);
int is_keyframe = (frame_num == 1) || (frame_num % KEYFRAME_INTERVAL == 0);
// Reset statistics
enc->blocks_skip = enc->blocks_intra = enc->blocks_inter = enc->blocks_motion = 0;
// Encode all 8x8 blocks
int blocks_x = (enc->width + 7) / 8;
int blocks_y = (enc->height + 7) / 8;
for (int by = 0; by < blocks_y; by++) {
for (int bx = 0; bx < blocks_x; bx++) {
encode_block(enc, bx, by, is_keyframe);
}
}
// Debug struct layout
fprintf(stderr, "Block size: %zu, DCT offset: %zu\n",
sizeof(tev_block_t), offsetof(tev_block_t, dct_coeffs));
// No endian conversion needed - system is already little-endian
// Compress block data using gzip
size_t block_data_size = blocks_x * blocks_y * sizeof(tev_block_t);
// Reset compression stream
enc->gzip_stream.next_in = (Bytef*)enc->block_data;
enc->gzip_stream.avail_in = block_data_size;
enc->gzip_stream.next_out = (Bytef*)enc->compressed_buffer;
enc->gzip_stream.avail_out = block_data_size * 2;
if (deflateReset(&enc->gzip_stream) != Z_OK) {
fprintf(stderr, "Gzip deflateReset failed\n");
return -1;
}
int result = deflate(&enc->gzip_stream, Z_FINISH);
if (result != Z_STREAM_END) {
fprintf(stderr, "Gzip compression failed: %d\n", result);
return -1;
}
size_t compressed_size = enc->gzip_stream.total_out;
// Write video packet
uint8_t packet_type[2] = {is_keyframe ? TEV_PACKET_IFRAME : TEV_PACKET_PFRAME, 0x00};
fwrite(packet_type, 1, 2, output);
uint32_t size = (uint32_t)compressed_size;
fwrite(&size, 4, 1, output);
fwrite(enc->compressed_buffer, 1, compressed_size, output);
// Write sync packet
uint8_t sync[2] = {0xFF, 0xFF};
fwrite(sync, 1, 2, output);
enc->total_output_bytes += 2 + 4 + compressed_size + 2;
// Swap frame buffers for next frame
uint8_t *temp_rgb = enc->previous_rgb;
enc->previous_rgb = enc->current_rgb;
enc->current_rgb = temp_rgb;
fprintf(stderr, "\rFrame %d/%d [%c] - Skip:%d Intra:%d Inter:%d - Ratio:%.1f%%",
frame_num, enc->total_frames, is_keyframe ? 'I' : 'P',
enc->blocks_skip, enc->blocks_intra, enc->blocks_inter,
(compressed_size * 100.0) / block_data_size);
fflush(stderr);
return 1;
}
// Initialize encoder
static tev_encoder_t *init_encoder() {
tev_encoder_t *enc = calloc(1, sizeof(tev_encoder_t));
if (!enc) return NULL;
enc->width = DEFAULT_WIDTH;
enc->height = DEFAULT_HEIGHT;
enc->quality = 5; // Default quality
enc->output_to_stdout = 1;
return enc;
}
// Allocate buffers
static int allocate_buffers(tev_encoder_t *enc) {
int pixels = enc->width * enc->height;
int blocks = ((enc->width + 7) / 8) * ((enc->height + 7) / 8);
enc->current_rgb = malloc(pixels * 3); // RGB: 3 bytes per pixel
enc->previous_rgb = malloc(pixels * 3);
enc->reference_rgb = malloc(pixels * 3);
enc->rgb_workspace = malloc(BLOCK_SIZE * BLOCK_SIZE * 3);
enc->dct_workspace = malloc(BLOCK_SIZE * BLOCK_SIZE * 3 * sizeof(float));
enc->block_data = malloc(blocks * sizeof(tev_block_t));
enc->compressed_buffer = malloc(blocks * sizeof(tev_block_t) * 2);
enc->mp2_buffer = malloc(2048);
// Initialize gzip compression stream
enc->gzip_stream.zalloc = Z_NULL;
enc->gzip_stream.zfree = Z_NULL;
enc->gzip_stream.opaque = Z_NULL;
int gzip_init_result = deflateInit2(&enc->gzip_stream, Z_DEFAULT_COMPRESSION,
Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); // 15+16 for gzip format
return (enc->current_rgb && enc->previous_rgb && enc->reference_rgb &&
enc->rgb_workspace && enc->dct_workspace && enc->block_data && enc->compressed_buffer &&
enc->mp2_buffer && gzip_init_result == Z_OK);
}
// Cleanup
static void cleanup_encoder(tev_encoder_t *enc) {
if (!enc) return;
if (enc->ffmpeg_video_pipe) pclose(enc->ffmpeg_video_pipe);
if (enc->mp2_file) fclose(enc->mp2_file);
deflateEnd(&enc->gzip_stream);
free(enc->input_file);
free(enc->output_file);
free(enc->current_rgb);
free(enc->previous_rgb);
free(enc->reference_rgb);
free(enc->rgb_workspace);
free(enc->dct_workspace);
free(enc->block_data);
free(enc->compressed_buffer);
free(enc->mp2_buffer);
unlink(TEMP_AUDIO_FILE);
free(enc);
}
// Print usage
static void print_usage(const char *program_name) {
printf("TSVM Enhanced Video (TEV) Encoder\n\n");
printf("Usage: %s [options] input_video\n\n", program_name);
printf("Options:\n");
printf(" -o, --output FILE Output TEV file (default: stdout)\n");
printf(" -s, --size WxH Video resolution (default: 560x448)\n");
printf(" -q, --quality N Quality level 0-7 (default: 5)\n");
printf(" -h, --help Show this help\n\n");
printf("TEV Features:\n");
printf(" - 8x8 DCT-based compression with motion compensation\n");
printf(" - Native 4096-color support (4:4:4 RGB)\n");
printf(" - Zstd compression for optimal efficiency\n");
printf(" - Hardware-accelerated encoding functions\n\n");
printf("Examples:\n");
printf(" %s input.mp4 -o output.tev\n", program_name);
printf(" %s input.avi -s 1024x768 -q 7 -o output.tev\n", program_name);
}
int main(int argc, char *argv[]) {
tev_encoder_t *enc = init_encoder();
if (!enc) {
fprintf(stderr, "Failed to initialize encoder\n");
return 1;
}
// Parse arguments
static struct option long_options[] = {
{"output", required_argument, 0, 'o'},
{"size", required_argument, 0, 's'},
{"quality", required_argument, 0, 'q'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
int c;
while ((c = getopt_long(argc, argv, "o:s:q:h", long_options, NULL)) != -1) {
switch (c) {
case 'o':
enc->output_file = strdup(optarg);
enc->output_to_stdout = 0;
break;
case 's':
if (sscanf(optarg, "%dx%d", &enc->width, &enc->height) != 2) {
fprintf(stderr, "Invalid resolution: %s\n", optarg);
cleanup_encoder(enc);
return 1;
}
break;
case 'q':
enc->quality = atoi(optarg);
if (enc->quality < 0 || enc->quality > 7) {
fprintf(stderr, "Quality must be 0-7\n");
cleanup_encoder(enc);
return 1;
}
break;
case 'h':
print_usage(argv[0]);
cleanup_encoder(enc);
return 0;
default:
print_usage(argv[0]);
cleanup_encoder(enc);
return 1;
}
}
if (optind >= argc) {
fprintf(stderr, "Input file required\n");
print_usage(argv[0]);
cleanup_encoder(enc);
return 1;
}
enc->input_file = strdup(argv[optind]);
// Initialize
if (!get_video_metadata(enc) || !allocate_buffers(enc) ||
!start_video_conversion(enc) || !start_audio_conversion(enc)) {
cleanup_encoder(enc);
return 1;
}
FILE *output = enc->output_to_stdout ? stdout : fopen(enc->output_file, "wb");
if (!output) {
fprintf(stderr, "Failed to open output\n");
cleanup_encoder(enc);
return 1;
}
write_tev_header(enc, output);
gettimeofday(&enc->start_time, NULL);
enc->total_output_bytes = 8 + 1 + 1 + 2 + 2 + 2 + 4 + 1 + 5; // TEV header size
// Process all frames
for (int frame = 1; frame <= enc->total_frames; frame++) {
int result = process_frame(enc, frame, output);
if (result <= 0) break;
}
fprintf(stderr, "\nEncoding complete\n");
if (!enc->output_to_stdout) {
fclose(output);
fprintf(stderr, "Output: %s (%.1f MB)\n", enc->output_file,
enc->total_output_bytes / (1024.0 * 1024.0));
}
cleanup_encoder(enc);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,200 +0,0 @@
// XYB Color Space Conversion Functions for TEV
// Based on JPEG XL XYB specification with proper sRGB linearization
// test with:
//// gcc -DXYB_TEST_MAIN -o test_xyb xyb_conversion.c -lm && ./test_xyb
#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#define CLAMP(x, min, max) ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x)))
// XYB conversion constants from JPEG XL specification
static const double XYB_BIAS = 0.00379307325527544933;
static const double CBRT_BIAS = 0.155954200549248620; // cbrt(XYB_BIAS)
// RGB to LMS mixing coefficients
static const double RGB_TO_LMS[3][3] = {
{0.3, 0.622, 0.078}, // L coefficients
{0.23, 0.692, 0.078}, // M coefficients
{0.24342268924547819, 0.20476744424496821, 0.55180986650955360} // S coefficients
};
// LMS to RGB inverse matrix (calculated via matrix inversion)
static const double LMS_TO_RGB[3][3] = {
{11.0315669046, -9.8669439081, -0.1646229965},
{-3.2541473811, 4.4187703776, -0.1646229965},
{-3.6588512867, 2.7129230459, 1.9459282408}
};
// sRGB linearization (0..1 range)
static inline double srgb_linearize(double val) {
if (val > 0.04045) {
return pow((val + 0.055) / 1.055, 2.4);
} else {
return val / 12.92;
}
}
// sRGB unlinearization (0..1 range)
static inline double srgb_unlinearize(double val) {
if (val > 0.0031308) {
return 1.055 * pow(val, 1.0 / 2.4) - 0.055;
} else {
return val * 12.92;
}
}
// Fast cube root approximation for performance
static inline double fast_cbrt(double x) {
if (x < 0) return -cbrt(-x);
return cbrt(x);
}
// RGB to XYB conversion with proper sRGB linearization
void rgb_to_xyb(uint8_t r, uint8_t g, uint8_t b, double *x, double *y, double *xyb_b) {
// Convert RGB to 0-1 range and linearize sRGB
double r_norm = srgb_linearize(r / 255.0);
double g_norm = srgb_linearize(g / 255.0);
double b_norm = srgb_linearize(b / 255.0);
// RGB to LMS mixing with bias
double lmix = RGB_TO_LMS[0][0] * r_norm + RGB_TO_LMS[0][1] * g_norm + RGB_TO_LMS[0][2] * b_norm + XYB_BIAS;
double mmix = RGB_TO_LMS[1][0] * r_norm + RGB_TO_LMS[1][1] * g_norm + RGB_TO_LMS[1][2] * b_norm + XYB_BIAS;
double smix = RGB_TO_LMS[2][0] * r_norm + RGB_TO_LMS[2][1] * g_norm + RGB_TO_LMS[2][2] * b_norm + XYB_BIAS;
// Apply gamma correction (cube root)
double lgamma = fast_cbrt(lmix) - CBRT_BIAS;
double mgamma = fast_cbrt(mmix) - CBRT_BIAS;
double sgamma = fast_cbrt(smix) - CBRT_BIAS;
// LMS to XYB transformation
*x = (lgamma - mgamma) / 2.0;
*y = (lgamma + mgamma) / 2.0;
*xyb_b = sgamma;
}
// XYB to RGB conversion with proper sRGB unlinearization
void xyb_to_rgb(double x, double y, double xyb_b, uint8_t *r, uint8_t *g, uint8_t *b) {
// XYB to LMS gamma
double lgamma = x + y;
double mgamma = y - x;
double sgamma = xyb_b;
// Remove gamma correction
double lmix = pow(lgamma + CBRT_BIAS, 3.0) - XYB_BIAS;
double mmix = pow(mgamma + CBRT_BIAS, 3.0) - XYB_BIAS;
double smix = pow(sgamma + CBRT_BIAS, 3.0) - XYB_BIAS;
// LMS to linear RGB using inverse matrix
double r_linear = LMS_TO_RGB[0][0] * lmix + LMS_TO_RGB[0][1] * mmix + LMS_TO_RGB[0][2] * smix;
double g_linear = LMS_TO_RGB[1][0] * lmix + LMS_TO_RGB[1][1] * mmix + LMS_TO_RGB[1][2] * smix;
double b_linear = LMS_TO_RGB[2][0] * lmix + LMS_TO_RGB[2][1] * mmix + LMS_TO_RGB[2][2] * smix;
// Clamp linear RGB to valid range
r_linear = CLAMP(r_linear, 0.0, 1.0);
g_linear = CLAMP(g_linear, 0.0, 1.0);
b_linear = CLAMP(b_linear, 0.0, 1.0);
// Convert back to sRGB gamma and 0-255 range
*r = CLAMP((int)(srgb_unlinearize(r_linear) * 255.0 + 0.5), 0, 255);
*g = CLAMP((int)(srgb_unlinearize(g_linear) * 255.0 + 0.5), 0, 255);
*b = CLAMP((int)(srgb_unlinearize(b_linear) * 255.0 + 0.5), 0, 255);
}
// Convert RGB to XYB with integer quantization suitable for TEV format
void rgb_to_xyb_quantized(uint8_t r, uint8_t g, uint8_t b, int *x_quant, int *y_quant, int *b_quant) {
double x, y, xyb_b;
rgb_to_xyb(r, g, b, &x, &y, &xyb_b);
// Quantize to suitable integer ranges for TEV
// Y channel: 0-255 (similar to current Y in YCoCg)
*y_quant = CLAMP((int)(y * 255.0 + 128.0), 0, 255);
// X channel: -128 to +127 (similar to Co range)
*x_quant = CLAMP((int)(x * 255.0), -128, 127);
// B channel: -128 to +127 (similar to Cg, can be aggressively quantized)
*b_quant = CLAMP((int)(xyb_b * 255.0), -128, 127);
}
// Test function to verify conversion accuracy
int test_xyb_conversion() {
printf("Testing XYB conversion accuracy with sRGB linearization...\n");
// Test with various RGB values
uint8_t test_colors[][3] = {
{255, 0, 0}, // Red
{0, 255, 0}, // Green
{0, 0, 255}, // Blue
{255, 255, 255}, // White
{0, 0, 0}, // Black
{128, 128, 128}, // Gray
{255, 255, 0}, // Yellow
{255, 0, 255}, // Magenta
{0, 255, 255}, // Cyan
// MacBeth chart colours converted to sRGB
{0x73,0x52,0x44},
{0xc2,0x96,0x82},
{0x62,0x7a,0x9d},
{0x57,0x6c,0x43},
{0x85,0x80,0xb1},
{0x67,0xbd,0xaa},
{0xd6,0x7e,0x2c},
{0x50,0x5b,0xa6},
{0xc1,0x5a,0x63},
{0x5e,0x3c,0x6c},
{0x9d,0xbc,0x40},
{0xe0,0xa3,0x2e},
{0x38,0x3d,0x96},
{0x46,0x94,0x49},
{0xaf,0x36,0x3c},
{0xe7,0xc7,0x1f},
{0xbb,0x56,0x95},
{0x08,0x85,0xa1},
{0xf3,0xf3,0xf3},
{0xc8,0xc8,0xc8},
{0xa0,0xa0,0xa0},
{0x7a,0x7a,0x7a},
{0x55,0x55,0x55},
{0x34,0x34,0x34}
};
int num_tests = sizeof(test_colors) / sizeof(test_colors[0]);
int errors = 0;
for (int i = 0; i < num_tests; i++) {
uint8_t r_orig = test_colors[i][0];
uint8_t g_orig = test_colors[i][1];
uint8_t b_orig = test_colors[i][2];
double x, y, xyb_b;
uint8_t r_conv, g_conv, b_conv;
// Forward and reverse conversion
rgb_to_xyb(r_orig, g_orig, b_orig, &x, &y, &xyb_b);
xyb_to_rgb(x, y, xyb_b, &r_conv, &g_conv, &b_conv);
// Check accuracy (allow small rounding errors)
int r_error = abs((int)r_orig - (int)r_conv);
int g_error = abs((int)g_orig - (int)g_conv);
int b_error = abs((int)b_orig - (int)b_conv);
printf("RGB(%3d,%3d,%3d) -> XYB(%6.3f,%6.3f,%6.3f) -> RGB(%3d,%3d,%3d) [Error: %d,%d,%d]\n",
r_orig, g_orig, b_orig, x, y, xyb_b, r_conv, g_conv, b_conv, r_error, g_error, b_error);
if (r_error > 2 || g_error > 2 || b_error > 2) {
errors++;
}
}
printf("Test completed: %d/%d passed\n", num_tests - errors, num_tests);
return errors == 0;
}
#ifdef XYB_TEST_MAIN
int main() {
return test_xyb_conversion() ? 0 : 1;
}
#endif