mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-15 23:46:06 +09:00
TAV: TAD integration wip
This commit is contained in:
@@ -19,14 +19,28 @@
|
||||
#define TAD32_QUALITY_DEFAULT 3
|
||||
#define TAD32_ZSTD_LEVEL 15
|
||||
|
||||
/**
|
||||
* Convert quality level (0-5) to max_index for quantization
|
||||
* Quality 0 = very low quality, small file (max_index=7, 3-bit)
|
||||
* Quality 1 = low quality (max_index=15, 4-bit)
|
||||
* Quality 2 = medium quality (max_index=31, 5-bit)
|
||||
* Quality 3 = good quality (max_index=63, 6-bit) [DEFAULT]
|
||||
* Quality 4 = high quality (max_index=127, 7-bit)
|
||||
* Quality 5 = very high quality (max_index=255, 8-bit)
|
||||
*/
|
||||
static inline int tad32_quality_to_max_index(int quality) {
|
||||
static const int quality_map[6] = {31, 35, 39, 47, 56, 89};
|
||||
if (quality < 0) quality = 0;
|
||||
if (quality > 5) quality = 5;
|
||||
return quality_map[quality];
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode audio chunk with TAD32 codec (PCM32f version)
|
||||
*
|
||||
* @param pcm32_stereo Input PCM32fLE stereo samples (interleaved L,R)
|
||||
* @param num_samples Number of samples per channel (min 1024)
|
||||
* @param quant_bits Quantization bits 4-12 (default: 7)
|
||||
* @param use_zstd 1=enable Zstd compression, 0=disable
|
||||
* @param use_twobitmap 1=enable twobitmap encoding, 0=raw int8_t storage
|
||||
* @param max_index Maximum quantization index (7=3bit, 15=4bit, 31=5bit, 63=6bit, 127=7bit)
|
||||
* @param quantiser_scale Quantiser scaling factor (1.0=baseline, 2.0=2x coarser quantization)
|
||||
* Higher values = more aggressive quantization = smaller files
|
||||
* @param output Output buffer (must be large enough)
|
||||
@@ -34,12 +48,12 @@
|
||||
*
|
||||
* Output format:
|
||||
* uint16 sample_count (samples per channel)
|
||||
* uint8 quant_bits (quantization bits used)
|
||||
* uint8 max_index (maximum quantization index)
|
||||
* uint32 payload_size (bytes in payload)
|
||||
* * payload (encoded M/S data, optionally Zstd-compressed)
|
||||
* * payload (encoded M/S data, Zstd-compressed with 2-bit twobitmap)
|
||||
*/
|
||||
size_t tad32_encode_chunk(const float *pcm32_stereo, size_t num_samples,
|
||||
int quant_bits,
|
||||
int max_index,
|
||||
float quantiser_scale, uint8_t *output);
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,13 +48,11 @@ static void print_usage(const char *prog_name) {
|
||||
printf("Options:\n");
|
||||
printf(" -i <file> Input audio file (any format supported by FFmpeg)\n");
|
||||
printf(" -o <file> Output TAD32 file (optional, auto-generated as input.qN.tad)\n");
|
||||
printf(" -q <bits> Quantization bits (default: 7, range: 4-8)\n");
|
||||
printf(" -q <bits> Positive side quantization steps (default: 47, range: up to 127)\n");
|
||||
printf(" Higher = more precision, larger files\n");
|
||||
printf(" -s <scale> Quantiser scaling factor (default: 1.0, range: 0.5-4.0)\n");
|
||||
printf(" Higher = more aggressive quantization, smaller files\n");
|
||||
printf(" 2.0 = quantize 2x coarser than baseline\n");
|
||||
printf(" --no-zstd Disable Zstd compression\n");
|
||||
printf(" --no-twobitmap Disable twobitmap encoding (use raw int8_t storage)\n");
|
||||
printf(" -v Verbose output\n");
|
||||
printf(" -h, --help Show this help\n");
|
||||
printf("\nVersion: %s\n", ENCODER_VENDOR_STRING);
|
||||
@@ -67,7 +65,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
char *input_file = NULL;
|
||||
char *output_file = NULL;
|
||||
int max_index = 7; // Default QUANT_BITS
|
||||
int max_index = 47; // Default QUANT_BITS
|
||||
float quantiser_scale = 1.0f; // Default quantiser scaling
|
||||
int verbose = 0;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
|
||||
#define ENCODER_VENDOR_STRING "Encoder-TAV 20251024 (3d-dwt,tad)"
|
||||
#define ENCODER_VENDOR_STRING "Encoder-TAV 20251030 (3d-dwt,tad)"
|
||||
|
||||
// TSVM Advanced Video (TAV) format constants
|
||||
#define TAV_MAGIC "\x1F\x54\x53\x56\x4D\x54\x41\x56" // "\x1FTSVM TAV"
|
||||
@@ -8996,11 +8996,15 @@ static int write_tad_packet_samples(tav_encoder_t *enc, FILE *output, int sample
|
||||
if (tad_quality > TAD32_QUALITY_MAX) tad_quality = TAD32_QUALITY_MAX;
|
||||
if (tad_quality < TAD32_QUALITY_MIN) tad_quality = TAD32_QUALITY_MIN;
|
||||
|
||||
// Convert quality (0-5) to max_index for quantization
|
||||
int max_index = tad32_quality_to_max_index(tad_quality);
|
||||
float quantiser_scale = 1.0f; // Baseline quantizer scaling
|
||||
|
||||
// Allocate output buffer (generous size for TAD chunk)
|
||||
size_t max_output_size = samples_to_read * 4 * sizeof(int16_t) + 1024;
|
||||
uint8_t *tad_output = malloc(max_output_size);
|
||||
|
||||
size_t tad_encoded_size = tad32_encode_chunk(pcm32_buffer, samples_to_read, tad_quality, 1, tad_output);
|
||||
size_t tad_encoded_size = tad32_encode_chunk(pcm32_buffer, samples_to_read, max_index, quantiser_scale, tad_output);
|
||||
|
||||
if (tad_encoded_size == 0) {
|
||||
fprintf(stderr, "Error: TAD32 encoding failed\n");
|
||||
@@ -9009,10 +9013,12 @@ static int write_tad_packet_samples(tav_encoder_t *enc, FILE *output, int sample
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Parse TAD chunk format: [sample_count][payload_size][payload]
|
||||
// Parse TAD chunk format: [sample_count][quantisation index][payload_size][payload]
|
||||
uint8_t *read_ptr = tad_output;
|
||||
uint16_t sample_count = *((uint16_t*)read_ptr);
|
||||
read_ptr += sizeof(uint16_t);
|
||||
uint8_t quant_size = *((uint8_t*)read_ptr);
|
||||
read_ptr += sizeof(uint8_t);
|
||||
uint32_t tad_payload_size = *((uint32_t*)read_ptr);
|
||||
read_ptr += sizeof(uint32_t);
|
||||
uint8_t *tad_payload = read_ptr;
|
||||
@@ -9022,10 +9028,11 @@ static int write_tad_packet_samples(tav_encoder_t *enc, FILE *output, int sample
|
||||
fwrite(&packet_type, 1, 1, output);
|
||||
|
||||
uint32_t tav_payload_size = (uint32_t)tad_payload_size;
|
||||
uint32_t tav_payload_size_plus_6 = (uint32_t)tad_payload_size + 6;
|
||||
uint32_t tav_payload_size_plus_6 = (uint32_t)tad_payload_size + 7;
|
||||
fwrite(&sample_count, sizeof(uint16_t), 1, output);
|
||||
fwrite(&tav_payload_size_plus_6, sizeof(uint32_t), 1, output);
|
||||
fwrite(&sample_count, sizeof(uint16_t), 1, output);
|
||||
fwrite(&quant_size, sizeof(uint8_t), 1, output);
|
||||
fwrite(&tav_payload_size, sizeof(uint32_t), 1, output);
|
||||
fwrite(tad_payload, 1, tad_payload_size, output);
|
||||
|
||||
@@ -10579,10 +10586,12 @@ int main(int argc, char *argv[]) {
|
||||
break;
|
||||
case 1027: // --pcm8-audio
|
||||
enc->pcm8_audio = 1;
|
||||
enc->tad_audio = 0;
|
||||
printf("8-bit PCM audio mode enabled (packet 0x21)\n");
|
||||
break;
|
||||
case 1028: // --tad-audio
|
||||
enc->tad_audio = 1;
|
||||
enc->pcm8_audio = 0;
|
||||
printf("TAD audio mode enabled (packet 0x24, quality follows -q)\n");
|
||||
break;
|
||||
case 1050: // --single-pass
|
||||
@@ -10659,7 +10668,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// if temporal-dwt is used, and user did not select suitable audio codec, force PCMu8 (or TAD when it's production-ready)
|
||||
if (enc->enable_temporal_dwt && !enc->pcm8_audio && !enc->tad_audio) {
|
||||
enc->pcm8_audio = 1; // TODO replace with tad_audio when it's production-ready
|
||||
enc->tad_audio = 1;
|
||||
}
|
||||
|
||||
if ((!enc->input_file && !enc->test_mode) || !enc->output_file) {
|
||||
|
||||
@@ -738,14 +738,23 @@ static const char* VERDESC[] = {"null", "YCoCg tiled, uniform", "ICtCp tiled, un
|
||||
case TAV_PACKET_AUDIO_TAD: {
|
||||
stats.audio_count++;
|
||||
stats.audio_tad_count++;
|
||||
// Read payload_size + 2
|
||||
uint32_t payload_size_plus_6;
|
||||
if (fread(&payload_size_plus_6, sizeof(uint32_t), 1, fp) != 1) break;
|
||||
|
||||
// Read sample count
|
||||
uint16_t sample_count0;
|
||||
if (fread(&sample_count0, sizeof(uint16_t), 1, fp) != 1) break;
|
||||
|
||||
// Read payload_size + 7
|
||||
uint32_t payload_size_plus_7;
|
||||
if (fread(&payload_size_plus_7, sizeof(uint32_t), 1, fp) != 1) break;
|
||||
|
||||
// Read sample count
|
||||
uint16_t sample_count;
|
||||
if (fread(&sample_count, sizeof(uint16_t), 1, fp) != 1) break;
|
||||
|
||||
// Read quantiser index
|
||||
uint8_t quantiser;
|
||||
if (fread(&quantiser, sizeof(uint8_t), 1, fp) != 1) break;
|
||||
|
||||
// Read compressed size
|
||||
uint32_t compressed_size;
|
||||
if (fread(&compressed_size, sizeof(uint32_t), 1, fp) != 1) break;
|
||||
@@ -754,8 +763,8 @@ static const char* VERDESC[] = {"null", "YCoCg tiled, uniform", "ICtCp tiled, un
|
||||
stats.audio_tad_bytes += compressed_size;
|
||||
|
||||
if (!opts.summary_only && display) {
|
||||
printf(" - samples=%u, size=%u bytes (zstd compressed TAD32)",
|
||||
sample_count, compressed_size);
|
||||
printf(" - samples=%u, size=%u bytes, quantiser=%u steps (index %u)",
|
||||
sample_count, compressed_size, quantiser * 2 + 1, quantiser);
|
||||
}
|
||||
|
||||
// Skip compressed data
|
||||
|
||||
Reference in New Issue
Block a user