* [FFmpeg-devel] [PATCH 0/4] avfilter/f_ebur128: various improvements
@ 2025-06-12 20:16 Niklas Haas
2025-06-12 20:16 ` [FFmpeg-devel] [PATCH 1/4] avfilter/f_ebur128: use transformed direct form II Niklas Haas
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Niklas Haas @ 2025-06-12 20:16 UTC (permalink / raw)
To: ffmpeg-devel
Some low-hanging fruit for the EBUR128 filter, mostly aimed at cleaning
this code up a bit for a proper SIMD implementation.
I have a separate branch where I am working on an AVX2/FMA3 version, but
I wanted to send these quick fixes ahead of time.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
* [FFmpeg-devel] [PATCH 1/4] avfilter/f_ebur128: use transformed direct form II
2025-06-12 20:16 [FFmpeg-devel] [PATCH 0/4] avfilter/f_ebur128: various improvements Niklas Haas
@ 2025-06-12 20:16 ` Niklas Haas
2025-06-12 20:16 ` [FFmpeg-devel] [PATCH 2/4] avfilter/f_ebur128: simplify sample cache array Niklas Haas
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Niklas Haas @ 2025-06-12 20:16 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Niklas Haas
From: Niklas Haas <git@haasn.dev>
Instead of direct form I. See af_biquads.c for math. Also eliminate
an unnecessary indirection.
---
libavfilter/f_ebur128.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/libavfilter/f_ebur128.c b/libavfilter/f_ebur128.c
index 768f062bac..173a4f75ca 100644
--- a/libavfilter/f_ebur128.c
+++ b/libavfilter/f_ebur128.c
@@ -686,17 +686,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
/* Y[i] = X[i]*b0 + X[i-1]*b1 + X[i-2]*b2 - Y[i-1]*a1 - Y[i-2]*a2 */
#define FILTER(Y, X, NUM, DEN) do { \
double *dst = ebur128->Y + ch*3; \
- double *src = ebur128->X + ch*3; \
- dst[2] = dst[1]; \
- dst[1] = dst[0]; \
- dst[0] = src[0]*NUM[0] + src[1]*NUM[1] + src[2]*NUM[2] \
- - dst[1]*DEN[1] - dst[2]*DEN[2]; \
+ double src = ebur128->X[ch*3] ; \
+ double dst0 = NUM[0] * src + dst[1]; \
+ dst[1] = NUM[1] * src + dst[2] - DEN[1] * dst0; \
+ dst[2] = NUM[2] * src - DEN[2] * dst0; \
+ dst[0] = dst0; \
} while (0)
// TODO: merge both filters in one?
FILTER(y, x, ebur128->pre_b, ebur128->pre_a); // apply pre-filter
- ebur128->x[ch * 3 + 2] = ebur128->x[ch * 3 + 1];
- ebur128->x[ch * 3 + 1] = ebur128->x[ch * 3 ];
FILTER(z, y, ebur128->rlb_b, ebur128->rlb_a); // apply RLB-filter
bin = ebur128->z[ch * 3] * ebur128->z[ch * 3];
--
2.49.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
* [FFmpeg-devel] [PATCH 2/4] avfilter/f_ebur128: simplify sample cache array
2025-06-12 20:16 [FFmpeg-devel] [PATCH 0/4] avfilter/f_ebur128: various improvements Niklas Haas
2025-06-12 20:16 ` [FFmpeg-devel] [PATCH 1/4] avfilter/f_ebur128: use transformed direct form II Niklas Haas
@ 2025-06-12 20:16 ` Niklas Haas
2025-06-12 20:16 ` [FFmpeg-devel] [PATCH 3/4] avfilter/f_ebur128: use structs for biquad weights Niklas Haas
2025-06-12 20:16 ` [FFmpeg-devel] [PATCH 4/4] avfilter/f_ebur128: use a single packed array for the integrator cache Niklas Haas
3 siblings, 0 replies; 5+ messages in thread
From: Niklas Haas @ 2025-06-12 20:16 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Niklas Haas
From: Niklas Haas <git@haasn.dev>
We don't need an X sample cache anymore, and we also can simplify the
access macro slightly.
---
libavfilter/f_ebur128.c | 29 +++++++++++------------------
1 file changed, 11 insertions(+), 18 deletions(-)
diff --git a/libavfilter/f_ebur128.c b/libavfilter/f_ebur128.c
index 173a4f75ca..d0707e9ef9 100644
--- a/libavfilter/f_ebur128.c
+++ b/libavfilter/f_ebur128.c
@@ -115,7 +115,6 @@ typedef struct EBUR128Context {
/* Filter caches.
* The mult by 3 in the following is for X[i], X[i-1] and X[i-2] */
- double *x; ///< 3 input samples cache for each channel
double *y; ///< 3 pre-filter samples cache for each channel
double *z; ///< 3 RLB-filter samples cache for each channel
double pre_b[3]; ///< pre-filter numerator coefficients
@@ -446,11 +445,10 @@ static int config_audio_output(AVFilterLink *outlink)
AV_CH_SURROUND_DIRECT_LEFT |AV_CH_SURROUND_DIRECT_RIGHT)
ebur128->nb_channels = nb_channels;
- ebur128->x = av_calloc(nb_channels, 3 * sizeof(*ebur128->x));
ebur128->y = av_calloc(nb_channels, 3 * sizeof(*ebur128->y));
ebur128->z = av_calloc(nb_channels, 3 * sizeof(*ebur128->z));
ebur128->ch_weighting = av_calloc(nb_channels, sizeof(*ebur128->ch_weighting));
- if (!ebur128->ch_weighting || !ebur128->x || !ebur128->y || !ebur128->z)
+ if (!ebur128->ch_weighting || !ebur128->y || !ebur128->z)
return AVERROR(ENOMEM);
#define I400_BINS(x) ((x) * 4 / 10)
@@ -673,34 +671,30 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
MOVE_TO_NEXT_CACHED_ENTRY(3000);
for (ch = 0; ch < nb_channels; ch++) {
- double bin;
-
if (ebur128->peak_mode & PEAK_MODE_SAMPLES_PEAKS)
ebur128->sample_peaks[ch] = FFMAX(ebur128->sample_peaks[ch], fabs(samples[idx_insample * nb_channels + ch]));
- ebur128->x[ch * 3] = samples[idx_insample * nb_channels + ch]; // set X[i]
-
if (!ebur128->ch_weighting[ch])
continue;
/* Y[i] = X[i]*b0 + X[i-1]*b1 + X[i-2]*b2 - Y[i-1]*a1 - Y[i-2]*a2 */
-#define FILTER(Y, X, NUM, DEN) do { \
- double *dst = ebur128->Y + ch*3; \
- double src = ebur128->X[ch*3] ; \
- double dst0 = NUM[0] * src + dst[1]; \
- dst[1] = NUM[1] * src + dst[2] - DEN[1] * dst0; \
- dst[2] = NUM[2] * src - DEN[2] * dst0; \
- dst[0] = dst0; \
+#define FILTER(DST, SRC, NUM, DEN) do { \
+ const double tmp = DST[0] = NUM[0] * SRC + DST[1]; \
+ DST[1] = NUM[1] * SRC + DST[2] - DEN[1] * tmp; \
+ DST[2] = NUM[2] * SRC - DEN[2] * tmp; \
} while (0)
+ const double x = samples[idx_insample * nb_channels + ch];
+ double *restrict y = &ebur128->y[3 * ch];
+ double *restrict z = &ebur128->z[3 * ch];
+
// TODO: merge both filters in one?
FILTER(y, x, ebur128->pre_b, ebur128->pre_a); // apply pre-filter
- FILTER(z, y, ebur128->rlb_b, ebur128->rlb_a); // apply RLB-filter
-
- bin = ebur128->z[ch * 3] * ebur128->z[ch * 3];
+ FILTER(z, *y, ebur128->rlb_b, ebur128->rlb_a); // apply RLB-filter
/* add the new value, and limit the sum to the cache size (400ms or 3s)
* by removing the oldest one */
+ double bin = *z * *z;
ebur128->i400.sum [ch] = ebur128->i400.sum [ch] + bin - ebur128->i400.cache [ch][bin_id_400];
ebur128->i3000.sum[ch] = ebur128->i3000.sum[ch] + bin - ebur128->i3000.cache[ch][bin_id_3000];
@@ -1073,7 +1067,6 @@ static av_cold void uninit(AVFilterContext *ctx)
}
av_freep(&ebur128->y_line_ref);
- av_freep(&ebur128->x);
av_freep(&ebur128->y);
av_freep(&ebur128->z);
av_freep(&ebur128->ch_weighting);
--
2.49.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
* [FFmpeg-devel] [PATCH 3/4] avfilter/f_ebur128: use structs for biquad weights
2025-06-12 20:16 [FFmpeg-devel] [PATCH 0/4] avfilter/f_ebur128: various improvements Niklas Haas
2025-06-12 20:16 ` [FFmpeg-devel] [PATCH 1/4] avfilter/f_ebur128: use transformed direct form II Niklas Haas
2025-06-12 20:16 ` [FFmpeg-devel] [PATCH 2/4] avfilter/f_ebur128: simplify sample cache array Niklas Haas
@ 2025-06-12 20:16 ` Niklas Haas
2025-06-12 20:16 ` [FFmpeg-devel] [PATCH 4/4] avfilter/f_ebur128: use a single packed array for the integrator cache Niklas Haas
3 siblings, 0 replies; 5+ messages in thread
From: Niklas Haas @ 2025-06-12 20:16 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Niklas Haas
From: Niklas Haas <git@haasn.dev>
Simplifies the code a bit. In particular, the copy to the stack is marginally
faster.
---
libavfilter/f_ebur128.c | 52 +++++++++++++++++++++++------------------
1 file changed, 29 insertions(+), 23 deletions(-)
diff --git a/libavfilter/f_ebur128.c b/libavfilter/f_ebur128.c
index d0707e9ef9..776329db1c 100644
--- a/libavfilter/f_ebur128.c
+++ b/libavfilter/f_ebur128.c
@@ -75,6 +75,11 @@ struct integrator {
struct rect { int x, y, w, h; };
+struct biquad {
+ double b0, b1, b2;
+ double a1, a2;
+};
+
typedef struct EBUR128Context {
const AVClass *class; ///< AVClass context for log and options purpose
@@ -117,10 +122,8 @@ typedef struct EBUR128Context {
* The mult by 3 in the following is for X[i], X[i-1] and X[i-2] */
double *y; ///< 3 pre-filter samples cache for each channel
double *z; ///< 3 RLB-filter samples cache for each channel
- double pre_b[3]; ///< pre-filter numerator coefficients
- double pre_a[3]; ///< pre-filter denominator coefficients
- double rlb_b[3]; ///< rlb-filter numerator coefficients
- double rlb_a[3]; ///< rlb-filter denominator coefficients
+ struct biquad pre;
+ struct biquad rlb;
struct integrator i400; ///< 400ms integrator, used for Momentary loudness (M), and Integrated loudness (I)
struct integrator i3000; ///< 3s integrator, used for Short term loudness (S), and Loudness Range (LRA)
@@ -405,21 +408,21 @@ static int config_audio_input(AVFilterLink *inlink)
double a0 = 1.0 + K / Q + K * K;
- ebur128->pre_b[0] = (Vh + Vb * K / Q + K * K) / a0;
- ebur128->pre_b[1] = 2.0 * (K * K - Vh) / a0;
- ebur128->pre_b[2] = (Vh - Vb * K / Q + K * K) / a0;
- ebur128->pre_a[1] = 2.0 * (K * K - 1.0) / a0;
- ebur128->pre_a[2] = (1.0 - K / Q + K * K) / a0;
+ ebur128->pre.b0 = (Vh + Vb * K / Q + K * K) / a0;
+ ebur128->pre.b1 = 2.0 * (K * K - Vh) / a0;
+ ebur128->pre.b2 = (Vh - Vb * K / Q + K * K) / a0;
+ ebur128->pre.a1 = 2.0 * (K * K - 1.0) / a0;
+ ebur128->pre.a2 = (1.0 - K / Q + K * K) / a0;
f0 = 38.13547087602444;
Q = 0.5003270373238773;
K = tan(M_PI * f0 / (double)inlink->sample_rate);
- ebur128->rlb_b[0] = 1.0;
- ebur128->rlb_b[1] = -2.0;
- ebur128->rlb_b[2] = 1.0;
- ebur128->rlb_a[1] = 2.0 * (K * K - 1.0) / (1.0 + K / Q + K * K);
- ebur128->rlb_a[2] = (1.0 - K / Q + K * K) / (1.0 + K / Q + K * K);
+ ebur128->rlb.b0 = 1.0;
+ ebur128->rlb.b1 = -2.0;
+ ebur128->rlb.b2 = 1.0;
+ ebur128->rlb.a1 = 2.0 * (K * K - 1.0) / (1.0 + K / Q + K * K);
+ ebur128->rlb.a2 = (1.0 - K / Q + K * K) / (1.0 + K / Q + K * K);
/* Force 100ms framing in case of metadata injection: the frames must have
* a granularity of the window overlap to be accurately exploited.
@@ -654,6 +657,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
}
#endif
+ const struct biquad pre = ebur128->pre;
+ const struct biquad rlb = ebur128->rlb;
+
for (idx_insample = ebur128->idx_insample; idx_insample < nb_samples; idx_insample++) {
const int bin_id_400 = ebur128->i400.cache_pos;
const int bin_id_3000 = ebur128->i3000.cache_pos;
@@ -678,10 +684,10 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
continue;
/* Y[i] = X[i]*b0 + X[i-1]*b1 + X[i-2]*b2 - Y[i-1]*a1 - Y[i-2]*a2 */
-#define FILTER(DST, SRC, NUM, DEN) do { \
- const double tmp = DST[0] = NUM[0] * SRC + DST[1]; \
- DST[1] = NUM[1] * SRC + DST[2] - DEN[1] * tmp; \
- DST[2] = NUM[2] * SRC - DEN[2] * tmp; \
+#define FILTER(DST, SRC, FILT) do { \
+ const double tmp = DST[0] = FILT.b0 * SRC + DST[1]; \
+ DST[1] = FILT.b1 * SRC + DST[2] - FILT.a1 * tmp; \
+ DST[2] = FILT.b2 * SRC - FILT.a2 * tmp; \
} while (0)
const double x = samples[idx_insample * nb_channels + ch];
@@ -689,14 +695,14 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
double *restrict z = &ebur128->z[3 * ch];
// TODO: merge both filters in one?
- FILTER(y, x, ebur128->pre_b, ebur128->pre_a); // apply pre-filter
- FILTER(z, *y, ebur128->rlb_b, ebur128->rlb_a); // apply RLB-filter
+ FILTER(y, x, pre); // apply pre-filter
+ FILTER(z, *y, rlb); // apply RLB-filter
/* add the new value, and limit the sum to the cache size (400ms or 3s)
* by removing the oldest one */
- double bin = *z * *z;
- ebur128->i400.sum [ch] = ebur128->i400.sum [ch] + bin - ebur128->i400.cache [ch][bin_id_400];
- ebur128->i3000.sum[ch] = ebur128->i3000.sum[ch] + bin - ebur128->i3000.cache[ch][bin_id_3000];
+ const double bin = *z * *z;
+ ebur128->i400.sum [ch] += bin - ebur128->i400.cache [ch][bin_id_400];
+ ebur128->i3000.sum[ch] += bin - ebur128->i3000.cache[ch][bin_id_3000];
/* override old cache entry with the new value */
ebur128->i400.cache [ch][bin_id_400 ] = bin;
--
2.49.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
* [FFmpeg-devel] [PATCH 4/4] avfilter/f_ebur128: use a single packed array for the integrator cache
2025-06-12 20:16 [FFmpeg-devel] [PATCH 0/4] avfilter/f_ebur128: various improvements Niklas Haas
` (2 preceding siblings ...)
2025-06-12 20:16 ` [FFmpeg-devel] [PATCH 3/4] avfilter/f_ebur128: use structs for biquad weights Niklas Haas
@ 2025-06-12 20:16 ` Niklas Haas
3 siblings, 0 replies; 5+ messages in thread
From: Niklas Haas @ 2025-06-12 20:16 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Niklas Haas
From: Niklas Haas <git@haasn.dev>
Instead of having a planar array for each channel, use a single packed array.
This will help processing multiple channels in parallel, as we can directly
load all channels' data in a single load instruction.
Also improves memory locality of data, as the loop order is:
for (samples) {
for (channels) {
process sample
}
}
---
libavfilter/f_ebur128.c | 36 ++++++++++--------------------------
1 file changed, 10 insertions(+), 26 deletions(-)
diff --git a/libavfilter/f_ebur128.c b/libavfilter/f_ebur128.c
index 776329db1c..9f7c080750 100644
--- a/libavfilter/f_ebur128.c
+++ b/libavfilter/f_ebur128.c
@@ -62,7 +62,7 @@ struct hist_entry {
};
struct integrator {
- double **cache; ///< window of filtered samples (N ms)
+ double *cache; ///< window of filtered samples (N ms)
int cache_pos; ///< focus on the last added bin in the cache array
int cache_size;
double *sum; ///< sum of the last N ms filtered samples (cache content)
@@ -457,10 +457,12 @@ static int config_audio_output(AVFilterLink *outlink)
#define I400_BINS(x) ((x) * 4 / 10)
#define I3000_BINS(x) ((x) * 3)
+ ebur128->i400.cache_size = I400_BINS(outlink->sample_rate);
+ ebur128->i3000.cache_size = I3000_BINS(outlink->sample_rate);
ebur128->i400.sum = av_calloc(nb_channels, sizeof(*ebur128->i400.sum));
ebur128->i3000.sum = av_calloc(nb_channels, sizeof(*ebur128->i3000.sum));
- ebur128->i400.cache = av_calloc(nb_channels, sizeof(*ebur128->i400.cache));
- ebur128->i3000.cache = av_calloc(nb_channels, sizeof(*ebur128->i3000.cache));
+ ebur128->i400.cache = av_calloc(nb_channels * ebur128->i400.cache_size, sizeof(*ebur128->i400.cache));
+ ebur128->i3000.cache = av_calloc(nb_channels * ebur128->i3000.cache_size, sizeof(*ebur128->i3000.cache));
if (!ebur128->i400.sum || !ebur128->i3000.sum ||
!ebur128->i400.cache || !ebur128->i3000.cache)
return AVERROR(ENOMEM);
@@ -475,17 +477,6 @@ static int config_audio_output(AVFilterLink *outlink)
} else {
ebur128->ch_weighting[i] = 1.0;
}
-
- if (!ebur128->ch_weighting[i])
- continue;
-
- /* bins buffer for the two integration window (400ms and 3s) */
- ebur128->i400.cache_size = I400_BINS(outlink->sample_rate);
- ebur128->i3000.cache_size = I3000_BINS(outlink->sample_rate);
- ebur128->i400.cache[i] = av_calloc(ebur128->i400.cache_size, sizeof(*ebur128->i400.cache[0]));
- ebur128->i3000.cache[i] = av_calloc(ebur128->i3000.cache_size, sizeof(*ebur128->i3000.cache[0]));
- if (!ebur128->i400.cache[i] || !ebur128->i3000.cache[i])
- return AVERROR(ENOMEM);
}
#if CONFIG_SWRESAMPLE
@@ -663,6 +654,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
for (idx_insample = ebur128->idx_insample; idx_insample < nb_samples; idx_insample++) {
const int bin_id_400 = ebur128->i400.cache_pos;
const int bin_id_3000 = ebur128->i3000.cache_pos;
+ double *restrict cache_400 = &ebur128->i400.cache[bin_id_400 * nb_channels];
+ double *restrict cache_3000 = &ebur128->i3000.cache[bin_id_3000 * nb_channels];
#define MOVE_TO_NEXT_CACHED_ENTRY(time) do { \
ebur128->i##time.cache_pos++; \
@@ -701,12 +694,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
/* add the new value, and limit the sum to the cache size (400ms or 3s)
* by removing the oldest one */
const double bin = *z * *z;
- ebur128->i400.sum [ch] += bin - ebur128->i400.cache [ch][bin_id_400];
- ebur128->i3000.sum[ch] += bin - ebur128->i3000.cache[ch][bin_id_3000];
-
- /* override old cache entry with the new value */
- ebur128->i400.cache [ch][bin_id_400 ] = bin;
- ebur128->i3000.cache[ch][bin_id_3000] = bin;
+ ebur128->i400.sum [ch] += bin - cache_400[ch];
+ ebur128->i3000.sum[ch] += bin - cache_3000[ch];
+ cache_400[ch] = cache_3000[ch] = bin;
}
#define FIND_PEAK(global, sp, ptype) do { \
@@ -1083,12 +1073,6 @@ static av_cold void uninit(AVFilterContext *ctx)
av_freep(&ebur128->i3000.sum);
av_freep(&ebur128->i400.histogram);
av_freep(&ebur128->i3000.histogram);
- for (int i = 0; i < ebur128->nb_channels; i++) {
- if (ebur128->i400.cache)
- av_freep(&ebur128->i400.cache[i]);
- if (ebur128->i3000.cache)
- av_freep(&ebur128->i3000.cache[i]);
- }
av_freep(&ebur128->i400.cache);
av_freep(&ebur128->i3000.cache);
av_frame_free(&ebur128->outpicref);
--
2.49.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-06-12 20:18 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-06-12 20:16 [FFmpeg-devel] [PATCH 0/4] avfilter/f_ebur128: various improvements Niklas Haas
2025-06-12 20:16 ` [FFmpeg-devel] [PATCH 1/4] avfilter/f_ebur128: use transformed direct form II Niklas Haas
2025-06-12 20:16 ` [FFmpeg-devel] [PATCH 2/4] avfilter/f_ebur128: simplify sample cache array Niklas Haas
2025-06-12 20:16 ` [FFmpeg-devel] [PATCH 3/4] avfilter/f_ebur128: use structs for biquad weights Niklas Haas
2025-06-12 20:16 ` [FFmpeg-devel] [PATCH 4/4] avfilter/f_ebur128: use a single packed array for the integrator cache Niklas Haas
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git