package org.jcodec.movtool.streaming.tracks; import java.lang.IllegalStateException; import java.lang.System; import org.jcodec.common.io.NIOUtils; import org.jcodec.movtool.streaming.AudioCodecMeta; import org.jcodec.movtool.streaming.CodecMeta; import org.jcodec.movtool.streaming.VirtualPacket; import org.jcodec.movtool.streaming.VirtualTrack; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; /** * This class is part of JCodec ( www.jcodec.org ) This software is distributed * under FreeBSD License * * Edits PCM sample track placing chunks of PCM data in place creating and * edit-less track * * @author The JCodec project * */ public class EditedPCMTrack implements VirtualTrack { private VirtualTrack src; private List<VirtualPacket>[] buckets; private VirtualEdit[] edits; private int curEdit; private int curPkt; private int frameNo; private double pts; private int frameSize; private float sampleRate; public EditedPCMTrack(VirtualTrack src) throws IOException { this.src = src; edits = src.getEdits(); buckets = new List[edits.length]; for (int i = 0; i < edits.length; i++) buckets[i] = new ArrayList<VirtualPacket>(); VirtualPacket pkt; while ((pkt = src.nextPacket()) != null) { for (int e = 0; e < edits.length; e++) { VirtualEdit ed = edits[e]; if (pkt.getPts() < ed.getIn() + ed.getDuration() && pkt.getPts() + pkt.getDuration() > ed.getIn()) { buckets[e].add(pkt); } } } AudioCodecMeta ase = (AudioCodecMeta) src.getCodecMeta(); frameSize = ase.getFrameSize(); sampleRate = ase.getSampleRate(); } @Override public VirtualPacket nextPacket() throws IOException { if (curEdit >= edits.length) return null; VirtualPacket pkt = buckets[curEdit].get(curPkt); VirtualEdit edt = edits[curEdit]; double start = Math.max(pkt.getPts(), edt.getIn()); double end = Math.min(pkt.getPts() + pkt.getDuration(), edt.getIn() + edt.getDuration()); double duration = end - start; double lead = start - pkt.getPts(); VirtualPacket ret = new EditedPCMPacket(pkt, (int) (Math.round(lead * sampleRate) * frameSize), (int) (Math.round(duration * sampleRate) * frameSize), pts, duration, frameNo); ++curPkt; if (curPkt >= buckets[curEdit].size()) { curEdit++; curPkt = 0; } frameNo++; pts += duration; return ret; } @Override public CodecMeta getCodecMeta() { return src.getCodecMeta(); } @Override public VirtualEdit[] getEdits() { return null; } @Override public void close() throws IOException { src.close(); } public static class EditedPCMPacket implements VirtualPacket { private VirtualPacket src; private int inBytes; private int dataLen; private double pts; private double duration; private int frameNo; public EditedPCMPacket(VirtualPacket src, int inBytes, int dataLen, double pts, double duration, int frameNo) { this.src = src; this.inBytes = inBytes; this.dataLen = dataLen; this.pts = pts; this.duration = duration; this.frameNo = frameNo; } @Override public ByteBuffer getData() throws IOException { ByteBuffer data = src.getData(); NIOUtils.skip(data, inBytes); return NIOUtils.read(data, dataLen); } @Override public int getDataLen() { return dataLen; } @Override public double getPts() { return pts; } @Override public double getDuration() { return duration; } @Override public boolean isKeyframe() { return true; } @Override public int getFrameNo() { return frameNo; } } @Override public int getPreferredTimescale() { return src.getPreferredTimescale(); } }