Support building of version 1 PSSH atoms

Issue: #3138

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=164590835
This commit is contained in:
olly 2017-08-08 07:36:31 -07:00 committed by Oliver Woodman
parent 24bf2aa0e2
commit 072788c88a
2 changed files with 83 additions and 9 deletions

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.extractor.mp4;
import android.test.MoreAsserts;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.ParsableByteArray;
import java.util.UUID;
import junit.framework.TestCase;
/**
* Tests for {@link PsshAtomUtil}.
*/
public class PsshAtomUtilTest extends TestCase {
public void testBuildPsshAtom() {
byte[] schemeData = new byte[]{0, 1, 2, 3, 4, 5};
byte[] psshAtom = PsshAtomUtil.buildPsshAtom(C.WIDEVINE_UUID, schemeData);
// Read the PSSH atom back and assert its content is as expected.
ParsableByteArray parsablePsshAtom = new ParsableByteArray(psshAtom);
assertEquals(psshAtom.length, parsablePsshAtom.readUnsignedIntToInt()); // length
assertEquals(Atom.TYPE_pssh, parsablePsshAtom.readInt()); // type
int fullAtomInt = parsablePsshAtom.readInt(); // version + flags
assertEquals(0, Atom.parseFullAtomVersion(fullAtomInt));
assertEquals(0, Atom.parseFullAtomFlags(fullAtomInt));
UUID systemId = new UUID(parsablePsshAtom.readLong(), parsablePsshAtom.readLong());
assertEquals(C.WIDEVINE_UUID, systemId);
assertEquals(schemeData.length, parsablePsshAtom.readUnsignedIntToInt());
byte[] psshSchemeData = new byte[schemeData.length];
parsablePsshAtom.readBytes(psshSchemeData, 0, schemeData.length);
MoreAsserts.assertEquals(schemeData, psshSchemeData);
}
}

View File

@ -31,22 +31,48 @@ public final class PsshAtomUtil {
private PsshAtomUtil() {}
/**
* Builds a PSSH atom for a given {@link UUID} containing the given scheme specific data.
* Builds a version 0 PSSH atom for a given system id, containing the given data.
*
* @param uuid The UUID of the scheme.
* @param systemId The system id of the scheme.
* @param data The scheme specific data.
* @return The PSSH atom.
*/
public static byte[] buildPsshAtom(UUID uuid, byte[] data) {
int psshBoxLength = Atom.FULL_HEADER_SIZE + 16 /* UUID */ + 4 /* DataSize */ + data.length;
public static byte[] buildPsshAtom(UUID systemId, byte[] data) {
return buildPsshAtom(systemId, null, data);
}
/**
* Builds a PSSH atom for the given system id, containing the given key ids and data.
*
* @param systemId The system id of the scheme.
* @param keyIds The key ids for a version 1 PSSH atom, or null for a version 0 PSSH atom.
* @param data The scheme specific data.
* @return The PSSH atom.
*/
public static byte[] buildPsshAtom(UUID systemId, UUID[] keyIds, byte[] data) {
boolean buildV1Atom = keyIds != null;
int dataLength = data != null ? data.length : 0;
int psshBoxLength = Atom.FULL_HEADER_SIZE + 16 /* SystemId */ + 4 /* DataSize */ + dataLength;
if (buildV1Atom) {
psshBoxLength += 4 /* KID_count */ + (keyIds.length * 16) /* KIDs */;
}
ByteBuffer psshBox = ByteBuffer.allocate(psshBoxLength);
psshBox.putInt(psshBoxLength);
psshBox.putInt(Atom.TYPE_pssh);
psshBox.putInt(0 /* version=0, flags=0 */);
psshBox.putLong(uuid.getMostSignificantBits());
psshBox.putLong(uuid.getLeastSignificantBits());
psshBox.putInt(buildV1Atom ? 0x01000000 : 0 /* version=(buildV1Atom ? 1 : 0), flags=0 */);
psshBox.putLong(systemId.getMostSignificantBits());
psshBox.putLong(systemId.getLeastSignificantBits());
if (buildV1Atom) {
psshBox.putInt(keyIds.length);
for (UUID keyId : keyIds) {
psshBox.putLong(keyId.getMostSignificantBits());
psshBox.putLong(keyId.getLeastSignificantBits());
}
}
if (dataLength != 0) {
psshBox.putInt(data.length);
psshBox.put(data);
} // Else the last 4 bytes are a 0 DataSize.
return psshBox.array();
}
@ -98,6 +124,7 @@ public final class PsshAtomUtil {
* @return A pair consisting of the parsed UUID and scheme specific data. Null if the input is
* not a valid PSSH atom, or if the PSSH atom has an unsupported version.
*/
// TODO: Support parsing of the key ids for version 1 PSSH atoms.
private static Pair<UUID, byte[]> parsePsshAtom(byte[] atom) {
ParsableByteArray atomData = new ParsableByteArray(atom);
if (atomData.limit() < Atom.FULL_HEADER_SIZE + 16 /* UUID */ + 4 /* DataSize */) {