Search in sources :

Example 1 with Mesh

use of androidx.media3.exoplayer.video.spherical.Projection.Mesh in project media by androidx.

the class ProjectionDecoder method parseRawMshpData.

/**
 * Parses MSHP data after the encoding_four_cc field.
 */
@Nullable
private static ArrayList<Mesh> parseRawMshpData(ParsableByteArray input) {
    ArrayList<Mesh> meshes = new ArrayList<>();
    int position = input.getPosition();
    int limit = input.limit();
    while (position < limit) {
        int childEnd = position + input.readInt();
        if (childEnd <= position || childEnd > limit) {
            return null;
        }
        int childAtomType = input.readInt();
        if (childAtomType == TYPE_MESH) {
            Mesh mesh = parseMesh(input);
            if (mesh == null) {
                return null;
            }
            meshes.add(mesh);
        }
        position = childEnd;
        input.setPosition(position);
    }
    return meshes;
}
Also used : ArrayList(java.util.ArrayList) SubMesh(androidx.media3.exoplayer.video.spherical.Projection.SubMesh) Mesh(androidx.media3.exoplayer.video.spherical.Projection.Mesh) Nullable(androidx.annotation.Nullable)

Example 2 with Mesh

use of androidx.media3.exoplayer.video.spherical.Projection.Mesh in project media by androidx.

the class ProjectionDecoder method parseMshp.

@Nullable
private static ArrayList<Mesh> parseMshp(ParsableByteArray input) {
    int version = input.readUnsignedByte();
    if (version != 0) {
        return null;
    }
    // flags + crc.
    input.skipBytes(7);
    int encoding = input.readInt();
    if (encoding == TYPE_DFL8) {
        ParsableByteArray output = new ParsableByteArray();
        Inflater inflater = new Inflater(true);
        try {
            if (!Util.inflate(input, output, inflater)) {
                return null;
            }
        } finally {
            inflater.end();
        }
        input = output;
    } else if (encoding != TYPE_RAW) {
        return null;
    }
    return parseRawMshpData(input);
}
Also used : ParsableByteArray(androidx.media3.common.util.ParsableByteArray) Inflater(java.util.zip.Inflater) Nullable(androidx.annotation.Nullable)

Example 3 with Mesh

use of androidx.media3.exoplayer.video.spherical.Projection.Mesh in project media by androidx.

the class ProjectionDecoder method parseMesh.

@Nullable
private static Mesh parseMesh(ParsableByteArray input) {
    // Read the coordinates.
    int coordinateCount = input.readInt();
    if (coordinateCount > MAX_COORDINATE_COUNT) {
        return null;
    }
    float[] coordinates = new float[coordinateCount];
    for (int coordinate = 0; coordinate < coordinateCount; coordinate++) {
        coordinates[coordinate] = input.readFloat();
    }
    // Read the vertices.
    int vertexCount = input.readInt();
    if (vertexCount > MAX_VERTEX_COUNT) {
        return null;
    }
    final double log2 = Math.log(2.0);
    int coordinateCountSizeBits = (int) Math.ceil(Math.log(2.0 * coordinateCount) / log2);
    ParsableBitArray bitInput = new ParsableBitArray(input.getData());
    bitInput.setPosition(input.getPosition() * 8);
    float[] vertices = new float[vertexCount * 5];
    int[] coordinateIndices = new int[5];
    int vertexIndex = 0;
    for (int vertex = 0; vertex < vertexCount; vertex++) {
        for (int i = 0; i < 5; i++) {
            int coordinateIndex = coordinateIndices[i] + decodeZigZag(bitInput.readBits(coordinateCountSizeBits));
            if (coordinateIndex >= coordinateCount || coordinateIndex < 0) {
                return null;
            }
            vertices[vertexIndex++] = coordinates[coordinateIndex];
            coordinateIndices[i] = coordinateIndex;
        }
    }
    // Pad to next byte boundary
    bitInput.setPosition(((bitInput.getPosition() + 7) & ~7));
    int subMeshCount = bitInput.readBits(32);
    SubMesh[] subMeshes = new SubMesh[subMeshCount];
    for (int i = 0; i < subMeshCount; i++) {
        int textureId = bitInput.readBits(8);
        int drawMode = bitInput.readBits(8);
        int triangleIndexCount = bitInput.readBits(32);
        if (triangleIndexCount > MAX_TRIANGLE_INDICES) {
            return null;
        }
        int vertexCountSizeBits = (int) Math.ceil(Math.log(2.0 * vertexCount) / log2);
        int index = 0;
        float[] triangleVertices = new float[triangleIndexCount * 3];
        float[] textureCoords = new float[triangleIndexCount * 2];
        for (int counter = 0; counter < triangleIndexCount; counter++) {
            index += decodeZigZag(bitInput.readBits(vertexCountSizeBits));
            if (index < 0 || index >= vertexCount) {
                return null;
            }
            triangleVertices[counter * 3] = vertices[index * 5];
            triangleVertices[counter * 3 + 1] = vertices[index * 5 + 1];
            triangleVertices[counter * 3 + 2] = vertices[index * 5 + 2];
            textureCoords[counter * 2] = vertices[index * 5 + 3];
            textureCoords[counter * 2 + 1] = vertices[index * 5 + 4];
        }
        subMeshes[i] = new SubMesh(textureId, triangleVertices, textureCoords, drawMode);
    }
    return new Mesh(subMeshes);
}
Also used : SubMesh(androidx.media3.exoplayer.video.spherical.Projection.SubMesh) SubMesh(androidx.media3.exoplayer.video.spherical.Projection.SubMesh) Mesh(androidx.media3.exoplayer.video.spherical.Projection.Mesh) ParsableBitArray(androidx.media3.common.util.ParsableBitArray) Nullable(androidx.annotation.Nullable)

Example 4 with Mesh

use of androidx.media3.exoplayer.video.spherical.Projection.Mesh in project media by androidx.

the class ProjectionDecoder method decode.

/*
   * Decodes the projection data.
   *
   * @param projectionData The projection data.
   * @param stereoMode A {@link C.StereoMode} value.
   * @return The projection or null if the data can't be decoded.
   */
@Nullable
public static Projection decode(byte[] projectionData, @C.StereoMode int stereoMode) {
    ParsableByteArray input = new ParsableByteArray(projectionData);
    // MP4 containers include the proj box but webm containers do not.
    // Both containers use mshp.
    ArrayList<Mesh> meshes = null;
    try {
        meshes = isProj(input) ? parseProj(input) : parseMshp(input);
    } catch (ArrayIndexOutOfBoundsException ignored) {
    // Do nothing.
    }
    if (meshes == null) {
        return null;
    } else {
        switch(meshes.size()) {
            case 1:
                return new Projection(meshes.get(0), stereoMode);
            case 2:
                return new Projection(meshes.get(0), meshes.get(1), stereoMode);
            case 0:
            default:
                return null;
        }
    }
}
Also used : ParsableByteArray(androidx.media3.common.util.ParsableByteArray) SubMesh(androidx.media3.exoplayer.video.spherical.Projection.SubMesh) Mesh(androidx.media3.exoplayer.video.spherical.Projection.Mesh) Nullable(androidx.annotation.Nullable)

Aggregations

Nullable (androidx.annotation.Nullable)4 Mesh (androidx.media3.exoplayer.video.spherical.Projection.Mesh)3 SubMesh (androidx.media3.exoplayer.video.spherical.Projection.SubMesh)3 ParsableByteArray (androidx.media3.common.util.ParsableByteArray)2 ParsableBitArray (androidx.media3.common.util.ParsableBitArray)1 ArrayList (java.util.ArrayList)1 Inflater (java.util.zip.Inflater)1