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,38 @@
package org.jcodec.codecs.wav;
import java.io.IOException;
import java.io.InputStream;
public abstract class ReaderLE {
public static short readShort(InputStream input) throws IOException {
int b2 = input.read();
int b1 = input.read();
if (b1 == -1 || b2 == -1)
return -1;
return (short)((b1 << 8) + b2);
}
public static int readInt(InputStream input) throws IOException {
long b4 = (long)input.read();
long b3 = (long)input.read();
long b2 = (long)input.read();
long b1 = (long)input.read();
if (b1 == -1L || b2 == -1L || b3 == -1L || b4 == -1L)
return -1;
return (int)((b1 << 24L) + (b2 << 16L) + (b3 << 8L) + b4);
}
public static long readLong(InputStream input) throws IOException {
long b8 = (long)input.read();
long b7 = (long)input.read();
long b6 = (long)input.read();
long b5 = (long)input.read();
long b4 = (long)input.read();
long b3 = (long)input.read();
long b2 = (long)input.read();
long b1 = (long)input.read();
if (b1 == -1L || b2 == -1L || b3 == -1L || b4 == -1L || b5 == -1L || b6 == -1L || b7 == -1L || b8 == -1L)
return -1L;
return (long)(int)((b1 << 56L) + (b2 << 48L) + (b3 << 40L) + (b4 << 32L) + (b5 << 24L) + (b6 << 16L) + (b7 << 8L) + b8);
}
}

View file

@ -0,0 +1,75 @@
package org.jcodec.codecs.wav;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import org.jcodec.common.AudioCodecMeta;
import org.jcodec.common.AudioFormat;
import org.jcodec.common.Codec;
import org.jcodec.common.Demuxer;
import org.jcodec.common.DemuxerTrack;
import org.jcodec.common.DemuxerTrackMeta;
import org.jcodec.common.TrackType;
import org.jcodec.common.io.NIOUtils;
import org.jcodec.common.io.SeekableByteChannel;
import org.jcodec.common.model.Packet;
public class WavDemuxer implements Demuxer, DemuxerTrack {
private static final int FRAMES_PER_PKT = 1024;
private SeekableByteChannel ch;
private WavHeader header;
private long dataSize;
private short frameSize;
private int frameNo;
private long pts;
public WavDemuxer(SeekableByteChannel ch) throws IOException {
this.ch = ch;
this.header = WavHeader.readChannel(ch);
this.dataSize = ch.size() - ch.position();
this.frameSize = this.header.getFormat().getFrameSize();
}
public void close() throws IOException {
this.ch.close();
}
public Packet nextFrame() throws IOException {
ByteBuffer data = NIOUtils.fetchFromChannel(this.ch, this.frameSize * 1024);
if (!data.hasRemaining())
return null;
long oldPts = this.pts;
int duration = data.remaining() / this.frameSize;
this.pts += (long)duration;
return Packet.createPacket(data, oldPts, this.header.getFormat().getFrameRate(), (long)(data.remaining() / this.frameSize), (long)this.frameNo++, Packet.FrameType.KEY, null);
}
public DemuxerTrackMeta getMeta() {
AudioFormat format = this.header.getFormat();
AudioCodecMeta audioCodecMeta = AudioCodecMeta.fromAudioFormat(format);
long totalFrames = this.dataSize / (long)format.getFrameSize();
return new DemuxerTrackMeta(TrackType.AUDIO, Codec.PCM, (double)totalFrames / (double)format.getFrameRate(), null, (int)totalFrames, null, null, audioCodecMeta);
}
public List<? extends DemuxerTrack> getTracks() {
List<DemuxerTrack> result = new ArrayList<>();
result.add(this);
return result;
}
public List<? extends DemuxerTrack> getVideoTracks() {
List<DemuxerTrack> result = new ArrayList<>();
return result;
}
public List<? extends DemuxerTrack> getAudioTracks() {
return getTracks();
}
}

View file

@ -0,0 +1,359 @@
package org.jcodec.codecs.wav;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.jcodec.api.UnhandledStateException;
import org.jcodec.common.AudioFormat;
import org.jcodec.common.JCodecUtil2;
import org.jcodec.common.io.IOUtils;
import org.jcodec.common.io.NIOUtils;
import org.jcodec.common.model.ChannelLabel;
public class WavHeader {
public static class FmtChunkExtended extends FmtChunk {
short cbSize;
short bitsPerCodedSample;
int channelLayout;
int guid;
public FmtChunkExtended(WavHeader.FmtChunk other, short cbSize, short bitsPerCodedSample, int channelLayout, int guid) {
super(other.audioFormat, other.numChannels, other.sampleRate, other.byteRate, other.blockAlign, other.bitsPerSample);
this.cbSize = cbSize;
this.bitsPerCodedSample = bitsPerCodedSample;
this.channelLayout = channelLayout;
this.guid = guid;
}
public static WavHeader.FmtChunk read(ByteBuffer bb) throws IOException {
WavHeader.FmtChunk fmtChunk = WavHeader.FmtChunk.get(bb);
ByteOrder old = bb.order();
try {
bb.order(ByteOrder.LITTLE_ENDIAN);
return new FmtChunkExtended(fmtChunk, bb.getShort(), bb.getShort(), bb.getInt(), bb.getInt());
} finally {
bb.order(old);
}
}
public void put(ByteBuffer bb) throws IOException {
super.put(bb);
ByteOrder old = bb.order();
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.putShort(this.cbSize);
bb.putShort(this.bitsPerCodedSample);
bb.putInt(this.channelLayout);
bb.putInt(this.guid);
bb.order(old);
}
public int size() {
return super.size() + 12;
}
public ChannelLabel[] getLabels() {
List<ChannelLabel> labels = new ArrayList<>();
for (int i = 0; i < WavHeader.mapping.length; i++) {
if ((this.channelLayout & 1 << i) != 0)
labels.add(WavHeader.mapping[i]);
}
return labels.<ChannelLabel>toArray(new ChannelLabel[0]);
}
}
static ChannelLabel[] mapping = new ChannelLabel[] {
ChannelLabel.FRONT_LEFT, ChannelLabel.FRONT_RIGHT, ChannelLabel.CENTER, ChannelLabel.LFE, ChannelLabel.REAR_LEFT, ChannelLabel.REAR_RIGHT, ChannelLabel.FRONT_CENTER_LEFT, ChannelLabel.FRONT_CENTER_RIGHT, ChannelLabel.REAR_CENTER, ChannelLabel.SIDE_LEFT,
ChannelLabel.SIDE_RIGHT, ChannelLabel.CENTER, ChannelLabel.FRONT_LEFT, ChannelLabel.CENTER, ChannelLabel.FRONT_RIGHT, ChannelLabel.REAR_LEFT, ChannelLabel.REAR_CENTER, ChannelLabel.REAR_RIGHT, ChannelLabel.STEREO_LEFT, ChannelLabel.STEREO_RIGHT };
public String chunkId;
public int chunkSize;
public String format;
public FmtChunk fmt;
public int dataOffset;
public long dataSize;
public static final int WAV_HEADER_SIZE = 44;
public static class FmtChunk {
public short audioFormat;
public short numChannels;
public int sampleRate;
public int byteRate;
public short blockAlign;
public short bitsPerSample;
public FmtChunk(short audioFormat, short numChannels, int sampleRate, int byteRate, short blockAlign, short bitsPerSample) {
this.audioFormat = audioFormat;
this.numChannels = numChannels;
this.sampleRate = sampleRate;
this.byteRate = byteRate;
this.blockAlign = blockAlign;
this.bitsPerSample = bitsPerSample;
}
public static FmtChunk get(ByteBuffer bb) throws IOException {
ByteOrder old = bb.order();
try {
bb.order(ByteOrder.LITTLE_ENDIAN);
return new FmtChunk(bb.getShort(), bb.getShort(), bb.getInt(), bb.getInt(), bb.getShort(),
bb.getShort());
} finally {
bb.order(old);
}
}
public void put(ByteBuffer bb) throws IOException {
ByteOrder old = bb.order();
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.putShort(this.audioFormat);
bb.putShort(this.numChannels);
bb.putInt(this.sampleRate);
bb.putInt(this.byteRate);
bb.putShort(this.blockAlign);
bb.putShort(this.bitsPerSample);
bb.order(old);
}
public int size() {
return 16;
}
}
public WavHeader(String chunkId, int chunkSize, String format, FmtChunk fmt, int dataOffset, long dataSize) {
this.chunkId = chunkId;
this.chunkSize = chunkSize;
this.format = format;
this.fmt = fmt;
this.dataOffset = dataOffset;
this.dataSize = dataSize;
}
public static WavHeader copyWithRate(WavHeader header, int rate) {
WavHeader result = new WavHeader(header.chunkId, header.chunkSize, header.format,
copyFmt(header.fmt), header.dataOffset, header.dataSize);
result.fmt.sampleRate = rate;
return result;
}
public static WavHeader copyWithChannels(WavHeader header, int channels) {
WavHeader result = new WavHeader(header.chunkId, header.chunkSize, header.format,
copyFmt(header.fmt), header.dataOffset, header.dataSize);
result.fmt.numChannels = (short)channels;
return result;
}
private static FmtChunk copyFmt(FmtChunk fmt) {
if (fmt instanceof FmtChunkExtended) {
FmtChunkExtended fmtext = (FmtChunkExtended)fmt;
fmt = new FmtChunkExtended(fmtext, fmtext.cbSize, fmtext.bitsPerCodedSample, fmtext.channelLayout, fmtext.guid);
} else {
fmt = new FmtChunk(fmt.audioFormat, fmt.numChannels, fmt.sampleRate, fmt.byteRate, fmt.blockAlign, fmt.bitsPerSample);
}
return fmt;
}
public static WavHeader createWavHeader(AudioFormat format, int samples) {
WavHeader w = new WavHeader("RIFF", 40, "WAVE", new FmtChunk((short)1, (short)format.getChannels(), format.getSampleRate(),
format.getSampleRate() * format.getChannels() * (format.getSampleSizeInBits() >> 3),
(short)(format.getChannels() * (format.getSampleSizeInBits() >> 3)),
(short)format.getSampleSizeInBits()), 44, calcDataSize(format.getChannels(),
format.getSampleSizeInBits() >> 3, (long)samples));
return w;
}
public static WavHeader stereo48k() {
return stereo48kWithSamples(0L);
}
public static WavHeader stereo48kWithSamples(long samples) {
return new WavHeader("RIFF", 40, "WAVE", new FmtChunk((short)1, (short)2, 48000, 192000, (short)4, (short)16), 44,
calcDataSize(2, 2, samples));
}
public static WavHeader mono48k(long samples) {
return new WavHeader("RIFF", 40, "WAVE", new FmtChunk((short)1, (short)1, 48000, 96000, (short)2, (short)16), 44,
calcDataSize(1, 2, samples));
}
public static WavHeader emptyWavHeader() {
return new WavHeader("RIFF", 40, "WAVE", newFmtChunk(), 44, 0L);
}
private static FmtChunk newFmtChunk() {
return new FmtChunk((short)1, (short)0, 0, 0, (short)0, (short)0);
}
public static WavHeader read(File file) throws IOException {
ReadableByteChannel is = null;
try {
is = NIOUtils.readableChannel(file);
return readChannel(is);
} finally {
IOUtils.closeQuietly(is);
}
}
public static WavHeader readChannel(ReadableByteChannel _in) throws IOException {
String fourcc;
ByteBuffer buf = ByteBuffer.allocate(128);
buf.order(ByteOrder.LITTLE_ENDIAN);
_in.read(buf);
if (buf.remaining() > 0)
throw new IOException("Incomplete wav header found");
buf.flip();
String chunkId = NIOUtils.readString(buf, 4);
int chunkSize = buf.getInt();
String format = NIOUtils.readString(buf, 4);
FmtChunk fmt = null;
if (!"RIFF".equals(chunkId) || !"WAVE".equals(format))
return null;
int size = 0;
do {
fourcc = NIOUtils.readString(buf, 4);
size = buf.getInt();
if ("fmt ".equals(fourcc) && size >= 14 && size <= 1048576) {
switch (size) {
case 16:
fmt = FmtChunk.get(buf);
break;
case 18:
fmt = FmtChunk.get(buf);
NIOUtils.skip(buf, 2);
break;
case 40:
fmt = FmtChunkExtended.get(buf);
NIOUtils.skip(buf, 12);
break;
case 28:
fmt = FmtChunkExtended.get(buf);
break;
default:
throw new UnhandledStateException("Don't know how to handle fmt size: " + size);
}
} else if (!"data".equals(fourcc)) {
NIOUtils.skip(buf, size);
}
} while (!"data".equals(fourcc));
return new WavHeader(chunkId, chunkSize, format, fmt, buf.position(), (long)size);
}
public static WavHeader multiChannelWavFromFiles(File[] files) throws IOException {
WavHeader[] headers = new WavHeader[files.length];
for (int i = 0; i < files.length; i++)
headers[i] = read(files[i]);
return multiChannelWav(headers);
}
public static WavHeader multiChannelWav(WavHeader[] headers) {
WavHeader w = emptyWavHeader();
int totalSize = 0;
for (int i = 0; i < headers.length; i++) {
WavHeader wavHeader = headers[i];
totalSize = (int)((long)totalSize + wavHeader.dataSize);
}
w.dataSize = (long)totalSize;
FmtChunk fmt = (headers[0]).fmt;
int bitsPerSample = fmt.bitsPerSample;
int bytesPerSample = bitsPerSample / 8;
int sampleRate = fmt.sampleRate;
w.fmt.bitsPerSample = (short)bitsPerSample;
w.fmt.blockAlign = (short)(headers.length * bytesPerSample);
w.fmt.byteRate = headers.length * bytesPerSample * sampleRate;
w.fmt.numChannels = (short)headers.length;
w.fmt.sampleRate = sampleRate;
return w;
}
public void write(WritableByteChannel out) throws IOException {
long chunkSize;
ByteBuffer bb = ByteBuffer.allocate(44);
bb.order(ByteOrder.LITTLE_ENDIAN);
if (this.dataSize <= 4294967295L) {
chunkSize = this.dataSize + 36L;
} else {
chunkSize = 40L;
}
bb.put(JCodecUtil2.asciiString("RIFF"));
bb.putInt((int)chunkSize);
bb.put(JCodecUtil2.asciiString("WAVE"));
bb.put(JCodecUtil2.asciiString("fmt "));
bb.putInt(this.fmt.size());
this.fmt.put(bb);
bb.put(JCodecUtil2.asciiString("data"));
if (this.dataSize <= 4294967295L) {
bb.putInt((int)this.dataSize);
} else {
bb.putInt(0);
}
bb.flip();
out.write(bb);
}
public static long calcDataSize(int numChannels, int bytesPerSample, long samples) {
return samples * (long)numChannels * (long)bytesPerSample;
}
public static WavHeader create(AudioFormat af, int size) {
WavHeader w = emptyWavHeader();
w.dataSize = (long)size;
FmtChunk fmt = newFmtChunk();
int bitsPerSample = af.getSampleSizeInBits();
int bytesPerSample = bitsPerSample / 8;
int sampleRate = af.getSampleRate();
w.fmt.bitsPerSample = (short)bitsPerSample;
w.fmt.blockAlign = af.getFrameSize();
w.fmt.byteRate = af.getFrameRate() * af.getFrameSize();
w.fmt.numChannels = (short)af.getChannels();
w.fmt.sampleRate = af.getSampleRate();
return w;
}
public ChannelLabel[] getChannelLabels() {
if (this.fmt instanceof FmtChunkExtended)
return ((FmtChunkExtended)this.fmt).getLabels();
switch (this.fmt.numChannels) {
case 1:
return new ChannelLabel[] { ChannelLabel.MONO };
case 2:
return new ChannelLabel[] { ChannelLabel.STEREO_LEFT, ChannelLabel.STEREO_RIGHT };
case 3:
return new ChannelLabel[] { ChannelLabel.FRONT_LEFT, ChannelLabel.FRONT_RIGHT, ChannelLabel.REAR_CENTER };
case 4:
return new ChannelLabel[] { ChannelLabel.FRONT_LEFT, ChannelLabel.FRONT_RIGHT, ChannelLabel.REAR_LEFT, ChannelLabel.REAR_RIGHT };
case 5:
return new ChannelLabel[] { ChannelLabel.FRONT_LEFT, ChannelLabel.FRONT_RIGHT, ChannelLabel.CENTER, ChannelLabel.REAR_LEFT, ChannelLabel.REAR_RIGHT };
case 6:
return new ChannelLabel[] { ChannelLabel.FRONT_LEFT, ChannelLabel.FRONT_RIGHT, ChannelLabel.CENTER, ChannelLabel.LFE, ChannelLabel.REAR_LEFT, ChannelLabel.REAR_RIGHT };
case 7:
return new ChannelLabel[] { ChannelLabel.FRONT_LEFT, ChannelLabel.FRONT_RIGHT, ChannelLabel.CENTER, ChannelLabel.LFE, ChannelLabel.REAR_LEFT, ChannelLabel.REAR_RIGHT, ChannelLabel.REAR_CENTER };
case 8:
return new ChannelLabel[] { ChannelLabel.FRONT_LEFT, ChannelLabel.FRONT_RIGHT, ChannelLabel.CENTER, ChannelLabel.LFE, ChannelLabel.REAR_LEFT, ChannelLabel.REAR_RIGHT, ChannelLabel.REAR_LEFT, ChannelLabel.REAR_RIGHT };
}
ChannelLabel[] labels = new ChannelLabel[this.fmt.numChannels];
Arrays.fill(labels, ChannelLabel.MONO);
return labels;
}
public AudioFormat getFormat() {
return new AudioFormat(this.fmt.sampleRate, this.fmt.bitsPerSample, this.fmt.numChannels, true, false);
}
}

View file

@ -0,0 +1,98 @@
package org.jcodec.codecs.wav;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.channels.ReadableByteChannel;
import org.jcodec.audio.AudioSource;
import org.jcodec.common.AudioFormat;
import org.jcodec.common.AudioUtil;
import org.jcodec.common.io.NIOUtils;
public class WavInput implements Closeable {
protected WavHeader header;
protected byte[] prevBuf;
protected ReadableByteChannel _in;
protected AudioFormat format;
public WavInput(ReadableByteChannel _in) throws IOException {
this.header = WavHeader.readChannel(_in);
this.format = this.header.getFormat();
this._in = _in;
}
public int read(ByteBuffer buf) throws IOException {
int maxRead = this.format.framesToBytes(this.format.bytesToFrames(buf.remaining()));
return NIOUtils.readL(this._in, buf, maxRead);
}
public void close() throws IOException {
this._in.close();
}
public WavHeader getHeader() {
return this.header;
}
public AudioFormat getFormat() {
return this.format;
}
public static class WavFile extends WavInput {
public WavFile(File f) throws IOException {
super(NIOUtils.readableChannel(f));
}
public void close() throws IOException {
super.close();
this._in.close();
}
}
public static class Source implements AudioSource, Closeable {
private WavInput src;
private AudioFormat format;
private int pos;
public Source(WavInput src) {
this.src = src;
this.format = src.getFormat();
}
public AudioFormat getFormat() {
return this.src.getFormat();
}
public void close() throws IOException {
this.src.close();
}
public int read(int[] samples, int max) throws IOException {
max = Math.min(max, samples.length);
ByteBuffer bb = ByteBuffer.allocate(this.format.samplesToBytes(max));
int read = this.src.read(bb);
bb.flip();
AudioUtil.toInt(this.format, bb, samples);
return this.format.bytesToFrames(read);
}
public int readFloat(FloatBuffer samples) throws IOException {
ByteBuffer bb = ByteBuffer.allocate(this.format.samplesToBytes(samples.remaining()));
int i = this.src.read(bb);
if (i == -1)
return -1;
bb.flip();
AudioUtil.toFloat(this.format, bb, samples);
int read = this.format.bytesToFrames(i);
this.pos += read;
return read;
}
}
}

View file

@ -0,0 +1,53 @@
package org.jcodec.codecs.wav;
import java.io.IOException;
import org.jcodec.common.AudioCodecMeta;
import org.jcodec.common.AudioFormat;
import org.jcodec.common.Codec;
import org.jcodec.common.Muxer;
import org.jcodec.common.MuxerTrack;
import org.jcodec.common.VideoCodecMeta;
import org.jcodec.common.io.NIOUtils;
import org.jcodec.common.io.SeekableByteChannel;
import org.jcodec.common.model.Packet;
public class WavMuxer implements Muxer, MuxerTrack {
protected SeekableByteChannel out;
protected WavHeader header;
protected int written;
private AudioFormat format;
public WavMuxer(SeekableByteChannel out) throws IOException {
this.out = out;
}
public void addFrame(Packet outPacket) throws IOException {
this.written += this.out.write(outPacket.getData());
}
public void close() throws IOException {
this.out.setPosition(0L);
WavHeader.createWavHeader(this.format, this.format.bytesToFrames(this.written)).write(this.out);
NIOUtils.closeQuietly(this.out);
}
public MuxerTrack addVideoTrack(Codec codec, VideoCodecMeta meta) {
return null;
}
public MuxerTrack addAudioTrack(Codec codec, AudioCodecMeta meta) {
this.header = WavHeader.createWavHeader(meta.getFormat(), 0);
this.format = meta.getFormat();
try {
this.header.write(this.out);
} catch (IOException e) {
throw new RuntimeException(e);
}
return this;
}
public void finish() throws IOException {}
}

View file

@ -0,0 +1,77 @@
package org.jcodec.codecs.wav;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import org.jcodec.audio.AudioSink;
import org.jcodec.common.AudioFormat;
import org.jcodec.common.AudioUtil;
import org.jcodec.common.io.NIOUtils;
import org.jcodec.common.io.SeekableByteChannel;
public class WavOutput implements Closeable {
protected SeekableByteChannel out;
protected WavHeader header;
protected int written;
protected AudioFormat format;
public WavOutput(SeekableByteChannel out, AudioFormat format) throws IOException {
this.out = out;
this.format = format;
this.header = WavHeader.createWavHeader(format, 0);
this.header.write(out);
}
public void write(ByteBuffer samples) throws IOException {
this.written += this.out.write(samples);
}
public void close() throws IOException {
this.out.setPosition(0L);
WavHeader.createWavHeader(this.format, this.format.bytesToFrames(this.written)).write(this.out);
NIOUtils.closeQuietly(this.out);
}
public static class WavOutFile extends WavOutput {
public WavOutFile(File f, AudioFormat format) throws IOException {
super(NIOUtils.writableChannel(f), format);
}
public void close() throws IOException {
super.close();
NIOUtils.closeQuietly(this.out);
}
}
public static class Sink implements AudioSink, Closeable {
private WavOutput out;
public Sink(WavOutput out) {
this.out = out;
}
public void writeFloat(FloatBuffer data) throws IOException {
ByteBuffer buf = ByteBuffer.allocate(this.out.format.samplesToBytes(data.remaining()));
AudioUtil.fromFloat(data, this.out.format, buf);
buf.flip();
this.out.write(buf);
}
public void write(int[] data, int len) throws IOException {
len = Math.min(data.length, len);
ByteBuffer buf = ByteBuffer.allocate(this.out.format.samplesToBytes(len));
AudioUtil.fromInt(data, len, this.out.format, buf);
buf.flip();
this.out.write(buf);
}
public void close() throws IOException {
this.out.close();
}
}
}

View file

@ -0,0 +1,29 @@
package org.jcodec.codecs.wav;
import java.io.IOException;
import java.io.OutputStream;
public abstract class WriterLE {
public static void writeShort(OutputStream out, short s) throws IOException {
out.write(s & 0xFF);
out.write(s >> 8 & 0xFF);
}
public static void writeInt(OutputStream out, int i) throws IOException {
out.write(i & 0xFF);
out.write(i >> 8 & 0xFF);
out.write(i >> 16 & 0xFF);
out.write(i >> 24 & 0xFF);
}
public static void writeLong(OutputStream out, long l) throws IOException {
out.write((int)(l & 0xFFL));
out.write((int)(l >> 8L & 0xFFL));
out.write((int)(l >> 16L & 0xFFL));
out.write((int)(l >> 24L & 0xFFL));
out.write((int)(l >> 32L & 0xFFL));
out.write((int)(l >> 40L & 0xFFL));
out.write((int)(l >> 48L & 0xFFL));
out.write((int)(l >> 56L & 0xFFL));
}
}