public SupHD(String supFile) throws CoreException {
try {
buffer = new FileBuffer(supFile);
} catch (FileBufferException ex) {
throw new CoreException(ex.getMessage());
}
int bufsize = (int)buffer.getSize();
SubPictureHD pic;
int index = 0;
try {
while (index < bufsize) {
if (Core.isCanceled()) {
throw new CoreException("Canceled by user!");
}
Core.setProgress(index);
if (buffer.getWord(index) != 0x5350) {
throw new CoreException("ID 'SP' missing at index " + ToolBox.toHexLeftZeroPadded(index, 8) + "\n");
}
int masterIndex = index + 10; //end of header
pic = new SubPictureHD();
// hard code size since it's not part of the format???
pic.setWidth(1920);
pic.setHeight(1080);
logger.info("#" + (subPictures.size() + 1) + "\n");
pic.setStartTime(buffer.getDWordLE(index+=2)); // read PTS
int packetSize = buffer.getDWord(index+=10);
// offset to command buffer
int ofsCmd = buffer.getDWord(index+=4) + masterIndex;
pic.setImageBufferSize(ofsCmd - (index + 4));
index = ofsCmd;
int dcsq = buffer.getWord(index);
pic.setStartTime(pic.getStartTime() + (dcsq * 1024));
logger.info("DCSQ start ofs: " + ToolBox.toHexLeftZeroPadded(index, 8) + " (" + ptsToTimeStr(pic.getStartTime()) + ")\n");
index += 2; // 2 bytes: dcsq
int nextIndex = buffer.getDWord(index) + masterIndex; // offset to next dcsq
index += 5; // 4 bytes: offset, 1 byte: start
int cmd;
boolean stopDisplay = false;
boolean stopCommand = false;
int alphaSum;
int minAlphaSum = 256 * 256; // 256 fully transparent entries
while(!stopDisplay) {
cmd = buffer.getByte(index++);
switch (cmd) {
case 0x01:
logger.info("DCSQ start ofs: " + ToolBox.toHexLeftZeroPadded(index, 8) + " (" + ptsToTimeStr(pic.getStartTime() + (dcsq * 1024)) + ")\n");
logger.warn("DCSQ start ignored due to missing DCSQ stop\n");
break;
case 0x02:
stopDisplay = true;
pic.setEndTime(pic.getStartTime() +(dcsq*1024));
logger.info("DCSQ stop ofs: " + ToolBox.toHexLeftZeroPadded(index, 8) + " (" + ptsToTimeStr(pic.getEndTime()) + ")\n");
break;
case 0x83: // palette
logger.trace("Palette info ofs: " + ToolBox.toHexLeftZeroPadded(index, 8) + "\n");
pic.setPaletteOffset(index);
index += 0x300;
break;
case 0x84: // alpha
logger.trace("Alpha info ofs: " + ToolBox.toHexLeftZeroPadded(index, 8) + "\n");
alphaSum = 0;
for (int i=index; i < index+0x100; i++) {
alphaSum += buffer.getByte(i);
}
if (alphaSum < minAlphaSum) {
pic.setAlphaOffset(index);
minAlphaSum = alphaSum;
} else {
logger.warn("Found faded alpha buffer -> alpha buffer skipped\n");
}
index += 0x100;
break;
case 0x85: // area
pic.setOfsX((buffer.getByte(index)<<4) | (buffer.getByte(index+1)>>4));
pic.setImageWidth((((buffer.getByte(index+1)&0xf)<<8) | (buffer.getByte(index+2))) - pic.getXOffset() + 1);
pic.setOfsY((buffer.getByte(index+3)<<4) | (buffer.getByte(index+4)>>4));
pic.setImageHeight((((buffer.getByte(index+4)&0xf)<<8) | (buffer.getByte(index+5))) - pic.getYOffset() + 1);
logger.trace("Area info ofs: " + ToolBox.toHexLeftZeroPadded(index, 8) + " ("
+ pic.getXOffset() + ", " + pic.getYOffset() + ") - (" + (pic.getXOffset() + pic.getImageWidth()) + ", "
+ (pic.getYOffset() + pic.getImageHeight()) + ")\n");
index += 6;
break;
case 0x86: // even/odd offsets
pic.setImageBufferOffsetEven(buffer.getDWord(index) + masterIndex);
pic.setImageBufferOffsetOdd(buffer.getDWord(index+4) + masterIndex);
logger.trace("RLE buffers ofs: " + ToolBox.toHexLeftZeroPadded(index, 8)
+ " (even: " + ToolBox.toHexLeftZeroPadded(pic.getImageBufferOffsetEven(), 8)
+ ", odd: " + ToolBox.toHexLeftZeroPadded(pic.getImageBufferOffsetOdd(), 8) + "\n");
index += 8;
break;
case 0xff:
if (stopCommand) {
logger.warn("DCSQ stop missing.\n");
for (++index; index < bufsize; index++)
if (buffer.getByte(index++) != 0xff) {
index--;
break;
}
stopDisplay = true;
} else {
index = nextIndex;
// add to display time
int d = buffer.getWord(index);
dcsq = d;
nextIndex = buffer.getDWord(index+2) + masterIndex;
stopCommand = (index == nextIndex);
logger.trace("DCSQ ofs: " + ToolBox.toHexLeftZeroPadded(index, 8) + " (" + (d * 1024 / 90)
+ "ms), next DCSQ at ofs: " + ToolBox.toHexLeftZeroPadded(nextIndex, 8) + "\n");
index += 6;
}
break;
default:
throw new CoreException("Unexpected command " + cmd + " at index " + ToolBox.toHexLeftZeroPadded(index, 8));
}
}
index = masterIndex + packetSize;
subPictures.add(pic);
}
} catch (CoreException ex) {
if (subPictures.size() == 0) {
throw ex;
}
logger.error(ex.getMessage() + "\n");
logger.trace("Probably not all caption imported due to error.\n");
} catch (FileBufferException ex) {
if (subPictures.size() == 0) {
throw new CoreException (ex.getMessage());
}
logger.error(ex.getMessage() + "\n");
logger.trace("Probably not all caption imported due to error.\n");
}
}