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 table can be used to find the group that a sample belongs to and the associated description of that
31  * sample group. The table is compactly coded with each entry giving the index of the first sample of a run of
32  * samples with the same sample group descriptor. The sample group description ID is an index that refers to a
33  * SampleGroupDescription box, which contains entries describing the characteristics of each sample group.
34  * <p/>
35  * There may be multiple instances of this box if there is more than one sample grouping for the samples in a
36  * track. Each instance of the SampleToGroup box has a type code that distinguishes different sample
37  * groupings. Within a track, there shall be at most one instance of this box with a particular grouping type. The
38  * associated SampleGroupDescription shall indicate the same value for the grouping type.
39  * <p/>
40  * Version 1 of this box should only be used if a grouping type parameter is needed.
41  */
42 public class SampleToGroupBox extends AbstractFullBox {
43     public static final String TYPE = "sbgp";
44 
45 
46     private String groupingType;
47     private String groupingTypeParameter;
48 
49     List<Entry> entries = new LinkedList<Entry>();
50 
SampleToGroupBox()51     public SampleToGroupBox() {
52         super(TYPE);
53 
54     }
55 
56     @Override
getContentSize()57     protected long getContentSize() {
58         return this.getVersion() == 1 ? entries.size() * 8 + 16 : entries.size() * 8 + 12;
59     }
60 
61     @Override
getContent(ByteBuffer byteBuffer)62     protected void getContent(ByteBuffer byteBuffer) {
63         writeVersionAndFlags(byteBuffer);
64         byteBuffer.put(groupingType.getBytes());
65         if (this.getVersion() == 1) {
66             byteBuffer.put(groupingTypeParameter.getBytes());
67         }
68         IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
69         for (Entry entry : entries) {
70             IsoTypeWriter.writeUInt32(byteBuffer, entry.getSampleCount());
71             IsoTypeWriter.writeUInt32(byteBuffer, entry.getGroupDescriptionIndex());
72         }
73 
74     }
75 
76     @Override
_parseDetails(ByteBuffer content)77     protected void _parseDetails(ByteBuffer content) {
78         parseVersionAndFlags(content);
79         groupingType = IsoTypeReader.read4cc(content);
80         if (this.getVersion() == 1) {
81             groupingTypeParameter = IsoTypeReader.read4cc(content);
82         }
83         long entryCount = IsoTypeReader.readUInt32(content);
84         while (entryCount-- > 0) {
85             entries.add(new Entry(l2i(IsoTypeReader.readUInt32(content)), l2i(IsoTypeReader.readUInt32(content))));
86         }
87     }
88 
89     public static class Entry {
90         private long sampleCount;
91         private int groupDescriptionIndex;
92 
Entry(long sampleCount, int groupDescriptionIndex)93         public Entry(long sampleCount, int groupDescriptionIndex) {
94             this.sampleCount = sampleCount;
95             this.groupDescriptionIndex = groupDescriptionIndex;
96         }
97 
getSampleCount()98         public long getSampleCount() {
99             return sampleCount;
100         }
101 
setSampleCount(long sampleCount)102         public void setSampleCount(long sampleCount) {
103             this.sampleCount = sampleCount;
104         }
105 
getGroupDescriptionIndex()106         public int getGroupDescriptionIndex() {
107             return groupDescriptionIndex;
108         }
109 
setGroupDescriptionIndex(int groupDescriptionIndex)110         public void setGroupDescriptionIndex(int groupDescriptionIndex) {
111             this.groupDescriptionIndex = groupDescriptionIndex;
112         }
113 
114         @Override
toString()115         public String toString() {
116             return "Entry{" +
117                     "sampleCount=" + sampleCount +
118                     ", groupDescriptionIndex=" + groupDescriptionIndex +
119                     '}';
120         }
121 
122         @Override
equals(Object o)123         public boolean equals(Object o) {
124             if (this == o) {
125                 return true;
126             }
127             if (o == null || getClass() != o.getClass()) {
128                 return false;
129             }
130 
131             Entry entry = (Entry) o;
132 
133             if (groupDescriptionIndex != entry.groupDescriptionIndex) {
134                 return false;
135             }
136             if (sampleCount != entry.sampleCount) {
137                 return false;
138             }
139 
140             return true;
141         }
142 
143         @Override
hashCode()144         public int hashCode() {
145             int result = (int) (sampleCount ^ (sampleCount >>> 32));
146             result = 31 * result + groupDescriptionIndex;
147             return result;
148         }
149     }
150 
getGroupingType()151     public String getGroupingType() {
152         return groupingType;
153     }
154 
setGroupingType(String groupingType)155     public void setGroupingType(String groupingType) {
156         this.groupingType = groupingType;
157     }
158 
getGroupingTypeParameter()159     public String getGroupingTypeParameter() {
160         return groupingTypeParameter;
161     }
162 
setGroupingTypeParameter(String groupingTypeParameter)163     public void setGroupingTypeParameter(String groupingTypeParameter) {
164         this.groupingTypeParameter = groupingTypeParameter;
165     }
166 
getEntries()167     public List<Entry> getEntries() {
168         return entries;
169     }
170 
setEntries(List<Entry> entries)171     public void setEntries(List<Entry> entries) {
172         this.entries = entries;
173     }
174 }
175