/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portlet.documentlibrary.util;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.StringUtil;
import java.io.IOException;
import java.io.RandomAccessFile;
/**
* Atoms are self-contained data units in that contain information about an MP4
* movie file.
*
* @author Juan González
* @see JQTFastStart
*/
public class Atom {
public static final String CMOV = "cmov";
public static final String CO64 = "co64";
public static final String FREE = "free";
public static final String FTYP = "ftyp";
public static final String JUNK = "junk";
public static final String MDAT = "mdat";
public static final String MOOV = "moov";
public static final String PICT = "PICT";
public static final String PNOT = "pnot";
public static final String SKIP = "skip";
public static final String STCO = "stco";
public static final String[] TOP_LEVEL_ATOMS = {
FREE, FTYP, JUNK, MDAT, MOOV, PICT, PNOT, SKIP, Atom.WIDE
};
public static final String WIDE = "wide";
public Atom(RandomAccessFile randomAccessFile) throws IOException {
_offset = randomAccessFile.getFilePointer();
_size = randomAccessFile.readInt();
byte[] bytes = new byte[4];
randomAccessFile.readFully(bytes);
_type = new String(bytes);
if (_size == 1) {
_size = randomAccessFile.readLong();
}
randomAccessFile.seek(_offset);
}
public void fillBuffer(RandomAccessFile randomAccessFile)
throws IOException {
_buffer = new byte[(int)_size];
randomAccessFile.readFully(_buffer);
}
public byte[] getBuffer() {
return _buffer;
}
public long getOffset() {
return _offset;
}
public long getSize() {
return _size;
}
public String getType() {
return _type;
}
public boolean isFTYP() {
return StringUtil.equalsIgnoreCase(_type, FTYP);
}
public boolean isMDAT() {
return StringUtil.equalsIgnoreCase(_type, MDAT);
}
public boolean isMOOV() {
return StringUtil.equalsIgnoreCase(_type, MOOV);
}
public boolean isTopLevelAtom() {
for (String topLevelAtom : TOP_LEVEL_ATOMS) {
if (StringUtil.equalsIgnoreCase(_type, topLevelAtom)) {
return true;
}
}
return false;
}
public void patchAtom() {
for (int index = 4; index < _size - 4; index++) {
String type = new String(
ArrayUtil.clone(_buffer, index, index + 4));
if (StringUtil.equalsIgnoreCase(type, Atom.STCO)) {
index += patchStcoAtom(index) - 4;
}
else if (StringUtil.equalsIgnoreCase(type, Atom.CO64)) {
index += patchCo64Atom(index) - 4;
}
}
}
public void setBuffer(byte[] buffer) {
_buffer = buffer;
}
public void setOffset(long offset) {
_offset = offset;
}
public void setSize(long size) {
_size = size;
}
public void setType(String type) {
_type = type;
}
protected long bytesToLong(byte[] buffer) {
long value = 0;
for (int i = 0; i < buffer.length; i++) {
value += (buffer[i] & _BITMASK) << 8 * (buffer.length - i - 1);
}
return value;
}
protected boolean hasCompressedMoovAtom() {
String type = new String(ArrayUtil.clone(_buffer, 12, 15));
if (StringUtil.equalsIgnoreCase(type, Atom.CMOV)) {
return true;
}
else {
return false;
}
}
protected int patchCo64Atom(int index) {
int size = (int)bytesToLong(ArrayUtil.clone(_buffer, index - 4, index));
int offsetCount = (int)bytesToLong(
ArrayUtil.clone(_buffer, index + 8, index + 12));
for (int i = 0; i < offsetCount; i++) {
int offsetIndex = index + 12 + i * 8;
long offset = bytesToLong(
ArrayUtil.clone(_buffer, offsetIndex, offsetIndex + 8));
offset += _size;
_buffer[offsetIndex + 0] = (byte)((offset >> 56) & 0xFF);
_buffer[offsetIndex + 1] = (byte)((offset >> 48) & 0xFF);
_buffer[offsetIndex + 2] = (byte)((offset >> 40) & 0xFF);
_buffer[offsetIndex + 3] = (byte)((offset >> 32) & 0xFF);
_buffer[offsetIndex + 4] = (byte)((offset >> 24) & 0xFF);
_buffer[offsetIndex + 5] = (byte)((offset >> 16) & 0xFF);
_buffer[offsetIndex + 6] = (byte)((offset >> 8) & 0xFF);
_buffer[offsetIndex + 7] = (byte)((offset >> 0) & 0xFF);
}
return size;
}
protected int patchStcoAtom(int index) {
int size = (int)bytesToLong(ArrayUtil.clone(_buffer, index - 4, index));
int offsetCount = (int)bytesToLong(
ArrayUtil.clone(_buffer, index + 8, index + 12));
for (int i = 0; i < offsetCount; i++) {
int offsetIndex = index + 12 + i * 4;
int offset = (int)bytesToLong(
ArrayUtil.clone(_buffer, offsetIndex, offsetIndex + 4));
offset += _size;
_buffer[offsetIndex + 0] = (byte)((offset >> 24) & 0xFF);
_buffer[offsetIndex + 1] = (byte)((offset >> 16) & 0xFF);
_buffer[offsetIndex + 2] = (byte)((offset >> 8) & 0xFF);
_buffer[offsetIndex + 3] = (byte)((offset >> 0) & 0xFF);
}
return size;
}
private static final int _BITMASK = 0x00000000000000FF;
private byte[] _buffer;
private long _offset;
private long _size;
private String _type;
}