Skip to content
Snippets Groups Projects
Commit 2757703c authored by Vojtech Moravec's avatar Vojtech Moravec
Browse files

Prepare QVC file changes.

parent c919c964
Branches
No related tags found
No related merge requests found
package cz.it4i.qcmp.cache;
import cz.it4i.qcmp.fileformat.IQvcHeader;
import cz.it4i.qcmp.fileformat.QvcHeaderV1;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
// TODO(Moravec): Rename to IQvcFile
public interface ICacheFile {
public interface IQvcFile {
void writeToStream(DataOutputStream outputStream) throws IOException;
void readFromStream(DataInputStream inputStream, IQvcHeader header) throws IOException;
void readFromStream(DataInputStream inputStream, QvcHeaderV1 header) throws IOException;
IQvcHeader getHeader();
void report(StringBuilder builder);
String klass();
}
package cz.it4i.qcmp.cache;
import cz.it4i.qcmp.fileformat.IQvcHeader;
import cz.it4i.qcmp.fileformat.QuantizationType;
import cz.it4i.qcmp.fileformat.QvcHeaderV1;
import cz.it4i.qcmp.fileformat.QvcHeaderV2;
import cz.it4i.qcmp.io.RawDataIO;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class QvcFileReader {
private static final int QVC_HEADER_MAGIC_VALUE_SIZE = 9;
/**
* Read cache file from file.
*
* @param path File path.
* @return Cache file or null if reading fails.
*/
public static IQvcFile readCacheFile(final String path) {
try (final FileInputStream fis = new FileInputStream(path)) {
return readCacheFileImpl(fis);
} catch (final IOException e) {
return null;
}
}
/**
* Make DataInputStream from InputStream.
*
* @param inputStream Some input stream.
* @return DataInputStream.
*/
private static DataInputStream asDataInputStream(final InputStream inputStream) {
if (inputStream instanceof DataInputStream) {
return (DataInputStream) inputStream;
} else {
return new DataInputStream(inputStream);
}
}
/**
* Create correct Qvc header version by analyzing the magic value.
*
* @param magicValue Magic value of the qvc file.
* @return Correct version of QVC header.
* @throws IOException when the magic value is unknown.
*/
private static IQvcHeader getCorrectQvcHeader(final String magicValue) throws IOException {
switch (magicValue) {
case QvcHeaderV1.MAGIC_VALUE:
return new QvcHeaderV1();
case QvcHeaderV2.MAGIC_VALUE:
return new QvcHeaderV2();
default:
throw new IOException("Invalid QVC file. Unknown QVC magic value: " + magicValue);
}
}
/**
* Create correct Qvc file by analyzing the quantization type.
*
* @param quantizationType Quantization type of codebook.
* @return Correct version of QVC file.
* @throws IOException when the quantization type is unknown.
*/
private static IQvcFile getCorrectQvcFile(final QuantizationType quantizationType) throws IOException {
switch (quantizationType) {
case Scalar:
return new SqQvcFile();
case Vector1D:
case Vector2D:
case Vector3D:
return new VqQvcFile();
default:
throw new IOException("Invalid quantization type. Unable to create qvc file impl.");
}
}
/**
* Read cache file by DataInputStream.
*
* @param inputStream Input stream.
* @return Cache file or null, if exception occurs.
*/
private static IQvcFile readCacheFileImpl(final InputStream inputStream) throws IOException {
final DataInputStream dis = asDataInputStream(inputStream);
final byte[] magicValueBuffer = new byte[QVC_HEADER_MAGIC_VALUE_SIZE];
RawDataIO.readFullBuffer(dis, magicValueBuffer);
final String magicValue = new String(magicValueBuffer);
final IQvcHeader header = getCorrectQvcHeader(magicValue);
header.readFromStream(dis);
final IQvcFile cacheFile = getCorrectQvcFile(header.getQuantizationType());
cacheFile.readFromStream(dis, header);
return cacheFile;
}
}
package cz.it4i.qcmp.cache;
import cz.it4i.qcmp.fileformat.QvcHeaderV1;
import cz.it4i.qcmp.fileformat.IQvcHeader;
import cz.it4i.qcmp.quantization.scalar.SQCodebook;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class SQCacheFile implements IQvcFile {
private QvcHeaderV1 header;
public class SqQvcFile implements IQvcFile {
private IQvcHeader header;
private SQCodebook codebook;
public SQCacheFile() {
public SqQvcFile() {
}
public SQCacheFile(final QvcHeaderV1 header, final SQCodebook codebook) {
public SqQvcFile(final IQvcHeader header, final SQCodebook codebook) {
this.header = header;
this.codebook = codebook;
assert (header.getCodebookSize() == codebook.getCodebookSize());
}
@Override
public void writeToStream(final DataOutputStream outputStream) throws IOException {
// TODO
header.writeToStream(outputStream);
final int[] quantizationValues = codebook.getCentroids();
final long[] frequencies = codebook.getSymbolFrequencies();
......@@ -33,13 +35,9 @@ public class SQCacheFile implements IQvcFile {
}
}
public void readFromStream(final DataInputStream inputStream) throws IOException {
header = new QvcHeaderV1();
header.readFromStream(inputStream);
readFromStream(inputStream, header);
}
public void readFromStream(final DataInputStream inputStream, final QvcHeaderV1 header) throws IOException {
@Override
public void readFromStream(final DataInputStream inputStream, final IQvcHeader header) throws IOException {
// TODO
this.header = header;
final int codebookSize = header.getCodebookSize();
final int[] centroids = new int[codebookSize];
......@@ -54,7 +52,8 @@ public class SQCacheFile implements IQvcFile {
codebook = new SQCodebook(centroids, frequencies);
}
public QvcHeaderV1 getHeader() {
@Override
public IQvcHeader getHeader() {
return header;
}
......
package cz.it4i.qcmp.cache;
import cz.it4i.qcmp.fileformat.QvcHeaderV1;
import cz.it4i.qcmp.fileformat.IQvcHeader;
import cz.it4i.qcmp.quantization.vector.VQCodebook;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class VQCacheFile implements IQvcFile {
private QvcHeaderV1 header;
public class VqQvcFile implements IQvcFile {
private IQvcHeader header;
private VQCodebook codebook;
public VQCacheFile() {
public VqQvcFile() {
}
public VQCacheFile(final QvcHeaderV1 header, final VQCodebook codebook) {
public VqQvcFile(final IQvcHeader header, final VQCodebook codebook) {
this.header = header;
this.codebook = codebook;
assert (header.getCodebookSize() == codebook.getCodebookSize());
}
@Override
public void writeToStream(final DataOutputStream outputStream) throws IOException {
// TODO
header.writeToStream(outputStream);
final int[][] entries = codebook.getVectors();
......@@ -36,18 +38,13 @@ public class VQCacheFile implements IQvcFile {
}
}
public void readFromStream(final DataInputStream inputStream) throws IOException {
header = new QvcHeaderV1();
header.readFromStream(inputStream);
readFromStream(inputStream, header);
}
@Override
public void readFromStream(final DataInputStream inputStream, final QvcHeaderV1 header) throws IOException {
public void readFromStream(final DataInputStream inputStream, final IQvcHeader header) throws IOException {
// TODO
this.header = header;
final int codebookSize = header.getCodebookSize();
final int entrySize = header.getVectorSizeX() * header.getVectorSizeY() * header.getVectorSizeZ();
final int entrySize = header.getVectorDim().multiplyTogether();
final int[][] vectors = new int[codebookSize][entrySize];
final long[] frequencies = new long[codebookSize];
......@@ -64,7 +61,8 @@ public class VQCacheFile implements IQvcFile {
codebook = new VQCodebook(header.getVectorDim(), vectors, frequencies);
}
public QvcHeaderV1 getHeader() {
@Override
public IQvcHeader getHeader() {
return header;
}
......
package cz.it4i.qcmp.fileformat;
import cz.it4i.qcmp.data.V3i;
public interface IQvcHeader extends IFileHeader {
QuantizationType getQuantizationType();
int getBitsPerCodebookIndex();
int getCodebookSize();
V3i getVectorDim();
}
......@@ -9,21 +9,22 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class QvcHeaderV1 implements IFileHeader {
public class QvcHeaderV1 implements IQvcHeader {
//region Constants
private static final int VERSION = 1;
private static final String MAGIC_VALUE = "QCMPCACHE";
public static final String MAGIC_VALUE = "QCMPCACHE";
public static final int BASE_HEADER_SIZE = 20;
//endregion
//region Header fields.
private String magicValue;
private QuantizationType quantizationType;
private int codebookSize;
private int trainFileNameSize;
private String trainFileName;
private int vectorSizeX;
private int vectorSizeY;
private int vectorSizeZ;
protected String magicValue;
protected QuantizationType quantizationType;
protected int codebookSize;
protected int trainFileNameSize;
protected String trainFileName;
protected int vectorSizeX;
protected int vectorSizeY;
protected int vectorSizeZ;
//endregion
//region IFileHeader implementation
......@@ -49,18 +50,6 @@ public class QvcHeaderV1 implements IFileHeader {
*/
@Override
public void readFromStream(final DataInputStream inputStream) throws IOException {
final int MIN_AVAIL = 9;
if (inputStream.available() < MIN_AVAIL) {
throw new IOException("Provided file is not QCMP cache file.");
}
final byte[] magicValueBuffer = new byte[MAGIC_VALUE.length()];
RawDataIO.readFullBuffer(inputStream, magicValueBuffer);
magicValue = new String(magicValueBuffer);
if (!magicValue.equals(MAGIC_VALUE)) {
throw new IOException("Invalid QCMP cache file. Wrong magic value.");
}
quantizationType = QuantizationType.fromByte(inputStream.readByte());
codebookSize = inputStream.readUnsignedShort();
......@@ -68,7 +57,6 @@ public class QvcHeaderV1 implements IFileHeader {
final byte[] fileNameBuffer = new byte[trainFileNameSize];
RawDataIO.readFullBuffer(inputStream, fileNameBuffer);
trainFileName = new String(fileNameBuffer);
vectorSizeX = inputStream.readUnsignedShort();
......@@ -84,7 +72,7 @@ public class QvcHeaderV1 implements IFileHeader {
*/
@Override
public void writeToStream(final DataOutputStream outputStream) throws IOException {
outputStream.writeBytes(MAGIC_VALUE);
outputStream.writeBytes(getMagicValue());
outputStream.writeByte(quantizationType.getValue());
outputStream.writeShort(codebookSize);
......@@ -98,16 +86,16 @@ public class QvcHeaderV1 implements IFileHeader {
@Override
public long getExpectedDataSize() {
long expectedFileSize = 20 + trainFileNameSize; // Base header size
expectedFileSize += (codebookSize * 8); // Frequency values
long expectedFileSize = BASE_HEADER_SIZE + trainFileNameSize;
expectedFileSize += codebookSize * 8L; // Frequency values
switch (quantizationType) {
case Scalar:
expectedFileSize += (codebookSize * 2); // Scalar quantization values
expectedFileSize += codebookSize * 2L; // Scalar quantization values
break;
case Vector1D:
case Vector2D:
case Vector3D:
expectedFileSize += ((vectorSizeX * vectorSizeY * vectorSizeZ) * codebookSize * 2); // Quantization vectors
expectedFileSize += (((long) vectorSizeX * vectorSizeY * vectorSizeZ) * codebookSize * 2L); // Quantization vectors
break;
case Invalid:
return -1;
......@@ -117,8 +105,8 @@ public class QvcHeaderV1 implements IFileHeader {
@Override
public void report(final StringBuilder sb, final String inputFile) {
sb.append("HeaderVersion: ").append(VERSION).append('\n');
sb.append("Magic: ").append(magicValue).append('\n');
sb.append("HeaderVersion: ").append(getHeaderVersion()).append('\n');
sb.append("Magic: ").append(getMagicValue()).append('\n');
sb.append("CodebookType: ");
switch (quantizationType) {
......@@ -155,18 +143,6 @@ public class QvcHeaderV1 implements IFileHeader {
this.trainFileNameSize = this.trainFileName.length();
}
public void setVectorSizeX(final int vectorSizeX) {
this.vectorSizeX = vectorSizeX;
}
public void setVectorSizeY(final int vectorSizeY) {
this.vectorSizeY = vectorSizeY;
}
public void setVectorSizeZ(final int vectorSizeZ) {
this.vectorSizeZ = vectorSizeZ;
}
public QuantizationType getQuantizationType() {
return quantizationType;
}
......@@ -179,10 +155,6 @@ public class QvcHeaderV1 implements IFileHeader {
return (int) Utils.log2(codebookSize);
}
public int getTrainFileNameSize() {
return trainFileNameSize;
}
public String getTrainFileName() {
return trainFileName;
}
......
package cz.it4i.qcmp.fileformat;
import java.io.DataInputStream;
import java.io.IOException;
public class QvcHeaderV2 extends QvcHeaderV1 {
//region Constants
private static final int VERSION = 2;
public static final String MAGIC_VALUE = "QVCFILEV2";
public static final int RESERVED_BYTES_SIZE = 10;
public static final int BASE_HEADER_SIZE = 32;
//endregion
//region Header fields.
int huffmanDataSize;
//endregion
//region IFileHeader implementation
@Override
public String getMagicValue() {
return MAGIC_VALUE;
}
@Override
public int getHeaderVersion() {
return VERSION;
}
@Override
public boolean validateHeader() {
return (magicValue != null && magicValue.equals(MAGIC_VALUE));
}
@Override
public void readFromStream(final DataInputStream inputStream) throws IOException {
super.readFromStream(inputStream);
huffmanDataSize = inputStream.readUnsignedShort();
final int skipped = inputStream.skipBytes(RESERVED_BYTES_SIZE);
if (skipped != RESERVED_BYTES_SIZE)
throw new IOException("Unable to read QvcHeaderV2. Unable to skip reserved bytes.");
}
@Override
public long getExpectedDataSize() {
long expectedFileSize = BASE_HEADER_SIZE + trainFileNameSize + huffmanDataSize;
switch (quantizationType) {
case Scalar:
expectedFileSize += codebookSize * 2L; // Scalar quantization values
break;
case Vector1D:
case Vector2D:
case Vector3D:
expectedFileSize += (((long) vectorSizeX * vectorSizeY * vectorSizeZ) * codebookSize * 2L); // Quantization vectors
break;
case Invalid:
return -1;
}
return expectedFileSize;
}
@Override
public void report(final StringBuilder sb, final String inputFile) {
super.report(sb, inputFile);
sb.append("HuffmanDataSize: ").append(huffmanDataSize).append('\n');
}
//endregion
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment