1 /* 2 * Copyright 2008 CoreMedia AG, Hamburg 3 * 4 * Licensed under the Apache License, Version 2.0 (the License); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an AS IS BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.coremedia.iso.boxes; 18 19 20 import com.coremedia.iso.IsoTypeReader; 21 import com.coremedia.iso.IsoTypeWriter; 22 import com.googlecode.mp4parser.AbstractFullBox; 23 24 import java.nio.ByteBuffer; 25 import java.util.ArrayList; 26 import java.util.Collections; 27 import java.util.List; 28 29 import static com.googlecode.mp4parser.util.CastUtils.l2i; 30 31 /** 32 * This box contains a compact version of a table that allows indexing from decoding time to sample number. 33 * Other tables give sample sizes and pointers, from the sample number. Each entry in the table gives the 34 * number of consecutive samples with the same time delta, and the delta of those samples. By adding the 35 * deltas a complete time-to-sample map may be built.<br> 36 * The Decoding Time to Sample Box contains decode time delta's: <code>DT(n+1) = DT(n) + STTS(n)</code> where STTS(n) 37 * is the (uncompressed) table entry for sample n.<br> 38 * The sample entries are ordered by decoding time stamps; therefore the deltas are all non-negative. <br> 39 * The DT axis has a zero origin; <code>DT(i) = SUM(for j=0 to i-1 of delta(j))</code>, and the sum of all 40 * deltas gives the length of the media in the track (not mapped to the overall timescale, and not considering 41 * any edit list). <br> 42 * The Edit List Box provides the initial CT value if it is non-empty (non-zero). 43 */ 44 public class TimeToSampleBox extends AbstractFullBox { 45 public static final String TYPE = "stts"; 46 47 List<Entry> entries = Collections.emptyList(); 48 49 TimeToSampleBox()50 public TimeToSampleBox() { 51 super(TYPE); 52 } 53 getContentSize()54 protected long getContentSize() { 55 return 8 + entries.size() * 8; 56 } 57 58 @Override _parseDetails(ByteBuffer content)59 public void _parseDetails(ByteBuffer content) { 60 parseVersionAndFlags(content); 61 int entryCount = l2i(IsoTypeReader.readUInt32(content)); 62 entries = new ArrayList<Entry>(entryCount); 63 64 for (int i = 0; i < entryCount; i++) { 65 entries.add(new Entry(IsoTypeReader.readUInt32(content), IsoTypeReader.readUInt32(content))); 66 } 67 68 } 69 70 @Override getContent(ByteBuffer byteBuffer)71 protected void getContent(ByteBuffer byteBuffer) { 72 writeVersionAndFlags(byteBuffer); 73 IsoTypeWriter.writeUInt32(byteBuffer, entries.size()); 74 for (Entry entry : entries) { 75 IsoTypeWriter.writeUInt32(byteBuffer, entry.getCount()); 76 IsoTypeWriter.writeUInt32(byteBuffer, entry.getDelta()); 77 } 78 } 79 getEntries()80 public List<Entry> getEntries() { 81 return entries; 82 } 83 setEntries(List<Entry> entries)84 public void setEntries(List<Entry> entries) { 85 this.entries = entries; 86 } 87 toString()88 public String toString() { 89 return "TimeToSampleBox[entryCount=" + entries.size() + "]"; 90 } 91 92 public static class Entry { 93 long count; 94 long delta; 95 Entry(long count, long delta)96 public Entry(long count, long delta) { 97 this.count = count; 98 this.delta = delta; 99 } 100 getCount()101 public long getCount() { 102 return count; 103 } 104 getDelta()105 public long getDelta() { 106 return delta; 107 } 108 setCount(long count)109 public void setCount(long count) { 110 this.count = count; 111 } 112 setDelta(long delta)113 public void setDelta(long delta) { 114 this.delta = delta; 115 } 116 117 @Override toString()118 public String toString() { 119 return "Entry{" + 120 "count=" + count + 121 ", delta=" + delta + 122 '}'; 123 } 124 } 125 126 /** 127 * Decompresses the list of entries and returns the list of decoding times. 128 * 129 * @return decoding time per sample 130 */ blowupTimeToSamples(List<TimeToSampleBox.Entry> entries)131 public static long[] blowupTimeToSamples(List<TimeToSampleBox.Entry> entries) { 132 long numOfSamples = 0; 133 for (TimeToSampleBox.Entry entry : entries) { 134 numOfSamples += entry.getCount(); 135 } 136 assert numOfSamples <= Integer.MAX_VALUE; 137 long[] decodingTime = new long[(int) numOfSamples]; 138 139 int current = 0; 140 141 142 for (TimeToSampleBox.Entry entry : entries) { 143 for (int i = 0; i < entry.getCount(); i++) { 144 decodingTime[current++] = entry.getDelta(); 145 } 146 } 147 148 return decodingTime; 149 } 150 151 152 } 153