Skip to content

Commit

Permalink
Make a Windows port
Browse files Browse the repository at this point in the history
  • Loading branch information
WyattBlue committed Nov 21, 2024
1 parent a50071a commit 53ad320
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 9 deletions.
60 changes: 52 additions & 8 deletions av/filter/loudnorm_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,23 @@
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/opt.h>
#include <pthread.h>
#include <string.h>

#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#include <time.h>
#endif

#ifdef _WIN32
static CRITICAL_SECTION json_mutex;
static CONDITION_VARIABLE json_cond;
static int mutex_initialized = 0;
#else
static pthread_mutex_t json_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t json_cond = PTHREAD_COND_INITIALIZER;
#endif

static char json_buffer[2048] = {0};
static int json_captured = 0;
Expand All @@ -20,11 +32,22 @@ static void logging_callback(void *ptr, int level, const char *fmt, va_list vl)

const char *json_start = strstr(line, "{");
if (json_start) {
#ifdef _WIN32
EnterCriticalSection(&json_mutex);
#else
pthread_mutex_lock(&json_mutex);
#endif

strncpy(json_buffer, json_start, sizeof(json_buffer) - 1);
json_captured = 1;
pthread_cond_signal(&json_cond); // Signal that we have the JSON

#ifdef _WIN32
WakeConditionVariable(&json_cond);
LeaveCriticalSection(&json_mutex);
#else
pthread_cond_signal(&json_cond);
pthread_mutex_unlock(&json_mutex);
#endif
}
}

Expand All @@ -36,6 +59,16 @@ char* loudnorm_get_stats(
char* result = NULL;
json_captured = 0; // Reset the captured flag
memset(json_buffer, 0, sizeof(json_buffer)); // Clear the buffer

#ifdef _WIN32
// Initialize synchronization objects if needed
if (!mutex_initialized) {
InitializeCriticalSection(&json_mutex);
InitializeConditionVariable(&json_cond);
mutex_initialized = 1;
}
#endif

av_log_set_callback(logging_callback);

AVFilterGraph *filter_graph = NULL;
Expand Down Expand Up @@ -65,8 +98,6 @@ char* loudnorm_get_stats(
av_get_sample_fmt_name(codec_ctx->sample_fmt),
ch_layout_str);



avfilter_graph_create_filter(&src_ctx, avfilter_get_by_name("abuffer"),
"src", args, NULL, filter_graph);
avfilter_graph_create_filter(&sink_ctx, avfilter_get_by_name("abuffersink"),
Expand Down Expand Up @@ -126,8 +157,7 @@ char* loudnorm_get_stats(

// Force stats print
if (loudnorm_ctx) {
av_log_set_level(AV_LOG_INFO); // Make sure log level is high enough
// Trigger stats print
av_log_set_level(AV_LOG_INFO);
av_opt_set(loudnorm_ctx, "print_format", "json", AV_OPT_SEARCH_CHILDREN);
av_opt_set(loudnorm_ctx, "measured_i", NULL, AV_OPT_SEARCH_CHILDREN);
av_opt_set(loudnorm_ctx, "measured_lra", NULL, AV_OPT_SEARCH_CHILDREN);
Expand All @@ -136,7 +166,6 @@ char* loudnorm_get_stats(
avfilter_init_str(loudnorm_ctx, NULL);
}

// Flush the filter graph to ensure all processing is done
avfilter_graph_request_oldest(filter_graph);

end:
Expand All @@ -147,9 +176,22 @@ char* loudnorm_get_stats(
av_frame_free(&frame);
av_packet_free(&packet);

#ifdef _WIN32
EnterCriticalSection(&json_mutex);
while (!json_captured) {
if (!SleepConditionVariableCS(&json_cond, &json_mutex, 5000)) { // 5 second timeout
fprintf(stderr, "Timeout waiting for JSON data\n");
break;
}
}
if (json_captured) {
result = _strdup(json_buffer); // Use _strdup on Windows
}
LeaveCriticalSection(&json_mutex);
#else
struct timespec timeout;
clock_gettime(CLOCK_REALTIME, &timeout);
//timeout.tv_sec += 0;
timeout.tv_sec += 5; // 5 second timeout

pthread_mutex_lock(&json_mutex);
while (json_captured == 0) {
Expand All @@ -163,6 +205,8 @@ char* loudnorm_get_stats(
result = strdup(json_buffer);
}
pthread_mutex_unlock(&json_mutex);
#endif

av_log_set_callback(av_log_default_callback);
return result;
}
2 changes: 1 addition & 1 deletion tests/test_streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def test_loudnorm(self) -> None:

assert isinstance(stats, bytes) and len(stats) > 30
assert b"inf" not in stats
assert b"\"input_i\"" in stats
assert b'"input_i"' in stats

def test_selection(self) -> None:
container = av.open(
Expand Down

0 comments on commit 53ad320

Please sign in to comment.