Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/framework/mlt_tractor.c
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,10 @@ static int producer_get_audio(mlt_frame self,
"producer_consumer_fps",
mlt_properties_get(properties, "producer_consumer_fps"));
mlt_frame_get_audio(frame, buffer, format, frequency, channels, samples);

// Propagate audio-level metadata onto the tractor output frame.
mlt_properties_copy(properties, frame_properties, "meta.");

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a wider net than I wanted, but I didn't want something application specific. Shotcut sets the audio level metadata prefix to meta.track..audiolevel..


mlt_frame_set_audio(self,
*buffer,
*format,
Expand Down
4 changes: 4 additions & 0 deletions src/modules/core/transition_mix.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ static int transition_get_audio(mlt_frame frame_a,

// Get the properties of the b frame
mlt_properties b_props = MLT_FRAME_PROPERTIES(frame_b);
mlt_properties a_props = MLT_FRAME_PROPERTIES(frame_a);

transition_mix self = transition->child;
float *buffer_b, *buffer_a;
Expand All @@ -160,6 +161,9 @@ static int transition_get_audio(mlt_frame frame_a,
mlt_frame_get_audio(frame_b, (void **) &buffer_b, format, &frequency_b, &channels_b, &samples_b);
mlt_frame_get_audio(frame_a, (void **) &buffer_a, format, &frequency_a, &channels_a, &samples_a);

// Merge b-frame level metadata onto a-frame after both callbacks run.
mlt_properties_copy(a_props, b_props, "meta.");

// Prevent dividing by zero.
if (!channels_a || !channels_b || !buffer_a || !buffer_b)
return 1;
Expand Down
42 changes: 39 additions & 3 deletions src/modules/normalize/filter_audiolevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* filter_audiolevel.c -- get the audio level of each channel
* Copyright (C) 2002 Steve Harris
* Copyright (C) 2010 Marco Gittler <g.marco@freenet.de>
* Copyright (C) 2012-2023 Dan Dennedy <dan@dennedy.org>
* Copyright (C) 2012-2026 Dan Dennedy <dan@dennedy.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand All @@ -24,8 +24,42 @@
#include <framework/mlt_log.h>

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

static const char *kDefaultPrefix = "meta.media.audio_level.";

static void append_int(char *out, size_t out_size, size_t *offset, int value)
{
if (!out || !out_size || !offset || *offset >= out_size)
return;

const int n = snprintf(out + *offset, out_size - *offset, "%d", value);
if (n < 0)
return;
*offset += (size_t) n;
if (*offset >= out_size)
out[out_size - 1] = '\0';
}

static void make_audio_level_key(const char *prefix, int channel, char *key, size_t key_size)
{
if (!key || key_size == 0)
return;

if (!prefix || !prefix[0])
prefix = kDefaultPrefix;

const int n = snprintf(key, key_size, "%s", prefix);
size_t offset = n > 0 ? (size_t) n : 0;
if (offset >= key_size)
offset = key_size - 1;
key[offset] = '\0';

append_int(key, key_size, &offset, channel);
key[offset < key_size ? offset : key_size - 1] = '\0';
}

#define AMPTODBFS(n) (log10(n) * 20.0)

//----------------------------------------------------------------------------
Expand Down Expand Up @@ -67,6 +101,7 @@ static int filter_get_audio(mlt_frame frame,

int iec_scale = mlt_properties_get_int(filter_props, "iec_scale");
int dbPeak = mlt_properties_get_int(filter_props, "dbpeak");
const char *prefix = mlt_properties_get(filter_props, "prefix");
*format = mlt_audio_s16;
int error = mlt_frame_get_audio(frame, buffer, format, frequency, channels, samples);
if (error || !buffer || !buffer[0])
Expand All @@ -76,7 +111,7 @@ static int filter_get_audio(mlt_frame frame,
int num_samples = *samples > 200 ? 200 : *samples;
int num_oversample = 0;
int c, s;
char key[50];
char key[128];
int16_t *pcm = (int16_t *) *buffer;

for (c = 0; c < *channels; c++) {
Expand Down Expand Up @@ -119,7 +154,7 @@ static int filter_get_audio(mlt_frame frame,
if (iec_scale)
level = IEC_Scale(AMPTODBFS(level));
}
sprintf(key, "meta.media.audio_level.%d", c);
make_audio_level_key(prefix, c, key, sizeof(key));
mlt_properties_set_double(MLT_FRAME_PROPERTIES(frame), key, level);
sprintf(key, "_audio_level.%d", c);
mlt_properties_set_double(filter_props, key, level);
Expand Down Expand Up @@ -152,6 +187,7 @@ mlt_filter filter_audiolevel_init(mlt_profile profile,
if (filter) {
filter->process = filter_process;
mlt_properties_set_int(MLT_FILTER_PROPERTIES(filter), "iec_scale", 1);
mlt_properties_set(MLT_FILTER_PROPERTIES(filter), "prefix", kDefaultPrefix);
}
return filter;
}
11 changes: 10 additions & 1 deletion src/modules/normalize/filter_audiolevel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ schema_version: 7.2
type: filter
identifier: audiolevel
title: Audio Levels
version: 3
version: 4
copyright: Meltytech, LLC, Marco Gittler, and Steve Harris
creator: Dan Dennedy
contributor:
Expand All @@ -17,11 +17,20 @@ notes: >
troughs of short duration like a VU meter.
Applications can also get this data on the frame as meta.media.audio_level.<N>
where <N> is the channel number starting with 0.
The prefix is configurable using the prefix property.
tags:
- Audio
audio_formats:
- s16
parameters:
- identifier: prefix
title: Frame Property Prefix
description: >
Prefix for frame audio level keys. The filter appends the channel index
to this prefix.
type: string
default: meta.media.audio_level.

- identifier: iec_scale
title: Use IEC 60268-18 Scale
type: boolean
Expand Down
Loading