1package com.coremedia.iso.boxes;
2
3import com.coremedia.iso.IsoTypeReader;
4import com.coremedia.iso.IsoTypeWriter;
5import com.googlecode.mp4parser.AbstractFullBox;
6
7import java.nio.ByteBuffer;
8import java.util.ArrayList;
9import java.util.List;
10
11import static com.googlecode.mp4parser.util.CastUtils.l2i;
12
13/**
14 * aligned(8) class SubSampleInformationBox
15 * extends FullBox('subs', version, 0) {
16 * unsigned int(32) entry_count;
17 * int i,j;
18 * for (i=0; i < entry_count; i++) {
19 * unsigned int(32) sample_delta;
20 * unsigned int(16) subsample_count;
21 * if (subsample_count > 0) {
22 * for (j=0; j < subsample_count; j++) {
23 * if(version == 1)
24 * {
25 * unsigned int(32) subsample_size;
26 * }
27 * else
28 * {
29 * unsigned int(16) subsample_size;
30 * }
31 * unsigned int(8) subsample_priority;
32 * unsigned int(8) discardable;
33 * unsigned int(32) reserved = 0;
34 * }
35 * }
36 * }
37 * }
38 */
39public class SubSampleInformationBox extends AbstractFullBox {
40    public static final String TYPE = "subs";
41
42    private long entryCount;
43    private List<SampleEntry> entries = new ArrayList<SampleEntry>();
44
45    public SubSampleInformationBox() {
46        super(TYPE);
47    }
48
49    public List<SampleEntry> getEntries() {
50        return entries;
51    }
52
53    public void setEntries(List<SampleEntry> entries) {
54        this.entries = entries;
55        entryCount = entries.size();
56    }
57
58    @Override
59    protected long getContentSize() {
60        long entries = 8 + ((4 + 2) * entryCount);
61        int subsampleEntries = 0;
62        for (SampleEntry sampleEntry : this.entries) {
63            subsampleEntries += sampleEntry.getSubsampleCount() * (((getVersion() == 1) ? 4 : 2) + 1 + 1 + 4);
64        }
65        return entries + subsampleEntries;
66    }
67
68    @Override
69    public void _parseDetails(ByteBuffer content) {
70        parseVersionAndFlags(content);
71
72        entryCount = IsoTypeReader.readUInt32(content);
73
74        for (int i = 0; i < entryCount; i++) {
75            SampleEntry sampleEntry = new SampleEntry();
76            sampleEntry.setSampleDelta(IsoTypeReader.readUInt32(content));
77            int subsampleCount = IsoTypeReader.readUInt16(content);
78            for (int j = 0; j < subsampleCount; j++) {
79                SampleEntry.SubsampleEntry subsampleEntry = new SampleEntry.SubsampleEntry();
80                subsampleEntry.setSubsampleSize(getVersion() == 1 ? IsoTypeReader.readUInt32(content) : IsoTypeReader.readUInt16(content));
81                subsampleEntry.setSubsamplePriority(IsoTypeReader.readUInt8(content));
82                subsampleEntry.setDiscardable(IsoTypeReader.readUInt8(content));
83                subsampleEntry.setReserved(IsoTypeReader.readUInt32(content));
84                sampleEntry.addSubsampleEntry(subsampleEntry);
85            }
86            entries.add(sampleEntry);
87        }
88
89    }
90
91    @Override
92    protected void getContent(ByteBuffer byteBuffer) {
93        writeVersionAndFlags(byteBuffer);
94        IsoTypeWriter.writeUInt32(byteBuffer, entries.size());
95        for (SampleEntry sampleEntry : entries) {
96            IsoTypeWriter.writeUInt32(byteBuffer, sampleEntry.getSampleDelta());
97            IsoTypeWriter.writeUInt16(byteBuffer, sampleEntry.getSubsampleCount());
98            List<SampleEntry.SubsampleEntry> subsampleEntries = sampleEntry.getSubsampleEntries();
99            for (SampleEntry.SubsampleEntry subsampleEntry : subsampleEntries) {
100                if (getVersion() == 1) {
101                    IsoTypeWriter.writeUInt32(byteBuffer, subsampleEntry.getSubsampleSize());
102                } else {
103                    IsoTypeWriter.writeUInt16(byteBuffer, l2i(subsampleEntry.getSubsampleSize()));
104                }
105                IsoTypeWriter.writeUInt8(byteBuffer, subsampleEntry.getSubsamplePriority());
106                IsoTypeWriter.writeUInt8(byteBuffer, subsampleEntry.getDiscardable());
107                IsoTypeWriter.writeUInt32(byteBuffer, subsampleEntry.getReserved());
108            }
109        }
110    }
111
112    @Override
113    public String toString() {
114        return "SubSampleInformationBox{" +
115                "entryCount=" + entryCount +
116                ", entries=" + entries +
117                '}';
118    }
119
120    public static class SampleEntry {
121        private long sampleDelta;
122        private int subsampleCount;
123        private List<SubsampleEntry> subsampleEntries = new ArrayList<SubsampleEntry>();
124
125        public long getSampleDelta() {
126            return sampleDelta;
127        }
128
129        public void setSampleDelta(long sampleDelta) {
130            this.sampleDelta = sampleDelta;
131        }
132
133        public int getSubsampleCount() {
134            return subsampleCount;
135        }
136
137        public void setSubsampleCount(int subsampleCount) {
138            this.subsampleCount = subsampleCount;
139        }
140
141        public List<SubsampleEntry> getSubsampleEntries() {
142            return subsampleEntries;
143        }
144
145        public void addSubsampleEntry(SubsampleEntry subsampleEntry) {
146            subsampleEntries.add(subsampleEntry);
147            subsampleCount++;
148        }
149
150        public static class SubsampleEntry {
151            private long subsampleSize;
152            private int subsamplePriority;
153            private int discardable;
154            private long reserved;
155
156            public long getSubsampleSize() {
157                return subsampleSize;
158            }
159
160            public void setSubsampleSize(long subsampleSize) {
161                this.subsampleSize = subsampleSize;
162            }
163
164            public int getSubsamplePriority() {
165                return subsamplePriority;
166            }
167
168            public void setSubsamplePriority(int subsamplePriority) {
169                this.subsamplePriority = subsamplePriority;
170            }
171
172            public int getDiscardable() {
173                return discardable;
174            }
175
176            public void setDiscardable(int discardable) {
177                this.discardable = discardable;
178            }
179
180            public long getReserved() {
181                return reserved;
182            }
183
184            public void setReserved(long reserved) {
185                this.reserved = reserved;
186            }
187
188            @Override
189            public String toString() {
190                return "SubsampleEntry{" +
191                        "subsampleSize=" + subsampleSize +
192                        ", subsamplePriority=" + subsamplePriority +
193                        ", discardable=" + discardable +
194                        ", reserved=" + reserved +
195                        '}';
196            }
197        }
198
199        @Override
200        public String toString() {
201            return "SampleEntry{" +
202                    "sampleDelta=" + sampleDelta +
203                    ", subsampleCount=" + subsampleCount +
204                    ", subsampleEntries=" + subsampleEntries +
205                    '}';
206        }
207    }
208}
209