Home | History | Annotate | Download | only in samplegrouping
      1 /*
      2  * Copyright 2012 castLabs, Berlin
      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.googlecode.mp4parser.boxes.mp4.samplegrouping;
     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.LinkedList;
     25 import java.util.List;
     26 
     27 import static com.googlecode.mp4parser.util.CastUtils.l2i;
     28 
     29 /**
     30  * This description table gives information about the characteristics of sample groups. The descriptive
     31  * information is any other information needed to define or characterize the sample group.
     32  * <p/>
     33  * There may be multiple instances of this box if there is more than one sample grouping for the samples in a
     34  * track. Each instance of the SampleGroupDescription box has a type code that distinguishes different
     35  * sample groupings. Within a track, there shall be at most one instance of this box with a particular grouping
     36  * type. The associated SampleToGroup shall indicate the same value for the grouping type.
     37  * <p/>
     38  * The information is stored in the sample group description box after the entry-count. An abstract entry type is
     39  * defined and sample groupings shall define derived types to represent the description of each sample group.
     40  * For video tracks, an abstract VisualSampleGroupEntry is used with similar types for audio and hint tracks.
     41  */
     42 public class SampleGroupDescriptionBox extends AbstractFullBox {
     43     public static final String TYPE = "sgpd";
     44 
     45     private String groupingType;
     46     private int defaultLength;
     47     private List<GroupEntry> groupEntries = new LinkedList<GroupEntry>();
     48     private int descriptionLength;
     49 
     50     public SampleGroupDescriptionBox() {
     51         super(TYPE);
     52     }
     53 
     54     @Override
     55     protected long getContentSize() {
     56         long size = 8;
     57         if (getVersion() == 1) {
     58             size += 4;
     59         }
     60         size += 4; // entryCount
     61         for (GroupEntry groupEntry : groupEntries) {
     62             if (getVersion() == 1 && defaultLength == 0) {
     63                 size += 4;
     64             }
     65             size += groupEntry.size();
     66         }
     67         return size;
     68     }
     69 
     70     @Override
     71     protected void getContent(ByteBuffer byteBuffer) {
     72         writeVersionAndFlags(byteBuffer);
     73         byteBuffer.put(groupingType.getBytes());
     74         if (this.getVersion() == 1) {
     75             IsoTypeWriter.writeUInt32(byteBuffer, defaultLength);
     76         }
     77         IsoTypeWriter.writeUInt32(byteBuffer, this.groupEntries.size());
     78         for (GroupEntry entry : groupEntries) {
     79             if (this.getVersion() == 1 && defaultLength == 0) {
     80                 IsoTypeWriter.writeUInt32(byteBuffer, entry.get().limit());
     81             }
     82             byteBuffer.put(entry.get());
     83         }
     84     }
     85 
     86     @Override
     87     protected void _parseDetails(ByteBuffer content) {
     88         parseVersionAndFlags(content);
     89         if (this.getVersion() != 1) {
     90             throw new RuntimeException("SampleGroupDescriptionBox are only supported in version 1");
     91         }
     92         groupingType = IsoTypeReader.read4cc(content);
     93         if (this.getVersion() == 1) {
     94             defaultLength = l2i(IsoTypeReader.readUInt32(content));
     95         }
     96         long entryCount = IsoTypeReader.readUInt32(content);
     97         while (entryCount-- > 0) {
     98             int length = defaultLength;
     99             if (this.getVersion() == 1) {
    100                 if (defaultLength == 0) {
    101                     descriptionLength = l2i(IsoTypeReader.readUInt32(content));
    102                     length = descriptionLength;
    103                 }
    104             } else {
    105                 throw new RuntimeException("This should be implemented");
    106             }
    107             int finalPos = content.position() + length;
    108             ByteBuffer parseMe = content.slice();
    109             parseMe.limit(length);
    110             groupEntries.add(parseGroupEntry(parseMe, groupingType));
    111             content.position(finalPos);
    112         }
    113 
    114     }
    115 
    116     private GroupEntry parseGroupEntry(ByteBuffer content, String groupingType) {
    117         GroupEntry groupEntry;
    118         if (RollRecoveryEntry.TYPE.equals(groupingType)) {
    119             groupEntry = new RollRecoveryEntry();
    120         } else if (RateShareEntry.TYPE.equals(groupingType)) {
    121             groupEntry = new RateShareEntry();
    122         } else if (CencSampleEncryptionInformationGroupEntry.TYPE.equals(groupingType)) {
    123             groupEntry = new CencSampleEncryptionInformationGroupEntry();
    124         } else if (VisualRandomAccessEntry.TYPE.equals(groupingType)) {
    125             groupEntry = new VisualRandomAccessEntry();
    126         } else if (TemporalLevelEntry.TYPE.equals(groupingType)) {
    127             groupEntry = new TemporalLevelEntry();
    128         } else {
    129             groupEntry = new UnknownEntry();
    130         }
    131         groupEntry.parse(content);
    132         return groupEntry;
    133     }
    134 
    135 
    136     public String getGroupingType() {
    137         return groupingType;
    138     }
    139 
    140     public void setGroupingType(String groupingType) {
    141         this.groupingType = groupingType;
    142     }
    143 
    144     public int getDefaultLength() {
    145         return defaultLength;
    146     }
    147 
    148     public void setDefaultLength(int defaultLength) {
    149         this.defaultLength = defaultLength;
    150     }
    151 
    152     public List<GroupEntry> getGroupEntries() {
    153         return groupEntries;
    154     }
    155 
    156     public void setGroupEntries(List<GroupEntry> groupEntries) {
    157         this.groupEntries = groupEntries;
    158     }
    159 
    160     @Override
    161     public boolean equals(Object o) {
    162         if (this == o) {
    163             return true;
    164         }
    165         if (o == null || getClass() != o.getClass()) {
    166             return false;
    167         }
    168 
    169         SampleGroupDescriptionBox that = (SampleGroupDescriptionBox) o;
    170 
    171         if (defaultLength != that.defaultLength) {
    172             return false;
    173         }
    174         if (groupEntries != null ? !groupEntries.equals(that.groupEntries) : that.groupEntries != null) {
    175             return false;
    176         }
    177         if (groupingType != null ? !groupingType.equals(that.groupingType) : that.groupingType != null) {
    178             return false;
    179         }
    180 
    181         return true;
    182     }
    183 
    184     @Override
    185     public int hashCode() {
    186         int result = groupingType != null ? groupingType.hashCode() : 0;
    187         result = 31 * result + defaultLength;
    188         result = 31 * result + (groupEntries != null ? groupEntries.hashCode() : 0);
    189         return result;
    190     }
    191 
    192     @Override
    193     public String toString() {
    194         return "SampleGroupDescriptionBox{" +
    195                 "groupingType='" + groupingType + '\'' +
    196                 ", defaultLength=" + defaultLength +
    197                 ", groupEntries=" + groupEntries +
    198                 '}';
    199     }
    200 }
    201