diff --git a/video_encoder/encoder_tav.c b/video_encoder/encoder_tav.c
index ff320a5..805d1fe 100644
--- a/video_encoder/encoder_tav.c
+++ b/video_encoder/encoder_tav.c
@@ -60,6 +60,7 @@
#define DEFAULT_FPS 30
#define DEFAULT_QUALITY 2
int KEYFRAME_INTERVAL = 60;
+#define ZSTD_COMPRESSON_LEVEL 15
// Audio/subtitle constants (reused from TEV)
#define MP2_DEFAULT_PACKET_SIZE 1152
@@ -631,6 +632,10 @@ static size_t serialise_tile_data(tav_encoder_t *enc, int tile_x, int tile_y,
buffer[offset++] = 0; // qY override
buffer[offset++] = 0; // qCo override
buffer[offset++] = 0; // qCg override
+ // technically, putting this in here would create three redundant copies of the same value, but it's much easier to code this way :v
+ int this_frame_qY = enc->quantiser_y;
+ int this_frame_qCo = enc->quantiser_co;
+ int this_frame_qCg = enc->quantiser_cg;
if (mode == TAV_MODE_SKIP) {
// No coefficient data for SKIP/MOTION modes
@@ -652,14 +657,14 @@ static size_t serialise_tile_data(tav_encoder_t *enc, int tile_x, int tile_y,
}
printf("\n");
printf("Encoder Debug: Quantisers - Y=%d, Co=%d, Cg=%d, rcf=%.2f\n",
- enc->quantiser_y, enc->quantiser_co, enc->quantiser_cg);
+ this_frame_qY, this_frame_qCo, this_frame_qCg);
}*/
if (mode == TAV_MODE_INTRA) {
// INTRA mode: quantise coefficients directly and store for future reference
- quantise_dwt_coefficients((float*)tile_y_data, quantised_y, tile_size, enc->quantiser_y);
- quantise_dwt_coefficients((float*)tile_co_data, quantised_co, tile_size, enc->quantiser_co);
- quantise_dwt_coefficients((float*)tile_cg_data, quantised_cg, tile_size, enc->quantiser_cg);
+ quantise_dwt_coefficients((float*)tile_y_data, quantised_y, tile_size, this_frame_qY);
+ quantise_dwt_coefficients((float*)tile_co_data, quantised_co, tile_size, this_frame_qCo);
+ quantise_dwt_coefficients((float*)tile_cg_data, quantised_cg, tile_size, this_frame_qCg);
// Store current coefficients for future delta reference
int tile_idx = tile_y * enc->tiles_x + tile_x;
@@ -689,15 +694,15 @@ static size_t serialise_tile_data(tav_encoder_t *enc, int tile_x, int tile_y,
}
// Quantise the deltas
- quantise_dwt_coefficients(delta_y, quantised_y, tile_size, enc->quantiser_y);
- quantise_dwt_coefficients(delta_co, quantised_co, tile_size, enc->quantiser_co);
- quantise_dwt_coefficients(delta_cg, quantised_cg, tile_size, enc->quantiser_cg);
+ quantise_dwt_coefficients(delta_y, quantised_y, tile_size, this_frame_qY);
+ quantise_dwt_coefficients(delta_co, quantised_co, tile_size, this_frame_qCo);
+ quantise_dwt_coefficients(delta_cg, quantised_cg, tile_size, this_frame_qCg);
// Reconstruct coefficients like decoder will (previous + dequantised_delta)
for (int i = 0; i < tile_size; i++) {
- float dequant_delta_y = (float)quantised_y[i] * enc->quantiser_y;
- float dequant_delta_co = (float)quantised_co[i] * enc->quantiser_co;
- float dequant_delta_cg = (float)quantised_cg[i] * enc->quantiser_cg;
+ float dequant_delta_y = (float)quantised_y[i] * this_frame_qY;
+ float dequant_delta_co = (float)quantised_co[i] * this_frame_qCo;
+ float dequant_delta_cg = (float)quantised_cg[i] * this_frame_qCg;
prev_y[i] = prev_y[i] + dequant_delta_y;
prev_co[i] = prev_co[i] + dequant_delta_co;
@@ -741,8 +746,7 @@ static size_t compress_and_write_frame(tav_encoder_t *enc, uint8_t packet_type)
// Serialise all tiles
for (int tile_y = 0; tile_y < enc->tiles_y; tile_y++) {
for (int tile_x = 0; tile_x < enc->tiles_x; tile_x++) {
- int tile_idx = tile_y * enc->tiles_x + tile_x;
-
+
// Determine tile mode based on frame type, coefficient availability, and intra_only flag
uint8_t mode;
int is_keyframe = (packet_type == TAV_PACKET_IFRAME);
@@ -784,8 +788,7 @@ static size_t compress_and_write_frame(tav_encoder_t *enc, uint8_t packet_type)
// Compress with zstd
size_t compressed_size = ZSTD_compress(enc->compressed_buffer, enc->compressed_buffer_size,
- uncompressed_buffer, uncompressed_offset,
- ZSTD_CLEVEL_DEFAULT);
+ uncompressed_buffer, uncompressed_offset, ZSTD_COMPRESSON_LEVEL);
if (ZSTD_isError(compressed_size)) {
fprintf(stderr, "Error: ZSTD compression failed: %s\n", ZSTD_getErrorName(compressed_size));
@@ -1292,29 +1295,29 @@ static int srt_time_to_frame(const char *time_str, int fps) {
return (int)(total_seconds * fps + 0.5); // Round to nearest frame
}
-// Convert SAMI milliseconds to frame number (copied from TEV)
+// Convert SAMI milliseconds to frame number
static int sami_ms_to_frame(int milliseconds, int fps) {
double seconds = milliseconds / 1000.0;
return (int)(seconds * fps + 0.5); // Round to nearest frame
}
-// Parse SubRip subtitle file (copied from TEV)
+// Parse SubRip subtitle file
static subtitle_entry_t* parse_srt_file(const char *filename, int fps) {
FILE *file = fopen(filename, "r");
if (!file) {
fprintf(stderr, "Failed to open subtitle file: %s\n", filename);
return NULL;
}
-
+
subtitle_entry_t *head = NULL;
subtitle_entry_t *tail = NULL;
char line[1024];
int state = 0; // 0=index, 1=time, 2=text, 3=blank
-
+
subtitle_entry_t *current_entry = NULL;
char *text_buffer = NULL;
size_t text_buffer_size = 0;
-
+
while (fgets(line, sizeof(line), file)) {
// Remove trailing newline
size_t len = strlen(line);
@@ -1326,7 +1329,7 @@ static subtitle_entry_t* parse_srt_file(const char *filename, int fps) {
line[len-1] = '\0';
len--;
}
-
+
if (state == 0) { // Expecting subtitle index
if (strlen(line) == 0) continue; // Skip empty lines
// Create new subtitle entry
@@ -1338,14 +1341,14 @@ static subtitle_entry_t* parse_srt_file(const char *filename, int fps) {
if (sscanf(line, "%31s --> %31s", start_time, end_time) == 2) {
current_entry->start_frame = srt_time_to_frame(start_time, fps);
current_entry->end_frame = srt_time_to_frame(end_time, fps);
-
+
if (current_entry->start_frame < 0 || current_entry->end_frame < 0) {
free(current_entry);
current_entry = NULL;
state = 3; // Skip to next blank line
continue;
}
-
+
// Initialize text buffer
text_buffer_size = 256;
text_buffer = malloc(text_buffer_size);
@@ -1368,7 +1371,7 @@ static subtitle_entry_t* parse_srt_file(const char *filename, int fps) {
current_entry->text = strdup(text_buffer);
free(text_buffer);
text_buffer = NULL;
-
+
// Add to list
if (!head) {
head = current_entry;
@@ -1384,7 +1387,7 @@ static subtitle_entry_t* parse_srt_file(const char *filename, int fps) {
size_t current_len = strlen(text_buffer);
size_t line_len = strlen(line);
size_t needed = current_len + line_len + 2; // +2 for newline and null
-
+
if (needed > text_buffer_size) {
text_buffer_size = needed + 256;
char *new_buffer = realloc(text_buffer, text_buffer_size);
@@ -1392,14 +1395,14 @@ static subtitle_entry_t* parse_srt_file(const char *filename, int fps) {
free(text_buffer);
free(current_entry);
current_entry = NULL;
- fprintf(stderr, "Memory reallocation failed while parsing subtitles\n");
+ fprintf(stderr, "Memory allocation failed while parsing subtitles\n");
break;
}
text_buffer = new_buffer;
}
-
+
if (current_len > 0) {
- strcat(text_buffer, "\\n"); // Use \n as newline marker in subtitle text
+ strcat(text_buffer, "\n");
}
strcat(text_buffer, line);
}
@@ -1409,90 +1412,348 @@ static subtitle_entry_t* parse_srt_file(const char *filename, int fps) {
}
}
}
-
+
// Handle final subtitle if file doesn't end with blank line
- if (current_entry && state == 2) {
+ if (current_entry && text_buffer) {
current_entry->text = strdup(text_buffer);
+ free(text_buffer);
+
if (!head) {
head = current_entry;
} else {
tail->next = current_entry;
}
- free(text_buffer);
}
-
- fclose(file);
+
+ //fclose(file); // why uncommenting it errors out with "Fatal error: glibc detected an invalid stdio handle"?
return head;
}
-// Parse SAMI subtitle file (simplified version from TEV)
+// Strip HTML tags from text but preserve and formatting tags
+static char* strip_html_tags(const char *html) {
+ if (!html) return NULL;
+
+ size_t len = strlen(html);
+ char *result = malloc(len + 1);
+ if (!result) return NULL;
+
+ int in_tag = 0;
+ int out_pos = 0;
+ int i = 0;
+
+ while (i < len) {
+ if (html[i] == '<') {
+ // Check if this is a formatting tag we want to preserve
+ int preserve_tag = 0;
+
+ // Check for , , , tags
+ if (i + 1 < len) {
+ if ((i + 2 < len && strncasecmp(&html[i], "", 3) == 0) ||
+ (i + 3 < len && strncasecmp(&html[i], "", 4) == 0) ||
+ (i + 2 < len && strncasecmp(&html[i], "", 3) == 0) ||
+ (i + 3 < len && strncasecmp(&html[i], "", 4) == 0)) {
+ preserve_tag = 1;
+ }
+ }
+
+ if (preserve_tag) {
+ // Copy the entire tag
+ while (i < len && html[i] != '>') {
+ result[out_pos++] = html[i++];
+ }
+ if (i < len) {
+ result[out_pos++] = html[i++]; // Copy the '>'
+ }
+ } else {
+ // Skip non-formatting tags
+ in_tag = 1;
+ i++;
+ }
+ } else if (html[i] == '>') {
+ in_tag = 0;
+ i++;
+ } else if (!in_tag) {
+ result[out_pos++] = html[i++];
+ } else {
+ i++;
+ }
+ }
+
+ result[out_pos] = '\0';
+ return result;
+}
+
+// Parse SAMI subtitle file
static subtitle_entry_t* parse_smi_file(const char *filename, int fps) {
FILE *file = fopen(filename, "r");
if (!file) {
fprintf(stderr, "Failed to open subtitle file: %s\n", filename);
return NULL;
}
-
+
subtitle_entry_t *head = NULL;
subtitle_entry_t *tail = NULL;
char line[2048];
-
+ char *content = NULL;
+ size_t content_size = 0;
+ size_t content_pos = 0;
+
+ // Read entire file into memory for easier parsing
while (fgets(line, sizeof(line), file)) {
- // Look for SYNC tags with Start= attribute
- char *sync_pos = strstr(line, "