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 18 package com.googlecode.mp4parser.boxes.mp4.samplegrouping; 19 20 import com.coremedia.iso.IsoTypeReader; 21 import com.coremedia.iso.IsoTypeWriter; 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 * Each sample of a track may be associated to (zero or) one of a number of sample group descriptions, each of 31 * which defines a record of rate-share information. Typically the same rate-share information applies to many 32 * consecutive samples and it may therefore be enough to define two or three sample group descriptions that 33 * can be used at different time intervals. 34 * <p/> 35 * The grouping type 'rash' (short for rate share) is defined as the grouping criterion for rate share information. 36 * Zero or one sample-to-group box ('sbgp') for the grouping type 'rash' can be contained in the sample 37 * table box ('stbl') of a track. It shall reside in a hint track, if a hint track is used, otherwise in a media track. 38 * <p/> 39 * Target rate share may be specified for several operation points that are defined in terms of the total available 40 * bitrate, i.e., the bitrate that should be shared. If only one operation point is defined, the target rate share 41 * applies to all available bitrates. If several operation points are defined, then each operation point specifies a 42 * target rate share. Target rate share values specified for the first and the last operation points also specify the 43 * target rate share values at lower and higher available bitrates, respectively. The target rate share between two 44 * operation points is specified to be in the range between the target rate shares of those operation points. One 45 * possibility is to estimate with linear interpolation. 46 */ 47 public class RateShareEntry extends GroupEntry { 48 public static final String TYPE = "rash"; 49 50 private short operationPointCut; 51 private short targetRateShare; 52 private List<Entry> entries = new LinkedList<Entry>(); 53 private int maximumBitrate; 54 private int minimumBitrate; 55 private short discardPriority; 56 57 58 @Override 59 public void parse(ByteBuffer byteBuffer) { 60 operationPointCut = byteBuffer.getShort(); 61 if (operationPointCut == 1) { 62 targetRateShare = byteBuffer.getShort(); 63 } else { 64 int entriesLeft = operationPointCut; 65 while (entriesLeft-- > 0) { 66 entries.add(new Entry(l2i(IsoTypeReader.readUInt32(byteBuffer)), byteBuffer.getShort())); 67 } 68 } 69 maximumBitrate = l2i(IsoTypeReader.readUInt32(byteBuffer)); 70 minimumBitrate = l2i(IsoTypeReader.readUInt32(byteBuffer)); 71 discardPriority = (short) IsoTypeReader.readUInt8(byteBuffer); 72 } 73 74 @Override 75 public ByteBuffer get() { 76 ByteBuffer buf = ByteBuffer.allocate(operationPointCut == 1?13:(operationPointCut * 6 + 11 )); 77 buf.putShort(operationPointCut); 78 if (operationPointCut == 1) { 79 buf.putShort(targetRateShare ); 80 } else { 81 for (Entry entry : entries) { 82 buf.putInt(entry.getAvailableBitrate()); 83 buf.putShort(entry.getTargetRateShare()); 84 } 85 } 86 buf.putInt(maximumBitrate); 87 buf.putInt(minimumBitrate); 88 IsoTypeWriter.writeUInt8(buf, discardPriority); 89 buf.rewind(); 90 return buf; 91 } 92 93 public static class Entry { 94 public Entry(int availableBitrate, short targetRateShare) { 95 this.availableBitrate = availableBitrate; 96 this.targetRateShare = targetRateShare; 97 } 98 99 int availableBitrate; 100 short targetRateShare; 101 102 @Override 103 public String toString() { 104 return "{" + 105 "availableBitrate=" + availableBitrate + 106 ", targetRateShare=" + targetRateShare + 107 '}'; 108 } 109 110 public int getAvailableBitrate() { 111 return availableBitrate; 112 } 113 114 public void setAvailableBitrate(int availableBitrate) { 115 this.availableBitrate = availableBitrate; 116 } 117 118 public short getTargetRateShare() { 119 return targetRateShare; 120 } 121 122 public void setTargetRateShare(short targetRateShare) { 123 this.targetRateShare = targetRateShare; 124 } 125 126 @Override 127 public boolean equals(Object o) { 128 if (this == o) { 129 return true; 130 } 131 if (o == null || getClass() != o.getClass()) { 132 return false; 133 } 134 135 Entry entry = (Entry) o; 136 137 if (availableBitrate != entry.availableBitrate) { 138 return false; 139 } 140 if (targetRateShare != entry.targetRateShare) { 141 return false; 142 } 143 144 return true; 145 } 146 147 @Override 148 public int hashCode() { 149 int result = availableBitrate; 150 result = 31 * result + (int) targetRateShare; 151 return result; 152 } 153 } 154 155 @Override 156 public boolean equals(Object o) { 157 if (this == o) { 158 return true; 159 } 160 if (o == null || getClass() != o.getClass()) { 161 return false; 162 } 163 164 RateShareEntry that = (RateShareEntry) o; 165 166 if (discardPriority != that.discardPriority) { 167 return false; 168 } 169 if (maximumBitrate != that.maximumBitrate) { 170 return false; 171 } 172 if (minimumBitrate != that.minimumBitrate) { 173 return false; 174 } 175 if (operationPointCut != that.operationPointCut) { 176 return false; 177 } 178 if (targetRateShare != that.targetRateShare) { 179 return false; 180 } 181 if (entries != null ? !entries.equals(that.entries) : that.entries != null) { 182 return false; 183 } 184 185 return true; 186 } 187 188 @Override 189 public int hashCode() { 190 int result = (int) operationPointCut; 191 result = 31 * result + (int) targetRateShare; 192 result = 31 * result + (entries != null ? entries.hashCode() : 0); 193 result = 31 * result + maximumBitrate; 194 result = 31 * result + minimumBitrate; 195 result = 31 * result + (int) discardPriority; 196 return result; 197 } 198 199 public short getOperationPointCut() { 200 return operationPointCut; 201 } 202 203 public void setOperationPointCut(short operationPointCut) { 204 this.operationPointCut = operationPointCut; 205 } 206 207 public short getTargetRateShare() { 208 return targetRateShare; 209 } 210 211 public void setTargetRateShare(short targetRateShare) { 212 this.targetRateShare = targetRateShare; 213 } 214 215 public List<Entry> getEntries() { 216 return entries; 217 } 218 219 public void setEntries(List<Entry> entries) { 220 this.entries = entries; 221 } 222 223 public int getMaximumBitrate() { 224 return maximumBitrate; 225 } 226 227 public void setMaximumBitrate(int maximumBitrate) { 228 this.maximumBitrate = maximumBitrate; 229 } 230 231 public int getMinimumBitrate() { 232 return minimumBitrate; 233 } 234 235 public void setMinimumBitrate(int minimumBitrate) { 236 this.minimumBitrate = minimumBitrate; 237 } 238 239 public short getDiscardPriority() { 240 return discardPriority; 241 } 242 243 public void setDiscardPriority(short discardPriority) { 244 this.discardPriority = discardPriority; 245 } 246 } 247