/** * */ package mp4.util.atom; import java.io.DataOutput; import java.io.IOException; import mp4.util.MP4Log; /** * The sample table container atom contains the atoms with the information * for converting from media time to sample number to sample location. * The atoms within the sample table tell the handler how to parse and process * the samples in media. */ public class StblAtom extends ContainerAtom { // sample description atom private StsdAtom stsd; // time-to-sample atom private SttsAtom stts; // sample size atom private StszAtom stsz; // sample-to-chunk atom private StscAtom stsc; // chunk offset atom private StcoAtom stco; // (composition) time-to-sample atom private CttsAtom ctts; // sync sample atom private StssAtom stss; // TODO: shadow sync atom /** * Constructor for the sample table atom */ public StblAtom() { super(new byte[]{'s','t','b','l'}); } /** * A copy constructor for the stbl atom * @param stbl the stbl atom to copy */ public StblAtom(StblAtom old) { super(old); stsd = new StsdAtom(old.stsd); stts = new SttsAtom(old.stts); stsz = new StszAtom(old.stsz); stsc = new StscAtom(old.stsc); stco = new StcoAtom(old.stco); if (old.ctts != null) { ctts = new CttsAtom(old.ctts); } if (old.stss != null) stss = new StssAtom(old.stss); } public StsdAtom getStsd() { return stsd; } public SttsAtom getStts() { return stts; } public StszAtom getStsz() { return stsz; } public StscAtom getStsc() { return stsc; } public StcoAtom getStco() { return stco; } public CttsAtom getCtts() { return ctts; } public StssAtom getStss() { return stss; } public void setStco(StcoAtom stco) { this.stco = stco; } @Override public void addChild(Atom child) { if (child instanceof StsdAtom) { stsd = (StsdAtom) child; } else if (child instanceof SttsAtom) { stts = (SttsAtom) child; } else if (child instanceof StszAtom) { stsz = (StszAtom) child; } else if (child instanceof StscAtom) { stsc = (StscAtom) child; } else if (child instanceof StcoAtom) { stco = (StcoAtom) child; } else if (child instanceof CttsAtom) { ctts = (CttsAtom) child; } else if (child instanceof StssAtom) { stss = (StssAtom) child; } else { //throw new AtomError("Can't add " + child + " to stbl"); addUnknownChild(child); } } /** * Compute the size for the stbl container atom. */ public void recomputeSize() { long newSize = stsd.size() + stts.size() + stsz.size() + stsc.size() + stco.size(); if (ctts != null) { newSize += ctts.size(); } if (stss != null) { newSize += stss.size(); } newSize += unknownChildrenSize(); setSize(ATOM_HEADER_SIZE + newSize); } public int timeToByteOffset(long time) { long sampleNum = getStts().timeToSample(time); // from sampleNum to Offset in file??? // getStsz(). return 0; } /** * Cut the sample table atom at the specified point. * @param time the time normalized to the track time * @return the new stbl atom that has been cut */ public StblAtom cut(long time) { long sampleNum = getStts().timeToSample(time); long keyFrame = sampleNum; if (getStss() != null) { keyFrame = getStss().getKeyFrame(sampleNum); } MP4Log.log("\tDBG: sampleNum " + sampleNum + " sync frame " + keyFrame); long chunk = getStsc().sampleToChunk(keyFrame); MP4Log.log("\tDBG: chunk " + chunk); //long offset = getStco().getChunkOffset(chunk); //MP4Log.log("\tDBG: offset " + offset); StblAtom cutStbl = new StblAtom(); cutStbl.stsd = stsd.cut(); cutStbl.stts = stts.cut(keyFrame); cutStbl.stsz = stsz.cut(keyFrame); cutStbl.stsc = stsc.cut(keyFrame); long chunkOffset = 0; for (long i=keyFrame-1;i>0 && getStsc().sampleToChunk(i) == chunk;i--) { chunkOffset += stsz.getSampleSize(i); } cutStbl.stco = stco.cut(chunk, chunkOffset); // Adjust the offset of the first chunk if (ctts != null) { cutStbl.ctts = ctts.cut(keyFrame); } if (stss != null) { cutStbl.stss = stss.cut(keyFrame); } // fix the size of the container atom cutStbl.recomputeSize(); return cutStbl; } @Override public void accept(AtomVisitor v) throws AtomException { v.visit(this); } /** * Write the stbl atom data to the specified output * @param out where the data goes * @throws IOException if there is an error writing the data */ @Override public void writeData(DataOutput out) throws IOException { writeHeader(out); stsd.writeData(out); stts.writeData(out); stsz.writeData(out); stsc.writeData(out); stco.writeData(out); if (ctts != null) { ctts.writeData(out); } if (stss != null) { stss.writeData(out); } writeUnknownChildren(out); } }