1dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu/*
2dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Copyright 2012 castLabs, Berlin
3dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu *
4dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Licensed under the Apache License, Version 2.0 (the License);
5dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * you may not use this file except in compliance with the License.
6dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * You may obtain a copy of the License at
7dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu *
8dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu *     http://www.apache.org/licenses/LICENSE-2.0
9dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu *
10dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Unless required by applicable law or agreed to in writing, software
11dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * distributed under the License is distributed on an AS IS BASIS,
12dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * See the License for the specific language governing permissions and
14dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * limitations under the License.
15dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */
16dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
17dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhupackage com.googlecode.mp4parser.boxes.mp4.samplegrouping;
18dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
19dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.IsoTypeReader;
20dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.IsoTypeWriter;
21dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.googlecode.mp4parser.AbstractFullBox;
22dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
23dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.ByteBuffer;
24dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.LinkedList;
25dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.List;
26dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
27dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport static com.googlecode.mp4parser.util.CastUtils.l2i;
28dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
29dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu/**
30dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * This table can be used to find the group that a sample belongs to and the associated description of that
31dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * sample group. The table is compactly coded with each entry giving the index of the first sample of a run of
32dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * samples with the same sample group descriptor. The sample group description ID is an index that refers to a
33dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * SampleGroupDescription box, which contains entries describing the characteristics of each sample group.
34dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <p/>
35dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * There may be multiple instances of this box if there is more than one sample grouping for the samples in a
36dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * track. Each instance of the SampleToGroup box has a type code that distinguishes different sample
37dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * groupings. Within a track, there shall be at most one instance of this box with a particular grouping type. The
38dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * associated SampleGroupDescription shall indicate the same value for the grouping type.
39dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <p/>
40dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Version 1 of this box should only be used if a grouping type parameter is needed.
41dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */
42dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhupublic class SampleToGroupBox extends AbstractFullBox {
43dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public static final String TYPE = "sbgp";
44dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
45dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
46dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    private String groupingType;
47dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    private String groupingTypeParameter;
48dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
49dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    List<Entry> entries = new LinkedList<Entry>();
50dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
51dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public SampleToGroupBox() {
52dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        super(TYPE);
53dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
54dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
55dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
56dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    @Override
57dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    protected long getContentSize() {
58dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return this.getVersion() == 1 ? entries.size() * 8 + 16 : entries.size() * 8 + 12;
59dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
60dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
61dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    @Override
62dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    protected void getContent(ByteBuffer byteBuffer) {
63dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        writeVersionAndFlags(byteBuffer);
64dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        byteBuffer.put(groupingType.getBytes());
65dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        if (this.getVersion() == 1) {
66dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            byteBuffer.put(groupingTypeParameter.getBytes());
67dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
68dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
69dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        for (Entry entry : entries) {
70dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            IsoTypeWriter.writeUInt32(byteBuffer, entry.getSampleCount());
71dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            IsoTypeWriter.writeUInt32(byteBuffer, entry.getGroupDescriptionIndex());
72dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
73dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
74dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
75dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
76dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    @Override
77dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    protected void _parseDetails(ByteBuffer content) {
78dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        parseVersionAndFlags(content);
79dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        groupingType = IsoTypeReader.read4cc(content);
80dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        if (this.getVersion() == 1) {
81dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            groupingTypeParameter = IsoTypeReader.read4cc(content);
82dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
83dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        long entryCount = IsoTypeReader.readUInt32(content);
84dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        while (entryCount-- > 0) {
85dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            entries.add(new Entry(l2i(IsoTypeReader.readUInt32(content)), l2i(IsoTypeReader.readUInt32(content))));
86dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
87dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
88dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
89dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public static class Entry {
90dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        private long sampleCount;
91dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        private int groupDescriptionIndex;
92dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
93dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        public Entry(long sampleCount, int groupDescriptionIndex) {
94dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            this.sampleCount = sampleCount;
95dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            this.groupDescriptionIndex = groupDescriptionIndex;
96dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
97dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
98dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        public long getSampleCount() {
99dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            return sampleCount;
100dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
101dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
102dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        public void setSampleCount(long sampleCount) {
103dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            this.sampleCount = sampleCount;
104dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
105dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
106dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        public int getGroupDescriptionIndex() {
107dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            return groupDescriptionIndex;
108dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
109dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
110dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        public void setGroupDescriptionIndex(int groupDescriptionIndex) {
111dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            this.groupDescriptionIndex = groupDescriptionIndex;
112dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
113dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
114dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        @Override
115dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        public String toString() {
116dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            return "Entry{" +
117dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                    "sampleCount=" + sampleCount +
118dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                    ", groupDescriptionIndex=" + groupDescriptionIndex +
119dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                    '}';
120dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
121dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
122dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        @Override
123dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        public boolean equals(Object o) {
124dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            if (this == o) {
125dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                return true;
126dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            }
127dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            if (o == null || getClass() != o.getClass()) {
128dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                return false;
129dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            }
130dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
131dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            Entry entry = (Entry) o;
132dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
133dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            if (groupDescriptionIndex != entry.groupDescriptionIndex) {
134dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                return false;
135dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            }
136dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            if (sampleCount != entry.sampleCount) {
137dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu                return false;
138dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            }
139dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
140dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            return true;
141dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
142dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
143dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        @Override
144dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        public int hashCode() {
145dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            int result = (int) (sampleCount ^ (sampleCount >>> 32));
146dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            result = 31 * result + groupDescriptionIndex;
147dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu            return result;
148dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        }
149dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
150dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
151dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public String getGroupingType() {
152dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return groupingType;
153dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
154dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
155dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public void setGroupingType(String groupingType) {
156dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        this.groupingType = groupingType;
157dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
158dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
159dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public String getGroupingTypeParameter() {
160dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return groupingTypeParameter;
161dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
162dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
163dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public void setGroupingTypeParameter(String groupingTypeParameter) {
164dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        this.groupingTypeParameter = groupingTypeParameter;
165dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
166dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
167dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public List<Entry> getEntries() {
168dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        return entries;
169dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
170dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu
171dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    public void setEntries(List<Entry> entries) {
172dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu        this.entries = entries;
173dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu    }
174dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu}
175