diff --git a/video_encoder/Makefile b/video_encoder/Makefile index d0525d6..f754965 100644 --- a/video_encoder/Makefile +++ b/video_encoder/Makefile @@ -3,9 +3,9 @@ CC = gcc CXX = g++ -CFLAGS = -std=c99 -Wall -Wextra -Ofast -D_GNU_SOURCE #-fsanitize=address -CXXFLAGS = -std=c++11 -Wall -Wextra -Ofast -D_GNU_SOURCE #-fsanitize=address -DBGFLAGS = #-fsanitize=address +CFLAGS = -std=c99 -Wall -Wextra -Ofast -D_GNU_SOURCE +CXXFLAGS = -std=c++11 -Wall -Wextra -Ofast -D_GNU_SOURCE +DBGFLAGS = # Zstd flags (use pkg-config if available, fallback for cross-platform compatibility) ZSTD_CFLAGS = $(shell pkg-config --cflags libzstd 2>/dev/null || echo "") @@ -81,7 +81,8 @@ test_mpeg_motion: test_mpeg_motion.cpp tests: $(TEST_TARGETS) # Build with debug symbols -debug: CFLAGS += -g -DDEBUG +debug: CFLAGS += -g -DDEBUG -fsanitize=address +debug: DBGFLAGS += -fsanitize=address debug: $(TARGETS) # Clean build artifacts diff --git a/video_encoder/encoder_tav.c b/video_encoder/encoder_tav.c index 30fc0af..b84e1cb 100644 --- a/video_encoder/encoder_tav.c +++ b/video_encoder/encoder_tav.c @@ -18,7 +18,7 @@ #include #include -#define ENCODER_VENDOR_STRING "Encoder-TAV 20251115 (3d-dwt,tad,ssf-tc)" +#define ENCODER_VENDOR_STRING "Encoder-TAV 20251121 (3d-dwt,tad,ssf-tc)" // TSVM Advanced Video (TAV) format constants #define TAV_MAGIC "\x1F\x54\x53\x56\x4D\x54\x41\x56" // "\x1FTSVM TAV" @@ -311,8 +311,14 @@ typedef struct { // Bitstream operations static void bitstream_init(bitstream_t *bs, size_t initial_capacity) { + // Ensure minimum capacity to avoid issues with zero-size allocations + if (initial_capacity < 64) initial_capacity = 64; bs->capacity = initial_capacity; bs->data = calloc(1, initial_capacity); + if (!bs->data) { + fprintf(stderr, "ERROR: Failed to allocate bitstream buffer of size %zu\n", initial_capacity); + exit(1); + } bs->byte_pos = 0; bs->bit_pos = 0; } @@ -320,10 +326,11 @@ static void bitstream_init(bitstream_t *bs, size_t initial_capacity) { static void bitstream_write_bit(bitstream_t *bs, int bit) { // Grow if needed if (bs->byte_pos >= bs->capacity) { + size_t old_capacity = bs->capacity; bs->capacity *= 2; bs->data = realloc(bs->data, bs->capacity); - // Clear new memory - memset(bs->data + bs->byte_pos, 0, bs->capacity - bs->byte_pos); + // Clear only the newly allocated memory region + memset(bs->data + old_capacity, 0, bs->capacity - old_capacity); } if (bit) { @@ -6007,15 +6014,24 @@ static size_t preprocess_coefficients_ezbc(int16_t *coeffs_y, int16_t *coeffs_co uint8_t *ezbc_data = NULL; size_t ezbc_size = encode_channel_ezbc(channel_coeffs[ch], coeff_count, width, height, &ezbc_data); + // Validate encoding result + if (!ezbc_data && ezbc_size > 0) { + fprintf(stderr, "ERROR: EZBC encoding returned NULL data with non-zero size %zu for channel %d\n", + ezbc_size, ch); + exit(1); + } + // Write size header (uint32_t) for this channel *((uint32_t*)write_ptr) = (uint32_t)ezbc_size; write_ptr += sizeof(uint32_t); total_size += sizeof(uint32_t); - // Copy EZBC-encoded data - memcpy(write_ptr, ezbc_data, ezbc_size); - write_ptr += ezbc_size; - total_size += ezbc_size; + // Copy EZBC-encoded data (skip if size is 0) + if (ezbc_size > 0 && ezbc_data) { + memcpy(write_ptr, ezbc_data, ezbc_size); + write_ptr += ezbc_size; + total_size += ezbc_size; + } // Free EZBC buffer free(ezbc_data); @@ -6860,6 +6876,12 @@ static size_t serialise_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) { + // Initialize GOP dimensions if not set (e.g., when not using temporal DWT) + if (enc->temporal_gop_width <= 0 || enc->temporal_gop_height <= 0) { + enc->temporal_gop_width = enc->encoding_width; + enc->temporal_gop_height = enc->encoding_height; + } + // Calculate total uncompressed size // Use encoding dimensions (cropped when crop encoding is enabled, full frame otherwise) const size_t coeff_count = enc->monoblock ? @@ -6885,9 +6907,9 @@ static size_t compress_and_write_frame(tav_encoder_t *enc, uint8_t packet_type) int is_keyframe = (packet_type == TAV_PACKET_IFRAME); // SKIP mode condition matches main loop logic: still frame during SKIP run - int can_use_skip = is_still_frame && enc->previous_coeffs_allocated; + int can_use_skip = is_still_frame && enc->previous_coeffs_allocated && !enc->intra_only; - if (is_keyframe || !enc->previous_coeffs_allocated) { + if (is_keyframe || !enc->previous_coeffs_allocated || enc->intra_only) { mode = TAV_MODE_INTRA; // I-frames, first frames, or intra-only mode always use INTRA count_intra++; } else if (can_use_skip) { @@ -12058,6 +12080,9 @@ static void cleanup_encoder(tav_encoder_t *enc) { free(enc->current_frame_co); free(enc->current_frame_cg); free(enc->current_frame_alpha); + free(enc->current_dwt_y); + free(enc->current_dwt_co); + free(enc->current_dwt_cg); free(enc->tiles); free(enc->compressed_buffer); free(enc->mp2_buffer);