www in docker support
This commit is contained in:
parent
539a848e95
commit
c227fce036
2145 changed files with 399596 additions and 58 deletions
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue