www in docker support

This commit is contained in:
MaddoScientisto 2026-04-22 18:41:37 +02:00
commit c227fce036
2145 changed files with 399596 additions and 58 deletions

View file

@ -0,0 +1,78 @@
package org.jcodec.audio;
import java.io.IOException;
import java.nio.FloatBuffer;
public class Audio {
public static void transfer(AudioSource src, AudioSink sink) throws IOException {
filterTransfer(src, new DummyFilter(1), sink);
}
public static void filterTransfer(AudioSource src, AudioFilter filter, AudioSink sink) throws IOException {
if (filter.getNInputs() != 1)
throw new IllegalArgumentException("Audio filter has # inputs != 1");
if (filter.getNOutputs() != 1)
throw new IllegalArgumentException("Audio filter has # outputs != 1");
if (filter.getDelay() != 0)
throw new IllegalArgumentException("Audio filter has delay");
FloatBuffer[] ins = { FloatBuffer.allocate(4096) };
FloatBuffer[] outs = { FloatBuffer.allocate(8192) };
long[] pos = new long[1];
while (src.readFloat(ins[0]) != -1) {
ins[0].flip();
filter.filter(ins, pos, outs);
pos[0] = pos[0] + (long)ins[0].position();
rotate(ins[0]);
outs[0].flip();
sink.writeFloat(outs[0]);
outs[0].clear();
}
}
public static void print(FloatBuffer buf) {
FloatBuffer dup = buf.duplicate();
while (dup.hasRemaining())
System.out.print(String.format("%.3f,", dup.get()));
System.out.println();
}
public static void rotate(FloatBuffer buf) {
int pos;
for (pos = 0; buf.hasRemaining(); pos++)
buf.put(pos, buf.get());
buf.position(pos);
buf.limit(buf.capacity());
}
public static class DummyFilter implements AudioFilter {
private int nInputs;
public DummyFilter(int nInputs) {
this.nInputs = nInputs;
}
public void filter(FloatBuffer[] _in, long[] inPos, FloatBuffer[] out) {
for (int i = 0; i < _in.length; i++) {
if (out[i].remaining() >= _in[i].remaining()) {
out[i].put(_in[i]);
} else {
FloatBuffer duplicate = _in[i].duplicate();
duplicate.limit(_in[i].position() + out[i].remaining());
out[i].put(duplicate);
}
}
}
public int getDelay() {
return 0;
}
public int getNInputs() {
return this.nInputs;
}
public int getNOutputs() {
return this.nInputs;
}
}
}

View file

@ -0,0 +1,13 @@
package org.jcodec.audio;
import java.nio.FloatBuffer;
public interface AudioFilter {
void filter(FloatBuffer[] paramArrayOfFloatBuffer1, long[] paramArrayOflong, FloatBuffer[] paramArrayOfFloatBuffer2);
int getDelay();
int getNInputs();
int getNOutputs();
}

View file

@ -0,0 +1,8 @@
package org.jcodec.audio;
import java.io.IOException;
import java.nio.FloatBuffer;
public interface AudioSink {
void writeFloat(FloatBuffer paramFloatBuffer) throws IOException;
}

View file

@ -0,0 +1,11 @@
package org.jcodec.audio;
import java.io.IOException;
import java.nio.FloatBuffer;
import org.jcodec.common.AudioFormat;
public interface AudioSource {
AudioFormat getFormat();
int readFloat(FloatBuffer paramFloatBuffer) throws IOException;
}

View file

@ -0,0 +1,46 @@
package org.jcodec.audio;
import java.nio.FloatBuffer;
import org.jcodec.common.AudioFormat;
import org.jcodec.common.Preconditions;
public class ChannelMerge implements AudioFilter {
private AudioFormat format;
public ChannelMerge(AudioFormat format) {
this.format = format;
}
public void filter(FloatBuffer[] _in, long[] inPos, FloatBuffer[] out) {
if (_in.length != this.format.getChannels())
throw new IllegalArgumentException("Channel merge must be supplied with " + this.format.getChannels() + " input buffers to hold the channels.");
if (out.length != 1)
throw new IllegalArgumentException("Channel merget invoked on more then one output");
FloatBuffer out0 = out[0];
int min = Integer.MAX_VALUE;
for (int k = 0; k < _in.length; k++) {
if (_in[k].remaining() < min)
min = _in[k].remaining();
}
for (int j = 0; j < _in.length; j++)
Preconditions.checkState((_in[j].remaining() == min));
if (out0.remaining() < min * _in.length)
throw new IllegalArgumentException("Supplied output buffer is not big enough to hold " + min + " * " + _in.length + " = " + min * _in.length + " output samples.");
for (int i = 0; i < min; i++) {
for (int m = 0; m < _in.length; m++)
out0.put(_in[m].get());
}
}
public int getDelay() {
return 0;
}
public int getNInputs() {
return this.format.getChannels();
}
public int getNOutputs() {
return 1;
}
}

View file

@ -0,0 +1,43 @@
package org.jcodec.audio;
import java.nio.FloatBuffer;
import org.jcodec.common.AudioFormat;
public class ChannelSplit implements AudioFilter {
private AudioFormat format;
public ChannelSplit(AudioFormat format) {
this.format = format;
}
public void filter(FloatBuffer[] _in, long[] inPos, FloatBuffer[] out) {
if (_in.length != 1)
throw new IllegalArgumentException("Channel split invoked on more then one input");
if (out.length != this.format.getChannels())
throw new IllegalArgumentException("Channel split must be supplied with " + this.format.getChannels() + " output buffers to hold the channels.");
FloatBuffer in0 = _in[0];
int outSampleCount = in0.remaining() / out.length;
for (int i = 0; i < out.length; i++) {
if (out[i].remaining() < outSampleCount)
throw new IllegalArgumentException("Supplied buffer for " + i + "th channel doesn't have sufficient space to put the samples ( required: " + outSampleCount + ", actual: " + out[i]
.remaining() + ")");
}
while (in0.remaining() >= this.format.getChannels()) {
for (int j = 0; j < out.length; j++)
out[j].put(in0.get());
}
}
public int getDelay() {
return 0;
}
public int getNInputs() {
return 1;
}
public int getNOutputs() {
return this.format.getChannels();
}
}

View file

@ -0,0 +1,47 @@
package org.jcodec.audio;
import java.nio.FloatBuffer;
public abstract class ConvolutionFilter implements AudioFilter {
private double[] kernel;
protected abstract double[] buildKernel();
public void filter(FloatBuffer[] _in, long[] pos, FloatBuffer[] out) {
if (_in.length != 1)
throw new IllegalArgumentException(getClass().getName() + " filter is designed to work only on one input");
if (out.length != 1)
throw new IllegalArgumentException(getClass().getName() + " filter is designed to work only on one output");
FloatBuffer in0 = _in[0];
FloatBuffer out0 = out[0];
if (this.kernel == null)
this.kernel = buildKernel();
if (out0.remaining() < in0.remaining() - this.kernel.length)
throw new IllegalArgumentException("Output buffer is too small");
if (in0.remaining() <= this.kernel.length)
throw new IllegalArgumentException("Input buffer should contain > kernel lenght (" + this.kernel.length + ") samples.");
int halfKernel = this.kernel.length / 2;
int i;
for (i = in0.position() + halfKernel; i < in0.limit() - halfKernel; i++) {
double result = 0.0D;
for (int j = 0; j < this.kernel.length; j++)
result += this.kernel[j] * (double)in0.get(i + j - halfKernel);
out0.put((float)result);
}
in0.position(i - halfKernel);
}
public int getDelay() {
if (this.kernel == null)
this.kernel = buildKernel();
return this.kernel.length / 2;
}
public int getNInputs() {
return 1;
}
public int getNOutputs() {
return 1;
}
}

View file

@ -0,0 +1,81 @@
package org.jcodec.audio;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class FilterGraph implements AudioFilter {
private FilterSocket[] sockets;
public static Factory addLevel(AudioFilter first) {
return new Factory(first);
}
public static class Factory {
private List<FilterSocket> sockets = new ArrayList<>();
protected Factory(AudioFilter firstFilter) {
if (firstFilter.getDelay() != 0) {
this.sockets.add(FilterSocket.createFilterSocket(new Audio.DummyFilter[] { new Audio.DummyFilter(firstFilter.getNInputs()) }));
addLevel(new AudioFilter[] { firstFilter });
} else {
this.sockets.add(FilterSocket.createFilterSocket(new AudioFilter[] { firstFilter }));
}
}
public Factory addLevel(AudioFilter[] filters) {
FilterSocket socket = FilterSocket.createFilterSocket(filters);
socket.allocateBuffers(4096);
this.sockets.add(socket);
return this;
}
public Factory addLevels(AudioFilter filter, int n) {
AudioFilter[] filters = new AudioFilter[n];
Arrays.fill(filters, filter);
return addLevel(filters);
}
public Factory addLevelSpan(AudioFilter filter) {
int prevLevelOuts = this.sockets.get(this.sockets.size() - 1).getTotalOutputs();
if (prevLevelOuts % filter.getNInputs() != 0)
throw new IllegalArgumentException("Can't fill " + prevLevelOuts + " with multiple of " +
filter.getNInputs());
return addLevels(filter, prevLevelOuts / filter.getNInputs());
}
public FilterGraph create() {
return new FilterGraph(this.sockets.<FilterSocket>toArray(new FilterSocket[0]));
}
}
private FilterGraph(FilterSocket[] sockets) {
this.sockets = sockets;
}
public void filter(FloatBuffer[] ins, long[] pos, FloatBuffer[] outs) {
this.sockets[0].setBuffers(ins, pos);
for (int i = 0; i < this.sockets.length; i++) {
FloatBuffer[] curOut = (i < this.sockets.length - 1) ? this.sockets[i + 1].getBuffers() : outs;
this.sockets[i].filter(curOut);
if (i > 0)
this.sockets[i].rotate();
if (i < this.sockets.length - 1)
for (FloatBuffer b : curOut)
b.flip();
}
}
public int getDelay() {
return this.sockets[0].getFilters()[0].getDelay();
}
public int getNInputs() {
return this.sockets[0].getTotalInputs();
}
public int getNOutputs() {
return this.sockets[this.sockets.length - 1].getTotalOutputs();
}
}

View file

@ -0,0 +1,101 @@
package org.jcodec.audio;
import java.nio.FloatBuffer;
import org.jcodec.platform.Platform;
public class FilterSocket {
private FloatBuffer[] buffers;
private long[] positions;
private int[] delays;
private AudioFilter[] filters;
private int totalInputs;
private int totalOutputs;
public static FilterSocket createFilterSocket(AudioFilter[] filters) {
FilterSocket fs = new FilterSocket();
fs.totalInputs = 0;
fs.totalOutputs = 0;
for (int j = 0; j < filters.length; j++) {
fs.totalInputs += filters[j].getNInputs();
fs.totalOutputs += filters[j].getNOutputs();
}
fs.buffers = new FloatBuffer[fs.totalInputs];
fs.positions = new long[fs.totalInputs];
fs.delays = new int[fs.totalInputs];
for (int i = 0, b = 0; i < filters.length; i++) {
for (int k = 0; k < filters[i].getNInputs(); k++, b++)
fs.delays[b] = filters[i].getDelay();
}
fs.filters = filters;
return fs;
}
public void allocateBuffers(int bufferSize) {
for (int i = 0; i < this.totalInputs; i++) {
this.buffers[i] = FloatBuffer.allocate(bufferSize + this.delays[i] * 2);
this.buffers[i].position(this.delays[i]);
}
}
public static FilterSocket createFilterSocket2(AudioFilter filter, FloatBuffer[] buffers, long[] positions) {
FilterSocket fs = new FilterSocket();
fs.filters = new AudioFilter[] { filter };
fs.buffers = buffers;
fs.positions = positions;
fs.delays = new int[] { filter.getDelay() };
fs.totalInputs = filter.getNInputs();
fs.totalOutputs = filter.getNOutputs();
return fs;
}
public void filter(FloatBuffer[] outputs) {
if (outputs.length != this.totalOutputs)
throw new IllegalArgumentException("Can not output to provided filter socket inputs != outputs (" + outputs.length + "!=" + this.totalOutputs + ")");
for (int i = 0, ii = 0, oi = 0; i < this.filters.length; ii += this.filters[i].getNInputs(), oi += this.filters[i]
.getNOutputs(), i++)
this.filters[i].filter(Platform.<FloatBuffer>copyOfRangeO(this.buffers, ii, this.filters[i].getNInputs() + ii),
Platform.copyOfRangeL(this.positions, ii, this.filters[i].getNInputs() + ii),
Platform.<FloatBuffer>copyOfRangeO(outputs, oi, this.filters[i].getNOutputs() + oi));
}
FloatBuffer[] getBuffers() {
return this.buffers;
}
public void rotate() {
for (int i = 0; i < this.buffers.length; i++) {
this.positions[i] = this.positions[i] + (long)this.buffers[i].position();
Audio.rotate(this.buffers[i]);
}
}
public void setBuffers(FloatBuffer[] ins, long[] pos) {
if (ins.length != this.totalInputs)
throw new IllegalArgumentException("Number of input buffers provided is less then the number of filter inputs.");
if (pos.length != this.totalInputs)
throw new IllegalArgumentException("Number of input buffer positions provided is less then the number of filter inputs.");
this.buffers = ins;
this.positions = pos;
}
public int getTotalInputs() {
return this.totalInputs;
}
public int getTotalOutputs() {
return this.totalOutputs;
}
AudioFilter[] getFilters() {
return this.filters;
}
public long[] getPositions() {
return this.positions;
}
}

View file

@ -0,0 +1,65 @@
package org.jcodec.audio;
import java.nio.FloatBuffer;
public class LanczosInterpolator implements AudioFilter {
private double rateStep;
public static double lanczos(double x, int a) {
return (x < (double)-a) ? 0.0D : ((x > (double)a) ? 0.0D : (
(double)a * Math.sin(Math.PI * x) * Math.sin(Math.PI * x / (double)a) / (9.869604401089358D * x * x)));
}
public LanczosInterpolator(int fromRate, int toRate) {
this.rateStep = (double)fromRate / (double)toRate;
}
public void filter(FloatBuffer[] _in, long[] pos, FloatBuffer[] out) {
if (_in.length != 1)
throw new IllegalArgumentException(getClass().getName() + " filter is designed to work only on one input");
if (out.length != 1)
throw new IllegalArgumentException(getClass().getName() + " filter is designed to work only on one output");
FloatBuffer in0 = _in[0];
FloatBuffer out0 = out[0];
if ((double)out0.remaining() < (double)(in0.remaining() - 6) / this.rateStep)
throw new IllegalArgumentException("Output buffer is too small");
if (in0.remaining() <= 6)
throw new IllegalArgumentException("Input buffer should contain > 6 samples.");
for (int outSample = 0;; outSample++) {
double inSample = 3.0D + (double)outSample * this.rateStep + Math.ceil((double)pos[0] / this.rateStep) * this.rateStep - (double)pos[0];
int p0i = (int)Math.floor(inSample);
int q0i = (int)Math.ceil(inSample);
if (p0i >= in0.limit() - 3) {
in0.position(p0i - 3);
break;
}
double p0d = (double)p0i - inSample;
if (p0d < -0.001D) {
double q0d = (double)q0i - inSample;
double p0c = lanczos(p0d, 3);
double q0c = lanczos(q0d, 3);
double p1c = lanczos(p0d - 1.0D, 3);
double q1c = lanczos(q0d + 1.0D, 3);
double p2c = lanczos(p0d - 2.0D, 3);
double q2c = lanczos(q0d + 2.0D, 3);
double factor = 1.0D / (p0c + p1c + p2c + q0c + q1c + q2c);
out0.put(
(float)(((double)in0.get(q0i) * q0c + (double)in0.get(q0i + 1) * q1c + (double)in0.get(q0i + 2) * q2c + (double)in0.get(p0i) * p0c + (double)in0.get(p0i - 1) * p1c + (double)in0.get(p0i - 2) * p2c) * factor));
} else {
out0.put(in0.get(p0i));
}
}
}
public int getDelay() {
return 3;
}
public int getNInputs() {
return 1;
}
public int getNOutputs() {
return 1;
}
}

View file

@ -0,0 +1,38 @@
package org.jcodec.audio;
public class SincLowPassFilter extends ConvolutionFilter {
private int kernelSize;
private double cutoffFreq;
public static SincLowPassFilter createSincLowPassFilter(double cutoffFreq) {
return new SincLowPassFilter(40, cutoffFreq);
}
public static SincLowPassFilter createSincLowPassFilter2(int cutoffFreq, int samplingRate) {
return new SincLowPassFilter(40, (double)cutoffFreq / (double)samplingRate);
}
public SincLowPassFilter(int kernelSize, double cutoffFreq) {
this.kernelSize = kernelSize;
this.cutoffFreq = cutoffFreq;
}
protected double[] buildKernel() {
double[] kernel = new double[this.kernelSize];
double sum = 0.0D;
for (int j = 0; j < this.kernelSize; j++) {
int a = j - this.kernelSize / 2;
if (a != 0) {
kernel[j] = Math.sin(6.283185307179586D * this.cutoffFreq * (double)(j - this.kernelSize / 2)) / (double)(j - this.kernelSize / 2) * (0.54D - 0.46D *
Math.cos(6.283185307179586D * (double)j / (double)this.kernelSize));
} else {
kernel[j] = 6.283185307179586D * this.cutoffFreq;
}
sum += kernel[j];
}
for (int i = 0; i < this.kernelSize; i++)
kernel[i] = kernel[i] / sum;
return kernel;
}
}