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

Prepare QVC file changes.

parent c919c964
No related branches found
No related tags found
No related merge requests found
package cz.it4i.qcmp.cache; package cz.it4i.qcmp.cache;
import cz.it4i.qcmp.fileformat.IQvcHeader; import cz.it4i.qcmp.fileformat.IQvcHeader;
import cz.it4i.qcmp.fileformat.QvcHeaderV1;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
// TODO(Moravec): Rename to IQvcFile public interface IQvcFile {
public interface ICacheFile {
void writeToStream(DataOutputStream outputStream) throws IOException; void writeToStream(DataOutputStream outputStream) throws IOException;
void readFromStream(DataInputStream inputStream, IQvcHeader header) throws IOException; void readFromStream(DataInputStream inputStream, IQvcHeader header) throws IOException;
void readFromStream(DataInputStream inputStream, QvcHeaderV1 header) throws IOException;
IQvcHeader getHeader(); IQvcHeader getHeader();
void report(StringBuilder builder); 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; 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 cz.it4i.qcmp.quantization.scalar.SQCodebook;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
public class SQCacheFile implements IQvcFile { public class SqQvcFile implements IQvcFile {
private QvcHeaderV1 header; private IQvcHeader header;
private SQCodebook codebook; 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.header = header;
this.codebook = codebook; this.codebook = codebook;
assert (header.getCodebookSize() == codebook.getCodebookSize()); assert (header.getCodebookSize() == codebook.getCodebookSize());
} }
@Override
public void writeToStream(final DataOutputStream outputStream) throws IOException { public void writeToStream(final DataOutputStream outputStream) throws IOException {
// TODO
header.writeToStream(outputStream); header.writeToStream(outputStream);
final int[] quantizationValues = codebook.getCentroids(); final int[] quantizationValues = codebook.getCentroids();
final long[] frequencies = codebook.getSymbolFrequencies(); final long[] frequencies = codebook.getSymbolFrequencies();
...@@ -33,13 +35,9 @@ public class SQCacheFile implements IQvcFile { ...@@ -33,13 +35,9 @@ public class SQCacheFile implements IQvcFile {
} }
} }
public void readFromStream(final DataInputStream inputStream) throws IOException { @Override
header = new QvcHeaderV1(); public void readFromStream(final DataInputStream inputStream, final IQvcHeader header) throws IOException {
header.readFromStream(inputStream); // TODO
readFromStream(inputStream, header);
}
public void readFromStream(final DataInputStream inputStream, final QvcHeaderV1 header) throws IOException {
this.header = header; this.header = header;
final int codebookSize = header.getCodebookSize(); final int codebookSize = header.getCodebookSize();
final int[] centroids = new int[codebookSize]; final int[] centroids = new int[codebookSize];
...@@ -54,7 +52,8 @@ public class SQCacheFile implements IQvcFile { ...@@ -54,7 +52,8 @@ public class SQCacheFile implements IQvcFile {
codebook = new SQCodebook(centroids, frequencies); codebook = new SQCodebook(centroids, frequencies);
} }
public QvcHeaderV1 getHeader() { @Override
public IQvcHeader getHeader() {
return header; return header;
} }
......
package cz.it4i.qcmp.cache; 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 cz.it4i.qcmp.quantization.vector.VQCodebook;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
public class VQCacheFile implements IQvcFile { public class VqQvcFile implements IQvcFile {
private QvcHeaderV1 header; private IQvcHeader header;
private VQCodebook codebook; 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.header = header;
this.codebook = codebook; this.codebook = codebook;
assert (header.getCodebookSize() == codebook.getCodebookSize()); assert (header.getCodebookSize() == codebook.getCodebookSize());
} }
@Override
public void writeToStream(final DataOutputStream outputStream) throws IOException { public void writeToStream(final DataOutputStream outputStream) throws IOException {
// TODO
header.writeToStream(outputStream); header.writeToStream(outputStream);
final int[][] entries = codebook.getVectors(); final int[][] entries = codebook.getVectors();
...@@ -36,18 +38,13 @@ public class VQCacheFile implements IQvcFile { ...@@ -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 @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; this.header = header;
final int codebookSize = header.getCodebookSize(); 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 int[][] vectors = new int[codebookSize][entrySize];
final long[] frequencies = new long[codebookSize]; final long[] frequencies = new long[codebookSize];
...@@ -64,7 +61,8 @@ public class VQCacheFile implements IQvcFile { ...@@ -64,7 +61,8 @@ public class VQCacheFile implements IQvcFile {
codebook = new VQCodebook(header.getVectorDim(), vectors, frequencies); codebook = new VQCodebook(header.getVectorDim(), vectors, frequencies);
} }
public QvcHeaderV1 getHeader() { @Override
public IQvcHeader getHeader() {
return header; 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; ...@@ -9,21 +9,22 @@ import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
public class QvcHeaderV1 implements IFileHeader { public class QvcHeaderV1 implements IQvcHeader {
//region Constants //region Constants
private static final int VERSION = 1; 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 //endregion
//region Header fields. //region Header fields.
private String magicValue; protected String magicValue;
private QuantizationType quantizationType; protected QuantizationType quantizationType;
private int codebookSize; protected int codebookSize;
private int trainFileNameSize; protected int trainFileNameSize;
private String trainFileName; protected String trainFileName;
private int vectorSizeX; protected int vectorSizeX;
private int vectorSizeY; protected int vectorSizeY;
private int vectorSizeZ; protected int vectorSizeZ;
//endregion //endregion
//region IFileHeader implementation //region IFileHeader implementation
...@@ -49,18 +50,6 @@ public class QvcHeaderV1 implements IFileHeader { ...@@ -49,18 +50,6 @@ public class QvcHeaderV1 implements IFileHeader {
*/ */
@Override @Override
public void readFromStream(final DataInputStream inputStream) throws IOException { 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()); quantizationType = QuantizationType.fromByte(inputStream.readByte());
codebookSize = inputStream.readUnsignedShort(); codebookSize = inputStream.readUnsignedShort();
...@@ -68,7 +57,6 @@ public class QvcHeaderV1 implements IFileHeader { ...@@ -68,7 +57,6 @@ public class QvcHeaderV1 implements IFileHeader {
final byte[] fileNameBuffer = new byte[trainFileNameSize]; final byte[] fileNameBuffer = new byte[trainFileNameSize];
RawDataIO.readFullBuffer(inputStream, fileNameBuffer); RawDataIO.readFullBuffer(inputStream, fileNameBuffer);
trainFileName = new String(fileNameBuffer); trainFileName = new String(fileNameBuffer);
vectorSizeX = inputStream.readUnsignedShort(); vectorSizeX = inputStream.readUnsignedShort();
...@@ -84,7 +72,7 @@ public class QvcHeaderV1 implements IFileHeader { ...@@ -84,7 +72,7 @@ public class QvcHeaderV1 implements IFileHeader {
*/ */
@Override @Override
public void writeToStream(final DataOutputStream outputStream) throws IOException { public void writeToStream(final DataOutputStream outputStream) throws IOException {
outputStream.writeBytes(MAGIC_VALUE); outputStream.writeBytes(getMagicValue());
outputStream.writeByte(quantizationType.getValue()); outputStream.writeByte(quantizationType.getValue());
outputStream.writeShort(codebookSize); outputStream.writeShort(codebookSize);
...@@ -98,16 +86,16 @@ public class QvcHeaderV1 implements IFileHeader { ...@@ -98,16 +86,16 @@ public class QvcHeaderV1 implements IFileHeader {
@Override @Override
public long getExpectedDataSize() { public long getExpectedDataSize() {
long expectedFileSize = 20 + trainFileNameSize; // Base header size long expectedFileSize = BASE_HEADER_SIZE + trainFileNameSize;
expectedFileSize += (codebookSize * 8); // Frequency values expectedFileSize += codebookSize * 8L; // Frequency values
switch (quantizationType) { switch (quantizationType) {
case Scalar: case Scalar:
expectedFileSize += (codebookSize * 2); // Scalar quantization values expectedFileSize += codebookSize * 2L; // Scalar quantization values
break; break;
case Vector1D: case Vector1D:
case Vector2D: case Vector2D:
case Vector3D: case Vector3D:
expectedFileSize += ((vectorSizeX * vectorSizeY * vectorSizeZ) * codebookSize * 2); // Quantization vectors expectedFileSize += (((long) vectorSizeX * vectorSizeY * vectorSizeZ) * codebookSize * 2L); // Quantization vectors
break; break;
case Invalid: case Invalid:
return -1; return -1;
...@@ -117,8 +105,8 @@ public class QvcHeaderV1 implements IFileHeader { ...@@ -117,8 +105,8 @@ public class QvcHeaderV1 implements IFileHeader {
@Override @Override
public void report(final StringBuilder sb, final String inputFile) { public void report(final StringBuilder sb, final String inputFile) {
sb.append("HeaderVersion: ").append(VERSION).append('\n'); sb.append("HeaderVersion: ").append(getHeaderVersion()).append('\n');
sb.append("Magic: ").append(magicValue).append('\n'); sb.append("Magic: ").append(getMagicValue()).append('\n');
sb.append("CodebookType: "); sb.append("CodebookType: ");
switch (quantizationType) { switch (quantizationType) {
...@@ -155,18 +143,6 @@ public class QvcHeaderV1 implements IFileHeader { ...@@ -155,18 +143,6 @@ public class QvcHeaderV1 implements IFileHeader {
this.trainFileNameSize = this.trainFileName.length(); 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() { public QuantizationType getQuantizationType() {
return quantizationType; return quantizationType;
} }
...@@ -179,10 +155,6 @@ public class QvcHeaderV1 implements IFileHeader { ...@@ -179,10 +155,6 @@ public class QvcHeaderV1 implements IFileHeader {
return (int) Utils.log2(codebookSize); return (int) Utils.log2(codebookSize);
} }
public int getTrainFileNameSize() {
return trainFileNameSize;
}
public String getTrainFileName() { public String getTrainFileName() {
return trainFileName; 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