diff --git a/include/video/mp4_writer_internal.h b/include/video/mp4_writer_internal.h index 55eac195..04951d02 100644 --- a/include/video/mp4_writer_internal.h +++ b/include/video/mp4_writer_internal.h @@ -66,7 +66,7 @@ bool is_audio_codec_compatible_with_mp4(enum AVCodecID codec_id, const char **co * @param transcoded_params Output parameter to store the transcoded codec parameters * @return 0 on success, negative on error */ -int transcode_mulaw_to_aac(const AVCodecParameters *codec_params, +int transcode_pcm_to_aac(const AVCodecParameters *codec_params, const AVRational *time_base, const char *stream_name, AVCodecParameters **transcoded_params); diff --git a/src/video/go2rtc/go2rtc_process.c b/src/video/go2rtc/go2rtc_process.c index 7c32c7da..d1b823dc 100644 --- a/src/video/go2rtc/go2rtc_process.c +++ b/src/video/go2rtc/go2rtc_process.c @@ -405,6 +405,7 @@ bool go2rtc_process_init(const char *binary_path, const char *config_dir, int ap if (!g_config_path) { log_error("Memory allocation failed for config path"); free(g_config_dir); + g_config_dir = NULL; return false; } @@ -473,7 +474,7 @@ bool go2rtc_process_generate_config(const char *config_path, int api_port) { } FILE *config_file = fdopen(config_fd, "w"); if (!config_file) { - log_error("Failed to open go2rtc config file for writing: %s", config_path); + log_error("Failed to create file stream for go2rtc config file: %s", config_path); close(config_fd); return false; } @@ -1137,10 +1138,10 @@ bool go2rtc_process_start(int api_port) { } // Redirect stdout and stderr to log files - char log_path[1024]; // Use a reasonable fixed size instead of PATH_MAX + char log_path[PATH_MAX]; // Use PATH_MAX to accommodate full filesystem paths // Extract directory from g_config->log_file - char log_dir[1024] = {0}; + char log_dir[PATH_MAX] = {0}; if (g_config.log_file[0] != '\0') { strncpy(log_dir, g_config.log_file, sizeof(log_dir) - 1); @@ -1161,11 +1162,11 @@ bool go2rtc_process_start(int api_port) { } // Log the path we're using for the log file - log_info("Using go2rtc log file: %s", log_path); + fprintf(stderr, "Using go2rtc log file: %s\n", log_path); int log_fd = open(log_path, O_WRONLY | O_CREAT | O_APPEND, 0644); if (log_fd == -1) { - log_error("Failed to open log file: %s", log_path); + fprintf(stderr, "Failed to open log file: %s\n", log_path); exit(EXIT_FAILURE); } diff --git a/src/video/hls/hls_unified_thread.c b/src/video/hls/hls_unified_thread.c index 83693086..1f5defc9 100644 --- a/src/video/hls/hls_unified_thread.c +++ b/src/video/hls/hls_unified_thread.c @@ -7,7 +7,7 @@ * * This file implements the unified thread approach for HLS streaming. * - * CRITICAL FIX (2025-04-11): Fixed segmentation fault issues related to thread safety + * CRITICAL FIX: Fixed segmentation fault issues related to thread safety * in the writer cleanup process. The main issue was that the hls_writer was being accessed * after it had been freed by another thread. The fix uses atomic operations to ensure * thread-safe access to the writer pointer. @@ -2982,7 +2982,7 @@ static void ffmpeg_buffer_cleanup(void) { // CRITICAL FIX: Skip direct av_freep(NULL) call during shutdown or hard deletion // This is the most likely cause of segmentation faults - if (!is_shutdown_initiated() && !is_stream_stopping(NULL)) { + if (!is_shutdown_initiated()) { // Use a safer approach to release memory log_debug("Using safer approach to release FFmpeg memory"); @@ -2993,7 +2993,7 @@ static void ffmpeg_buffer_cleanup(void) { av_free(dummy); } } else { - log_info("Skipping av_freep(NULL) during shutdown or stream deletion to prevent segmentation fault"); + log_info("Skipping av_freep(NULL) during shutdown to prevent segmentation fault"); } // Call FFmpeg's internal memory cleanup functions - safely diff --git a/src/video/mp4_writer_utils.c b/src/video/mp4_writer_utils.c index ee29be77..12ea7e64 100644 --- a/src/video/mp4_writer_utils.c +++ b/src/video/mp4_writer_utils.c @@ -185,7 +185,7 @@ static int init_audio_transcoder(const char *stream_name, strncpy(audio_transcoder_stream_names[slot], stream_name, MAX_STREAM_NAME - 1); audio_transcoder_stream_names[slot][MAX_STREAM_NAME - 1] = '\0'; - log_info("Successfully initialized audio transcoder from μ-law to AAC for %s", stream_name); + log_info("Successfully initialized audio transcoder from PCM to AAC for %s", stream_name); #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 37, 100) log_info("Sample rate: %d, Channels: %d, Bit rate: %ld", @@ -395,7 +395,7 @@ int transcode_audio_packet(const char *stream_name, * @param transcoded_params Output parameter to store the transcoded codec parameters * @return 0 on success, negative on error */ -int transcode_mulaw_to_aac(const AVCodecParameters *codec_params, +int transcode_pcm_to_aac(const AVCodecParameters *codec_params, const AVRational *time_base, const char *stream_name, AVCodecParameters **transcoded_params) { @@ -456,7 +456,7 @@ int transcode_mulaw_to_aac(const AVCodecParameters *codec_params, // Open decoder ret = avcodec_open2(decoder_ctx, decoder, NULL); if (ret < 0) { - log_ffmpeg_error(ret, "Failed to open μ-law decoder"); + log_ffmpeg_error(ret, "Failed to open PCM decoder"); goto cleanup; } @@ -505,7 +505,7 @@ int transcode_mulaw_to_aac(const AVCodecParameters *codec_params, goto cleanup; } - log_info("Successfully configured transcoding from μ-law to AAC for %s", + log_info("Successfully configured transcoding from PCM to AAC for %s", stream_name ? stream_name : "unknown"); #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 37, 100) @@ -871,7 +871,7 @@ int mp4_writer_initialize(mp4_writer_t *writer, const AVPacket *pkt, const AVStr // Try to transcode PCM to AAC AVCodecParameters *transcoded_params = NULL; - int transcode_ret = transcode_mulaw_to_aac(input_stream->codecpar, + int transcode_ret = transcode_pcm_to_aac(input_stream->codecpar, &input_stream->time_base, writer->stream_name, &transcoded_params); @@ -1290,7 +1290,7 @@ int mp4_writer_add_audio_stream(mp4_writer_t *writer, const AVCodecParameters *c // Try to transcode PCM to AAC AVCodecParameters *transcoded_params = NULL; - int transcode_ret = transcode_mulaw_to_aac(codec_params, &safe_time_base, + int transcode_ret = transcode_pcm_to_aac(codec_params, &safe_time_base, writer->stream_name, &transcoded_params); if (transcode_ret >= 0 && transcoded_params) { diff --git a/src/video/onvif_device_management.c b/src/video/onvif_device_management.c index f20e579a..88a33ef0 100644 --- a/src/video/onvif_device_management.c +++ b/src/video/onvif_device_management.c @@ -87,7 +87,8 @@ static char* create_security_header(const char *username, const char *password, memcpy(concatenated, nonce_bytes, nonce_len); // Raw byte copies for SHA-1 input: intermediate parts are not C strings memcpy((void *)(concatenated + nonce_len), created, created_len); // NOLINT(bugprone-not-null-terminated-result) - memcpy((void *)(concatenated + nonce_len + created_len), password, password_len + 1); + // Exclude the null terminator: WS-Security spec requires raw bytes only + memcpy((void *)(concatenated + nonce_len + created_len), password, password_len); // Calculate SHA1 digest mbedtls_sha1((unsigned char*)concatenated, nonce_len + created_len + password_len, digest); diff --git a/web/js/components/preact/WebRTCView.jsx b/web/js/components/preact/WebRTCView.jsx index 3117072a..0d8bd14d 100644 --- a/web/js/components/preact/WebRTCView.jsx +++ b/web/js/components/preact/WebRTCView.jsx @@ -184,8 +184,11 @@ export function WebRTCView() { setIsLoading(isLoadingStreams); }, [isLoadingStreams]); - // Process streams data when it's loaded or when the selected stream changes. + // Process streams data when it's loaded. useEffect(() => { + // If a stream is already selected (e.g. by the user or URL), don't override it here. + if (selectedStream) return; + if (streamsData && Array.isArray(streamsData)) { // Process the streams data const processStreams = async () => { @@ -226,9 +229,9 @@ export function WebRTCView() { processStreams(); } - // Note: This effect now explicitly depends on selectedStream. - // It is written to be idempotent and will only update selectedStream when necessary. - }, [streamsData, selectedStream]); + // Note: This effect now explicitly depends on streamsData and autoGrid. + // It will only update selectedStream when none is already selected. + }, [streamsData, autoGrid]); // Sync layout/page/stream to URL — only meaningful once streams are loaded. useEffect(() => {