![JAR search and dependency download from the Maven repository](/logo.png)
org.jcodec.containers.mp4.muxer.PCMMP4MuxerTrack Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jcodec Show documentation
Show all versions of jcodec Show documentation
Pure Java implementation of video/audio codecs and formats
package org.jcodec.containers.mp4.muxer;
import org.jcodec.common.Assert;
import org.jcodec.common.AudioFormat;
import org.jcodec.common.LongArrayList;
import org.jcodec.common.model.Packet;
import org.jcodec.common.model.Rational;
import org.jcodec.common.model.Size;
import org.jcodec.common.model.Unit;
import org.jcodec.containers.mp4.MP4TrackType;
import org.jcodec.containers.mp4.boxes.AudioSampleEntry;
import org.jcodec.containers.mp4.boxes.Box;
import org.jcodec.containers.mp4.boxes.ChunkOffsets64Box;
import org.jcodec.containers.mp4.boxes.HandlerBox;
import org.jcodec.containers.mp4.boxes.Header;
import org.jcodec.containers.mp4.boxes.MediaBox;
import org.jcodec.containers.mp4.boxes.MediaHeaderBox;
import org.jcodec.containers.mp4.boxes.MediaInfoBox;
import org.jcodec.containers.mp4.boxes.MovieHeaderBox;
import org.jcodec.containers.mp4.boxes.NodeBox;
import org.jcodec.containers.mp4.boxes.SampleDescriptionBox;
import org.jcodec.containers.mp4.boxes.SampleEntry;
import org.jcodec.containers.mp4.boxes.SampleSizesBox;
import org.jcodec.containers.mp4.boxes.SampleToChunkBox;
import org.jcodec.containers.mp4.boxes.SampleToChunkBox.SampleToChunkEntry;
import org.jcodec.containers.mp4.boxes.TimeToSampleBox;
import org.jcodec.containers.mp4.boxes.TimeToSampleBox.TimeToSampleEntry;
import org.jcodec.containers.mp4.boxes.TrackHeaderBox;
import org.jcodec.containers.mp4.boxes.TrakBox;
import java.io.IOException;
import java.lang.IllegalStateException;
import java.nio.ByteBuffer;
import java.util.Date;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* @author The JCodec project
*
*/
public class PCMMP4MuxerTrack extends AbstractMP4MuxerTrack {
private int frameDuration;
private int frameSize;
private int framesInCurChunk;
private LongArrayList chunkOffsets;
private int totalFrames;
public PCMMP4MuxerTrack(int trackId, AudioFormat format) {
super(trackId, MP4TrackType.SOUND);
this.chunkOffsets = LongArrayList.createLongArrayList();
this.frameDuration = 1;
this.frameSize = (format.getSampleSizeInBits() >> 3) * format.getChannels();
addSampleEntry(AudioSampleEntry.audioSampleEntryPCM(format));
this._timescale = format.getSampleRate();
setTgtChunkDuration(new Rational(1, 2), Unit.SEC);
}
@Override
public void addFrame(Packet outPacket) throws IOException {
addSamples(outPacket.getData().duplicate());
}
public void addSamples(ByteBuffer buffer) throws IOException {
curChunk.add(buffer);
int frames = buffer.remaining() / frameSize;
totalFrames += frames;
framesInCurChunk += frames;
chunkDuration += frames * frameDuration;
outChunkIfNeeded();
}
private void outChunkIfNeeded() throws IOException {
Assert.assertTrue(tgtChunkDurationUnit == Unit.FRAME || tgtChunkDurationUnit == Unit.SEC);
if (tgtChunkDurationUnit == Unit.FRAME
&& framesInCurChunk * tgtChunkDuration.getDen() == tgtChunkDuration.getNum()) {
outChunk();
} else if (tgtChunkDurationUnit == Unit.SEC && chunkDuration > 0
&& chunkDuration * tgtChunkDuration.getDen() >= tgtChunkDuration.getNum() * _timescale) {
outChunk();
}
}
private void outChunk() throws IOException {
if (framesInCurChunk == 0)
return;
chunkOffsets.add(out.position());
for (ByteBuffer b : curChunk) {
out.write(b);
}
curChunk.clear();
if (samplesInLastChunk == -1 || framesInCurChunk != samplesInLastChunk) {
samplesInChunks.add(new SampleToChunkEntry(chunkNo + 1, framesInCurChunk, 1));
}
samplesInLastChunk = framesInCurChunk;
chunkNo++;
framesInCurChunk = 0;
chunkDuration = 0;
}
@Override
protected Box finish(MovieHeaderBox mvhd) throws IOException {
if (finished)
throw new IllegalStateException("The muxer track has finished muxing");
outChunk();
finished = true;
TrakBox trak = TrakBox.createTrakBox();
Size dd = getDisplayDimensions();
TrackHeaderBox tkhd = TrackHeaderBox.createTrackHeaderBox(trackId,
((long) mvhd.getTimescale() * totalFrames * frameDuration) / _timescale, dd.getWidth(), dd.getHeight(),
new Date().getTime(), new Date().getTime(), 1.0f, (short) 0, 0,
new int[] { 0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000 });
tkhd.setFlags(0xf);
trak.add(tkhd);
tapt(trak);
MediaBox media = MediaBox.createMediaBox();
trak.add(media);
media.add(MediaHeaderBox.createMediaHeaderBox(_timescale, totalFrames * frameDuration, 0, new Date().getTime(),
new Date().getTime(), 0));
HandlerBox hdlr = HandlerBox.createHandlerBox("mhlr", type.getHandler(), "appl", 0, 0);
media.add(hdlr);
MediaInfoBox minf = MediaInfoBox.createMediaInfoBox();
media.add(minf);
mediaHeader(minf, type);
minf.add(HandlerBox.createHandlerBox("dhlr", "url ", "appl", 0, 0));
addDref(minf);
NodeBox stbl = new NodeBox(new Header("stbl"));
minf.add(stbl);
putEdits(trak);
putName(trak);
stbl.add(SampleDescriptionBox.createSampleDescriptionBox(sampleEntries.toArray(new SampleEntry[0])));
stbl.add(SampleToChunkBox.createSampleToChunkBox(samplesInChunks.toArray(new SampleToChunkEntry[0])));
stbl.add(SampleSizesBox.createSampleSizesBox(frameSize, totalFrames));
stbl.add(TimeToSampleBox
.createTimeToSampleBox(new TimeToSampleEntry[] { new TimeToSampleEntry(totalFrames, frameDuration) }));
stbl.add(ChunkOffsets64Box.createChunkOffsets64Box(chunkOffsets.toArray()));
return trak;
}
@Override
public long getTrackTotalDuration() {
return totalFrames * frameDuration;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy