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 import com.coremedia.iso.IsoTypeReader;
     20 import com.coremedia.iso.IsoTypeWriter;
     21 import com.googlecode.mp4parser.AbstractFullBox;
     22 
     23 import java.nio.ByteBuffer;
     24 import java.util.ArrayList;
     25 import java.util.Collections;
     26 import java.util.Iterator;
     27 import java.util.LinkedList;
     28 import java.util.List;
     29 
     30 import static com.googlecode.mp4parser.util.CastUtils.l2i;
     31 
     32 /**
     33  * Samples within the media data are grouped into chunks. Chunks can be of different sizes, and the
     34  * samples within a chunk can have different sizes. This table can be used to find the chunk that
     35  * contains a sample, its position, and the associated sample description. Defined in ISO/IEC 14496-12.
     36  */
     37 public class SampleToChunkBox extends AbstractFullBox {
     38     List<Entry> entries = Collections.emptyList();
     39 
     40     public static final String TYPE = "stsc";
     41 
     42     public SampleToChunkBox() {
     43         super(TYPE);
     44     }
     45 
     46     public List<Entry> getEntries() {
     47         return entries;
     48     }
     49 
     50     public void setEntries(List<Entry> entries) {
     51         this.entries = entries;
     52     }
     53 
     54     protected long getContentSize() {
     55         return entries.size() * 12 + 8;
     56     }
     57 
     58     @Override
     59     public void _parseDetails(ByteBuffer content) {
     60         parseVersionAndFlags(content);
     61 
     62         int entryCount = l2i(IsoTypeReader.readUInt32(content));
     63         entries = new ArrayList<Entry>(entryCount);
     64         for (int i = 0; i < entryCount; i++) {
     65             entries.add(new Entry(
     66                     IsoTypeReader.readUInt32(content),
     67                     IsoTypeReader.readUInt32(content),
     68                     IsoTypeReader.readUInt32(content)));
     69         }
     70     }
     71 
     72     @Override
     73     protected void getContent(ByteBuffer byteBuffer) {
     74         writeVersionAndFlags(byteBuffer);
     75         IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
     76         for (Entry entry : entries) {
     77             IsoTypeWriter.writeUInt32(byteBuffer, entry.getFirstChunk());
     78             IsoTypeWriter.writeUInt32(byteBuffer, entry.getSamplesPerChunk());
     79             IsoTypeWriter.writeUInt32(byteBuffer, entry.getSampleDescriptionIndex());
     80         }
     81     }
     82 
     83     public String toString() {
     84         return "SampleToChunkBox[entryCount=" + entries.size() + "]";
     85     }
     86 
     87     /**
     88      * Decompresses the list of entries and returns the number of samples per chunk for
     89      * every single chunk.
     90      *
     91      * @param chunkCount overall number of chunks
     92      * @return number of samples per chunk
     93      */
     94     public long[] blowup(int chunkCount) {
     95         long[] numberOfSamples = new long[chunkCount];
     96         int j = 0;
     97         List<SampleToChunkBox.Entry> sampleToChunkEntries = new LinkedList<Entry>(entries);
     98         Collections.reverse(sampleToChunkEntries);
     99         Iterator<Entry> iterator = sampleToChunkEntries.iterator();
    100         SampleToChunkBox.Entry currentEntry = iterator.next();
    101 
    102         for (int i = numberOfSamples.length; i > 1; i--) {
    103             numberOfSamples[i - 1] = currentEntry.getSamplesPerChunk();
    104             if (i == currentEntry.getFirstChunk()) {
    105                 currentEntry = iterator.next();
    106             }
    107         }
    108         numberOfSamples[0] = currentEntry.getSamplesPerChunk();
    109         return numberOfSamples;
    110     }
    111 
    112     public static class Entry {
    113         long firstChunk;
    114         long samplesPerChunk;
    115         long sampleDescriptionIndex;
    116 
    117         public Entry(long firstChunk, long samplesPerChunk, long sampleDescriptionIndex) {
    118             this.firstChunk = firstChunk;
    119             this.samplesPerChunk = samplesPerChunk;
    120             this.sampleDescriptionIndex = sampleDescriptionIndex;
    121         }
    122 
    123         public long getFirstChunk() {
    124             return firstChunk;
    125         }
    126 
    127         public void setFirstChunk(long firstChunk) {
    128             this.firstChunk = firstChunk;
    129         }
    130 
    131         public long getSamplesPerChunk() {
    132             return samplesPerChunk;
    133         }
    134 
    135         public void setSamplesPerChunk(long samplesPerChunk) {
    136             this.samplesPerChunk = samplesPerChunk;
    137         }
    138 
    139         public long getSampleDescriptionIndex() {
    140             return sampleDescriptionIndex;
    141         }
    142 
    143         public void setSampleDescriptionIndex(long sampleDescriptionIndex) {
    144             this.sampleDescriptionIndex = sampleDescriptionIndex;
    145         }
    146 
    147         @Override
    148         public String toString() {
    149             return "Entry{" +
    150                     "firstChunk=" + firstChunk +
    151                     ", samplesPerChunk=" + samplesPerChunk +
    152                     ", sampleDescriptionIndex=" + sampleDescriptionIndex +
    153                     '}';
    154         }
    155     }
    156 }
    157