1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 package org.mozilla.gecko.media; 6 7 import android.media.MediaCodec; 8 import android.media.MediaCodec.BufferInfo; 9 import android.media.MediaCodec.CryptoInfo; 10 import android.os.Parcel; 11 import android.os.Parcelable; 12 13 import org.mozilla.gecko.annotation.WrapForJNI; 14 15 import java.nio.ByteBuffer; 16 17 // Parcelable carrying input/output sample data and info cross process. 18 public final class Sample implements Parcelable { 19 public static final Sample EOS; 20 static { 21 final BufferInfo eosInfo = new BufferInfo(); 22 EOS = new Sample(); 23 EOS.info.set(0, 0, Long.MIN_VALUE, MediaCodec.BUFFER_FLAG_END_OF_STREAM); 24 } 25 @WrapForJNI 26 public long session; 27 28 public static final int NO_BUFFER = -1; 29 30 public int bufferId = NO_BUFFER; 31 @WrapForJNI 32 public BufferInfo info = new BufferInfo(); 33 public CryptoInfo cryptoInfo; 34 35 // Simple Linked list for recycling objects. 36 // Used to nodify Sample objects. Do not marshal/unmarshal. 37 private Sample mNext; 38 private static Sample sPool = new Sample(); 39 private static int sPoolSize = 1; 40 Sample()41 private Sample() { } 42 readInfo(final Parcel in)43 private void readInfo(final Parcel in) { 44 final int offset = in.readInt(); 45 final int size = in.readInt(); 46 final long pts = in.readLong(); 47 final int flags = in.readInt(); 48 49 info.set(offset, size, pts, flags); 50 } 51 readCrypto(final Parcel in)52 private void readCrypto(final Parcel in) { 53 final int hasCryptoInfo = in.readInt(); 54 if (hasCryptoInfo == 0) { 55 cryptoInfo = null; 56 return; 57 } 58 59 final byte[] iv = in.createByteArray(); 60 final byte[] key = in.createByteArray(); 61 final int mode = in.readInt(); 62 final int[] numBytesOfClearData = in.createIntArray(); 63 final int[] numBytesOfEncryptedData = in.createIntArray(); 64 final int numSubSamples = in.readInt(); 65 66 if (cryptoInfo == null) { 67 cryptoInfo = new CryptoInfo(); 68 } 69 cryptoInfo.set(numSubSamples, 70 numBytesOfClearData, 71 numBytesOfEncryptedData, 72 key, 73 iv, 74 mode); 75 } 76 set(final BufferInfo info, final CryptoInfo cryptoInfo)77 public Sample set(final BufferInfo info, final CryptoInfo cryptoInfo) { 78 setBufferInfo(info); 79 setCryptoInfo(cryptoInfo); 80 return this; 81 } 82 setBufferInfo(final BufferInfo info)83 public void setBufferInfo(final BufferInfo info) { 84 this.info.set(0, info.size, info.presentationTimeUs, info.flags); 85 } 86 setCryptoInfo(final CryptoInfo crypto)87 public void setCryptoInfo(final CryptoInfo crypto) { 88 if (crypto == null) { 89 cryptoInfo = null; 90 return; 91 } 92 93 if (cryptoInfo == null) { 94 cryptoInfo = new CryptoInfo(); 95 } 96 cryptoInfo.set(crypto.numSubSamples, 97 crypto.numBytesOfClearData, 98 crypto.numBytesOfEncryptedData, 99 crypto.key, 100 crypto.iv, 101 crypto.mode); 102 } 103 104 @WrapForJNI dispose()105 public void dispose() { 106 if (isEOS()) { 107 return; 108 } 109 110 bufferId = NO_BUFFER; 111 info.set(0, 0, 0, 0); 112 if (cryptoInfo != null) { 113 cryptoInfo.set(0, null, null, null, null, 0); 114 } 115 116 // Recycle it. 117 synchronized (CREATOR) { 118 this.mNext = sPool; 119 sPool = this; 120 sPoolSize++; 121 } 122 } 123 isEOS()124 public boolean isEOS() { 125 return (this == EOS) || 126 ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0); 127 } 128 obtain()129 public static Sample obtain() { 130 synchronized (CREATOR) { 131 Sample s = null; 132 if (sPoolSize > 0) { 133 s = sPool; 134 sPool = s.mNext; 135 s.mNext = null; 136 sPoolSize--; 137 } else { 138 s = new Sample(); 139 } 140 return s; 141 } 142 } 143 144 public static final Creator<Sample> CREATOR = new Creator<Sample>() { 145 @Override 146 public Sample createFromParcel(final Parcel in) { 147 return obtainSample(in); 148 } 149 150 @Override 151 public Sample[] newArray(final int size) { 152 return new Sample[size]; 153 } 154 155 private Sample obtainSample(final Parcel in) { 156 final Sample s = obtain(); 157 s.session = in.readLong(); 158 s.bufferId = in.readInt(); 159 s.readInfo(in); 160 s.readCrypto(in); 161 return s; 162 } 163 }; 164 165 @Override describeContents()166 public int describeContents() { 167 return 0; 168 } 169 170 @Override writeToParcel(final Parcel dest, final int parcelableFlags)171 public void writeToParcel(final Parcel dest, final int parcelableFlags) { 172 dest.writeLong(session); 173 dest.writeInt(bufferId); 174 writeInfo(dest); 175 writeCrypto(dest); 176 } 177 writeInfo(final Parcel dest)178 private void writeInfo(final Parcel dest) { 179 dest.writeInt(info.offset); 180 dest.writeInt(info.size); 181 dest.writeLong(info.presentationTimeUs); 182 dest.writeInt(info.flags); 183 } 184 writeCrypto(final Parcel dest)185 private void writeCrypto(final Parcel dest) { 186 if (cryptoInfo != null) { 187 dest.writeInt(1); 188 dest.writeByteArray(cryptoInfo.iv); 189 dest.writeByteArray(cryptoInfo.key); 190 dest.writeInt(cryptoInfo.mode); 191 dest.writeIntArray(cryptoInfo.numBytesOfClearData); 192 dest.writeIntArray(cryptoInfo.numBytesOfEncryptedData); 193 dest.writeInt(cryptoInfo.numSubSamples); 194 } else { 195 dest.writeInt(0); 196 } 197 } 198 byteArrayFromBuffer(final ByteBuffer buffer, final int offset, final int size)199 public static byte[] byteArrayFromBuffer(final ByteBuffer buffer, final int offset, 200 final int size) { 201 if (buffer == null || buffer.capacity() == 0 || size == 0) { 202 return null; 203 } 204 if (buffer.hasArray() && offset == 0 && buffer.array().length == size) { 205 return buffer.array(); 206 } 207 final int length = Math.min(offset + size, buffer.capacity()) - offset; 208 final byte[] bytes = new byte[length]; 209 buffer.position(offset); 210 buffer.get(bytes); 211 return bytes; 212 } 213 214 @Override toString()215 public String toString() { 216 if (isEOS()) { 217 return "EOS sample"; 218 } 219 220 final StringBuilder str = new StringBuilder(); 221 str.append("{ session#:").append(session). 222 append(", buffer#").append(bufferId). 223 append(", info="). 224 append("{ offset=").append(info.offset). 225 append(", size=").append(info.size). 226 append(", pts=").append(info.presentationTimeUs). 227 append(", flags=").append(Integer.toHexString(info.flags)).append(" }"). 228 append(" }"); 229 return str.toString(); 230 } 231 } 232