Home | History | Annotate | Download | only in boxes
      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 
     50     public TimeToSampleBox() {
     51         super(TYPE);
     52     }
     53 
     54     protected long getContentSize() {
     55         return 8 + entries.size() * 8;
     56     }
     57 
     58     @Override
     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
     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 
     80     public List<Entry> getEntries() {
     81         return entries;
     82     }
     83 
     84     public void setEntries(List<Entry> entries) {
     85         this.entries = entries;
     86     }
     87 
     88     public String toString() {
     89         return "TimeToSampleBox[entryCount=" + entries.size() + "]";
     90     }
     91 
     92     public static class Entry {
     93         long count;
     94         long delta;
     95 
     96         public Entry(long count, long delta) {
     97             this.count = count;
     98             this.delta = delta;
     99         }
    100 
    101         public long getCount() {
    102             return count;
    103         }
    104 
    105         public long getDelta() {
    106             return delta;
    107         }
    108 
    109         public void setCount(long count) {
    110             this.count = count;
    111         }
    112 
    113         public void setDelta(long delta) {
    114             this.delta = delta;
    115         }
    116 
    117         @Override
    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      */
    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