diff --git a/jpsxdec/doc/CHANGES.txt b/jpsxdec/doc/CHANGES.txt
index 875c964..86ec512 100644
--- a/jpsxdec/doc/CHANGES.txt
+++ b/jpsxdec/doc/CHANGES.txt
@@ -1,3 +1,24 @@
+v0.99.9 rev3898 (9 Aug 2019)
+ - Added Italian translation (thanks Gianluigi "Infrid" Cusimano!)
+ - Updated Spanish translation (still many thanks to Víctor González, Sergi Medina!)
+ - Minimum required Java version is now version 6
+ - Updated to be compatible with Java version 9 and higher
+ - Added support for ReBoot video (thanks to XBrav!)
+ - Added support for Policenauts FMVs
+ - Added support for Road Rash 3D FMVs
+ - Added support for opening video of Aconcagua
+ - Improved real-time audio/video player on Linux (hopefully)
+ Bug fixes:
+ - Couldn't save 24-bit TIM images as png
+ - Videos with odd frame dimensions caused errors
+ - Lots of small fixes
+ Internal:
+ - Revamped bitstream handling
+ - Several simplifications
+ Known issues:
+ - Videos with variable frames rates saved as AVI do not play right in
+ some video players (primarily on Windows). Use a more reliable player
+ such as VLC media player.
v0.99.8 rev3788 (21 Jan 2019)
- Updated Spanish translation (still many thanks to Víctor González, Sergi Medina)
- Updated Japanese translation (still using Google translate)
@@ -34,7 +55,7 @@ v0.99.8 rev3788 (21 Jan 2019)
- Frame numbering redesign
Known issues:
- Video playback on Linux may still not work right
- - Videos with variable frames rates saved as AVI do not play right in the
+ - Videos with variable frames rates saved as AVI do not play right in the
default video players found in some Windows versions.
Use a more reliable player such VLC media player.
v0.99.7 rev3397 (8 Jan 2017) The "road to v1.0" release
diff --git a/jpsxdec/doc/CREDITS.txt b/jpsxdec/doc/CREDITS.txt
index fbcaffb..ddeebcb 100644
--- a/jpsxdec/doc/CREDITS.txt
+++ b/jpsxdec/doc/CREDITS.txt
@@ -68,6 +68,10 @@ Sony's official SDK movconv tool.
Víctor González and Sergi Medina for the Spanish translation.
+Gianluigi "Infrid" Cusimano for adding the Italian translation.
+
+XBrav for adding support for Reboot video.
+
The Hitmen for releasing invaluable source code related to PSX hacking.
The countless people who created so many open source tools that I've used
diff --git a/jpsxdec/doc/LICENSE.txt b/jpsxdec/doc/LICENSE.txt
index 0cd4a65..03c5f51 100644
--- a/jpsxdec/doc/LICENSE.txt
+++ b/jpsxdec/doc/LICENSE.txt
@@ -53,10 +53,15 @@ Some individual components are licensed under compatible licenses:
The jPSXdec translations
Specifically src/jpsxdec/i18n/I.java and Translations*.properties
-Copyright Michael Sabin, Víctor González, Sergi Medina
+Copyright:
+ Michael Sabin
+ Víctor González
+ Sergi Medina
+ Gianluigi "Infrid" Cusimano
English and Japanese by Michael Sabin
Spanish by Víctor González and Sergi Medina
+Italian by Gianluigi "Infrid" Cusimano
Licensed under the Apache License, Version 2.0
The text of this license is contained in the file apache-2.0.txt
diff --git a/jpsxdec/doc/jPSXdec-manual.odt b/jpsxdec/doc/jPSXdec-manual.odt
index 3503d4a..7fd91ec 100644
Binary files a/jpsxdec/doc/jPSXdec-manual.odt and b/jpsxdec/doc/jPSXdec-manual.odt differ
diff --git a/jpsxdec/jpsxdec.exe b/jpsxdec/jpsxdec.exe
index 90d0c29..30750c2 100644
Binary files a/jpsxdec/jpsxdec.exe and b/jpsxdec/jpsxdec.exe differ
diff --git a/jpsxdec/launch4j.xml b/jpsxdec/launch4j.xml
index bcae9ff..6a1e8a1 100644
--- a/jpsxdec/launch4j.xml
+++ b/jpsxdec/launch4j.xml
@@ -18,7 +18,7 @@
false
false
- 1.5.0
+ 1.6.0
preferJre
64/32
diff --git a/jpsxdec/src-lgpl/com/sun/java/swing/plaf/windows/WindowsTreeTableUI.java b/jpsxdec/src-lgpl/com/sun/java/swing/plaf/windows/WindowsTreeTableUI.java
deleted file mode 100644
index 534f7b5..0000000
--- a/jpsxdec/src-lgpl/com/sun/java/swing/plaf/windows/WindowsTreeTableUI.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-package com.sun.java.swing.plaf.windows;
-
-import java.awt.Color;
-import java.awt.Graphics;
-
-
-/**
- * Performance improvement for {@link org.jdesktop.swingx.JXTreeTable}.
- *
- * The infamous JTreeTable. Nearly all Java tree-tables are based on an
- * example published by Sun many years ago. The trick is to render just a
- * small rectangle of the {@link javax.swing.JTree} component in each cell.
- * With the cells stacked up, it looks like one continuous component.
- *
- * To render each rectangle, {@link Graphics#translate(int, int)} is called
- * when the JTree returned by {@link javax.swing.table.TableCellRenderer} is
- * painted. This is functional in theory, but Windows has some serious
- * performance side-effects when painting with a translation. Now combine
- * that with painting the tree dotted lines one dot at a time as the
- * {@link javax.swing.plaf.basic.BasicTreeUI} does, and the tree-table becomes
- * painfully slow.
- *
- * This little hack overrides the dotted line paint
- * call with a single solid line paint call. Performance is improved
- * significantly.
- *
- * This class is instantiated dynamically on Windows and passed to
- * {@link org.jdesktop.swingx.JXTreeTable#setUI(javax.swing.plaf.TableUI)}.
- *
- * I also tried {@link java.awt.Graphics2D#setStroke(java.awt.Stroke)} to a dotted line, but the
- * performance was still abysmal.
- *
- * @author Michael
- */
-public class WindowsTreeTableUI extends WindowsTreeUI {
-
- @Override
- protected void drawDashedHorizontalLine(Graphics g, int y, int x1, int x2) {
- Color c = g.getColor();
- g.setColor(c.brighter());
- g.drawLine(x1, y, x2, y);
- g.setColor(c);
- }
-
- @Override
- protected void drawDashedVerticalLine(Graphics g, int x, int y1, int y2) {
- Color c = g.getColor();
- g.setColor(c.brighter());
- g.drawLine(x, y1, x, y2);
- g.setColor(c);
- }
-
-}
\ No newline at end of file
diff --git a/jpsxdec/src-lgpl/com/sun/java/swing/plaf/windows/WindowsTreeUI.java b/jpsxdec/src-lgpl/com/sun/java/swing/plaf/windows/WindowsTreeUI.java
deleted file mode 100644
index e175d2b..0000000
--- a/jpsxdec/src-lgpl/com/sun/java/swing/plaf/windows/WindowsTreeUI.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-package com.sun.java.swing.plaf.windows;
-
-import javax.swing.plaf.basic.BasicTreeUI;
-
-/**
- * A dummy class just so jPSXdec will build on non-Windows platforms.
- * On Windows, it will be ignored and the JRE's will be used instead.
- *
- * @see WindowsTreeTableUI
- *
- * @author Michael
- */
-public class WindowsTreeUI extends BasicTreeUI {
-
-}
diff --git a/jpsxdec/src-lgpl/org/jdesktop/swingx/JXTable.java b/jpsxdec/src-lgpl/org/jdesktop/swingx/JXTable.java
index dfd7903..11fe02a 100644
--- a/jpsxdec/src-lgpl/org/jdesktop/swingx/JXTable.java
+++ b/jpsxdec/src-lgpl/org/jdesktop/swingx/JXTable.java
@@ -533,7 +533,7 @@ public JXTable(int numRows, int numColumns) {
* @param rowData Row data, as a Vector of Objects.
* @param columnNames Column names, as a Vector of Strings.
*/
- public JXTable(Vector> rowData, Vector> columnNames) {
+ public JXTable(Vector extends Vector> rowData, Vector> columnNames) {
super(rowData, columnNames);
init();
}
diff --git a/jpsxdec/src-lgpl/org/jdesktop/swingx/JXTreeTable.java b/jpsxdec/src-lgpl/org/jdesktop/swingx/JXTreeTable.java
index de42eec..f98a9a9 100644
--- a/jpsxdec/src-lgpl/org/jdesktop/swingx/JXTreeTable.java
+++ b/jpsxdec/src-lgpl/org/jdesktop/swingx/JXTreeTable.java
@@ -36,7 +36,6 @@
import java.util.Enumeration;
import java.util.EventObject;
import java.util.List;
-import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ActionMap;
@@ -58,7 +57,6 @@
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeWillExpandListener;
-import javax.swing.plaf.TreeUI;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
@@ -2809,18 +2807,6 @@ protected void setExpandedState(TreePath path, boolean state) {
}
- @Override
- public void setUI(TreeUI ui) {
- if (ui.getClass().getName().equals("com.sun.java.swing.plaf.windows.WindowsTreeUI")) {
- try {
- ui = (TreeUI) Class.forName("com.sun.java.swing.plaf.windows.WindowsTreeTableUI").newInstance();
- } catch (Exception ex) {
- Logger.getLogger(JXTreeTable.class.getName()).log(Level.SEVERE, null, ex);
- }
- }
- super.setUI(ui);
- }
-
/**
* updateUI is overridden to set the colors of the Tree's renderer
* to match that of the table.
diff --git a/jpsxdec/src-lgpl/org/jdesktop/swingx/plaf/LookAndFeelAddons.java b/jpsxdec/src-lgpl/org/jdesktop/swingx/plaf/LookAndFeelAddons.java
index 24f92d4..e50bdbe 100644
--- a/jpsxdec/src-lgpl/org/jdesktop/swingx/plaf/LookAndFeelAddons.java
+++ b/jpsxdec/src-lgpl/org/jdesktop/swingx/plaf/LookAndFeelAddons.java
@@ -28,9 +28,9 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.ServiceLoader;
import java.util.logging.Level;
import java.util.logging.Logger;
-import javax.imageio.spi.ServiceRegistry;
import javax.swing.JComponent;
import javax.swing.LookAndFeel;
@@ -258,8 +258,8 @@ public static String getBestMatchAddonClassName() {
} else if (UIManager.getSystemLookAndFeelClassName().equals(laf.getClass().getName())) {
className = getSystemAddonClassName();
} else {
- Iterator addonLoader = ServiceRegistry.lookupProviders(LookAndFeelAddons.class,
- getClassLoader());
+ Iterator addonLoader = ServiceLoader.load(LookAndFeelAddons.class,
+ getClassLoader()).iterator();
while (addonLoader.hasNext()) {
LookAndFeelAddons addon = addonLoader.next();
@@ -297,8 +297,8 @@ public String run() {
* @return the addon matching the native operating system platform.
*/
public static String getSystemAddonClassName() {
- Iterator addonLoader = ServiceRegistry.lookupProviders(LookAndFeelAddons.class,
- getClassLoader());
+ Iterator addonLoader = ServiceLoader.load(LookAndFeelAddons.class,
+ getClassLoader()).iterator();
String className = null;
while (addonLoader.hasNext()) {
diff --git a/jpsxdec/src-lgpl/org/jdesktop/swingx/plaf/basic/core/BasicTransferable.java b/jpsxdec/src-lgpl/org/jdesktop/swingx/plaf/basic/core/BasicTransferable.java
index 557acbb..f86a555 100644
--- a/jpsxdec/src-lgpl/org/jdesktop/swingx/plaf/basic/core/BasicTransferable.java
+++ b/jpsxdec/src-lgpl/org/jdesktop/swingx/plaf/basic/core/BasicTransferable.java
@@ -144,7 +144,7 @@ public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorExcepti
} else if (Reader.class.equals(flavor.getRepresentationClass())) {
return new StringReader(data);
} else if (InputStream.class.equals(flavor.getRepresentationClass())) {
- return new StringBufferInputStream(data);
+ return new ByteArrayInputStream(data.getBytes("US-ASCII"));
}
// fall through to unsupported
} else if (isPlainFlavor(flavor)) {
@@ -155,7 +155,7 @@ public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorExcepti
} else if (Reader.class.equals(flavor.getRepresentationClass())) {
return new StringReader(data);
} else if (InputStream.class.equals(flavor.getRepresentationClass())) {
- return new StringBufferInputStream(data);
+ return new ByteArrayInputStream(data.getBytes("US-ASCII"));
}
// fall through to unsupported
diff --git a/jpsxdec/src-lgpl/org/jdesktop/swingx/plaf/basic/core/LazyActionMap.java b/jpsxdec/src-lgpl/org/jdesktop/swingx/plaf/basic/core/LazyActionMap.java
index 6b2bd90..a9f5393 100644
--- a/jpsxdec/src-lgpl/org/jdesktop/swingx/plaf/basic/core/LazyActionMap.java
+++ b/jpsxdec/src-lgpl/org/jdesktop/swingx/plaf/basic/core/LazyActionMap.java
@@ -136,6 +136,7 @@ public void setParent(ActionMap map) {
super.setParent(map);
}
+ @SuppressWarnings("unchecked")
private void loadIfNecessary() {
if (_loader != null) {
Object loader = _loader;
diff --git a/jpsxdec/src-lgpl/org/jdesktop/swingx/renderer/DefaultVisuals.java b/jpsxdec/src-lgpl/org/jdesktop/swingx/renderer/DefaultVisuals.java
index ab255c3..e0dab8c 100644
--- a/jpsxdec/src-lgpl/org/jdesktop/swingx/renderer/DefaultVisuals.java
+++ b/jpsxdec/src-lgpl/org/jdesktop/swingx/renderer/DefaultVisuals.java
@@ -119,7 +119,7 @@ public void configureVisuals(T renderingComponent, CellContext context) {
*/
protected void configurePainter(T renderingComponent, CellContext context) {
if (renderingComponent instanceof PainterAware) {
- ((PainterAware) renderingComponent).setPainter(null);
+ ((PainterAware>) renderingComponent).setPainter(null);
}
}
diff --git a/jpsxdec/src-lgpl/org/jdesktop/swingx/renderer/JRendererCheckBox.java b/jpsxdec/src-lgpl/org/jdesktop/swingx/renderer/JRendererCheckBox.java
index ab8fdd4..866776c 100644
--- a/jpsxdec/src-lgpl/org/jdesktop/swingx/renderer/JRendererCheckBox.java
+++ b/jpsxdec/src-lgpl/org/jdesktop/swingx/renderer/JRendererCheckBox.java
@@ -38,13 +38,13 @@
*
* @author Jeanette Winzenburg
*/
-public class JRendererCheckBox extends JCheckBox implements PainterAware {
- protected Painter painter;
+public class JRendererCheckBox extends JCheckBox implements PainterAware {
+ protected Painter painter;
/**
* {@inheritDoc}
*/
- public Painter getPainter() {
+ public Painter getPainter() {
return painter;
}
@@ -52,7 +52,7 @@ public Painter getPainter() {
/**
* {@inheritDoc}
*/
- public void setPainter(Painter painter) {
+ public void setPainter(Painter painter) {
Painter old = getPainter();
this.painter = painter;
if (painter != null) {
diff --git a/jpsxdec/src-lgpl/org/jdesktop/swingx/renderer/JRendererLabel.java b/jpsxdec/src-lgpl/org/jdesktop/swingx/renderer/JRendererLabel.java
index 8be392a..3affd74 100644
--- a/jpsxdec/src-lgpl/org/jdesktop/swingx/renderer/JRendererLabel.java
+++ b/jpsxdec/src-lgpl/org/jdesktop/swingx/renderer/JRendererLabel.java
@@ -61,9 +61,9 @@
*
* @author Jeanette Winzenburg
*/
-public class JRendererLabel extends JLabel implements PainterAware, IconAware {
+public class JRendererLabel extends JLabel implements PainterAware, IconAware {
- protected Painter painter;
+ protected Painter painter;
/**
*
@@ -100,7 +100,7 @@ public boolean isOpaque() {
/**
* {@inheritDoc}
*/
- public void setPainter(Painter painter) {
+ public void setPainter(Painter painter) {
Painter old = getPainter();
this.painter = painter;
firePropertyChange("painter", old, getPainter());
@@ -109,7 +109,7 @@ public void setPainter(Painter painter) {
/**
* {@inheritDoc}
*/
- public Painter getPainter() {
+ public Painter getPainter() {
return painter;
}
/**
diff --git a/jpsxdec/src-lgpl/org/jdesktop/swingx/renderer/PainterAware.java b/jpsxdec/src-lgpl/org/jdesktop/swingx/renderer/PainterAware.java
index 43df74a..4947520 100644
--- a/jpsxdec/src-lgpl/org/jdesktop/swingx/renderer/PainterAware.java
+++ b/jpsxdec/src-lgpl/org/jdesktop/swingx/renderer/PainterAware.java
@@ -30,7 +30,7 @@
*
* @author Jeanette Winzenburg
*/
-public interface PainterAware {
- void setPainter(Painter> painter);
- Painter> getPainter();
+public interface PainterAware {
+ void setPainter(Painter painter);
+ Painter getPainter();
}
diff --git a/jpsxdec/src/argparser/ArgParser.java b/jpsxdec/src/argparser/ArgParser.java
index 3d84447..dcabad1 100644
--- a/jpsxdec/src/argparser/ArgParser.java
+++ b/jpsxdec/src/argparser/ArgParser.java
@@ -380,7 +380,7 @@
*/
public class ArgParser
{
- Vector matchList;
+ Vector matchList;
// int tabSpacing = 8;
String synopsisString;
boolean helpOptionsEnabled = true;
@@ -979,7 +979,7 @@ public ArgParser(String synopsisString)
*/
public ArgParser(String synopsisString, boolean defaultHelp)
{
- matchList = new Vector(128);
+ matchList = new Vector(128);
this.synopsisString = synopsisString;
if (defaultHelp)
{ addOption ("-help,-? %h #displays help information", null);
@@ -1794,7 +1794,7 @@ private Object createResultHolder (Record rec)
return null; // can't happen
}
- static void stringToArgs (Vector vec, String s,
+ static void stringToArgs (Vector vec, String s,
boolean allowQuotedStrings)
throws StringScanException
{
@@ -1830,7 +1830,7 @@ public static String[] prependArgs (Reader reader, String[] args)
{ args = new String[0];
}
LineNumberReader lineReader = new LineNumberReader (reader);
- Vector vec = new Vector(100, 100);
+ Vector vec = new Vector(100, 100);
String line;
int i, k;
@@ -1969,7 +1969,7 @@ public void matchAllArgs (String[] args)
*/
public String[] matchAllArgs (String[] args, int idx, int exitFlags)
{
- Vector unmatched = new Vector(10);
+ Vector unmatched = new Vector(10);
while (idx < args.length)
{ try
@@ -2031,6 +2031,7 @@ public String[] matchAllArgs (String[] args, int idx, int exitFlags)
* @see ArgParser#getErrorMessage
* @see ArgParser#getUnmatchedArgument
*/
+ @SuppressWarnings("unchecked")
public int matchArg (String[] args, int idx)
throws ArgParseException
{
@@ -2089,7 +2090,7 @@ else if (rec.convertCode != 'v')
}
}
if (rec.resHolder instanceof Vector)
- { ((Vector)rec.resHolder).add (result);
+ { ((Vector)rec.resHolder).add (result);
}
}
catch (ArgParseException e)
diff --git a/jpsxdec/src/com/jhlabs/awt/ConstraintLayout.java b/jpsxdec/src/com/jhlabs/awt/ConstraintLayout.java
index bf1ec80..8171542 100644
--- a/jpsxdec/src/com/jhlabs/awt/ConstraintLayout.java
+++ b/jpsxdec/src/com/jhlabs/awt/ConstraintLayout.java
@@ -30,7 +30,7 @@ public class ConstraintLayout implements LayoutManager2 {
protected int hMargin = 0;
protected int vMargin = 0;
- private Hashtable constraints;
+ private Hashtable constraints;
protected boolean includeInvisible = false;
public void addLayoutComponent(String constraint, Component c) {
@@ -49,7 +49,7 @@ public void removeLayoutComponent(Component c) {
public void setConstraint(Component c, Object constraint) {
if (constraint != null) {
if (constraints == null)
- constraints = new Hashtable();
+ constraints = new Hashtable();
constraints.put(c, constraint);
} else if (constraints != null)
constraints.remove(c);
diff --git a/jpsxdec/src/com/l2fprod/common/swing/JDirectoryChooserBeanInfo.java b/jpsxdec/src/com/l2fprod/common/swing/JDirectoryChooserBeanInfo.java
index 6af3441..5f6ca10 100644
--- a/jpsxdec/src/com/l2fprod/common/swing/JDirectoryChooserBeanInfo.java
+++ b/jpsxdec/src/com/l2fprod/common/swing/JDirectoryChooserBeanInfo.java
@@ -57,7 +57,7 @@ public JDirectoryChooserBeanInfo() throws java.beans.IntrospectionException {
* @return The additionalBeanInfo value
*/
public BeanInfo[] getAdditionalBeanInfo() {
- Vector bi = new Vector();
+ Vector bi = new Vector();
BeanInfo[] biarr = null;
try {
for (Class cl = com.l2fprod.common.swing.JDirectoryChooser.class
@@ -119,7 +119,7 @@ public Image getIcon(int type) {
*/
public PropertyDescriptor[] getPropertyDescriptors() {
try {
- Vector descriptors = new Vector();
+ Vector descriptors = new Vector();
PropertyDescriptor descriptor = null;
try {
diff --git a/jpsxdec/src/com/l2fprod/common/swing/PercentLayout.java b/jpsxdec/src/com/l2fprod/common/swing/PercentLayout.java
index 3d8f85d..ca5a7eb 100644
--- a/jpsxdec/src/com/l2fprod/common/swing/PercentLayout.java
+++ b/jpsxdec/src/com/l2fprod/common/swing/PercentLayout.java
@@ -94,7 +94,7 @@ public float floatValue() {
private int orientation;
private int gap;
- private Hashtable m_ComponentToConstraint;
+ private Hashtable m_ComponentToConstraint;
/**
* Creates a new HORIZONTAL PercentLayout with a gap of 0.
@@ -107,7 +107,7 @@ public PercentLayout(int orientation, int gap) {
setOrientation(orientation);
this.gap = gap;
- m_ComponentToConstraint = new Hashtable();
+ m_ComponentToConstraint = new Hashtable();
}
public void setGap(int gap) {
@@ -145,7 +145,7 @@ public Constraint getConstraint(Component component) {
public void setConstraint(Component component, Object constraints) {
if (constraints instanceof Constraint) {
- m_ComponentToConstraint.put(component, constraints);
+ m_ComponentToConstraint.put(component, (Constraint)constraints);
} else if (constraints instanceof Number) {
setConstraint(
component,
@@ -334,7 +334,7 @@ public void layoutContainer(Container parent) {
}
// finally share the remaining space between the other components
- ArrayList remaining = new ArrayList();
+ ArrayList remaining = new ArrayList();
for (int i = 0, c = components.length; i < c; i++) {
if (components[i].isVisible()) {
Constraint constraint =
@@ -348,8 +348,8 @@ public void layoutContainer(Container parent) {
if (remaining.size() > 0) {
int rest = availableSize / remaining.size();
- for (Iterator iter = remaining.iterator(); iter.hasNext();) {
- sizes[((Integer)iter.next()).intValue()] = rest;
+ for (Iterator iter = remaining.iterator(); iter.hasNext();) {
+ sizes[iter.next().intValue()] = rest;
}
}
diff --git a/jpsxdec/src/com/l2fprod/common/swing/PercentLayoutAnimator.java b/jpsxdec/src/com/l2fprod/common/swing/PercentLayoutAnimator.java
index 37da807..9f27116 100644
--- a/jpsxdec/src/com/l2fprod/common/swing/PercentLayoutAnimator.java
+++ b/jpsxdec/src/com/l2fprod/common/swing/PercentLayoutAnimator.java
@@ -33,7 +33,7 @@
public class PercentLayoutAnimator implements ActionListener {
private Timer animatorTimer;
- private List tasks = new ArrayList();
+ private List tasks = new ArrayList();
private PercentLayout layout;
private Container container;
diff --git a/jpsxdec/src/com/l2fprod/common/swing/plaf/AbstractComponentAddon.java b/jpsxdec/src/com/l2fprod/common/swing/plaf/AbstractComponentAddon.java
index 84c8c23..71f6cfa 100644
--- a/jpsxdec/src/com/l2fprod/common/swing/plaf/AbstractComponentAddon.java
+++ b/jpsxdec/src/com/l2fprod/common/swing/plaf/AbstractComponentAddon.java
@@ -51,7 +51,7 @@ public void uninitialize(LookAndFeelAddons addon) {
* @param addon
* @param defaults
*/
- protected void addBasicDefaults(LookAndFeelAddons addon, List defaults) {
+ protected void addBasicDefaults(LookAndFeelAddons addon, List defaults) {
}
/**
@@ -60,7 +60,7 @@ protected void addBasicDefaults(LookAndFeelAddons addon, List defaults) {
* @param addon
* @param defaults
*/
- protected void addMacDefaults(LookAndFeelAddons addon, List defaults) {
+ protected void addMacDefaults(LookAndFeelAddons addon, List defaults) {
addBasicDefaults(addon, defaults);
}
@@ -70,7 +70,7 @@ protected void addMacDefaults(LookAndFeelAddons addon, List defaults) {
* @param addon
* @param defaults
*/
- protected void addMetalDefaults(LookAndFeelAddons addon, List defaults) {
+ protected void addMetalDefaults(LookAndFeelAddons addon, List defaults) {
addBasicDefaults(addon, defaults);
}
@@ -80,7 +80,7 @@ protected void addMetalDefaults(LookAndFeelAddons addon, List defaults) {
* @param addon
* @param defaults
*/
- protected void addMotifDefaults(LookAndFeelAddons addon, List defaults) {
+ protected void addMotifDefaults(LookAndFeelAddons addon, List defaults) {
addBasicDefaults(addon, defaults);
}
@@ -90,7 +90,7 @@ protected void addMotifDefaults(LookAndFeelAddons addon, List defaults) {
* @param addon
* @param defaults
*/
- protected void addWindowsDefaults(LookAndFeelAddons addon, List defaults) {
+ protected void addWindowsDefaults(LookAndFeelAddons addon, List defaults) {
addBasicDefaults(addon, defaults);
}
@@ -118,7 +118,7 @@ protected void addWindowsDefaults(LookAndFeelAddons addon, List defaults) {
*
*/
private Object[] getDefaults(LookAndFeelAddons addon) {
- List defaults = new ArrayList();
+ List defaults = new ArrayList();
if (isWindows(addon)) {
addWindowsDefaults(addon, defaults);
} else if (isMetal(addon)) {
@@ -142,7 +142,7 @@ private Object[] getDefaults(LookAndFeelAddons addon) {
* Adds the all keys/values from the given named resource bundle to the
* defaults
*/
- protected void addResource(List defaults, String bundleName) {
+ protected void addResource(List defaults, String bundleName) {
ResourceBundle bundle = ResourceBundle.getBundle(bundleName);
for (Enumeration keys = bundle.getKeys(); keys.hasMoreElements(); ) {
String key = (String)keys.nextElement();
diff --git a/jpsxdec/src/com/l2fprod/common/swing/plaf/JDirectoryChooserAddon.java b/jpsxdec/src/com/l2fprod/common/swing/plaf/JDirectoryChooserAddon.java
index 53ac9a3..cb50bdc 100644
--- a/jpsxdec/src/com/l2fprod/common/swing/plaf/JDirectoryChooserAddon.java
+++ b/jpsxdec/src/com/l2fprod/common/swing/plaf/JDirectoryChooserAddon.java
@@ -33,7 +33,7 @@ public JDirectoryChooserAddon() {
super("JDirectoryChooser");
}
- protected void addBasicDefaults(LookAndFeelAddons addon, List defaults) {
+ protected void addBasicDefaults(LookAndFeelAddons addon, List defaults) {
defaults.addAll(Arrays.asList(new Object[]{
JDirectoryChooser.UI_CLASS_ID,
"com.l2fprod.common.swing.plaf.windows.WindowsDirectoryChooserUI",
diff --git a/jpsxdec/src/com/l2fprod/common/swing/plaf/LookAndFeelAddons.java b/jpsxdec/src/com/l2fprod/common/swing/plaf/LookAndFeelAddons.java
index 3816caa..4bac639 100644
--- a/jpsxdec/src/com/l2fprod/common/swing/plaf/LookAndFeelAddons.java
+++ b/jpsxdec/src/com/l2fprod/common/swing/plaf/LookAndFeelAddons.java
@@ -59,7 +59,7 @@
*/
public class LookAndFeelAddons {
- private static List contributedComponents = new ArrayList();
+ private static List contributedComponents = new ArrayList();
/**
* Key used to ensure the current UIManager has been populated by the
@@ -273,7 +273,7 @@ public static ComponentUI getUI(JComponent component, Class expectedUIClass) {
return ui;
} else {
String realUI = ui.getClass().getName();
- Class realUIClass;
+ Class> realUIClass;
try {
realUIClass = expectedUIClass.getClassLoader()
.loadClass(realUI);
diff --git a/jpsxdec/src/com/l2fprod/common/swing/plaf/windows/WindowsDirectoryChooserUI.java b/jpsxdec/src/com/l2fprod/common/swing/plaf/windows/WindowsDirectoryChooserUI.java
index c191d25..4348202 100644
--- a/jpsxdec/src/com/l2fprod/common/swing/plaf/windows/WindowsDirectoryChooserUI.java
+++ b/jpsxdec/src/com/l2fprod/common/swing/plaf/windows/WindowsDirectoryChooserUI.java
@@ -324,13 +324,13 @@ private void findFile(File fileToLocate, boolean selectFile, boolean reload) {
// split the full path into individual files to locate them in
// the tree
// model
- List files = new ArrayList();
+ List files = new ArrayList();
files.add(file);
while ((file = chooser.getFileSystemView().getParentDirectory(file)) != null) {
files.add(0, file);
}
- List path = new ArrayList();
+ List path = new ArrayList();
// start from the root
DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getModel()
@@ -457,7 +457,7 @@ private void setSelectedFiles() {
return;
}
- List files = new ArrayList();
+ List files = new ArrayList();
for (int i = 0, c = selectedPaths.length; i < c; i++) {
LazyMutableTreeNode node = (LazyMutableTreeNode)selectedPaths[i]
.getLastPathComponent();
@@ -639,7 +639,7 @@ private FileTreeNode[] getChildren() {
chooser.getFileSystemView().getFiles(
getFile(),
chooser.isFileHidingEnabled());
- ArrayList nodes = new ArrayList();
+ ArrayList nodes = new ArrayList();
// keep only directories, no "file" in the tree.
if (files != null) {
for (int i = 0, c = files.length; i < c; i++) {
@@ -652,7 +652,7 @@ private FileTreeNode[] getChildren() {
}
}
// sort directories, FileTreeNode implements Comparable
- FileTreeNode[] result = (FileTreeNode[])nodes
+ FileTreeNode[] result = nodes
.toArray(new FileTreeNode[0]);
Arrays.sort(result);
return result;
@@ -712,7 +712,7 @@ private static synchronized void addToQueue(FileTreeNode node, JTree tree) {
*/
private static final class Queue extends Thread {
- private volatile Stack nodes = new Stack();
+ private volatile Stack nodes = new Stack();
private Object lock = new Object();
diff --git a/jpsxdec/src/com/l2fprod/common/util/ResourceManager.java b/jpsxdec/src/com/l2fprod/common/util/ResourceManager.java
index f52de13..0baf102 100644
--- a/jpsxdec/src/com/l2fprod/common/util/ResourceManager.java
+++ b/jpsxdec/src/com/l2fprod/common/util/ResourceManager.java
@@ -27,7 +27,7 @@
*/
public class ResourceManager {
- static Map nameToRM = new HashMap();
+ static Map nameToRM = new HashMap();
private ResourceBundle bundle;
diff --git a/jpsxdec/src/jpsxdec/Version.java b/jpsxdec/src/jpsxdec/Version.java
index 92e0dda..af46d68 100644
--- a/jpsxdec/src/jpsxdec/Version.java
+++ b/jpsxdec/src/jpsxdec/Version.java
@@ -39,7 +39,7 @@
public class Version {
- public final static String Version = "0.99.8 (beta)";
+ public final static String Version = "0.99.9 (beta)";
public final static String IndexHeader = "[jPSXdec v"+Version+"]";
}
diff --git a/jpsxdec/src/jpsxdec/adpcm/PSoundPpl.java b/jpsxdec/src/jpsxdec/adpcm/PSoundPpl.java
index f59af5b..f0bf544 100644
--- a/jpsxdec/src/jpsxdec/adpcm/PSoundPpl.java
+++ b/jpsxdec/src/jpsxdec/adpcm/PSoundPpl.java
@@ -220,6 +220,7 @@ public long getOffset() {
return _lngDecryptedOffset;
}
+ @Override
public String toString() {
return String.format("\"%s\" \"%s\" %02x%02x%02x%02x%02x? %08x -> %d",
_sSourceFilePath, _sItemName,
diff --git a/jpsxdec/src/jpsxdec/adpcm/SoundUnitDecoder.java b/jpsxdec/src/jpsxdec/adpcm/SoundUnitDecoder.java
index afbd9a4..3cb53a0 100644
--- a/jpsxdec/src/jpsxdec/adpcm/SoundUnitDecoder.java
+++ b/jpsxdec/src/jpsxdec/adpcm/SoundUnitDecoder.java
@@ -148,6 +148,7 @@ public String sample(int iSample) {
);
}
+ @Override
public String toString() {
return String.format("%s Filter.Range %d.%d",
_loggingContext,
diff --git a/jpsxdec/src/jpsxdec/adpcm/SpuAdpcmSoundUnit.java b/jpsxdec/src/jpsxdec/adpcm/SpuAdpcmSoundUnit.java
index bfe1727..cb4c5b7 100644
--- a/jpsxdec/src/jpsxdec/adpcm/SpuAdpcmSoundUnit.java
+++ b/jpsxdec/src/jpsxdec/adpcm/SpuAdpcmSoundUnit.java
@@ -112,8 +112,8 @@ public SpuAdpcmSoundUnit(@Nonnull byte[] abSource) {
this(abSource, 0);
}
public SpuAdpcmSoundUnit(@Nonnull byte[] abSource, int iSourceOffset) {
- if (iSourceOffset < 0 || iSourceOffset + SIZEOF_SOUND_UNIT >= abSource.length)
- throw new IllegalArgumentException();
+ if (iSourceOffset < 0 || iSourceOffset + SIZEOF_SOUND_UNIT > abSource.length)
+ throw new IllegalArgumentException("iSourceOffset out of bounds " + iSourceOffset);
System.arraycopy(abSource, iSourceOffset, _abSoundUnit, 0, SIZEOF_SOUND_UNIT);
checkRange();
diff --git a/jpsxdec/src/jpsxdec/cdreaders/CdFileSectorReader.java b/jpsxdec/src/jpsxdec/cdreaders/CdFileSectorReader.java
index dae817b..996d4f9 100644
--- a/jpsxdec/src/jpsxdec/cdreaders/CdFileSectorReader.java
+++ b/jpsxdec/src/jpsxdec/cdreaders/CdFileSectorReader.java
@@ -52,7 +52,6 @@
import jpsxdec.i18n.exception.LocalizedDeserializationFail;
import jpsxdec.i18n.log.ProgressLogger;
import jpsxdec.util.IO;
-import jpsxdec.util.IOException6;
import jpsxdec.util.Misc;
import jpsxdec.util.TaskCanceledException;
@@ -91,7 +90,7 @@ public CdFileNotFoundException(@Nonnull File file, FileNotFoundException ex) {
}
/** Exception if there is an error reading from the CD file. */
- public static class CdReadException extends IOException6 {
+ public static class CdReadException extends IOException {
@Nonnull
private final File _file;
@@ -106,7 +105,7 @@ public CdReadException(@Nonnull File file, IOException ex) {
}
}
/** Exception if there is an error writing to the CD file. */
- public static class CdWriteException extends IOException6 {
+ public static class CdWriteException extends IOException {
@Nonnull
private final File _file;
@@ -138,7 +137,7 @@ public long getFileSize() {
/** Exception if there is an error re-opening the CD file
* (like for write-access). */
- public static class CdReopenException extends IOException6 {
+ public static class CdReopenException extends IOException {
@Nonnull
private final File _file;
diff --git a/jpsxdec/src/jpsxdec/cdreaders/CdSector.java b/jpsxdec/src/jpsxdec/cdreaders/CdSector.java
index 188900e..55415cd 100644
--- a/jpsxdec/src/jpsxdec/cdreaders/CdSector.java
+++ b/jpsxdec/src/jpsxdec/cdreaders/CdSector.java
@@ -37,11 +37,11 @@
package jpsxdec.cdreaders;
+import java.util.Arrays;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import jpsxdec.util.ByteArrayFPIS;
import jpsxdec.util.IO;
-import jpsxdec.util.Misc;
/** Represents a single sector on a CD. */
@@ -136,8 +136,8 @@ final public long getUserDataFilePointer() {
/** Returns copy of the 'user data' portion of the sector. */
final public @Nonnull byte[] getCdUserDataCopy() {
int iStart = _iByteStartOffset + getHeaderDataSize();
- return Misc.copyOfRange(_abSectorBytes,
- iStart, iStart + getCdUserDataSize());
+ return Arrays.copyOfRange(_abSectorBytes,
+ iStart, iStart + getCdUserDataSize());
}
/** Copies a block of bytes out of the user data portion of this CD sector to the supplied array.
@@ -155,9 +155,9 @@ final public void getCdUserDataCopy(int iSourcePos, @Nonnull byte[] abOut, int i
/** Returns a copy of the underlying sector data, with raw
* header/footer and everything it has. */
final public @Nonnull byte[] getRawSectorDataCopy() {
- return Misc.copyOfRange(_abSectorBytes,
- _iByteStartOffset,
- _iByteStartOffset+getRawCdSectorSize());
+ return Arrays.copyOfRange(_abSectorBytes,
+ _iByteStartOffset,
+ _iByteStartOffset+getRawCdSectorSize());
}
/** Returns an InputStream of the 'user data' portion of the sector. */
diff --git a/jpsxdec/src/jpsxdec/cdreaders/CdSectorHeader.java b/jpsxdec/src/jpsxdec/cdreaders/CdSectorHeader.java
index c170838..ca5da62 100644
--- a/jpsxdec/src/jpsxdec/cdreaders/CdSectorHeader.java
+++ b/jpsxdec/src/jpsxdec/cdreaders/CdSectorHeader.java
@@ -166,6 +166,7 @@ private static int binaryCodedDecimalToInt(int i) {
return ((i >> 4) & 0xf)*10 + (i & 0xf);
}
+ @Override
public String toString() {
if (_eType == Type.CD_AUDIO)
return "CD audio sector";
diff --git a/jpsxdec/src/jpsxdec/cdreaders/CdSectorXaSubHeader.java b/jpsxdec/src/jpsxdec/cdreaders/CdSectorXaSubHeader.java
index fd0808e..5e0a5ed 100644
--- a/jpsxdec/src/jpsxdec/cdreaders/CdSectorXaSubHeader.java
+++ b/jpsxdec/src/jpsxdec/cdreaders/CdSectorXaSubHeader.java
@@ -173,11 +173,6 @@ public int getChannel() {
private final int _iConfidenceBalance;
- private static boolean isFileValid(int iFileNumber) {
- return iFileNumber >= 0 && iFileNumber <= 2 ;
- }
-
-
public CdSectorXaSubHeader(int iSector, @Nonnull byte[] abSectorData, int iStartOffset) {
_iFileNum1 = abSectorData[iStartOffset+0] & 0xff;
@@ -191,14 +186,12 @@ public CdSectorXaSubHeader(int iSector, @Nonnull byte[] abSectorData, int iStart
int iConfidenceBalance = 0;
- boolean blnValid1 = isFileValid(_iFileNum1);
- if (_iFileNum1 == _iFileNum2) {
- _eFileIssue = blnValid1 ? IssueType.EQUAL_BOTH_GOOD :
- IssueType.EQUAL_BOTHBAD;
- } else {
- _eFileIssue = IssueType.diffIssue(blnValid1, isFileValid(_iFileNum2));
- iConfidenceBalance += _eFileIssue.Balance;
- }
+ // I've tried to put some constraint on what is considered a
+ // 'good' file number, but PSX seems to allow for any byte value.
+ if (_iFileNum1 == _iFileNum2)
+ _eFileIssue = IssueType.EQUAL_BOTH_GOOD;
+ else
+ _eFileIssue = IssueType.DIFF_BOTHGOOD;
// my understanding is channel is technically supposed to be
// between 0 and 31, but PSX seems to allow for any byte value.
@@ -207,7 +200,7 @@ public CdSectorXaSubHeader(int iSector, @Nonnull byte[] abSectorData, int iStart
else
_eChannelIssue = IssueType.DIFF_BOTHGOOD;
- blnValid1 = _submode1.isValid();
+ boolean blnValid1 = _submode1.isValid();
if (_submode1.toByte() == _submode2.toByte()) {
_eSubModeIssue = blnValid1 ? IssueType.EQUAL_BOTH_GOOD :
IssueType.EQUAL_BOTHBAD;
diff --git a/jpsxdec/src/jpsxdec/cdreaders/DiscPatcher.java b/jpsxdec/src/jpsxdec/cdreaders/DiscPatcher.java
index f6d82d6..a03f497 100644
--- a/jpsxdec/src/jpsxdec/cdreaders/DiscPatcher.java
+++ b/jpsxdec/src/jpsxdec/cdreaders/DiscPatcher.java
@@ -49,7 +49,6 @@
import jpsxdec.i18n.UnlocalizedMessage;
import jpsxdec.i18n.log.ProgressLogger;
import jpsxdec.util.IO;
-import jpsxdec.util.IOException6;
import jpsxdec.util.Misc;
import jpsxdec.util.TaskCanceledException;
@@ -64,7 +63,7 @@ public class DiscPatcher {
private static final Logger LOG = Logger.getLogger(DiscPatcher.class.getName());
- public static class CreatePatchFileException extends IOException6 {
+ public static class CreatePatchFileException extends IOException {
@Nonnull
private final File _file;
@@ -79,7 +78,7 @@ public File getFile() {
}
- public static class WritePatchException extends IOException6 {
+ public static class WritePatchException extends IOException {
@Nonnull
private final File _file;
@@ -93,7 +92,7 @@ public File getFile() {
}
}
- public static class PatchReadException extends IOException6 {
+ public static class PatchReadException extends IOException {
@Nonnull
private final File _file;
@@ -107,7 +106,7 @@ public File getFile() {
}
}
- public static class ApplyPatchToCdException extends IOException6 {
+ public static class ApplyPatchToCdException extends IOException {
@Nonnull
private final File _file;
@@ -160,6 +159,15 @@ public int compareTo(PatchEntry o) {
}
}
+ @Override
+ public boolean equals(Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int hashCode() {
+ throw new UnsupportedOperationException();
+ }
}
@Nonnull
diff --git a/jpsxdec/src/jpsxdec/cmdline/CommandLine.java b/jpsxdec/src/jpsxdec/cmdline/CommandLine.java
index 9da84fd..40596b4 100644
--- a/jpsxdec/src/jpsxdec/cmdline/CommandLine.java
+++ b/jpsxdec/src/jpsxdec/cmdline/CommandLine.java
@@ -151,9 +151,9 @@ private static void checkVerbosity(@Nonnull ArgParser ap,
if (iValue >= FeedbackStream.NONE && iValue <= FeedbackStream.MORE)
fbs.setLevel(iValue);
else
- fbs.printlnWarn(I.CMD_VERBOSE_LVL_INVALID_NUM(iValue));
+ fbs.printlnWarn(I.CMD_INVALID_VALUE_FOR_CMD(verbose.value, "-v,-verbose"));
} catch (NumberFormatException ex) {
- fbs.printlnWarn(I.CMD_VERBOSE_LVL_INVALID_STR(verbose.value));
+ fbs.printlnWarn(I.CMD_INVALID_VALUE_FOR_CMD(verbose.value, "-v,-verbose"));
}
}
}
diff --git a/jpsxdec/src/jpsxdec/cmdline/Command_CopySect.java b/jpsxdec/src/jpsxdec/cmdline/Command_CopySect.java
index 58198da..4531da2 100644
--- a/jpsxdec/src/jpsxdec/cmdline/Command_CopySect.java
+++ b/jpsxdec/src/jpsxdec/cmdline/Command_CopySect.java
@@ -70,7 +70,7 @@ public Command_CopySect() {
protected @CheckForNull ILocalizedMessage validate(@Nonnull String s) {
_aiStartEndSectors = parseNumberRange(s);
if (_aiStartEndSectors == null) {
- return I.CMD_SECTOR_RANGE_INVALID(s);
+ return I.CMD_INVALID_VALUE_FOR_CMD(s, "-copysect");
} else {
return null;
}
diff --git a/jpsxdec/src/jpsxdec/cmdline/Command_Items.java b/jpsxdec/src/jpsxdec/cmdline/Command_Items.java
index 6878beb..e030486 100644
--- a/jpsxdec/src/jpsxdec/cmdline/Command_Items.java
+++ b/jpsxdec/src/jpsxdec/cmdline/Command_Items.java
@@ -80,12 +80,12 @@ public Command_Item() {
try {
_iItemNum = Integer.parseInt(s);
if (_iItemNum < 0)
- return I.CMD_ITEM_NUMBER_INVALID(s);
+ return I.CMD_INVALID_VALUE_FOR_CMD(s, "-i,-item");
else
return null;
} catch (NumberFormatException ex) {
if (s.contains(" "))
- return I.CMD_ITEM_ID_INVALID(s);
+ return I.CMD_INVALID_VALUE_FOR_CMD(s, "-i,-item");
_sItemId = s;
return null;
}
@@ -286,7 +286,7 @@ private static void decodeDiscItem(@Nonnull DiscItem item, @CheckForNull File di
fbs.println();
- builder.printSelectedOptions(fbs);
+ builder.printSelectedOptions(fbs.makeLogger());
long lngStart, lngEnd;
lngStart = System.currentTimeMillis();
diff --git a/jpsxdec/src/jpsxdec/cmdline/Command_SectorDump.java b/jpsxdec/src/jpsxdec/cmdline/Command_SectorDump.java
index 863de9d..2da990f 100644
--- a/jpsxdec/src/jpsxdec/cmdline/Command_SectorDump.java
+++ b/jpsxdec/src/jpsxdec/cmdline/Command_SectorDump.java
@@ -45,8 +45,7 @@
import jpsxdec.cdreaders.CdFileSectorReader;
import jpsxdec.i18n.I;
import jpsxdec.i18n.ILocalizedMessage;
-import jpsxdec.i18n.log.ILocalizedLogger;
-import jpsxdec.i18n.log.ShouldNotLog;
+import jpsxdec.i18n.log.DebugLogger;
import jpsxdec.modules.IIdentifiedSector;
import jpsxdec.modules.SectorClaimSystem;
import jpsxdec.util.ArgParser;
@@ -82,9 +81,8 @@ public void execute(@Nonnull ArgParser ap) throws CommandLineException {
}
SectorCounter counter = new SectorCounter();
SectorClaimSystem it = SectorClaimSystem.create(cdReader);
- ILocalizedLogger log = new ShouldNotLog();
while (it.hasNext()) {
- SectorClaimSystem.ClaimedSector cs = it.next(log);
+ SectorClaimSystem.ClaimedSector cs = it.next(DebugLogger.Log);
IIdentifiedSector idSect = cs.getClaimer();
if (idSect != null)
ps.println(idSect);
diff --git a/jpsxdec/src/jpsxdec/cmdline/Command_Static.java b/jpsxdec/src/jpsxdec/cmdline/Command_Static.java
index 6906af9..3183777 100644
--- a/jpsxdec/src/jpsxdec/cmdline/Command_Static.java
+++ b/jpsxdec/src/jpsxdec/cmdline/Command_Static.java
@@ -44,22 +44,29 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.imageio.ImageIO;
+import jpsxdec.i18n.FeedbackStream;
import jpsxdec.i18n.I;
import jpsxdec.i18n.ILocalizedMessage;
import jpsxdec.i18n.UnlocalizedMessage;
import jpsxdec.i18n.exception.LoggedFailure;
+import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.i18n.log.UserFriendlyLogger;
+import jpsxdec.modules.video.save.AutowireVDP;
import jpsxdec.modules.video.save.MdecDecodeQuality;
import jpsxdec.modules.video.save.VDP;
import jpsxdec.modules.video.save.VideoFileNameFormatter;
import jpsxdec.modules.video.save.VideoFormat;
-import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor;
+import jpsxdec.psxvideo.bitstreams.BitStreamDebugging;
+import jpsxdec.psxvideo.mdec.ChromaUpsample;
import jpsxdec.psxvideo.mdec.MdecDecoder;
-import jpsxdec.psxvideo.mdec.MdecDecoder_double_interpolate;
+import jpsxdec.psxvideo.mdec.MdecDecoder_double;
import jpsxdec.psxvideo.mdec.MdecInputStreamReader;
import jpsxdec.tim.Tim;
import jpsxdec.util.ArgParser;
@@ -88,7 +95,7 @@ private static enum StaticType {
return null;
}
}
- return I.CMD_STATIC_TYPE_INVALID(s);
+ return I.CMD_INVALID_VALUE_FOR_CMD(s, "-static");
}
public void execute(@Nonnull ArgParser ap) throws CommandLineException {
@@ -99,21 +106,45 @@ public void execute(@Nonnull ArgParser ap) throws CommandLineException {
BooleanHolder debug = ap.addBoolOption("-debug");
StringHolder dimentions = ap.addStringOption("-dim");
StringHolder quality = ap.addStringOption("-quality","-q");
- StringHolder format = ap.addStringOption("-fmt");
+ StringHolder outFormat = ap.addStringOption("-fmt");
StringHolder upsample = ap.addStringOption("-up");
//......
ap.match();
//......
+
+ // verify dimensions
if (dimentions.value == null) {
throw new CommandLineException(I.CMD_DIM_OPTION_REQURIED());
}
final int iWidth;
final int iHeight;
int[] aiDim = Misc.splitInt(dimentions.value, "x");
+ if (aiDim == null || aiDim.length != 2)
+ throw new CommandLineException(I.CMD_INVALID_VALUE_FOR_CMD(dimentions.value, "-dim"));
iWidth = aiDim[0];
iHeight = aiDim[1];
+
+ // valid output formats
+ List validOutputFormat = new ArrayList(Arrays.asList(
+ VideoFormat.IMGSEQ_BITSTREAM, VideoFormat.IMGSEQ_JPG, VideoFormat.IMGSEQ_BMP, VideoFormat.IMGSEQ_PNG
+ ));
+ if (_eStaticType == StaticType.bs)
+ validOutputFormat.add(VideoFormat.IMGSEQ_MDEC);
+
+ // verify output format
+ VideoFormat outputFormat;
+ _fbs.println(I.CMD_READING_STATIC_FILE(inFile));
+ if (outFormat.value == null) {
+ outputFormat = VideoFormat.IMGSEQ_PNG;
+ } else {
+ outputFormat = VideoFormat.fromCmdLine(outFormat.value);
+ if (!validOutputFormat.contains(outputFormat))
+ throw new CommandLineException(I.CMD_INVALID_VALUE_FOR_CMD(outFormat.value, "-fmt"));
+ }
+
+ // enable debugging
if (debug.value) {
- BitStreamUncompressor.DEBUG = true;
+ BitStreamDebugging.DEBUG = true;
MdecDecoder.DEBUG = true;
boolean blnAssertsEnabled = false;
assert blnAssertsEnabled = true;
@@ -122,96 +153,156 @@ public void execute(@Nonnull ArgParser ap) throws CommandLineException {
_fbs.printlnWarn(I.CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA());
}
}
- _fbs.println(I.CMD_READING_STATIC_FILE(inFile));
- String sFileBaseName = Misc.removeExt(inFile.getName());
- VideoFormat vf = VideoFormat.IMGSEQ_PNG;
- if (format.value != null) {
- vf = VideoFormat.fromCmdLine(format.value);
- if (vf == null || vf.isAvi() || vf == VideoFormat.IMGSEQ_BITSTREAM)
- throw new CommandLineException(I.CMD_FORMAT_INVALID(format.value));
- }
- VDP.IMdecListener mdecOut;
- VideoFileNameFormatter formatter = new VideoFileNameFormatter(null, sFileBaseName, vf, iWidth, iHeight);
+
+ // make logger
UserFriendlyLogger log = new UserFriendlyLogger("static", _fbs.getUnderlyingStream());
- UserFriendlyLogger.WarnErrCounter warnErrCount = new UserFriendlyLogger.WarnErrCounter();
- log.setListener(warnErrCount);
- if (vf == VideoFormat.IMGSEQ_MDEC) {
- mdecOut = new VDP.Mdec2File(formatter, iWidth, iHeight, log);
- } else if (vf == VideoFormat.IMGSEQ_JPG) {
- VDP.Mdec2Jpeg m2j = new VDP.Mdec2Jpeg(formatter, iWidth, iHeight, log);
- mdecOut = m2j;
- } else {
- MdecDecodeQuality decQuality = MdecDecodeQuality.HIGH_PLUS;
- if (quality.value != null) {
- decQuality = MdecDecodeQuality.fromCmdLine(quality.value);
- if (decQuality == null)
- throw new CommandLineException(I.CMD_QUALITY_INVALID(quality.value));
- }
- MdecDecoder vidDecoder = decQuality.makeDecoder(iWidth, iHeight);
- _fbs.println(I.CMD_USING_QUALITY(decQuality.getCmdLine()));
- if (vidDecoder instanceof MdecDecoder_double_interpolate) {
- MdecDecoder_double_interpolate.Upsampler up =
- MdecDecoder_double_interpolate.Upsampler.Bicubic;
- if (upsample.value != null) {
- up = MdecDecoder_double_interpolate.Upsampler.fromCmdLine(upsample.value);
- if (up == null)
- throw new CommandLineException(I.CMD_UPSAMPLING_INVALID(upsample.value));
- }
- _fbs.println(I.CMD_USING_UPSAMPLING(up.getDescription()));
- ((MdecDecoder_double_interpolate) vidDecoder).setResampler(up);
- }
- VDP.Mdec2Decoded m2d = new VDP.Mdec2Decoded(vidDecoder, log);
- mdecOut = m2d;
- VDP.Decoded2JavaImage imgOut = new VDP.Decoded2JavaImage(formatter, vf.getImgFmt(), iWidth, iHeight, log);
- m2d.setDecoded(imgOut);
+ FileAndIssueListener fileAndIssueListener = new FileAndIssueListener(_fbs);
+ log.setListener(fileAndIssueListener);
+
+ // file listener
+ String sFileBaseName = Misc.removeExt(inFile.getName());
+
+ // build pipeline
+ AutowireVDP pipeline = setupPipeline(iWidth, iHeight, outputFormat, sFileBaseName, quality.value, upsample.value, log);
+
+ // read input file
+ byte[] abFileData;
+ try {
+ abFileData = IO.readFile(inFile);
+ } catch (FileNotFoundException ex) {
+ throw new CommandLineException(I.IO_OPENING_FILE_NOT_FOUND_NAME(inFile.toString()), ex);
+ } catch (IOException ex) {
+ throw new CommandLineException(I.IO_READING_FILE_ERROR_NAME(inFile.toString()), ex);
}
- _fbs.println(I.CMD_SAVING_AS(formatter.format(null, log)));
+
+ Fraction dummyFrameNumber = new Fraction(-1);
try {
- byte[] abBitstream = IO.readFile(inFile); // TODO: separate exception for reading here
if (_eStaticType == StaticType.bs) {
- VDP.Bitstream2Mdec b2m = new VDP.Bitstream2Mdec(mdecOut);
- b2m.bitstream(abBitstream, abBitstream.length, null, new Fraction(-1));
+ pipeline.setMap(new VDP.Bitstream2Mdec());
+ pipeline.autowire();
+ // finally convert the file
+ pipeline.getBitstreamListener().bitstream(abFileData, abFileData.length, null, dummyFrameNumber);
} else {
- mdecOut.mdec(new MdecInputStreamReader(abBitstream), null, new Fraction(-1));
+ pipeline.autowire();
+ // finally convert the file
+ pipeline.getMdecListener().mdec(new MdecInputStreamReader(abFileData), null, dummyFrameNumber);
}
- if (warnErrCount.getWarnCount() == 0 && warnErrCount.getErrCount() == 0)
- _fbs.println(I.CMD_FRAME_CONVERT_OK()); // TODO: have another message saying complete with issues
- // TODO: how do I know the operation even generated any output?
- } catch (FileNotFoundException ex) {
- throw new CommandLineException(I.IO_OPENING_FILE_NOT_FOUND_NAME(inFile.toString()), ex);
- } catch (IOException ex) {
- throw new CommandLineException(I.IO_WRITING_TO_FILE_ERROR_NAME(inFile.toString()), ex);
+
+ if (!fileAndIssueListener.blnHadIssue) {
+ _fbs.println(I.CMD_FRAME_CONVERT_OK());
+ }
+ _fbs.println(I.CMD_NUM_FILES_CREATED(fileAndIssueListener.genFiles.size()));
+
} catch (LoggedFailure ex) {
_fbs.printErr(ex.getSourceMessage());
}
return;
case tim:
- _fbs.println(I.CMD_READING_TIM(inFile));
- FileInputStream is = null;
- try {
- is = new FileInputStream(inFile);
- String sOutBaseName = Misc.removeExt(inFile.getName());
- Tim tim = Tim.read(is);
- _fbs.println(new UnlocalizedMessage(tim.toString()));
- int iDigitCount = String.valueOf(tim.getPaletteCount()).length();
- for (int i = 0; i < tim.getPaletteCount(); i++) {
- BufferedImage bi = tim.toBufferedImage(i);
- String sFileName = String.format("%s_p%0" + iDigitCount + "d.png", sOutBaseName, i);
- File file = new File(sFileName);
- _fbs.println(I.IO_WRITING_FILE(file.getName()));
- ImageIO.write(bi, "png", file);
- }
- _fbs.println(I.CMD_IMAGE_CONVERT_OK());
- } catch (BinaryDataNotRecognized ex) {
- throw new CommandLineException(I.CMD_NOT_TIM(), ex);
- } catch (IOException ex) {
- throw new CommandLineException(I.CMD_TIM_IO_ERR(), ex);
- } finally {
- IO.closeSilently(is, Logger.getLogger(Command_Static.class.getName()));
- }
+ saveTim(inFile);
return;
}
throw new RuntimeException("Shouldn't happen");
}
+ private static class FileAndIssueListener implements VDP.GeneratedFileListener, UserFriendlyLogger.OnWarnErr {
+ public final List genFiles = new ArrayList();
+ public final FeedbackStream fbs;
+ public boolean blnHadIssue = false;
+ public FileAndIssueListener(FeedbackStream fbs) {
+ this.fbs = fbs;
+ }
+ public void fileGenerated(File f) {
+ genFiles.add(f);
+ }
+ public void onWarn(ILocalizedMessage msg) {
+ fbs.printlnWarn(msg);
+ blnHadIssue = true;
+ }
+ public void onErr(ILocalizedMessage msg) {
+ fbs.printlnErr(msg);
+ blnHadIssue = true;
+ }
+ }
+
+ private AutowireVDP setupPipeline(
+ int iWidth, int iHeight,
+ @Nonnull VideoFormat outputFormat, @Nonnull String sOutputBaseName,
+ @CheckForNull String sOutputQuality, @CheckForNull String sUpsampleQuality,
+ @Nonnull ILocalizedLogger log)
+ throws CommandLineException
+ {
+ VideoFileNameFormatter formatter = new VideoFileNameFormatter(null, sOutputBaseName, outputFormat, iWidth, iHeight);
+ AutowireVDP pipline = new AutowireVDP();
+
+ switch (outputFormat) {
+ case IMGSEQ_MDEC:
+ pipline.setMap(new VDP.Mdec2File(formatter, iWidth, iHeight, log));
+ break;
+ case IMGSEQ_JPG:
+ pipline.setMap(new VDP.Mdec2Jpeg(formatter, iWidth, iHeight, log));
+ break;
+
+ case IMGSEQ_BMP:
+ case IMGSEQ_PNG:
+ // made decoder, verify decoding quality
+ MdecDecodeQuality decQuality = MdecDecodeQuality.HIGH;
+ if (sOutputQuality != null) {
+ decQuality = MdecDecodeQuality.fromCmdLine(sOutputQuality);
+ if (decQuality == null)
+ throw new CommandLineException(I.CMD_INVALID_VALUE_FOR_CMD(sOutputQuality, "-q,-quality"));
+ }
+ MdecDecoder vidDecoder = decQuality.makeDecoder(iWidth, iHeight);
+ _fbs.println(I.CMD_USING_QUALITY(decQuality.getCmdLine()));
+
+ // verify upsample quality
+ ChromaUpsample up = ChromaUpsample.Bicubic;
+ if (vidDecoder instanceof MdecDecoder_double) {
+ if (sUpsampleQuality != null) {
+ up = ChromaUpsample.fromCmdLine(sUpsampleQuality);
+ if (up == null)
+ throw new CommandLineException(I.CMD_INVALID_VALUE_FOR_CMD(sUpsampleQuality, "-up"));
+ }
+ _fbs.println(I.CMD_UPSAMPLE_QUALITY(up.getDescription().getLocalizedMessage()));
+ ((MdecDecoder_double) vidDecoder).setUpsampler(up);
+ }
+
+ pipline.setMap(new VDP.Mdec2Decoded(vidDecoder, log));
+
+ pipline.setMap(new VDP.Decoded2JavaImage(formatter, outputFormat.getImgFmt(), iWidth, iHeight, log));
+ break;
+ default:
+ throw new RuntimeException();
+ }
+
+ _fbs.println(I.CMD_SAVING_AS(formatter.format(null, log)));
+
+ return pipline;
+ }
+
+ private void saveTim(@Nonnull File inFile) throws CommandLineException {
+ _fbs.println(I.CMD_READING_TIM(inFile));
+ FileInputStream is = null;
+ try {
+ is = new FileInputStream(inFile);
+ String sOutBaseName = Misc.removeExt(inFile.getName());
+ Tim tim = Tim.read(is);
+ _fbs.println(new UnlocalizedMessage(tim.toString()));
+ int iDigitCount = String.valueOf(tim.getPaletteCount()).length();
+ for (int i = 0; i < tim.getPaletteCount(); i++) {
+ BufferedImage bi = tim.toBufferedImage(i);
+ String sFileName = String.format("%s_p%0" + iDigitCount + "d.png", sOutBaseName, i);
+ File file = new File(sFileName);
+ _fbs.println(I.IO_WRITING_FILE(file.getName()));
+ ImageIO.write(bi, "png", file);
+ }
+ _fbs.println(I.CMD_IMAGE_CONVERT_OK());
+ } catch (BinaryDataNotRecognized ex) {
+ throw new CommandLineException(I.CMD_NOT_TIM(), ex);
+ } catch (IOException ex) {
+ throw new CommandLineException(I.CMD_TIM_IO_ERR(), ex);
+ } finally {
+ IO.closeSilently(is, Logger.getLogger(Command_Static.class.getName()));
+ }
+ }
+
}
diff --git a/jpsxdec/src/jpsxdec/discitems/CombinedBuilderListener.java b/jpsxdec/src/jpsxdec/discitems/CombinedBuilderListener.java
index 71f6ff2..d4a1830 100644
--- a/jpsxdec/src/jpsxdec/discitems/CombinedBuilderListener.java
+++ b/jpsxdec/src/jpsxdec/discitems/CombinedBuilderListener.java
@@ -79,6 +79,7 @@ public void addListeners(ChangeListener ... aoControls) {
* All listening controls will be notified of the change.
* @return if the {@link DiscItemSaverBuilder} is compatible.
*/
+ @SuppressWarnings("unchecked")
public boolean changeSourceBuilder(@Nonnull DiscItemSaverBuilder saverBuilder) {
if (_cls.equals(saverBuilder.getClass())) {
T oldBuilder = _saverBuilder;
diff --git a/jpsxdec/src/jpsxdec/discitems/DiscItemSaverBuilder.java b/jpsxdec/src/jpsxdec/discitems/DiscItemSaverBuilder.java
index 6153e87..3d7d4bd 100644
--- a/jpsxdec/src/jpsxdec/discitems/DiscItemSaverBuilder.java
+++ b/jpsxdec/src/jpsxdec/discitems/DiscItemSaverBuilder.java
@@ -48,6 +48,7 @@
import jpsxdec.i18n.FeedbackStream;
import jpsxdec.i18n.ILocalizedMessage;
import jpsxdec.i18n.exception.LoggedFailure;
+import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.i18n.log.ProgressLogger;
import jpsxdec.util.ArgParser;
import jpsxdec.util.TaskCanceledException;
@@ -123,7 +124,7 @@ final protected void addGeneratedFile(@Nonnull File file) {
/** Configure the saver builder from command-line arguments. */
abstract public void commandLineOptions(@Nonnull ArgParser ap, @Nonnull FeedbackStream fbs);
/** Prints the options used for saving. */
- abstract public void printSelectedOptions(@Nonnull FeedbackStream fbs);
+ abstract public void printSelectedOptions(@Nonnull ILocalizedLogger log);
/** Get a localized summary of what files will be generated on save. */
abstract public @Nonnull ILocalizedMessage getOutputSummary();
diff --git a/jpsxdec/src/jpsxdec/discitems/ParagraphPanel.java b/jpsxdec/src/jpsxdec/discitems/ParagraphPanel.java
index 0b3d0ad..067ed95 100644
--- a/jpsxdec/src/jpsxdec/discitems/ParagraphPanel.java
+++ b/jpsxdec/src/jpsxdec/discitems/ParagraphPanel.java
@@ -87,10 +87,14 @@ public void stateChanged(ChangeEvent e) {
fireStateChanged();
if (__label.isEnabled() != isEnabled())
__label.setEnabled(isEnabled());
+ boolean v = isVisibile();
+ __label.setVisible(v);
+ __chk.setVisible(v);
}
@Override abstract public boolean isSelected();
@Override abstract public void setSelected(boolean b);
@Override abstract public boolean isEnabled();
+ public boolean isVisibile() { return true; }
}
diff --git a/jpsxdec/src/jpsxdec/discitems/SerializedDiscItem.java b/jpsxdec/src/jpsxdec/discitems/SerializedDiscItem.java
index 32f4b51..1318515 100644
--- a/jpsxdec/src/jpsxdec/discitems/SerializedDiscItem.java
+++ b/jpsxdec/src/jpsxdec/discitems/SerializedDiscItem.java
@@ -237,6 +237,10 @@ private void checkValidKey(String sKey) {
// =========================================================================
// Reading fields
+ public boolean hasField(@Nonnull String sFieldName) {
+ return _fields.containsKey(sFieldName);
+ }
+
public @Nonnull String getString(@Nonnull String sFieldName) throws LocalizedDeserializationFail {
String sValue = _fields.get(sFieldName);
if (sValue == null) throw new LocalizedDeserializationFail(I.SERIALIZATION_FIELD_NOT_FOUND(sFieldName));
@@ -260,7 +264,7 @@ public long getLong(@Nonnull String sFieldName) throws LocalizedDeserializationF
try {
return Long.parseLong(sValue);
} catch (NumberFormatException e) {
- throw new LocalizedDeserializationFail(I.SERIALIZATION_FAILED_TO_CONVERT_TO_LONG(sValue));
+ throw new LocalizedDeserializationFail(I.SERIALIZATION_FAILED_TO_CONVERT_TO_NUMBER(sValue));
}
}
@@ -270,7 +274,7 @@ public int getInt(@Nonnull String sFieldName) throws LocalizedDeserializationFai
try {
return Integer.parseInt(sValue);
} catch (NumberFormatException e) {
- throw new LocalizedDeserializationFail(I.SERIALIZATION_FAILED_TO_CONVERT_TO_INT(sValue));
+ throw new LocalizedDeserializationFail(I.SERIALIZATION_FAILED_TO_CONVERT_TO_NUMBER(sValue));
}
}
@@ -282,7 +286,7 @@ public int getInt(@Nonnull String sFieldName, int iDefault) throws LocalizedDese
try {
return Integer.parseInt(sValue);
} catch (NumberFormatException e) {
- throw new LocalizedDeserializationFail(I.SERIALIZATION_FAILED_TO_CONVERT_TO_INT(sValue));
+ throw new LocalizedDeserializationFail(I.SERIALIZATION_FAILED_TO_CONVERT_TO_NUMBER(sValue));
}
}
diff --git a/jpsxdec/src/jpsxdec/formats/RGB.java b/jpsxdec/src/jpsxdec/formats/RGB.java
index d90a389..f2ac3b5 100644
--- a/jpsxdec/src/jpsxdec/formats/RGB.java
+++ b/jpsxdec/src/jpsxdec/formats/RGB.java
@@ -79,6 +79,7 @@ public int toInt() {
return 0xFF000000 | clampr | clampg | clampb;
}
+ @Override
public String toString() {
return String.format("(%d, %d, %d)", r, g, b);
}
diff --git a/jpsxdec/src/jpsxdec/formats/Rec601YCbCr.java b/jpsxdec/src/jpsxdec/formats/Rec601YCbCr.java
index 5a76e8b..ab3b051 100644
--- a/jpsxdec/src/jpsxdec/formats/Rec601YCbCr.java
+++ b/jpsxdec/src/jpsxdec/formats/Rec601YCbCr.java
@@ -116,6 +116,7 @@ public void toRgb(@Nonnull RGB rgb1, @Nonnull RGB rgb2, @Nonnull RGB rgb3, @Nonn
rgb4.setB(dblYshift + dblChromBlue );
}
+ @Override
public String toString() {
return String.format("([%f, %f, %f, %f] %f, %f)", y1, y2, y3, y4, cb, cr);
}
diff --git a/jpsxdec/src/jpsxdec/gui/Gui.java b/jpsxdec/src/jpsxdec/gui/Gui.java
index 7486f9c..421e59c 100644
--- a/jpsxdec/src/jpsxdec/gui/Gui.java
+++ b/jpsxdec/src/jpsxdec/gui/Gui.java
@@ -48,14 +48,12 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
-import java.lang.reflect.Method;
import java.util.ArrayList;
-import java.util.List;
+import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
-import javax.sound.sampled.LineUnavailableException;
import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
@@ -77,6 +75,7 @@
import jpsxdec.util.Misc;
import jpsxdec.util.player.PlayController;
import jpsxdec.util.player.PlayController.Event;
+import jpsxdec.util.player.PlayerException;
import org.openide.awt.DropDownButtonFactory;
public class Gui extends javax.swing.JFrame {
@@ -86,22 +85,21 @@ public class Gui extends javax.swing.JFrame {
// -------------------------------------------------------------------------
@CheckForNull
- private DiscIndex _index;
+ private transient DiscIndex _index;
@CheckForNull
- private PlayController _currentPlayer;
+ private transient PlayController _currentPlayer;
private final ArrayList _saverGuis =
new ArrayList();
@Nonnull
- private final GuiSettings _settings;
+ private final transient GuiSettings _settings;
@CheckForNull
private String _sCommandLineFile;
- private boolean _blnIsPaused = true;
// -------------------------------------------------------------------------
public Gui() {
- // use the system's L&F if available (for great justice!)
+ // use the system's L&F if available
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
SwingUtilities.updateComponentTreeUI(this);
@@ -125,23 +123,10 @@ public Gui() {
convertToolbar();
- Image icon16 = Toolkit.getDefaultToolkit().createImage(getClass().getResource("icon16.png"));
- try {
- // setIconImages() is only available in Java 6+, but jPSXdec is targetted for Java 5
- // we optionally take advantage of it using reflection
- Method setIconImages = this.getClass().getMethod("setIconImages", List.class);
- ArrayList icons = new ArrayList(3);
- Image icon32 = Toolkit.getDefaultToolkit().createImage(getClass().getResource("icon32.png"));
- Image icon48 = Toolkit.getDefaultToolkit().createImage(getClass().getResource("icon48.png"));
- icons.add(icon16);
- icons.add(icon32);
- icons.add(icon48);
- setIconImages.invoke(this, icons);
- } catch (Exception ex) {
- LOG.log(Level.INFO, "Unable to set multiple icons", ex);
- setIconImage(icon16);
- }
-
+ Image icon16 = Toolkit.getDefaultToolkit().createImage(Gui.class.getResource("icon16.png"));
+ Image icon32 = Toolkit.getDefaultToolkit().createImage(Gui.class.getResource("icon32.png"));
+ Image icon48 = Toolkit.getDefaultToolkit().createImage(Gui.class.getResource("icon48.png"));
+ setIconImages(Arrays.asList(icon16, icon32, icon48));
}
@@ -403,7 +388,7 @@ private void openDisc(@Nonnull File file) {
cd.close(); // expose close exception
} else {
if (generatedIndex.size() == 0) {
- JOptionPane.showMessageDialog(this, "Could not identify anything in " + file.toString()); // I18N
+ JOptionPane.showMessageDialog(this, I.GUI_DIALOG_COULD_NOT_IDENTIFY_ANYTHING(file.toString()).getLocalizedMessage());
} else {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
setIndex(generatedIndex, null);
@@ -750,14 +735,10 @@ private void _guiDiscTreeValueChanged(javax.swing.event.TreeSelectionEvent evt)
private void _guiPlayPauseBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event__guiPlayPauseBtnActionPerformed
try {
if (_currentPlayer != null) {
- if (_blnIsPaused) {
+ if (_currentPlayer.isPaused()) {
_currentPlayer.unpause();
- _guiPlayPauseBtn.setText(I.GUI_PAUSE_BTN().getLocalizedMessage());
- _blnIsPaused = false;
} else {
_currentPlayer.pause();
- _guiPlayPauseBtn.setText(I.GUI_PLAY_BTN().getLocalizedMessage());
- _blnIsPaused = true;
}
}
} catch (Throwable ex) {
@@ -890,12 +871,22 @@ private void _guiChooseDirActionPerformed(java.awt.event.ActionEvent evt) {//GEN
private transient final PlayController.PlayerListener _playerListener = new PlayController.PlayerListener() {
- public void update(@Nonnull Event eEvent) {
- switch (eEvent) {
- case Stop:
- _guiPlayPauseBtn.setEnabled(false);
- break;
- }
+ public void event(@Nonnull final Event eEvent) {
+ java.awt.EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ switch (eEvent) {
+ case End:
+ _guiPlayPauseBtn.setEnabled(false);
+ break;
+ case Pause:
+ _guiPlayPauseBtn.setText(I.GUI_PLAY_BTN().getLocalizedMessage());
+ break;
+ case Play:
+ _guiPlayPauseBtn.setText(I.GUI_PAUSE_BTN().getLocalizedMessage());
+ break;
+ }
+ }
+ });
}
};
@@ -908,8 +899,8 @@ private void _guiTabStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST
_currentPlayer = selection.getPlayer();
if (_currentPlayer != null) {
try {
- _currentPlayer.start();
- } catch (LineUnavailableException ex) {
+ _currentPlayer.activate();
+ } catch (PlayerException ex) {
LOG.log(Level.SEVERE, null, ex);
_currentPlayer = null;
}
@@ -919,14 +910,13 @@ private void _guiTabStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST
_guiPreviewPanel.add(_currentPlayer.getVideoScreen());
_guiPreviewPanel.revalidate();
}
- _currentPlayer.addLineListener(_playerListener);
+ _currentPlayer.addEventListener(_playerListener);
_guiPlayPauseBtn.setText(I.GUI_PLAY_BTN().getLocalizedMessage());
_guiPlayPauseBtn.setEnabled(true);
- _blnIsPaused = true;
}
} else {
if (_currentPlayer != null) {
- _currentPlayer.stop();
+ _currentPlayer.terminate();
_currentPlayer = null;
_guiPreviewPanel.removeAll();
_guiPreviewPanel.validate();
@@ -985,7 +975,7 @@ private void formWindowOpened(java.awt.event.WindowEvent evt) {//GEN-FIRST:event
byte[] ab = new byte[iCount];
int iSize = IO.readByteArrayMax(is, ab, 0, ab.length);
if (iSize < ab.length)
- return Misc.copyOfRange(ab, 0, iSize);
+ return Arrays.copyOfRange(ab, 0, iSize);
else
return ab;
}
diff --git a/jpsxdec/src/jpsxdec/gui/GuiFileFilters.java b/jpsxdec/src/jpsxdec/gui/GuiFileFilters.java
index 30af590..9d09430 100644
--- a/jpsxdec/src/jpsxdec/gui/GuiFileFilters.java
+++ b/jpsxdec/src/jpsxdec/gui/GuiFileFilters.java
@@ -70,10 +70,8 @@ public boolean accept(File f) {
s.endsWith(".img") ||
s.endsWith(".mdf") ||
s.endsWith(".str") ||
- s.endsWith(".mov") ||
s.endsWith(".iki") ||
- s.endsWith(".xa") ||
- s.endsWith(".xai");
+ s.endsWith(".xa");
}
},
new FileFilter() {
@@ -103,8 +101,7 @@ public boolean accept(File f) {
public boolean accept(File f) {
String s = f.getName().toLowerCase();
return f.isDirectory() ||
- s.endsWith(".xa") ||
- s.endsWith(".xai");
+ s.endsWith(".xa");
}
},
};
diff --git a/jpsxdec/src/jpsxdec/gui/GuiTree.java b/jpsxdec/src/jpsxdec/gui/GuiTree.java
index 473c45b..9302288 100644
--- a/jpsxdec/src/jpsxdec/gui/GuiTree.java
+++ b/jpsxdec/src/jpsxdec/gui/GuiTree.java
@@ -126,20 +126,6 @@ public static Select[] getAvailableValues() {
public void formatTreeTable(@Nonnull DiscIndex index) {
_root = buildTree(index.getRoot());
- /* If using Netbeans Outline
- setDefaultRenderer(Boolean.class, new OptionalBooleanTableCellRenderer());
- DiscTreeModel ttModel = new DiscTreeModel(_root);
- OutlineModel om = DefaultOutlineModel.createOutlineModel(ttModel, ttModel);
- setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- setFillsViewportHeight(true);
- setIntercellSpacing(new Dimension(0, 0));
- setShowGrid(false);
- setRootVisible(false);
- setModel(om);
- setRowSorter(null);
- setRowHeight(getRowHeight() - 2);
- / */
-
FontMetrics fm = getFontMetrics(getFont());
int iSectorWidth = fm.stringWidth("999999-999999");
int iNumberWidth = fm.stringWidth(String.valueOf(index.size()) + "99");
@@ -147,7 +133,6 @@ public void formatTreeTable(@Nonnull DiscIndex index) {
int iTypeWidth = fm.stringWidth(DiscItem.GeneralType.Sound.getName().toString());
setDefaultRenderer(Boolean.class, new OptionalBooleanTableCellRenderer());
- //_guiDiscTree.setDefaultRenderer(Integer.class, new CenteredIntegerTableCellRenderer());
setTreeCellRenderer(new TreeIconRenderer());
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
@@ -160,12 +145,8 @@ public void formatTreeTable(@Nonnull DiscIndex index) {
colMod.getColumn(COLUMNS.Type.ordinal()).setPreferredWidth(iTypeWidth + 10);
TableColumn detailsCol = colMod.getColumn(COLUMNS.Details.ordinal());
detailsCol.setPreferredWidth(Math.max(250, detailsCol.getWidth()));
- // */
}
- //public void expandAll() {} public void collapseAll() {}
- //public void addTreeSelectionListener(TreeSelectionListener tsl) {}
-
public @CheckForNull TreeItem getTreeTblSelection() {
return (TreeItem) getValueAt(getSelectedRow(), convertColumnIndexToView(COLUMNS.Name.ordinal()));
}
@@ -519,9 +500,7 @@ else if (cmd == Select.ALL_SOUND) // SPU support
// -------------------------------------------------------------------------
- private static class DiscTreeModel implements TreeTableModel
- //, RowModel // Outline
- {
+ private static class DiscTreeModel implements TreeTableModel {
@Nonnull
private final TreeItem _treeRoot;
@@ -581,16 +560,6 @@ public void setValueAt(@Nonnull Object value, @Nonnull Object node, int i) {
assert i == COLUMNS.Save.ordinal();
((DiscItemTreeItem)node).setSave(((Boolean)value).booleanValue());
}
-
- // for Netbeans Outline
- public @CheckForNull Object getValueFor(@Nonnull Object node, int column) {
- return getValueAt(node, column);
- }
-
- // for Netbeans Outline
- public void setValueFor(@Nonnull Object node, int column, @Nonnull Object value) {
- setValueAt(value, node, column);
- }
}
// -------------------------------------------------------------------------
diff --git a/jpsxdec/src/jpsxdec/i18n/FeedbackStream.java b/jpsxdec/src/jpsxdec/i18n/FeedbackStream.java
index 660466b..a6070ef 100644
--- a/jpsxdec/src/jpsxdec/i18n/FeedbackStream.java
+++ b/jpsxdec/src/jpsxdec/i18n/FeedbackStream.java
@@ -34,16 +34,23 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+
package jpsxdec.i18n;
import java.io.PrintStream;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
+import jpsxdec.i18n.log.ILocalizedLogger;
/**
* Filters outputting text based on verbosity level.
*/
public class FeedbackStream {
+ private static final Logger LOG = Logger.getLogger(FeedbackStream.class.getName());
+
public static final int MORE = 4;
public static final int NORM = 3;
public static final int WARN = 2;
@@ -136,4 +143,32 @@ public int getLevel() {
public @Nonnull PrintStream getUnderlyingStream() {
return _ps;
}
+
+ public @Nonnull ILocalizedLogger makeLogger() {
+ return new FbsLogger();
+ }
+
+ private class FbsLogger implements ILocalizedLogger {
+
+ public void log(@Nonnull Level level, @Nonnull ILocalizedMessage msg) {
+ log(level, msg, null);
+ }
+
+ public void log(@Nonnull Level level, @Nonnull ILocalizedMessage msg,
+ @CheckForNull Throwable debugException)
+ {
+ LOG.log(level, msg.getEnglishMessage(), debugException);
+ if (level.intValue() < Level.INFO.intValue() ||
+ level.intValue() == Level.ALL.intValue() ||
+ level.intValue() == Level.CONFIG.intValue())
+ printlnMore(msg);
+ else if (level.intValue() < Level.WARNING.intValue())
+ println(msg);
+ else if (level.intValue() < Level.SEVERE.intValue())
+ printlnWarn(msg);
+ else if (level.intValue() >= Level.SEVERE.intValue() &&
+ level.intValue() != Level.OFF.intValue())
+ printlnErr(msg);
+ }
+ }
}
diff --git a/jpsxdec/src/jpsxdec/i18n/I.java b/jpsxdec/src/jpsxdec/i18n/I.java
index 15e8d15..1ab8cab 100644
--- a/jpsxdec/src/jpsxdec/i18n/I.java
+++ b/jpsxdec/src/jpsxdec/i18n/I.java
@@ -1,6 +1,7 @@
/*
* jPSXdec Translations
- * Copyright (c) 2015-2017 Michael Sabin, Víctor González, Sergi Medina
+ * Copyright (c) 2015-2019
+ * Michael Sabin, Víctor González, Sergi Medina, Gianluigi "Infrid" Cusimano
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -137,10 +138,7 @@ private static ILocalizedMessage msg(String sKey, String sEnglishDefault, Object
- Trying to look-up and item by its numeric index and the number is invalid (probably negative)
-
+ Trying to look-up an item by its numeric index and the number is invalid (probably negative)
*/
public static @Nonnull ILocalizedMessage CMD_ITEM_NUMBER_INVALID(@Nonnull String badItemNumber) {
return msg("CMD_ITEM_NUMBER_INVALID", "Invalid item number: {0}", badItemNumber);
@@ -151,9 +149,6 @@ private static ILocalizedMessage msg(String sKey, String sEnglishDefault, Object
Invalid item identifier: {0}
Trying to look-up an item by its string index identifier that is invalid (probably contains space)
-
*/
public static @Nonnull ILocalizedMessage CMD_ITEM_ID_INVALID(@Nonnull String badItemIdentifier) {
return msg("CMD_ITEM_ID_INVALID", "Invalid item identifier: {0}", badItemIdentifier);
@@ -245,7 +240,7 @@ private static ILocalizedMessage msg(String sKey, String sEnglishDefault, Object
- The next line will display the item info
+ The next line printed to the console after this will be the description of the item
@@ -321,6 +316,7 @@ private static ILocalizedMessage msg(String sKey, String sEnglishDefault, Object
Command_Items.java
+ Command_Static.java
*/
public static @Nonnull ILocalizedMessage CMD_NUM_FILES_CREATED(int fileCount) {
@@ -440,6 +436,7 @@ private static ILocalizedMessage msg(String sKey, String sEnglishDefault, Object
+ e.g. [INFO] Some message
@@ -452,6 +449,7 @@ private static ILocalizedMessage msg(String sKey, String sEnglishDefault, Object
+ e.g. [WARN] Some message BadException
*/
public static @Nonnull ILocalizedMessage USER_LOG_MESSAGE_EXCEPTION(@Nonnull String logLevel, @Nonnull String logMessage, @Nonnull String exceptionName) {
return msg("USER_LOG_MESSAGE_EXCEPTION", "[{0}] {1} {2}", logLevel, logMessage, exceptionName);
@@ -461,6 +459,7 @@ private static ILocalizedMessage msg(String sKey, String sEnglishDefault, Object
+ e.g. [WARN] Some message BadException: Something bad happened
*/
public static @Nonnull ILocalizedMessage USER_LOG_MESSAGE_EXCEPTION_MSG(@Nonnull String logLevel, @Nonnull String logMessage, @Nonnull String exceptionName, @Nonnull String exceptionMessage) {
return msg("USER_LOG_MESSAGE_EXCEPTION_MSG", "[{0}] {1} {2} : {3}", logLevel, logMessage, exceptionName, exceptionMessage);
@@ -470,6 +469,7 @@ private static ILocalizedMessage msg(String sKey, String sEnglishDefault, Object
+ e.g. [WARN] BadException
*/
public static @Nonnull ILocalizedMessage USER_LOG_EXCEPTION(@Nonnull String logLevel, @Nonnull String exceptionName) {
return msg("USER_LOG_EXCEPTION", "[{0}] {1}", logLevel, exceptionName);
@@ -479,6 +479,7 @@ private static ILocalizedMessage msg(String sKey, String sEnglishDefault, Object
+ e.g. [WARN] BadException: Something bad happened
*/
public static @Nonnull ILocalizedMessage USER_LOG_EXCEPTION_MSG(@Nonnull String logLevel, @Nonnull String exceptionName, @Nonnull String exceptionMessage) {
return msg("USER_LOG_EXCEPTION_MSG", "[{0}] {1} : {2}", logLevel, exceptionName, exceptionMessage);
@@ -488,9 +489,7 @@ private static ILocalizedMessage msg(String sKey, String sEnglishDefault, Object
Invalid sector range: {0}
-
- Command_CopySect.java
-
+ Sector range should be in the format "start-end"
*/
public static @Nonnull ILocalizedMessage CMD_SECTOR_RANGE_INVALID(@Nonnull String badSectorRangeString) {
return msg("CMD_SECTOR_RANGE_INVALID", "Invalid sector range: {0}", badSectorRangeString);
@@ -532,13 +531,19 @@ private static ILocalizedMessage msg(String sKey, String sEnglishDefault, Object
return msg("CMD_DIM_OPTION_REQURIED", "-dim option required");
}
+ /**
+
+ Invalid dimensions: {0}
+
+ */
+ public static @Nonnull ILocalizedMessage CMD_INVALID_DIMENSIONS(@Nonnull String badDimensionsString) {
+ return msg("CMD_INVALID_DIMENSIONS", "Invalid dimensions: {0}", badDimensionsString);
+ }
+
/**
-
*/
public static @Nonnull ILocalizedMessage CMD_QUALITY_INVALID(@Nonnull String badQuality) {
return msg("CMD_QUALITY_INVALID", "Invalid quality {0}", badQuality);
@@ -573,9 +578,6 @@ private static ILocalizedMessage msg(String sKey, String sEnglishDefault, Object
Using upsampling {0}
See CHROMA_UPSAMPLE_*_DESCRIPTION
-
*/
public static @Nonnull ILocalizedMessage CMD_USING_UPSAMPLING(@Nonnull ILocalizedMessage upsampleDescription) {
return msg("CMD_USING_UPSAMPLING", "Using upsampling {0}", upsampleDescription);
@@ -597,9 +599,6 @@ private static ILocalizedMessage msg(String sKey, String sEnglishDefault, Object
-
*/
public static @Nonnull ILocalizedMessage CMD_FORMAT_INVALID(@Nonnull String badFormat) {
return msg("CMD_FORMAT_INVALID", "Invalid format type {0}", badFormat);
@@ -646,9 +645,6 @@ Right after this string, the next string (CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA
-
*/
public static @Nonnull ILocalizedMessage CMD_STATIC_TYPE_INVALID(@Nonnull String badStaticTypeName) {
return msg("CMD_STATIC_TYPE_INVALID", "Invalid static type: {0}", badStaticTypeName);
@@ -690,18 +686,6 @@ Right after this string, the next string (CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA
return msg("CMD_IMAGE_CONVERT_OK", "Image converted successfully");
}
- /**
-
- Invalid upsampling {0}
-
-
- */
- public static @Nonnull ILocalizedMessage CMD_UPSAMPLING_INVALID(@Nonnull String badUpsamplingName) {
- return msg("CMD_UPSAMPLING_INVALID", "Invalid upsampling {0}", badUpsamplingName);
- }
-
/**
Saving as: {0}
@@ -788,9 +772,6 @@ Right after this string, the next string (CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA
Invalid verbosity level {0}
-
*/
public static @Nonnull ILocalizedMessage CMD_VERBOSE_LVL_INVALID_STR(@Nonnull String badVerbosityLevel) {
return msg("CMD_VERBOSE_LVL_INVALID_STR", "Invalid verbosity level {0}", badVerbosityLevel);
@@ -800,9 +781,6 @@ Right after this string, the next string (CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA
Invalid verbosity level {0,number,#}
-
*/
public static @Nonnull ILocalizedMessage CMD_VERBOSE_LVL_INVALID_NUM(int badVerbosityNumber) {
return msg("CMD_VERBOSE_LVL_INVALID_NUM", "Invalid verbosity level {0,number,#}", badVerbosityNumber);
@@ -1004,6 +982,18 @@ Right after this string, the next string (CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA
return msg("GUI_DISC_NO_RAW_HEADERS_WARNING", "Disc image does not have raw headers -- audio may not be detected.");
}
+ /**
+
+ Could not identify anything in file {0}
+
+
+ */
+ public static @Nonnull ILocalizedMessage GUI_DIALOG_COULD_NOT_IDENTIFY_ANYTHING(@Nonnull String fileName) {
+ return msg("GUI_DIALOG_COULD_NOT_IDENTIFY_ANYTHING", "Could not identify anything in file {0}", fileName);
+ }
+
/**
Select disc image or media file
@@ -1164,6 +1154,7 @@ Right after this string, the next string (CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA
+ Button
@@ -1176,6 +1167,7 @@ Right after this string, the next string (CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA
+ Button
@@ -1188,6 +1180,7 @@ Right after this string, the next string (CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA
+ Button
@@ -1200,6 +1193,7 @@ Right after this string, the next string (CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA
+ Button
@@ -1212,6 +1206,7 @@ Right after this string, the next string (CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA
+ Button
@@ -1249,6 +1244,7 @@ Right after this string, the next string (CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA
Applied settings to {0,number,#} items.
+ Dialog box
@@ -1261,6 +1257,7 @@ Right after this string, the next string (CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA
The index has not been saved. Save index?
+ Dialog box
@@ -1273,6 +1270,7 @@ Right after this string, the next string (CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA
+ Dialog box
@@ -1311,6 +1309,7 @@ Right after this string, the next string (CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA
+ Button
@@ -1348,6 +1347,7 @@ Right after this string, the next string (CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA
CD images (*.iso, *.bin, *.img, *.mdf)
+ File dialog format
@@ -1360,6 +1360,7 @@ CD images (*.iso, *.bin, *.img, *.mdf)
+ File dialog format
@@ -1372,6 +1373,7 @@ Index files (*.idx)
PlayStation video (*.str, *.mov, *.iki, *.ik2)
+ File dialog format
@@ -1384,6 +1386,7 @@ PlayStation video (*.str, *.mov, *.iki, *.ik2)
+ File dialog format
@@ -1396,6 +1399,7 @@ PlayStation video (*.str, *.mov, *.iki, *.ik2)
PlayStation/CD-i audio (*.xa, *.xai)
+ File dialog format
@@ -1409,6 +1413,7 @@ PlayStation video (*.str, *.mov, *.iki, *.ik2)
The file "{0}" already exists!
Do you want to replace it?
+ Dialog
@@ -1470,6 +1475,7 @@ PlayStation video (*.str, *.mov, *.iki, *.ik2)
+ Drop-down
@@ -1482,6 +1488,7 @@ PlayStation video (*.str, *.mov, *.iki, *.ik2)
+ Drop-down
@@ -1494,6 +1501,7 @@ PlayStation video (*.str, *.mov, *.iki, *.ik2)
all Audio (excluding video audio)
+ Drop-down
@@ -1506,6 +1514,7 @@ all Audio (excluding video audio)
all Audio (including video audio)
+ Drop-down
@@ -1518,6 +1527,7 @@ all Audio (including video audio)
+ Drop-down
@@ -1530,6 +1540,7 @@ all Audio (including video audio)
+ Drop-down
@@ -1542,8 +1553,9 @@ all Audio (including video audio)
+ Column name
- VideoSaverBuilderStrGui.java
+ SectorBasedVideoSaverBuilderGui.java
GuiTree.java
*/
@@ -1555,8 +1567,9 @@ all Audio (including video audio)
+ Column name
- VideoSaverBuilderStrGui.java
+ SectorBasedVideoSaverBuilderGui.java
GuiTree.java
*/
@@ -1568,8 +1581,9 @@ all Audio (including video audio)
+ Column name
- VideoSaverBuilderStrGui.java
+ SectorBasedVideoSaverBuilderGui.java
GuiTree.java
*/
@@ -1713,6 +1727,7 @@ all Audio (including video audio)
+ Button
IndexingGui.java
SavingGui.java
@@ -1726,6 +1741,7 @@ all Audio (including video audio)
+ Button
IndexingGui.java
SavingGui.java
@@ -1739,6 +1755,7 @@ all Audio (including video audio)
+ Button
IndexingGui.java
SavingGui.java
@@ -1825,6 +1842,7 @@ all Audio (including video audio)
+ Column header for the number of errors in the GUI
@@ -2002,10 +2020,6 @@ partial header (2336 bytes/sector) format
Failed to convert serialized field to int: {0}
- TODO combine with next one
-
- SerializedDiscItem.java
-
*/
public static @Nonnull ILocalizedMessage SERIALIZATION_FAILED_TO_CONVERT_TO_INT(@Nonnull String badNumber) {
return msg("SERIALIZATION_FAILED_TO_CONVERT_TO_INT", "Failed to convert serialized field to int: {0}", badNumber);
@@ -2015,12 +2029,21 @@ partial header (2336 bytes/sector) format
Failed to convert serialized field to long: {0}
+ */
+ public static @Nonnull ILocalizedMessage SERIALIZATION_FAILED_TO_CONVERT_TO_LONG(@Nonnull String badNumber) {
+ return msg("SERIALIZATION_FAILED_TO_CONVERT_TO_LONG", "Failed to convert serialized field to long: {0}", badNumber);
+ }
+
+ /**
+
+ Failed to convert text to number: {0}
+
*/
- public static @Nonnull ILocalizedMessage SERIALIZATION_FAILED_TO_CONVERT_TO_LONG(@Nonnull String badNumber) {
- return msg("SERIALIZATION_FAILED_TO_CONVERT_TO_LONG", "Failed to convert serialized field to long: {0}", badNumber);
+ public static @Nonnull ILocalizedMessage SERIALIZATION_FAILED_TO_CONVERT_TO_NUMBER(@Nonnull String badNumber) {
+ return msg("SERIALIZATION_FAILED_TO_CONVERT_TO_NUMBER", "Failed to convert text to number: {0}", badNumber);
}
/**
@@ -2039,6 +2062,7 @@ partial header (2336 bytes/sector) format
Failed to convert serialized value to range: {0}
+ This is when trying to parse a "range" value, which is supposed to like "number-number" (e.g. "7-14"), but in this case the "range" format isn't right
@@ -2063,6 +2087,7 @@ partial header (2336 bytes/sector) format
+ A .idx line is missing a field, e.g. a video is missing "dimensions"
@@ -2073,14 +2098,14 @@ partial header (2336 bytes/sector) format
/**
- Disc format does not match what index says "{0}" != "{1}".
+ Disc format "{0}" does not match the format in the index file "{1}"
*/
public static @Nonnull ILocalizedMessage CD_FORMAT_MISMATCH(@Nonnull String actualFormatDescription, @Nonnull String expectedFormatDescription) {
- return msg("CD_FORMAT_MISMATCH", "Disc format does not match what index says \"{0}\" != \"{1}\".", actualFormatDescription, expectedFormatDescription);
+ return msg("CD_FORMAT_MISMATCH", "Disc format \"{0}\" does not match the format in the index file \"{1}\"", actualFormatDescription, expectedFormatDescription);
}
/**
@@ -2118,12 +2143,22 @@ partial header (2336 bytes/sector) format
/**
- Non-continuous sector header number: {0,number,#} -> {1,number,#}
+ Detected corruption at sector {0,number,#}. This may affect identification and conversion.
*/
+ public static @Nonnull ILocalizedMessage INDEX_SECTOR_CORRUPTED_AT(int sectorNumber) {
+ return msg("INDEX_SECTOR_CORRUPTED_AT", "Detected corruption at sector {0,number,#}. This may affect identification and conversion.", sectorNumber);
+ }
+
+ /**
+
+ Non-continuous sector header number: {0,number,#} -> {1,number,#}
+
+ Sector header numbers should always be sequential. If some number is skipped, this error appears.
+ */
public static @Nonnull ILocalizedMessage INDEX_SECTOR_HEADER_NUM_BREAK(int previousSectorNumber, int currentSectorNumber) {
return msg("INDEX_SECTOR_HEADER_NUM_BREAK", "Non-continuous sector header number: {0,number,#} -> {1,number,#}", previousSectorNumber, currentSectorNumber);
}
@@ -2132,9 +2167,7 @@ partial header (2336 bytes/sector) format
Sector {0,number,#} is Mode 1 found among Mode 2 sectors
-
+ This is another case where these is inconsistencies in the sequence of sectors. "Mode 1" and "Mode 2" are sector types, and should never be mixed together.
*/
public static @Nonnull ILocalizedMessage INDEX_MODE1_AMONG_MODE2(int sectorNumber) {
return msg("INDEX_MODE1_AMONG_MODE2", "Sector {0,number,#} is Mode 1 found among Mode 2 sectors", sectorNumber);
@@ -2144,6 +2177,8 @@ partial header (2336 bytes/sector) format
Failed to parse "{0}" because "{1}"
+ When trying to open a .idx file, if there is a line that it doesn't recognize or has an error, this is the message that is logged. So 0 is the text of the line, and 1 is the error message. For a silly example:
+ Failed to parse "bad line" because "That line makes no sense"
@@ -2168,7 +2203,7 @@ partial header (2336 bytes/sector) format
Index contains multiple lines that start with "{0}"
- The lines it's talking about are the lines indicating the source disc file
+ The .idx file has a line that described the source disc file format. The line starts with "{0}". There should only be 1 line of this type in a .idx file. In this case, there are more than one, which is weird.
@@ -2206,6 +2241,7 @@ partial header (2336 bytes/sector) format
Sector {0,number,#} / {1,number,#} {2,number,#} items found
+ Progress bar string
@@ -2365,14 +2401,26 @@ partial header (2336 bytes/sector) format
/**
- {0,number,#}x{1,number,#}, {2,number,#} frames, {3,number,#} fps = {4,time,m:ss}
+ {0,number,#}x{1,number,#}, {2,number,#} frames, {3,number,#.###} fps = {4,time,m:ss}
- DiscItemCrusader.java
+ DiscItemPacketBasedVideoStream.java
*/
- public static @Nonnull ILocalizedMessage GUI_CRUSADER_VID_DETAILS(int videoWidth, int videoHeight, int frameCount, int framesPerSecond, @Nonnull java.util.Date duration) {
- return msg("GUI_CRUSADER_VID_DETAILS", "{0,number,#}x{1,number,#}, {2,number,#} frames, {3,number,#} fps = {4,time,m:ss}", videoWidth, videoHeight, frameCount, framesPerSecond, duration);
+ public static @Nonnull ILocalizedMessage GUI_PACKET_BASED_VID_DETAILS(int videoWidth, int videoHeight, int frameCount, double framesPerSecond, @Nonnull java.util.Date duration) {
+ return msg("GUI_PACKET_BASED_VID_DETAILS", "{0,number,#}x{1,number,#}, {2,number,#} frames, {3,number,#.###} fps = {4,time,m:ss}", videoWidth, videoHeight, frameCount, framesPerSecond, duration);
+ }
+
+ /**
+
+ {0,number,#}x{1,number,#}, {2,number,#} frames, {3,number,#.###} fps = {4,time,m:ss}, {5,number,#} Hz
+
+
+ DiscItemPacketBasedVideoStream.java
+
+ */
+ public static @Nonnull ILocalizedMessage GUI_PACKET_BASED_VID_DETAILS_WITH_AUDIO(int videoWidth, int videoHeight, int frameCount, double framesPerSecond, @Nonnull java.util.Date duration, int audioHz) {
+ return msg("GUI_PACKET_BASED_VID_DETAILS_WITH_AUDIO", "{0,number,#}x{1,number,#}, {2,number,#} frames, {3,number,#.###} fps = {4,time,m:ss}, {5,number,#} Hz", videoWidth, videoHeight, frameCount, framesPerSecond, duration, audioHz);
}
/**
@@ -2389,7 +2437,7 @@ partial header (2336 bytes/sector) format
{0,number,#}x{1,number,#}, {2,number,#} frames, {3,number,#.###} fps = {4,time,m:ss} (or {5,number,#.###} fps = {6,time,m:ss})
- DiscItemStrVideoStream.java
+ DiscItemSectorBasedVideoStream.java
*/
public static @Nonnull ILocalizedMessage GUI_STR_VIDEO_DETAILS_UNKNOWN_FPS(int videoWidth, int videoHeight, int frameCount, double doubleSpeedFramesPerSecond, @Nonnull java.util.Date doubleSpeedDuration, double singleSpeedFramesPerSecond, @Nonnull java.util.Date singleSpeedDuration) {
@@ -2401,7 +2449,7 @@ partial header (2336 bytes/sector) format
{0,number,#}x{1,number,#}, {2,number,#} frames, {3,number,#.###} fps = {4,time,m:ss}
- DiscItemStrVideoStream.java
+ DiscItemSectorBasedVideoStream.java
*/
public static @Nonnull ILocalizedMessage GUI_STR_VIDEO_DETAILS(int videoWidth, int videoHeight, int frameCount, double framesPerSecond, @Nonnull java.util.Date duration) {
@@ -2647,7 +2695,6 @@ Adjust volume (default {0,number,#}).
Ignoring invalid format {0}
- AudioSaverBuilder.java
SpuSaverBuilder.java
*/
@@ -2660,7 +2707,6 @@ Adjust volume (default {0,number,#}).
Ignoring invalid volume {0}
- AudioSaverBuilder.java
SpuSaverBuilder.java
*/
@@ -2672,9 +2718,6 @@ Adjust volume (default {0,number,#}).
Ignoring invalid disc speed {0}
-
- VideoSaverBuilder.java
-
*/
public static @Nonnull ILocalizedMessage CMD_IGNORING_INVALID_DISC_SPEED(@Nonnull String badDiscSpeed) {
return msg("CMD_IGNORING_INVALID_DISC_SPEED", "Ignoring invalid disc speed {0}", badDiscSpeed);
@@ -2728,7 +2771,7 @@ Adjust volume (default {0,number,#}).
- Combined with next string
+ TODO Combined with next string
DiscItemXaAudioStream.java
@@ -2817,6 +2860,7 @@ Adjust volume (default {0,number,#}).
+ This line comes before the next line
DiscItemXaAudioStream.java
@@ -2829,6 +2873,7 @@ Adjust volume (default {0,number,#}).
+ This line comes after the previous line
DiscItemXaAudioStream.java
@@ -3002,6 +3047,7 @@ Adjust volume (default {0,number,#}).
Found an unexpected number of frames, the frames may be saved in an inconsistent order.
+ When the file is indexed, the number of frames in a video are saved. When saving as a sequence of imgaes, that number is necessary to properly format the file names with extra zeroes. e.g. a video with 99 frames needs all frame numbers to be 2 digits, but a video with 100 frames, needs frame numbers to be 3 digits. If the index says there are 99 frames, but there are actually 100, then the file name "videoframe[100].png" will come before "videoframe[99].png".
Bicubic
- MdecDecoder_double_interpolate.java
+ ChromaUpsample.java
*/
public static @Nonnull ILocalizedMessage CHROMA_UPSAMPLE_BICUBIC_DESCRIPTION() {
@@ -3105,7 +3151,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
1 word (no spaces) user can type on command-line. Not case sensitive
- MdecDecoder_double_interpolate.java
+ ChromaUpsample.java
*/
public static @Nonnull ILocalizedMessage CHROMA_UPSAMPLE_BICUBIC_CMDLINE() {
@@ -3117,7 +3163,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
Bell
- MdecDecoder_double_interpolate.java
+ ChromaUpsample.java
*/
public static @Nonnull ILocalizedMessage CHROMA_UPSAMPLE_BELL_DESCRIPTION() {
@@ -3130,7 +3176,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
1 word (no spaces) user can type on command-line. Not case sensitive
- MdecDecoder_double_interpolate.java
+ ChromaUpsample.java
*/
public static @Nonnull ILocalizedMessage CHROMA_UPSAMPLE_BELL_CMDLINE() {
@@ -3142,7 +3188,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
Nearest Neighbor
- MdecDecoder_double_interpolate.java
+ ChromaUpsample.java
*/
public static @Nonnull ILocalizedMessage CHROMA_UPSAMPLE_NEAR_NEIGHBOR_DESCRIPTION() {
@@ -3155,7 +3201,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
1 word (no spaces) user can type on command-line. Not case sensitive
- MdecDecoder_double_interpolate.java
+ ChromaUpsample.java
*/
public static @Nonnull ILocalizedMessage CHROMA_UPSAMPLE_NEAR_NEIGHBOR_CMDLINE() {
@@ -3167,7 +3213,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
Lanczos3
- MdecDecoder_double_interpolate.java
+ ChromaUpsample.java
*/
public static @Nonnull ILocalizedMessage CHROMA_UPSAMPLE_LANCZOS3_DESCRIPTION() {
@@ -3180,7 +3226,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
1 word (no spaces) user can type on command-line. Not case sensitive
- MdecDecoder_double_interpolate.java
+ ChromaUpsample.java
*/
public static @Nonnull ILocalizedMessage CHROMA_UPSAMPLE_LANCZOS3_CMDLINE() {
@@ -3192,7 +3238,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
Mitchell
- MdecDecoder_double_interpolate.java
+ ChromaUpsample.java
*/
public static @Nonnull ILocalizedMessage CHROMA_UPSAMPLE_MITCHELL_DESCRIPTION() {
@@ -3205,7 +3251,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
1 word (no spaces) user can type on command-line. Not case sensitive
- MdecDecoder_double_interpolate.java
+ ChromaUpsample.java
*/
public static @Nonnull ILocalizedMessage CHROMA_UPSAMPLE_MITCHELL_CMDLINE() {
@@ -3217,7 +3263,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
Hermite
- MdecDecoder_double_interpolate.java
+ ChromaUpsample.java
*/
public static @Nonnull ILocalizedMessage CHROMA_UPSAMPLE_HERMITE_DESCRIPTION() {
@@ -3230,7 +3276,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
1 word (no spaces) user can type on command-line. Not case sensitive
- MdecDecoder_double_interpolate.java
+ ChromaUpsample.java
*/
public static @Nonnull ILocalizedMessage CHROMA_UPSAMPLE_HERMITE_CMDLINE() {
@@ -3242,7 +3288,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
BSpline
- MdecDecoder_double_interpolate.java
+ ChromaUpsample.java
*/
public static @Nonnull ILocalizedMessage CHROMA_UPSAMPLE_BSPLINE_DESCRIPTION() {
@@ -3255,7 +3301,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
1 word (no spaces) user can type on command-line. Not case sensitive
- MdecDecoder_double_interpolate.java
+ ChromaUpsample.java
*/
public static @Nonnull ILocalizedMessage CHROMA_UPSAMPLE_BSPLINE_CMDLINE() {
@@ -3267,7 +3313,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
Bilinear
- MdecDecoder_double_interpolate.java
+ ChromaUpsample.java
*/
public static @Nonnull ILocalizedMessage CHROMA_UPSAMPLE_BILINEAR_DESCRIPTION() {
@@ -3280,7 +3326,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
1 word (no spaces) user can type on command-line. Not case sensitive
- MdecDecoder_double_interpolate.java
+ ChromaUpsample.java
*/
public static @Nonnull ILocalizedMessage CHROMA_UPSAMPLE_BILINEAR_CMDLINE() {
@@ -3293,7 +3339,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
See CHROMA_UPSAMPLE_*_DESCRIPTION and CHROMA_UPSAMPLE_*_CMDLINE
- MdecDecoder_double_interpolate.java
+ ChromaUpsample.java
*/
public static @Nonnull ILocalizedMessage CHROMA_UPSAMPLE_CMDLINE_HELP(@Nonnull ILocalizedMessage commandLineId, @Nonnull ILocalizedMessage interplationName) {
@@ -3367,7 +3413,6 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
Invalid replacement image format {0}
- "mdec" is a file type
@@ -3400,7 +3445,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
/**
- Unable to compress frame {0} small enough to fit in {1,number,#} bytes!!!
+ Unable to compress frame {0} small enough to fit in {1,number,#} bytes
*/
public static @Nonnull ILocalizedMessage CMD_UNABLE_TO_COMPRESS_FRAME_SMALL_ENOUGH(@Nonnull String frameNumber, int maxSize) {
- return msg("CMD_UNABLE_TO_COMPRESS_FRAME_SMALL_ENOUGH", "Unable to compress frame {0} small enough to fit in {1,number,#} bytes!!!", frameNumber, maxSize);
+ return msg("CMD_UNABLE_TO_COMPRESS_FRAME_SMALL_ENOUGH", "Unable to compress frame {0} small enough to fit in {1,number,#} bytes", frameNumber, maxSize);
}
/**
- No differences found, skipping.
+ No differences found in frame {0}, skipping.
*/
- public static @Nonnull ILocalizedMessage CMD_NO_DIFFERENCE_SKIPPING() {
- return msg("CMD_NO_DIFFERENCE_SKIPPING", "No differences found, skipping.");
+ public static @Nonnull ILocalizedMessage CMD_NO_DIFFERENCE_SKIPPING(@Nonnull String frameNumber) {
+ return msg("CMD_NO_DIFFERENCE_SKIPPING", "No differences found in frame {0}, skipping.", frameNumber);
}
/**
@@ -3461,14 +3506,14 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
/**
- Replacement frame dimensions smaller than source frame
+ Replacement frame dimensions {0,number,#}x{1,number,#} are smaller than source frame {2,number,#}x{3,number,#}
*/
- public static @Nonnull ILocalizedMessage REPLACE_FRAME_DIMENSIONS_TOO_SMALL() {
- return msg("REPLACE_FRAME_DIMENSIONS_TOO_SMALL", "Replacement frame dimensions smaller than source frame");
+ public static @Nonnull ILocalizedMessage REPLACE_FRAME_DIMENSIONS_TOO_SMALL(int newWidth, int newHeight, int existingWidth, int existingHeight) {
+ return msg("REPLACE_FRAME_DIMENSIONS_TOO_SMALL", "Replacement frame dimensions {0,number,#}x{1,number,#} are smaller than source frame {2,number,#}x{3,number,#}", newWidth, newHeight, existingWidth, existingHeight);
}
/**
@@ -3500,6 +3545,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
+ The root xml tag should be "str-replace", but it's "{0}"
@@ -3569,9 +3615,6 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
-
- BitStreamUncompressor_Lain.java
-
*/
public static @Nonnull ILocalizedMessage FRAME_NOT_LAIN() {
return msg("FRAME_NOT_LAIN", "Frame is not Lain format");
@@ -3581,9 +3624,6 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
Frame is not STRv1 format
-
- BitStreamUncompressor_STRv1.java
-
*/
public static @Nonnull ILocalizedMessage FRAME_NOT_STRV1() {
return msg("FRAME_NOT_STRV1", "Frame is not STRv1 format");
@@ -3593,9 +3633,6 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
Frame is not STRv2 format
-
- BitStreamUncompressor_STRv2.java
-
*/
public static @Nonnull ILocalizedMessage FRAME_NOT_STRV2() {
return msg("FRAME_NOT_STRV2", "Frame is not STRv2 format");
@@ -3605,14 +3642,23 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
Frame is not STRv3 format
-
- BitStreamUncompressor_STRv3.java
-
*/
public static @Nonnull ILocalizedMessage FRAME_NOT_STRV3() {
return msg("FRAME_NOT_STRV3", "Frame is not STRv3 format");
}
+ /**
+
+ Frame is not {0} format
+
+
+ */
+ public static @Nonnull ILocalizedMessage FRAME_IS_NOT_BITSTREAM_FORMAT(@Nonnull String frameFormatName) {
+ return msg("FRAME_IS_NOT_BITSTREAM_FORMAT", "Frame is not {0} format", frameFormatName);
+ }
+
/**
Iki frame dimensions do not match sector dimensions: {0,number,#}x{1,number,#} != {2,number,#}x{3,number,#}
@@ -3648,23 +3694,22 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
/**
- Trying to reduce Qscale of ({0,number,#},{1,number,#}) to {2,number,#}
+ Trying to reduce quantization scale of macroblock ({0,number,#},{1,number,#}) to {2,number,#}
+ Overly technical message when trying to replace a video frame. I don't really expect anyone to understand what it means. Probably should repalce it with something more generic.
BitStreamUncompressor_Iki.java
*/
public static @Nonnull ILocalizedMessage IKI_REDUCING_QSCALE_OF_MB_TO_VAL(int macroBlockX, int macroBlockY, int quantizationScale) {
- return msg("IKI_REDUCING_QSCALE_OF_MB_TO_VAL", "Trying to reduce Qscale of ({0,number,#},{1,number,#}) to {2,number,#}", macroBlockX, macroBlockY, quantizationScale);
+ return msg("IKI_REDUCING_QSCALE_OF_MB_TO_VAL", "Trying to reduce quantization scale of macroblock ({0,number,#},{1,number,#}) to {2,number,#}", macroBlockX, macroBlockY, quantizationScale);
}
/**
New frame {0} demux size {1,number,#} > max source {2,number,#}, so stopping
-
- BitStreamUncompressor_Iki.java
-
+ Overly technical message when trying to replace a video frame. I don't really expect anyone to understand what it means. Probably should repalce it with something more generic.
*/
public static @Nonnull ILocalizedMessage IKI_NEW_FRAME_GT_SRC_STOPPING(@Nonnull String frameNumber, int demuxSize, int sourceSize) {
return msg("IKI_NEW_FRAME_GT_SRC_STOPPING", "New frame {0} demux size {1,number,#} > max source {2,number,#}, so stopping", frameNumber, demuxSize, sourceSize);
@@ -3672,7 +3717,7 @@ Trying to reduce Qscale of ({0,number,#},{1,number,#}) to {2,number,#}
- New frame {0} demux size {1,number,#} <= max source {2,number,#}
+ New frame {0} replacement size {1,number,#} fits within the existing available size {2,number,#}
BitStreamUncompressor_Iki.java
@@ -3681,7 +3726,7 @@ Trying to reduce Qscale of ({0,number,#},{1,number,#}) to {2,number,#}
*/
public static @Nonnull ILocalizedMessage NEW_FRAME_FITS(@Nonnull String frameNumber, int demuxSize, int sourceSize) {
- return msg("NEW_FRAME_FITS", "New frame {0} demux size {1,number,#} <= max source {2,number,#}", frameNumber, demuxSize, sourceSize);
+ return msg("NEW_FRAME_FITS", "New frame {0} replacement size {1,number,#} fits within the existing available size {2,number,#}", frameNumber, demuxSize, sourceSize);
}
/**
@@ -3708,19 +3753,20 @@ Trying to reduce Qscale of ({0,number,#},{1,number,#}) to {2,number,#}
- Trying luma {0,number,#} chroma {1,number,#}
+ Trying to compress with luma quantization scale {0,number,#} and chroma quantization scale {1,number,#}
+ Overly technical message when trying to replace a video frame. I don't really expect anyone to understand what it means. Probably should repalce it with something more generic.
BitStreamUncompressor_Lain.java
*/
public static @Nonnull ILocalizedMessage TRYING_LUMA_CHROMA(int lumaQuantizationScale, int chromaQuantizationScale) {
- return msg("TRYING_LUMA_CHROMA", "Trying luma {0,number,#} chroma {1,number,#}", lumaQuantizationScale, chromaQuantizationScale);
+ return msg("TRYING_LUMA_CHROMA", "Trying to compress with luma quantization scale {0,number,#} and chroma quantization scale {1,number,#}", lumaQuantizationScale, chromaQuantizationScale);
}
/**
- !!! New frame {0} demux size {1,number,#} > max source {2,number,#} !!!
+ New frame {0} replacement size {1,number,#} does not fit in the existing available size {2,number,#}
BitStreamUncompressor_Iki.java
@@ -3730,19 +3776,19 @@ Trying to reduce Qscale of ({0,number,#},{1,number,#}) to {2,number,#}
*/
public static @Nonnull ILocalizedMessage NEW_FRAME_DOES_NOT_FIT(@Nonnull String frameNumber, int newFrameSize, int sourceFrameSize) {
- return msg("NEW_FRAME_DOES_NOT_FIT", "!!! New frame {0} demux size {1,number,#} > max source {2,number,#} !!!", frameNumber, newFrameSize, sourceFrameSize);
+ return msg("NEW_FRAME_DOES_NOT_FIT", "New frame {0} replacement size {1,number,#} does not fit in the existing available size {2,number,#}", frameNumber, newFrameSize, sourceFrameSize);
}
/**
- Video format cannot handle the magnitude of the new data for frame {0}
+ Replacement image for frame {0} is too detailed to compress
BitStreamUncompressor_Lain.java
*/
public static @Nonnull ILocalizedMessage COMPRESS_TOO_MUCH_ENERGY(@Nonnull String frameNumber) {
- return msg("COMPRESS_TOO_MUCH_ENERGY", "Video format cannot handle the magnitude of the new data for frame {0}", frameNumber);
+ return msg("COMPRESS_TOO_MUCH_ENERGY", "Replacement image for frame {0} is too detailed to compress", frameNumber);
}
/**
@@ -3765,14 +3811,14 @@ Trying to reduce Qscale of ({0,number,#},{1,number,#}) to {2,number,#}
- Embedded Crusader audio {0,number,#}Hz
+ Embedded audio {0,number,#} Hz
- VideoSaverBuilderCrusader.java
+ PacketBasedVideoSaverBuilder.java
*/
- public static @Nonnull ILocalizedMessage EMBEDDED_CRUSADER_AUDIO_HZ(int audioSampleRate) {
- return msg("EMBEDDED_CRUSADER_AUDIO_HZ", "Embedded Crusader audio {0,number,#}Hz", audioSampleRate);
+ public static @Nonnull ILocalizedMessage CMD_EMBEDDED_PACKET_BASED_AUDIO_HZ(int audioSampleRate) {
+ return msg("CMD_EMBEDDED_PACKET_BASED_AUDIO_HZ", "Embedded audio {0,number,#} Hz", audioSampleRate);
}
/**
@@ -3785,6 +3831,19 @@ Trying to reduce Qscale of ({0,number,#},{1,number,#}) to {2,number,#}
+ Policenauts data corruption
+
+
+ DiscIndexerPolicenauts.java
+ SectorClaimToPolicenauts.java
+
+ */
+ public static @Nonnull ILocalizedMessage POLICENAUTS_DATA_CORRUPTION() {
+ return msg("POLICENAUTS_DATA_CORRUPTION", "Policenauts data corruption");
+ }
+
/**
Crusader: No Remorse audio is corrupted
@@ -3808,9 +3867,6 @@ Trying to reduce Qscale of ({0,number,#},{1,number,#}) to {2,number,#}
Sector {0,number,#} chunks in frame changed from {1,number,#} to {2,number,#}
-
- SectorFrameBuilder.java
-
*/
public static @Nonnull ILocalizedMessage DEMUX_FRAME_CHUNKS_CHANGED_FROM_TO(int sectorNumber, int currentChunkCount, int newChunkCount) {
return msg("DEMUX_FRAME_CHUNKS_CHANGED_FROM_TO", "Sector {0,number,#} chunks in frame changed from {1,number,#} to {2,number,#}", sectorNumber, currentChunkCount, newChunkCount);
@@ -3820,9 +3876,6 @@ Trying to reduce Qscale of ({0,number,#},{1,number,#}) to {2,number,#}
Sector {0,number,#} chunk number {1,number,#} >= chunks in frame {2,number,#}
-
- SectorFrameBuilder.java
-
*/
public static @Nonnull ILocalizedMessage DEMUX_CHUNK_NUM_GTE_CHUNKS_IN_FRAME(int sectorNumber, int chunkNumber, int chunksInFrame) {
return msg("DEMUX_CHUNK_NUM_GTE_CHUNKS_IN_FRAME", "Sector {0,number,#} chunk number {1,number,#} >= chunks in frame {2,number,#}", sectorNumber, chunkNumber, chunksInFrame);
@@ -3833,7 +3886,7 @@ Trying to reduce Qscale of ({0,number,#},{1,number,#}) to {2,number,#} Frame in sectors {0,number,#}-{1,number,#} is missing chunk {2,number,#}
- SectorFrameBuilder.java
+ SectorBasedFrameBuilder.java
*/
public static @Nonnull ILocalizedMessage MISSING_CHUNK_FRAME_IN_SECTORS(int frameStartSector, int frameEndSector, int chunkNumber) {
@@ -3842,7 +3895,7 @@ Trying to reduce Qscale of ({0,number,#},{1,number,#}) to {2,number,#}
- Trying to replace a frame with missing chunks??
+ Trying to replace an existing corrupted frame
DemuxedCrusaderFrame.java
@@ -3850,7 +3903,7 @@ Trying to reduce Qscale of ({0,number,#},{1,number,#}) to {2,number,#}
*/
public static @Nonnull ILocalizedMessage CMD_FRAME_TO_REPLACE_MISSING_CHUNKS() {
- return msg("CMD_FRAME_TO_REPLACE_MISSING_CHUNKS", "Trying to replace a frame with missing chunks??");
+ return msg("CMD_FRAME_TO_REPLACE_MISSING_CHUNKS", "Trying to replace an existing corrupted frame");
}
/**
@@ -3861,6 +3914,7 @@ Trying to reduce Qscale of ({0,number,#},{1,number,#}) to {2,number,#} VDP.java
ReplaceFrameFull.java
ReplaceFramePartial.java
+ SectorBasedFrameBuilder.java
*/
public static @Nonnull ILocalizedMessage FRAME_NUM_CORRUPTED(@Nonnull String frameNumber) {
@@ -3933,26 +3987,28 @@ Trying to reduce Qscale of ({0,number,#},{1,number,#}) to {2,number,#}
- Frame {0} is ahead of reading by {1,number,#} {1,choice,1#frame|2#frames}.
+ Presentation time of frame {0} in video file will be {1,number,#} {1,choice,1#frame|2#frames} ahead of original timing
+ Message when saving an .avi and the frames are slightly out of sync with the audio
*/
public static @Nonnull ILocalizedMessage FRAME_NUM_AHEAD_OF_READING(@Nonnull String frameNumber, int frameCount) {
- return msg("FRAME_NUM_AHEAD_OF_READING", "Frame {0} is ahead of reading by {1,number,#} {1,choice,1#frame|2#frames}.", frameNumber, frameCount);
+ return msg("FRAME_NUM_AHEAD_OF_READING", "Presentation time of frame {0} in video file will be {1,number,#} {1,choice,1#frame|2#frames} ahead of original timing", frameNumber, frameCount);
}
/**
- Frame is ahead of reading by {0,number,#} {0,choice,1#frame|2#frames}.
+ Presentation time of frame in video file will be {0,number,#} {0,choice,1#frame|2#frames} ahead of original timing
+ Message when saving an .avi and the frames are slightly out of sync with the audio
*/
public static @Nonnull ILocalizedMessage FRAME_AHEAD_OF_READING(int frameCount) {
- return msg("FRAME_AHEAD_OF_READING", "Frame is ahead of reading by {0,number,#} {0,choice,1#frame|2#frames}.", frameCount);
+ return msg("FRAME_AHEAD_OF_READING", "Presentation time of frame in video file will be {0,number,#} {0,choice,1#frame|2#frames} ahead of original timing", frameCount);
}
/**
@@ -4011,14 +4067,26 @@ Trying to reduce Qscale of ({0,number,#},{1,number,#}) to {2,number,#}
- Writing {0,number,#} blank frame(s) to align audio/video playback.
+ Writing {0,number,#} blank {0,choice,1#frame|2#frames} to align audio/video playback.
*/
public static @Nonnull ILocalizedMessage WRITING_BLANK_FRAMES_TO_ALIGN_AV(int frameCount) {
- return msg("WRITING_BLANK_FRAMES_TO_ALIGN_AV", "Writing {0,number,#} blank frame(s) to align audio/video playback.", frameCount);
+ return msg("WRITING_BLANK_FRAMES_TO_ALIGN_AV", "Writing {0,number,#} blank {0,choice,1#frame|2#frames} to align audio/video playback.", frameCount);
+ }
+
+ /**
+
+ Writing {0,number,#} duplicate {0,choice,1#frame|2#frames} to align audio/video playback.
+
+
+ */
+ public static @Nonnull ILocalizedMessage WRITING_DUP_FRAMES_TO_ALIGN_AV(int frameCount) {
+ return msg("WRITING_DUP_FRAMES_TO_ALIGN_AV", "Writing {0,number,#} duplicate {0,choice,1#frame|2#frames} to align audio/video playback.", frameCount);
}
/**
@@ -4037,6 +4105,7 @@ Trying to reduce Qscale of ({0,number,#},{1,number,#}) to {2,number,#}
Writing {0,number,#} samples of silence to align audio/video playback.
+ TODO combine with next line
@@ -4286,6 +4355,7 @@ 1 word (no spaces) user can type on command-line. Not case sensitive
+ Display the range of frame files that will be saved. e.g. "frame[001].png-frame[077].png"
@@ -4387,6 +4457,7 @@ With audio item(s):
See CHROMA_UPSAMPLE_*_DESCRIPTION
VideoSaverBuilder.java
+ Command_Static.java
*/
public static @Nonnull ILocalizedMessage CMD_UPSAMPLE_QUALITY(@Nonnull String upsampleDescription) {
@@ -4443,6 +4514,30 @@ With audio item(s):
return msg("CMD_CROPPING", "Cropping: {0,choice,0#No|1#Yes}", willCrop);
}
+ /**
+
+ Video must have even dimensions to save as {0}, increasing size by 1 pixel
+
+
+ VideoSaverBuilder.java
+
+ */
+ public static @Nonnull ILocalizedMessage CMD_VIDEO_MUST_HAVE_EVEN_DIMS(@Nonnull String videoFormatDescription) {
+ return msg("CMD_VIDEO_MUST_HAVE_EVEN_DIMS", "Video must have even dimensions to save as {0}, increasing size by 1 pixel", videoFormatDescription);
+ }
+
+ /**
+
+ Dimensions: {0,number,#}x{1,number,#}
+
+
+ VideoSaverBuilder.java
+
+ */
+ public static @Nonnull ILocalizedMessage CMD_DIMENSIONS(int width, int height) {
+ return msg("CMD_DIMENSIONS", "Dimensions: {0,number,#}x{1,number,#}", width, height);
+ }
+
/**
Error closing AVI
@@ -4533,9 +4628,7 @@ With audio item(s):
Invalid upsample quality {0}
-
- VideoSaverBuilder.java
-
+ TODO replace this and similar lines with "invalid option/value for {-command}"
*/
public static @Nonnull ILocalizedMessage CMD_UPSAMPLE_QUALITY_INVALID(@Nonnull String badQualityName) {
return msg("CMD_UPSAMPLE_QUALITY_INVALID", "Invalid upsample quality {0}", badQualityName);
@@ -4545,9 +4638,7 @@ With audio item(s):
Invalid decode quality {0}
-
- VideoSaverBuilder.java
-
+ TODO replace this and similar lines with "invalid option/value for {-command}"
*/
public static @Nonnull ILocalizedMessage CMD_DECODE_QUALITY_INVALID(@Nonnull String badQualityName) {
return msg("CMD_DECODE_QUALITY_INVALID", "Invalid decode quality {0}", badQualityName);
@@ -4608,9 +4699,6 @@ Decoding quality (default {0}). Options:
Invalid frame number type {0}
-
- VideoSaverBuilder.java
-
*/
public static @Nonnull ILocalizedMessage CMD_FRAME_NUMBER_TYPE_INVALID(@Nonnull String badFrameNumberType) {
return msg("CMD_FRAME_NUMBER_TYPE_INVALID", "Invalid frame number type {0}", badFrameNumberType);
@@ -4618,15 +4706,15 @@ Decoding quality (default {0}). Options:
/**
- -frame,-frames # or #-#
+ -start #, -end #
- Note that the commands -frame and -frames are hard-coded
+ Note that the commands -start and -end are hard-coded
*/
public static @Nonnull ILocalizedMessage CMD_VIDEO_FRAMES() {
- return msg("CMD_VIDEO_FRAMES", "-frame,-frames # or #-#");
+ return msg("CMD_VIDEO_FRAMES", "-start #, -end #");
}
/**
@@ -4672,9 +4760,7 @@ Decoding quality (default {0}). Options:
-
- VideoSaverBuilder.java
-
+ TODO replace this and similar lines with "invalid option/value for {-command}"
*/
public static @Nonnull ILocalizedMessage CMD_VIDEO_FORMAT_INVALID(@Nonnull String badFormatString) {
return msg("CMD_VIDEO_FORMAT_INVALID", "Invalid video format {0}", badFormatString);
@@ -4724,6 +4810,7 @@ Output video format (default {0}).
+ TODO replace this and similar lines with "invalid option/value for {-command}"
*/
public static @Nonnull ILocalizedMessage CMD_FRAME_RANGE_INVALID(@Nonnull String badFrameNumberString) {
return msg("CMD_FRAME_RANGE_INVALID", "Invalid frame(s) {0}", badFrameNumberString);
@@ -4735,8 +4822,8 @@ Invalid frame(s) {0}
Note that the command -noaud is hard-coded
- VideoSaverBuilderCrusader.java
- VideoSaverBuilderStr.java
+ PacketBasedVideoSaverBuilder.java
+ SectorBasedVideoSaverBuilder.java
*/
public static @Nonnull ILocalizedMessage CMD_VIDEO_NOAUD() {
@@ -4748,8 +4835,8 @@ Invalid frame(s) {0}
Don't save audio.
- VideoSaverBuilderCrusader.java
- VideoSaverBuilderStr.java
+ PacketBasedVideoSaverBuilder.java
+ SectorBasedVideoSaverBuilder.java
*/
public static @Nonnull ILocalizedMessage CMD_VIDEO_NOAUD_HELP() {
@@ -4761,7 +4848,7 @@ Invalid frame(s) {0}
Save audio:
- VideoSaverBuilderCrusaderGui.java
+ PacketBasedVideoSaverBuilderGui.java
*/
public static @Nonnull ILocalizedMessage GUI_SAVE_AUDIO_LABEL() {
@@ -4927,7 +5014,7 @@ Invalid frame(s) {0}
-psxav
- VideoSaverBuilderStr.java
+ SectorBasedVideoSaverBuilder.java
*/
public static @Nonnull ILocalizedMessage CMD_VIDEO_PSXAV() {
@@ -4939,7 +5026,7 @@ Invalid frame(s) {0}
Emulate PSX audio/video timing.
- VideoSaverBuilderStr.java
+ SectorBasedVideoSaverBuilder.java
*/
public static @Nonnull ILocalizedMessage CMD_VIDEO_PSXAV_HELP() {
@@ -4951,7 +5038,7 @@ Invalid frame(s) {0}
Emulate PSX a/v sync:
- VideoSaverBuilderStrGui.java
+ SectorBasedVideoSaverBuilderGui.java
*/
public static @Nonnull ILocalizedMessage GUI_EMULATE_PSX_AV_SYNC_LABEL() {
@@ -4964,7 +5051,7 @@ Invalid frame(s) {0}
Column name is empty in English
- VideoSaverBuilderStrGui.java
+ SectorBasedVideoSaverBuilderGui.java
*/
public static @Nonnull ILocalizedMessage GUI_VID_AUDIO_SAVE_ID_COLUMN() {
@@ -5011,9 +5098,6 @@ Invalid frame(s) {0}
-
*/
public static @Nonnull ILocalizedMessage CMD_TIM_SAVE_FORMAT_INVALID(@Nonnull String badFileFormat) {
return msg("CMD_TIM_SAVE_FORMAT_INVALID", "Invalid format {0}", badFileFormat);
@@ -5023,9 +5107,6 @@ Invalid frame(s) {0}
Invalid list of palettes {0}
-
*/
public static @Nonnull ILocalizedMessage CMD_TIM_PALETTE_LIST_INVALID(@Nonnull String badPaletteList) {
return msg("CMD_TIM_PALETTE_LIST_INVALID", "Invalid list of palettes {0}", badPaletteList);
@@ -5145,7 +5226,7 @@ Output image format (default {0}). Options:
Error reading TIM preview
{0}
- {0} is a multi-line exception stack trace
+ {0} is a technical multi-line error (exception stack trace)
@@ -5199,6 +5280,32 @@ Output image format (default {0}). Options:
return msg("TIM_REPLACE_MULTI_CLUT_UNABLE", "Unable to replace a multi-paletted TIM with a simple image");
}
+ /**
+
+ Invalid value "{0}" for {1}
+
+ command' means the command-line flag, for example "-quality"
+
+ */
+ public static @Nonnull ILocalizedMessage CMD_INVALID_VALUE_FOR_CMD(@Nonnull String invalidValue, @Nonnull String command) {
+ return msg("CMD_INVALID_VALUE_FOR_CMD", "Invalid value \"{0}\" for {1}", invalidValue, command);
+ }
+
+ /**
+
+ Ignoring invalid value "{0}" for {1}
+
+ command' means the command-line flag, for example "-quality"
+
+ */
+ public static @Nonnull ILocalizedMessage CMD_IGNORING_INVALID_VALUE_FOR_CMD(@Nonnull String invalidValue, @Nonnull String command) {
+ return msg("CMD_IGNORING_INVALID_VALUE_FOR_CMD", "Ignoring invalid value \"{0}\" for {1}", invalidValue, command);
+ }
+
/**
Opening file {0}
diff --git a/jpsxdec/src/jpsxdec/i18n/MiscResources_it.java b/jpsxdec/src/jpsxdec/i18n/MiscResources_it.java
new file mode 100644
index 0000000..312dbb6
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/i18n/MiscResources_it.java
@@ -0,0 +1,50 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.i18n;
+
+import java.util.ListResourceBundle;
+
+/** Italian resources. */
+public class MiscResources_it extends ListResourceBundle {
+ @Override
+ protected Object[][] getContents() {
+ return new Object[][] {
+ { MiscResources.MAIN_CMDLINE_HELP, "main_cmdline_help_it.dat" }
+ };
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/i18n/TabularFeedback.java b/jpsxdec/src/jpsxdec/i18n/TabularFeedback.java
index 343fe4c..523fe0d 100644
--- a/jpsxdec/src/jpsxdec/i18n/TabularFeedback.java
+++ b/jpsxdec/src/jpsxdec/i18n/TabularFeedback.java
@@ -121,6 +121,7 @@ public void write(@Nonnull PrintStream ps) {
for (ArrayList row : _rows) {
iColCount = Math.max(iColCount, row.size());
}
+ @SuppressWarnings("unchecked")
ArrayList[][] aaoCells = new ArrayList[iRowCount][iColCount];
int[] aiRowHeights = new int[iRowCount];
diff --git a/jpsxdec/src/jpsxdec/i18n/Translations.properties b/jpsxdec/src/jpsxdec/i18n/Translations.properties
index cd45796..66a8e2f 100644
--- a/jpsxdec/src/jpsxdec/i18n/Translations.properties
+++ b/jpsxdec/src/jpsxdec/i18n/Translations.properties
@@ -1,5 +1,6 @@
# jPSXdec Translations
-# Copyright (c) 2015-2017 Michael Sabin, Víctor González, Sergi Medina
+# Copyright (c) 2015-2019
+# Michael Sabin, Víctor González, Sergi Medina, Gianluigi "Infrid" Cusimano
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -55,17 +56,13 @@ CMD_READING_INDEX_FILE=Reading index file {0}
#java.io.File fileName
CMD_INPUT_FILE_NOT_FOUND=Input file not found {0}
-#Trying to look-up and item by its numeric index and the number is invalid (probably negative)
-#
-#[Command_Items.java]
+#Trying to look-up an item by its numeric index and the number is invalid (probably negative)
#
#String badItemNumber
CMD_ITEM_NUMBER_INVALID=Invalid item number\: {0}
#Trying to look-up an item by its string index identifier that is invalid (probably contains space)
#
-#[Command_Items.java]
-#
#String badItemIdentifier
CMD_ITEM_ID_INVALID=Invalid item identifier\: {0}
@@ -97,7 +94,7 @@ CMD_DISC_ITEM_NOT_FOUND_NUM=Could not find disc item {0,number,\#}
#String discItemId
CMD_DISC_ITEM_NOT_FOUND_STR=Could not find disc item {0}
-#The next line will display the item info
+#The next line printed to the console after this will be the description of the item
#
#[Command_Items.java]
CMD_DETAILED_HELP_FOR=Detailed help for
@@ -121,7 +118,7 @@ CMD_PROCESS_COMPLETE=Disc decoding/extracting complete.
#double durationInSeconds
PROCESS_TIME=Time\: {0,number,\#.\#\#} sec
-#[Command_Items.java]
+#[Command_Items.java, Command_Static.java]
#
#int fileCount
CMD_NUM_FILES_CREATED={0,choice,0\#No files created|1\#1 file created|2\#'{0,number,\#}' files created}
@@ -162,24 +159,34 @@ INDEX_LOG_FILE_BASE_NAME=index
#[Command_Items.java]
REPLACE_LOG_FILE_BASE_NAME=replace
+#e.g. [INFO] Some message
+#
#[UserFriendlyLogger.java]
#
#String logLevel,String logMessage
USER_LOG_MESSAGE=[{0}] {1}
+#e.g. [WARN] Some message BadException
+#
#String logLevel,String logMessage,String exceptionName
USER_LOG_MESSAGE_EXCEPTION=[{0}] {1} {2}
+#e.g. [WARN] Some message BadException: Something bad happened
+#
#String logLevel,String logMessage,String exceptionName,String exceptionMessage
USER_LOG_MESSAGE_EXCEPTION_MSG=[{0}] {1} {2} \: {3}
+#e.g. [WARN] BadException
+#
#String logLevel,String exceptionName
USER_LOG_EXCEPTION=[{0}] {1}
+#e.g. [WARN] BadException: Something bad happened
+#
#String logLevel,String exceptionName,String exceptionMessage
USER_LOG_EXCEPTION_MSG=[{0}] {1} \: {2}
-#[Command_CopySect.java]
+#Sector range should be in the format "start-end"
#
#String badSectorRangeString
CMD_SECTOR_RANGE_INVALID=Invalid sector range\: {0}
@@ -195,8 +202,9 @@ CMD_GENERATING_SECTOR_LIST=Generating sector list
#[Command_Static.java]
CMD_DIM_OPTION_REQURIED=-dim option required
-#[Command_Static.java]
-#
+#String badDimensionsString
+CMD_INVALID_DIMENSIONS=Invalid dimensions\: {0}
+
#String badQuality
CMD_QUALITY_INVALID=Invalid quality {0}
@@ -210,16 +218,12 @@ CMD_NOT_TIM=Error\: not a Tim image
#See CHROMA_UPSAMPLE_*_DESCRIPTION
#
-#[Command_Static.java]
-#
#ILocalizedMessage upsampleDescription
CMD_USING_UPSAMPLING=Using upsampling {0}
#[Command_Static.java]
CMD_TIM_IO_ERR=Error reading or writing TIM file
-#[Command_Static.java]
-#
#String badFormat
CMD_FORMAT_INVALID=Invalid format type {0}
@@ -236,8 +240,6 @@ CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA=Start java using the -ea option.
#java.io.File timFileName
CMD_READING_TIM=Reading TIM file {0}
-#[Command_Static.java]
-#
#String badStaticTypeName
CMD_STATIC_TYPE_INVALID=Invalid static type\: {0}
@@ -252,11 +254,6 @@ CMD_READING_STATIC_FILE=Reading static file {0}
#[Command_Static.java]
CMD_IMAGE_CONVERT_OK=Image converted successfully
-#[Command_Static.java]
-#
-#String badUpsamplingName
-CMD_UPSAMPLING_INVALID=Invalid upsampling {0}
-
#[Command_Static.java, VideoSaverBuilder.java]
#
#java.io.File fileName
@@ -283,13 +280,9 @@ CMD_BUILDING_INDEX=Building index
CMD_DISC_READ_ERROR=Disc read error.
-#[CommandLine.java]
-#
#String badVerbosityLevel
CMD_VERBOSE_LVL_INVALID_STR=Invalid verbosity level {0}
-#[CommandLine.java]
-#
#int badVerbosityNumber
CMD_VERBOSE_LVL_INVALID_NUM=Invalid verbosity level {0,number,\#}
@@ -363,6 +356,11 @@ GUI_OPEN_ANALYZE_DISC_BTN=Open and Analyze File
#[Gui.java]
GUI_DISC_NO_RAW_HEADERS_WARNING=Disc image does not have raw headers -- audio may not be detected.
+#[Gui.java]
+#
+#String fileName
+GUI_DIALOG_COULD_NOT_IDENTIFY_ANYTHING=Could not identify anything in file {0}
+
#[Gui.java]
GUI_OPEN_DISC_DIALOG_TITLE=Select disc image or media file
@@ -410,18 +408,28 @@ GUI_SAVE_INDEX_ERR=Error saving index
#[Gui.java]
GUI_DIRECTORY_LABEL=Directory\:
+#Button
+#
#[Gui.java]
GUI_DIR_CHOOSER_BTN=...
+#Button
+#
#[Gui.java]
GUI_SELECT_BTN=Select ...
+#Button
+#
#[Gui.java]
GUI_COLLAPSE_ALL_BTN=Collapse All
+#Button
+#
#[Gui.java]
GUI_EXPAND_ALL_BTN=Expand All
+#Button
+#
#[Gui.java]
GUI_SAVE_ALL_SELECTED_BTN=Save All Selected
@@ -435,14 +443,20 @@ GUI_NOTHING_IS_MARKED_FOR_SAVING=Nothing is marked for saving.
#ILocalizedMessage itemTypeName
GUI_APPLY_TO_ALL_BTN=Apply to all {0}
+#Dialog box
+#
#[Gui.java]
#
#int itemCount
GUI_APPLIED_SETTINGS=Applied settings to {0,number,\#} items.
+#Dialog box
+#
#[Gui.java]
GUI_SAVE_INDEX_PROMPT=The index has not been saved. Save index?
+#Dialog box
+#
#[Gui.java]
GUI_SAVE_INDEX_PROMPT_TITLE=Save index?
@@ -456,6 +470,8 @@ GUI_PLAY_TAB=\ Play
#[Gui.java]
GUI_SAVE_TAB=\ Save
+#Button
+#
#[Gui.java]
GUI_PAUSE_BTN=Pause
@@ -467,21 +483,33 @@ GUI_BAD_ERROR=Bad error
#[Gui.java]
ERR_LOADING_INDEX_FILE=Error loading index file
+#File dialog format
+#
#[GuiFileFilters.java]
GUI_CD_IMAGE_EXTENSIONS=CD images (*.iso, *.bin, *.img, *.mdf)
+#File dialog format
+#
#[GuiFileFilters.java]
GUI_INDEX_EXTENSION=Index files (*.idx)
+#File dialog format
+#
#[GuiFileFilters.java]
GUI_PSX_VIDEO_EXTENSIONS=PlayStation video (*.str, *.mov, *.iki, *.ik2)
+#File dialog format
+#
#[GuiFileFilters.java]
GUI_ALL_COMPATIBLE_EXTENSIONS=All compatible types
+#File dialog format
+#
#[GuiFileFilters.java]
GUI_XA_EXTENSION=PlayStation/CD-i audio (*.xa, *.xai)
+#Dialog
+#
#[BetterFileChooser.java]
#
#String fileName
@@ -501,31 +529,49 @@ GUI_TREE_TYPE_COLUMN=Type
#[GuiTree.java]
GUI_SELECT_NONE=none
+#Drop-down
+#
#[GuiTree.java]
GUI_SELECT_ALL_VIDEO=all Videos
+#Drop-down
+#
#[GuiTree.java]
GUI_SELECT_ALL_FILES=all Files
+#Drop-down
+#
#[GuiTree.java]
GUI_SELECT_ALL_AUIO_EX_VID=all Audio (excluding video audio)
+#Drop-down
+#
#[GuiTree.java]
GUI_SELECT_ALL_AUDIO_INC_VID=all Audio (including video audio)
+#Drop-down
+#
#[GuiTree.java]
GUI_SELECT_ALL_IMAGES=all Images
+#Drop-down
+#
#[GuiTree.java]
GUI_SELECT_ALL_SOUNDS=all Sound clips
-#[VideoSaverBuilderStrGui.java, GuiTree.java]
+#Column name
+#
+#[SectorBasedVideoSaverBuilderGui.java, GuiTree.java]
GUI_TREE_DETAILS_COLUMN=Details
-#[VideoSaverBuilderStrGui.java, GuiTree.java]
+#Column name
+#
+#[SectorBasedVideoSaverBuilderGui.java, GuiTree.java]
GUI_TREE_SAVE_COLUMN=Save
-#[VideoSaverBuilderStrGui.java, GuiTree.java]
+#Column name
+#
+#[SectorBasedVideoSaverBuilderGui.java, GuiTree.java]
GUI_TREE_INDEX_NUMBER_COLUMN=\#
#[IndexId.java]
@@ -567,12 +613,18 @@ GUI_INDEX_ERRORS_LABEL=Errors\:
#[IndexingGui.java]
GUI_INDEX_RESULT_SUCCESS=Success\!
+#Button
+#
#[IndexingGui.java, SavingGui.java]
GUI_CANCEL_BTN=Cancel
+#Button
+#
#[IndexingGui.java, SavingGui.java]
GUI_CLOSE_BTN=Close
+#Button
+#
#[IndexingGui.java, SavingGui.java]
GUI_START_BTN=Start
@@ -598,6 +650,8 @@ GUI_SAVE_STATUS_CANCELED=Canceled
#[SavingGuiTable.java]
GUI_SRC_COLUMN=Source
+#Column header for the number of errors in the GUI
+#
#[SavingGuiTable.java]
GUI_ERR_COLUMN=Err
@@ -646,23 +700,24 @@ FAILED_TO_READ_1_SECTOR=Failed to read at least 1 entire sector.
#[SerializedDiscItem.java]
EMPTY_SERIALIZED_STRING=Empty serialized string
-#TODO combine with next one
-#
-#[SerializedDiscItem.java]
-#
#String badNumber
SERIALIZATION_FAILED_TO_CONVERT_TO_INT=Failed to convert serialized field to int\: {0}
+#String badNumber
+SERIALIZATION_FAILED_TO_CONVERT_TO_LONG=Failed to convert serialized field to long\: {0}
+
#[SerializedDiscItem.java]
#
#String badNumber
-SERIALIZATION_FAILED_TO_CONVERT_TO_LONG=Failed to convert serialized field to long\: {0}
+SERIALIZATION_FAILED_TO_CONVERT_TO_NUMBER=Failed to convert text to number\: {0}
#[SerializedDiscItem.java]
#
#String lineFromIndexFile
SERIALIZATION_FIELD_IMPROPERLY_FORMATTED=Improperly formatted field serialization\: {0}
+#This is when trying to parse a "range" value, which is supposed to like "number-number" (e.g. "7-14"), but in this case the "range" format isn't right
+#
#[SerializedDiscItem.java]
#
#String badRange
@@ -673,6 +728,8 @@ SERIALIZATION_FAILED_TO_CONVERT_TO_RANGE=Failed to convert serialized value to r
#String lineFromIndexFile
SERIALIZATION_MISSING_REQUIRED_FIELDS=Line missing vital fields {0}
+#A .idx line is missing a field, e.g. a video is missing "dimensions"
+#
#[SerializedDiscItem.java]
#
#String missingField
@@ -681,7 +738,7 @@ SERIALIZATION_FIELD_NOT_FOUND={0} field not found.
#[DiscIndex.java]
#
#String actualFormatDescription,String expectedFormatDescription
-CD_FORMAT_MISMATCH=Disc format does not match what index says "{0}" \!\= "{1}".
+CD_FORMAT_MISMATCH=Disc format "{0}" does not match the format in the index file "{1}"
#[DiscIndex.java]
INDEX_HEADER_MISSING=Missing proper index header.
@@ -695,14 +752,22 @@ INDEX_SECTOR_CORRUPTED=Detected corruption in sector {0,number,\#}. This may aff
#[DiscIndex.java]
#
+#int sectorNumber
+INDEX_SECTOR_CORRUPTED_AT=Detected corruption at sector {0,number,\#}. This may affect identification and conversion.
+
+#Sector header numbers should always be sequential. If some number is skipped, this error appears.
+#
#int previousSectorNumber,int currentSectorNumber
INDEX_SECTOR_HEADER_NUM_BREAK=Non-continuous sector header number\: {0,number,\#} -> {1,number,\#}
-#[DiscIndex.java]
+#This is another case where these is inconsistencies in the sequence of sectors. "Mode 1" and "Mode 2" are sector types, and should never be mixed together.
#
#int sectorNumber
INDEX_MODE1_AMONG_MODE2=Sector {0,number,\#} is Mode 1 found among Mode 2 sectors
+#When trying to open a .idx file, if there is a line that it doesn't recognize or has an error, this is the message that is logged. So 0 is the text of the line, and 1 is the error message. For a silly example:
+#Failed to parse "bad line" because "That line makes no sense"
+#
#[DiscIndex.java]
#
#String lineFromIndexFile,ILocalizedMessage localizedErrorMessage
@@ -713,7 +778,7 @@ INDEX_PARSE_LINE_FAIL=Failed to parse "{0}" because "{1}"
#String lineFromIndexFile
INDEX_UNHANDLED_LINE=Line not recognized {0}
-#The lines it's talking about are the lines indicating the source disc file
+#The .idx file has a line that described the source disc file format. The line starts with "{0}". There should only be 1 line of this type in a .idx file. In this case, there are more than one, which is weird.
#
#[DiscIndex.java]
#
@@ -730,6 +795,8 @@ INDEX_NO_CD=Index is missing a line that starts with "{0}", and no source file w
#[DiscIndex.java]
INDEX_INCONSTSTENCIES=Found inconsistencies in the index, has it been modified?
+#Progress bar string
+#
#[DiscIndex.java]
#
#int currentSectorNumber,int totalSectorCount,int itemsFound
@@ -785,20 +852,25 @@ ITEM_TYPE_SOUND=Sound clip
#[DiscItem.java]
ITEM_TYPE_SOUND_APPLY=Sound clips
-#[DiscItemCrusader.java]
+#[DiscItemPacketBasedVideoStream.java]
+#
+#int videoWidth,int videoHeight,int frameCount,double framesPerSecond,java.util.Date duration
+GUI_PACKET_BASED_VID_DETAILS={0,number,\#}x{1,number,\#}, {2,number,\#} frames, {3,number,\#.\#\#\#} fps \= {4,time,m\:ss}
+
+#[DiscItemPacketBasedVideoStream.java]
#
-#int videoWidth,int videoHeight,int frameCount,int framesPerSecond,java.util.Date duration
-GUI_CRUSADER_VID_DETAILS={0,number,\#}x{1,number,\#}, {2,number,\#} frames, {3,number,\#} fps \= {4,time,m\:ss}
+#int videoWidth,int videoHeight,int frameCount,double framesPerSecond,java.util.Date duration,int audioHz
+GUI_PACKET_BASED_VID_DETAILS_WITH_AUDIO={0,number,\#}x{1,number,\#}, {2,number,\#} frames, {3,number,\#.\#\#\#} fps \= {4,time,m\:ss}, {5,number,\#} Hz
#java.util.Date duration,int sampleRate
GUI_SQUARE_AUDIO_DETAILS={0,time,m\:ss}, {1,number,\#} Hz Stereo
-#[DiscItemStrVideoStream.java]
+#[DiscItemSectorBasedVideoStream.java]
#
#int videoWidth,int videoHeight,int frameCount,double doubleSpeedFramesPerSecond,java.util.Date doubleSpeedDuration,double singleSpeedFramesPerSecond,java.util.Date singleSpeedDuration
GUI_STR_VIDEO_DETAILS_UNKNOWN_FPS={0,number,\#}x{1,number,\#}, {2,number,\#} frames, {3,number,\#.\#\#\#} fps \= {4,time,m\:ss} (or {5,number,\#.\#\#\#} fps \= {6,time,m\:ss})
-#[DiscItemStrVideoStream.java]
+#[DiscItemSectorBasedVideoStream.java]
#
#int videoWidth,int videoHeight,int frameCount,double framesPerSecond,java.util.Date duration
GUI_STR_VIDEO_DETAILS={0,number,\#}x{1,number,\#}, {2,number,\#} frames, {3,number,\#.\#\#\#} fps \= {4,time,m\:ss}
@@ -889,18 +961,16 @@ CMD_AUDIO_VOL=-vol <0-100>
#int defaultVolumeLevel
CMD_AUDIO_VOL_HELP=Adjust volume (default {0,number,\#}).
-#[AudioSaverBuilder.java, SpuSaverBuilder.java]
+#[SpuSaverBuilder.java]
#
#String invalidFormatName
CMD_IGNORING_INVALID_FORMAT=Ignoring invalid format {0}
-#[AudioSaverBuilder.java, SpuSaverBuilder.java]
+#[SpuSaverBuilder.java]
#
#String invalidVolume
CMD_IGNORING_INVALID_VOLUME=Ignoring invalid volume {0}
-#[VideoSaverBuilder.java]
-#
#String badDiscSpeed
CMD_IGNORING_INVALID_DISC_SPEED=Ignoring invalid disc speed {0}
@@ -918,7 +988,7 @@ WRITING_SAMPLES_TO_SECTOR=Writing samples starting at {0,number,\#} to sector se
#int sectorNumber
CMD_PATCHING_SECTOR_NUMBER=Patching sector {0,number,\#}
-#Combined with next string
+#TODO Combined with next string
#
#[DiscItemXaAudioStream.java]
#
@@ -957,11 +1027,15 @@ SPU_ADPCM_CORRUPTED=Audio corrupted near sector {0,number,\#} affecting samples
#java.util.Date duration,int audioSampleRate,int audioChannelCount
GUI_AUDIO_DESCRIPTION={0,time,m\:ss}, {1,number,\#} Hz {2,choice,1\#Mono|2\#Stereo}
+#This line comes before the next line
+#
#[DiscItemXaAudioStream.java]
#
#String discItemDescription
CMD_PATCHING_DISC_ITEM=Patching {0}
+#This line comes after the previous line
+#
#[DiscItemXaAudioStream.java]
#
#String otherDiscItemDescription
@@ -1026,6 +1100,8 @@ FRAME_NUM_FORMAT_INVALID=Invalid frame number format {0}
#int frameNumber
FRAME_MISSING_FRAME_NUMBER_HEADER=Frame {0,number,\#} missing frame number information
+#When the file is indexed, the number of frames in a video are saved. When saving as a sequence of imgaes, that number is necessary to properly format the file names with extra zeroes. e.g. a video with 99 frames needs all frame numbers to be 2 digits, but a video with 100 frames, needs frame numbers to be 3 digits. If the index says there are 99 frames, but there are actually 100, then the file name "videoframe[100].png" will come before "videoframe[99].png".
+#
#[HeaderFrameNumber.java, IndexSectorFrameNumber.java, VideoFileNameFormatter.java]
FRAMES_UNEXPECTED_NUMBER=Found an unexpected number of frames, the frames may be saved in an inconsistent order.
@@ -1053,73 +1129,73 @@ QUALITY_PSX_DESCRIPTION=Emulate PSX (low) quality
#[MdecDecodeQuality.java]
QUALITY_PSX_COMMAND=psx
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BICUBIC_DESCRIPTION=Bicubic
#1 word (no spaces) user can type on command-line. Not case sensitive
#
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BICUBIC_CMDLINE=Bicubic
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BELL_DESCRIPTION=Bell
#1 word (no spaces) user can type on command-line. Not case sensitive
#
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BELL_CMDLINE=Bell
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_NEAR_NEIGHBOR_DESCRIPTION=Nearest Neighbor
#1 word (no spaces) user can type on command-line. Not case sensitive
#
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_NEAR_NEIGHBOR_CMDLINE=NearestNeighbor
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_LANCZOS3_DESCRIPTION=Lanczos3
#1 word (no spaces) user can type on command-line. Not case sensitive
#
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_LANCZOS3_CMDLINE=Lanczos3
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_MITCHELL_DESCRIPTION=Mitchell
#1 word (no spaces) user can type on command-line. Not case sensitive
#
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_MITCHELL_CMDLINE=Mitchell
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_HERMITE_DESCRIPTION=Hermite
#1 word (no spaces) user can type on command-line. Not case sensitive
#
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_HERMITE_CMDLINE=Hermite
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BSPLINE_DESCRIPTION=BSpline
#1 word (no spaces) user can type on command-line. Not case sensitive
#
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BSPLINE_CMDLINE=BSpline
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BILINEAR_DESCRIPTION=Bilinear
#1 word (no spaces) user can type on command-line. Not case sensitive
#
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BILINEAR_CMDLINE=Bilinear
#See CHROMA_UPSAMPLE_*_DESCRIPTION and CHROMA_UPSAMPLE_*_CMDLINE
#
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
#
#ILocalizedMessage commandLineId,ILocalizedMessage interplationName
CHROMA_UPSAMPLE_CMDLINE_HELP={0} ({1})
@@ -1155,8 +1231,6 @@ REPLACE_INCOMPLETE_MDEC=Incomplete mdec file {0} for frame {1}
#String mdecFileName,String frameNumber
REPLACE_CORRUPTED_MDEC=Corrupted mdec file {0} for frame {1}
-#"mdec" is a file type
-#
#[ReplaceFrameFull.java]
#
#String badFormatName
@@ -1174,10 +1248,12 @@ CMD_UNABLE_TO_IDENTIFY_FRAME_TYPE=Unable to identify frame type
#[ReplaceFrameFull.java, ReplaceFramePartial.java]
#
#String frameNumber,int maxSize
-CMD_UNABLE_TO_COMPRESS_FRAME_SMALL_ENOUGH=Unable to compress frame {0} small enough to fit in {1,number,\#} bytes\!\!\!
+CMD_UNABLE_TO_COMPRESS_FRAME_SMALL_ENOUGH=Unable to compress frame {0} small enough to fit in {1,number,\#} bytes
#[ReplaceFramePartial.java]
-CMD_NO_DIFFERENCE_SKIPPING=No differences found, skipping.
+#
+#String frameNumber
+CMD_NO_DIFFERENCE_SKIPPING=No differences found in frame {0}, skipping.
#[ReplaceFramePartial.java]
#
@@ -1193,7 +1269,9 @@ CMD_ENTIRE_FRAME_DIFFERENT=Warning\: Entire frame is different.
REPLACE_UNABLE_READ_IMAGE=Unable to load {0} as image
#[ReplaceFramePartial.java]
-REPLACE_FRAME_DIMENSIONS_TOO_SMALL=Replacement frame dimensions smaller than source frame
+#
+#int newWidth,int newHeight,int existingWidth,int existingHeight
+REPLACE_FRAME_DIMENSIONS_TOO_SMALL=Replacement frame dimensions {0,number,\#}x{1,number,\#} are smaller than source frame {2,number,\#}x{3,number,\#}
#[ReplaceFrames.java]
#
@@ -1207,6 +1285,8 @@ CMD_REPLACING_FRAME_WITH_FILE=Replacing frame {0} with {1}
#String xmlErrorInEnglish
REPLACE_FRAME_XML_ERROR=Error with frame replacement xml\: {0}
+#The root xml tag should be "str-replace", but it's "{0}"
+#
#[ReplaceFrames.java]
#
#String xmlRootNodeName
@@ -1228,18 +1308,19 @@ REPLACE_FRAME_TYPE_NOT_IKI=Frame type is not iki
FRAME_NOT_IKI=Frame is not Iki format
-#[BitStreamUncompressor_Lain.java]
FRAME_NOT_LAIN=Frame is not Lain format
-#[BitStreamUncompressor_STRv1.java]
FRAME_NOT_STRV1=Frame is not STRv1 format
-#[BitStreamUncompressor_STRv2.java]
FRAME_NOT_STRV2=Frame is not STRv2 format
-#[BitStreamUncompressor_STRv3.java]
FRAME_NOT_STRV3=Frame is not STRv3 format
+#[*]
+#
+#String frameFormatName
+FRAME_IS_NOT_BITSTREAM_FORMAT=Frame is not {0} format
+
#[SectorIkiVideo.java]
#
#int sourceWidth,int sourceHeight,int replaceWidth,int replaceHeight
@@ -1250,12 +1331,14 @@ REPLACE_FRAME_TYPE_NOT_LAIN=Incompatible frame data for Lain
UNEXPECTED_END_OF_AUDIO=Unexpected end of audio data
+#Overly technical message when trying to replace a video frame. I don't really expect anyone to understand what it means. Probably should repalce it with something more generic.
+#
#[BitStreamUncompressor_Iki.java]
#
#int macroBlockX,int macroBlockY,int quantizationScale
-IKI_REDUCING_QSCALE_OF_MB_TO_VAL=Trying to reduce Qscale of ({0,number,\#},{1,number,\#}) to {2,number,\#}
+IKI_REDUCING_QSCALE_OF_MB_TO_VAL=Trying to reduce quantization scale of macroblock ({0,number,\#},{1,number,\#}) to {2,number,\#}
-#[BitStreamUncompressor_Iki.java]
+#Overly technical message when trying to replace a video frame. I don't really expect anyone to understand what it means. Probably should repalce it with something more generic.
#
#String frameNumber,int demuxSize,int sourceSize
IKI_NEW_FRAME_GT_SRC_STOPPING=New frame {0} demux size {1,number,\#} > max source {2,number,\#}, so stopping
@@ -1263,7 +1346,7 @@ IKI_NEW_FRAME_GT_SRC_STOPPING=New frame {0} demux size {1,number,\#} > max sourc
#[BitStreamUncompressor_Iki.java, BitStreamUncompressor_Lain.java, BitStreamUncompressor_STRv2.java]
#
#String frameNumber,int demuxSize,int sourceSize
-NEW_FRAME_FITS=New frame {0} demux size {1,number,\#} <\= max source {2,number,\#}
+NEW_FRAME_FITS=New frame {0} replacement size {1,number,\#} fits within the existing available size {2,number,\#}
#[BitStreamUncompressor_Iki.java, BitStreamUncompressor_STRv2.java]
#
@@ -1272,20 +1355,22 @@ TRYING_QSCALE=Trying {0,number,\#}
END_OF_STREAM=End of stream
+#Overly technical message when trying to replace a video frame. I don't really expect anyone to understand what it means. Probably should repalce it with something more generic.
+#
#[BitStreamUncompressor_Lain.java]
#
#int lumaQuantizationScale,int chromaQuantizationScale
-TRYING_LUMA_CHROMA=Trying luma {0,number,\#} chroma {1,number,\#}
+TRYING_LUMA_CHROMA=Trying to compress with luma quantization scale {0,number,\#} and chroma quantization scale {1,number,\#}
#[BitStreamUncompressor_Iki.java, BitStreamUncompressor_Lain.java, BitStreamUncompressor_STRv2.java, ReplaceFrameFull.java]
#
#String frameNumber,int newFrameSize,int sourceFrameSize
-NEW_FRAME_DOES_NOT_FIT=\!\!\! New frame {0} demux size {1,number,\#} > max source {2,number,\#} \!\!\!
+NEW_FRAME_DOES_NOT_FIT=New frame {0} replacement size {1,number,\#} does not fit in the existing available size {2,number,\#}
#[BitStreamUncompressor_Lain.java]
#
#String frameNumber
-COMPRESS_TOO_MUCH_ENERGY=Video format cannot handle the magnitude of the new data for frame {0}
+COMPRESS_TOO_MUCH_ENERGY=Replacement image for frame {0} is too detailed to compress
#int currentWidth,int newWidth
INCONSISTENT_WIDTH=Inconsistent width {0,number,\#} \!\= {1,number,\#}
@@ -1293,39 +1378,38 @@ INCONSISTENT_WIDTH=Inconsistent width {0,number,\#} \!\= {1,number,\#}
#int currentHeight,int newHeight
INCONSISTENT_HEIGHT=Inconsistent height {0,number,\#} \!\= {1,number,\#}
-#[VideoSaverBuilderCrusader.java]
+#[PacketBasedVideoSaverBuilder.java]
#
#int audioSampleRate
-EMBEDDED_CRUSADER_AUDIO_HZ=Embedded Crusader audio {0,number,\#}Hz
+CMD_EMBEDDED_PACKET_BASED_AUDIO_HZ=Embedded audio {0,number,\#} Hz
#"Crusader: No Remorse" is the name of a game
CRUSADER_VIDEO_CORRUPTED=Crusader\: No Remorse video is corrupted
+#[DiscIndexerPolicenauts.java, SectorClaimToPolicenauts.java]
+POLICENAUTS_DATA_CORRUPTION=Policenauts data corruption
+
#"Crusader: No Remorse" is the name of a game
CRUSADER_AUDIO_CORRUPTED=Crusader\: No Remorse audio is corrupted
#String frameNumber,int chunkNumber
MISSING_CHUNK=Frame {0} chunk {1,number,\#} missing.
-#[SectorFrameBuilder.java]
-#
#int sectorNumber,int currentChunkCount,int newChunkCount
DEMUX_FRAME_CHUNKS_CHANGED_FROM_TO=Sector {0,number,\#} chunks in frame changed from {1,number,\#} to {2,number,\#}
-#[SectorFrameBuilder.java]
-#
#int sectorNumber,int chunkNumber,int chunksInFrame
DEMUX_CHUNK_NUM_GTE_CHUNKS_IN_FRAME=Sector {0,number,\#} chunk number {1,number,\#} >\= chunks in frame {2,number,\#}
-#[SectorFrameBuilder.java]
+#[SectorBasedFrameBuilder.java]
#
#int frameStartSector,int frameEndSector,int chunkNumber
MISSING_CHUNK_FRAME_IN_SECTORS=Frame in sectors {0,number,\#}-{1,number,\#} is missing chunk {2,number,\#}
#[DemuxedCrusaderFrame.java, SectorBasedFrameReplace.java]
-CMD_FRAME_TO_REPLACE_MISSING_CHUNKS=Trying to replace a frame with missing chunks??
+CMD_FRAME_TO_REPLACE_MISSING_CHUNKS=Trying to replace an existing corrupted frame
-#[VDP.java, ReplaceFrameFull.java, ReplaceFramePartial.java]
+#[VDP.java, ReplaceFrameFull.java, ReplaceFramePartial.java, SectorBasedFrameBuilder.java]
#
#String frameNumber
FRAME_NUM_CORRUPTED=Error with frame {0}\: Frame is corrupted
@@ -1349,15 +1433,19 @@ UNABLE_TO_DETERMINE_FRAME_TYPE_FRM=Error with frame {0}\: Unable to determine fr
#[VDP.java]
UNABLE_TO_DETERMINE_FRAME_TYPE=Error\: Unable to determine frame type.
+#Message when saving an .avi and the frames are slightly out of sync with the audio
+#
#[VDP.java]
#
#String frameNumber,int frameCount
-FRAME_NUM_AHEAD_OF_READING=Frame {0} is ahead of reading by {1,number,\#} {1,choice,1\#frame|2\#frames}.
+FRAME_NUM_AHEAD_OF_READING=Presentation time of frame {0} in video file will be {1,number,\#} {1,choice,1\#frame|2\#frames} ahead of original timing
+#Message when saving an .avi and the frames are slightly out of sync with the audio
+#
#[VDP.java]
#
#int frameCount
-FRAME_AHEAD_OF_READING=Frame is ahead of reading by {0,number,\#} {0,choice,1\#frame|2\#frames}.
+FRAME_AHEAD_OF_READING=Presentation time of frame in video file will be {0,number,\#} {0,choice,1\#frame|2\#frames} ahead of original timing
#[VDP.java]
#
@@ -1381,13 +1469,20 @@ JPEG_ENCODER_FRAME_FAIL_NO_FRAME=The simple jPSXdec JPEG encoder can't handle fr
#[VDP.java]
#
#int frameCount
-WRITING_BLANK_FRAMES_TO_ALIGN_AV=Writing {0,number,\#} blank frame(s) to align audio/video playback.
+WRITING_BLANK_FRAMES_TO_ALIGN_AV=Writing {0,number,\#} blank {0,choice,1\#frame|2\#frames} to align audio/video playback.
+
+#[VDP.java]
+#
+#int frameCount
+WRITING_DUP_FRAMES_TO_ALIGN_AV=Writing {0,number,\#} duplicate {0,choice,1\#frame|2\#frames} to align audio/video playback.
#[VDP.java]
#
#java.io.File fileName,String frameNumber
FRAME_WRITE_ERR=Error writing file {0} for frame {1}
+#TODO combine with next line
+#
#[VDP.java]
#
#long sampleCount
@@ -1470,6 +1565,8 @@ VID_AVI_YUV_DESCRIPTION=AVI\: YUV
#[VideoFormat.java]
VID_AVI_YUV_COMMAND=avi\:yuv
+#Display the range of frame files that will be saved. e.g. "frame[001].png-frame[077].png"
+#
#[VideoSaverBuilder.java]
#
#java.io.File startFileName,java.io.File endFileName
@@ -1508,7 +1605,7 @@ CMD_NO_AUDIO=No audio
#See CHROMA_UPSAMPLE_*_DESCRIPTION
#
-#[VideoSaverBuilder.java]
+#[VideoSaverBuilder.java, Command_Static.java]
#
#String upsampleDescription
CMD_UPSAMPLE_QUALITY=Chroma upsampling\: {0}
@@ -1537,6 +1634,16 @@ CMD_FRAME_RANGE_AFTER=Skip frames after {0}
#int willCrop
CMD_CROPPING=Cropping\: {0,choice,0\#No|1\#Yes}
+#[VideoSaverBuilder.java]
+#
+#String videoFormatDescription
+CMD_VIDEO_MUST_HAVE_EVEN_DIMS=Video must have even dimensions to save as {0}, increasing size by 1 pixel
+
+#[VideoSaverBuilder.java]
+#
+#int width,int height
+CMD_DIMENSIONS=Dimensions\: {0,number,\#}x{1,number,\#}
+
AVI_CLOSE_ERR=Error closing AVI
#[VideoSaverBuilder.java]
@@ -1571,12 +1678,12 @@ CMD_VIDEO_UP=-up
#ILocalizedMessage defaultUpsamplingMethod
CMD_VIDEO_UP_HELP=Chroma upsampling method\n(default {0}). Options\:
-#[VideoSaverBuilder.java]
+#TODO replace this and similar lines with "invalid option/value for {-command}"
#
#String badQualityName
CMD_UPSAMPLE_QUALITY_INVALID=Invalid upsample quality {0}
-#[VideoSaverBuilder.java]
+#TODO replace this and similar lines with "invalid option/value for {-command}"
#
#String badQualityName
CMD_DECODE_QUALITY_INVALID=Invalid decode quality {0}
@@ -1601,15 +1708,13 @@ CMD_VIDEO_NOCROP=-nocrop
#[VideoSaverBuilder.java]
CMD_VIDEO_NOCROP_HELP=Don't crop data around unused frame edges.
-#[VideoSaverBuilder.java]
-#
#String badFrameNumberType
CMD_FRAME_NUMBER_TYPE_INVALID=Invalid frame number type {0}
-#Note that the commands -frame and -frames are hard-coded
+#Note that the commands -start and -end are hard-coded
#
#[VideoSaverBuilder.java]
-CMD_VIDEO_FRAMES=-frame,-frames \# or \#-\#
+CMD_VIDEO_FRAMES=-start \#, -end \#
#[VideoSaverBuilder.java]
CMD_VIDEO_FRAMES_HELP=Process only frames in range.
@@ -1626,7 +1731,7 @@ CMD_VIDEO_NUM=-num
#ILocalizedMessage frameNumberType
CMD_VIDEO_NUM_HELP=Frame number to use when saving image sequence\n(default {0}). Options\:
-#[VideoSaverBuilder.java]
+#TODO replace this and similar lines with "invalid option/value for {-command}"
#
#String badFormatString
CMD_VIDEO_FORMAT_INVALID=Invalid video format {0}
@@ -1648,18 +1753,20 @@ CMD_VIDEO_VF_HELP=Output video format (default {0}).\nOptions\:
#[VideoSaverBuilder.java]
CMD_VIDEO_HEADER_FRAME_NUMBER_UNSUPPORTED=Video does not support indexing frames by header frame number, -start -end -num ignored
+#TODO replace this and similar lines with "invalid option/value for {-command}"
+#
#String badFrameNumberString
CMD_FRAME_RANGE_INVALID=Invalid frame(s) {0}
#Note that the command -noaud is hard-coded
#
-#[VideoSaverBuilderCrusader.java, VideoSaverBuilderStr.java]
+#[PacketBasedVideoSaverBuilder.java, SectorBasedVideoSaverBuilder.java]
CMD_VIDEO_NOAUD=-noaud
-#[VideoSaverBuilderCrusader.java, VideoSaverBuilderStr.java]
+#[PacketBasedVideoSaverBuilder.java, SectorBasedVideoSaverBuilder.java]
CMD_VIDEO_NOAUD_HELP=Don't save audio.
-#[VideoSaverBuilderCrusaderGui.java]
+#[PacketBasedVideoSaverBuilderGui.java]
GUI_SAVE_AUDIO_LABEL=Save audio\:
#[VideoSaverPanel.java]
@@ -1708,18 +1815,18 @@ GUI_CROP_CHECKBOX=Crop
#[VideoSaverPanel.java]
GUI_CHROMA_UPSAMPLING_LABEL=Chroma upsampling\:
-#[VideoSaverBuilderStr.java]
+#[SectorBasedVideoSaverBuilder.java]
CMD_VIDEO_PSXAV=-psxav
-#[VideoSaverBuilderStr.java]
+#[SectorBasedVideoSaverBuilder.java]
CMD_VIDEO_PSXAV_HELP=Emulate PSX audio/video timing.
-#[VideoSaverBuilderStrGui.java]
+#[SectorBasedVideoSaverBuilderGui.java]
GUI_EMULATE_PSX_AV_SYNC_LABEL=Emulate PSX a/v sync\:
#Column name is empty in English
#
-#[VideoSaverBuilderStrGui.java]
+#[SectorBasedVideoSaverBuilderGui.java]
GUI_VID_AUDIO_SAVE_ID_COLUMN=
#[TimPaletteSelector.java]
@@ -1735,13 +1842,9 @@ CMD_PALETTE_IMAGE_SAVE_FAIL=Unable to write image file {0} for palette {1,number
#String fileFormat
CMD_TIM_SAVE_FORMAT=Format\: {0}
-#[TimSaverBuilder.java]
-#
#String badFileFormat
CMD_TIM_SAVE_FORMAT_INVALID=Invalid format {0}
-#[TimSaverBuilder.java]
-#
#String badPaletteList
CMD_TIM_PALETTE_LIST_INVALID=Invalid list of palettes {0}
@@ -1784,7 +1887,7 @@ TIM_DATA_NOT_FOUND=TIM image data not found
#[TimSaverBuilderGui.java]
GUI_TIM_SAVE_FORMAT_LABEL=Format\:
-#{0} is a multi-line exception stack trace
+#{0} is a technical multi-line error (exception stack trace)
#
#[TimSaverBuilderGui.java]
#
@@ -1808,6 +1911,20 @@ TIM_INCOMPATIBLE=New TIM format "{0}" does not match existing TIM format "{1}"
TIM_REPLACE_MULTI_CLUT_UNABLE=Unable to replace a multi-paletted TIM with a simple image
+#command' means the command-line flag, for example "-quality"
+#
+#[*]
+#
+#String invalidValue,String command
+CMD_INVALID_VALUE_FOR_CMD=Invalid value "{0}" for {1}
+
+#command' means the command-line flag, for example "-quality"
+#
+#[*]
+#
+#String invalidValue,String command
+CMD_IGNORING_INVALID_VALUE_FOR_CMD=Ignoring invalid value "{0}" for {1}
+
#[*]
#
#String fileName
diff --git a/jpsxdec/src/jpsxdec/i18n/Translations_es.properties b/jpsxdec/src/jpsxdec/i18n/Translations_es.properties
index e279942..163ea23 100644
--- a/jpsxdec/src/jpsxdec/i18n/Translations_es.properties
+++ b/jpsxdec/src/jpsxdec/i18n/Translations_es.properties
@@ -1,5 +1,6 @@
# jPSXdec Translations
-# Copyright (c) 2015-2017 Michael Sabin, Víctor González, Sergi Medina
+# Copyright (c) 2015-2019
+# Michael Sabin, Víctor González, Sergi Medina, Gianluigi "Infrid" Cusimano
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -47,13 +48,9 @@ CMD_READING_INDEX_FILE=Leyendo archivo de \u00EDndice {0}
#java.io.File fileName
CMD_INPUT_FILE_NOT_FOUND=No se ha encontrado el archivo de entrada {0}
-#[Command_Items.java]
-#
#String badItemNumber
CMD_ITEM_NUMBER_INVALID=N\u00FAmero de elemento no v\u00E1lido\: {0}
-#[Command_Items.java]
-#
#String badItemIdentifier
CMD_ITEM_ID_INVALID=Identificador de elemento no v\u00E1lido\: {0}
@@ -105,7 +102,7 @@ CMD_PROCESS_COMPLETE=Decodificaci\u00F3n/extracci\u00F3n del disco terminada.
#double durationInSeconds
PROCESS_TIME=Tiempo\: {0,number,\#.\#\#} s
-#[Command_Items.java]
+#[Command_Items.java, Command_Static.java]
#
#int fileCount
CMD_NUM_FILES_CREATED={0,choice,0\#No se han creado archivos|1\#Se ha creado un archivo|2\#Se han creado '{0,number,\#}' archivos}
@@ -156,8 +153,6 @@ USER_LOG_EXCEPTION=[{0}] {1}
#String logLevel,String exceptionName,String exceptionMessage
USER_LOG_EXCEPTION_MSG=[{0}] {1} \: {2}
-#[Command_CopySect.java]
-#
#String badSectorRangeString
CMD_SECTOR_RANGE_INVALID=Rango del sector no v\u00E1lido\: {0}
@@ -172,8 +167,9 @@ CMD_GENERATING_SECTOR_LIST=Generando lista de sectores
#[Command_Static.java]
CMD_DIM_OPTION_REQURIED=se requiere la opci\u00F3n -dim
-#[Command_Static.java]
-#
+#String badDimensionsString
+CMD_INVALID_DIMENSIONS=Dimensiones no v\u00E1lidas\: {0}
+
#String badQuality
CMD_QUALITY_INVALID=Calidad no v\u00E1lida {0}
@@ -188,16 +184,12 @@ CMD_NOT_TIM=Error\: No es una imagen TIM
#It's impossible to translate upsampling to Spanish in one word, but aumento de muestreo would be the most approximate translation, I think.
#- VICTOR: Interpolación would be a better approach -> http://www.proz.com/kudoz/english_to_spanish/computers_software/5731822-upsampling.html
#
-#[Command_Static.java]
-#
#ILocalizedMessage upsampleDescription
CMD_USING_UPSAMPLING=Utilizando la interpolaci\u00F3n {0}
#[Command_Static.java]
CMD_TIM_IO_ERR=Error al leer o escribir el archivo TIM
-#[Command_Static.java]
-#
#String badFormat
CMD_FORMAT_INVALID=Tipo de formato no v\u00E1lido {0}
@@ -214,8 +206,6 @@ CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA=Inicia java con la opci\u00F3n -ea.
#java.io.File timFileName
CMD_READING_TIM=Leyendo el archivo TIM {0}
-#[Command_Static.java]
-#
#String badStaticTypeName
CMD_STATIC_TYPE_INVALID=Tipo est\u00E1tico no v\u00E1lido\: {0}
@@ -230,11 +220,6 @@ CMD_READING_STATIC_FILE=Leyendo archivo est\u00E1tico {0}
#[Command_Static.java]
CMD_IMAGE_CONVERT_OK=Imagen convertida con \u00E9xito
-#[Command_Static.java]
-#
-#String badUpsamplingName
-CMD_UPSAMPLING_INVALID=Interpolaci\u00F3n no v\u00E1lida {0}
-
#[Command_Static.java, VideoSaverBuilder.java]
#
#java.io.File fileName
@@ -261,13 +246,9 @@ CMD_BUILDING_INDEX=Creando \u00EDndice
CMD_DISC_READ_ERROR=Error al leer el disco.
-#[CommandLine.java]
-#
#String badVerbosityLevel
CMD_VERBOSE_LVL_INVALID_STR=Nivel de verbosidad no v\u00E1lido {0}
-#[CommandLine.java]
-#
#int badVerbosityNumber
CMD_VERBOSE_LVL_INVALID_NUM=Nivel de verbosidad no v\u00E1lido {0,number,\#}
@@ -333,6 +314,11 @@ GUI_OPEN_ANALYZE_DISC_BTN=Abrir y analizar archivo
#[Gui.java]
GUI_DISC_NO_RAW_HEADERS_WARNING=La imagen del disco no tiene encabezados en bruto\: puede que no se detecten sus audios.
+#[Gui.java]
+#
+#String fileName
+GUI_DIALOG_COULD_NOT_IDENTIFY_ANYTHING=El archivo {0} no contiene elementos identificables.
+
#[Gui.java]
GUI_OPEN_DISC_DIALOG_TITLE=Selecciona una imagen de disco o un archivo multimedia
@@ -476,13 +462,13 @@ GUI_SELECT_ALL_IMAGES=todas las im\u00E1genes
#[GuiTree.java]
GUI_SELECT_ALL_SOUNDS=todos los clips de sonido
-#[VideoSaverBuilderStrGui.java, GuiTree.java]
+#[SectorBasedVideoSaverBuilderGui.java, GuiTree.java]
GUI_TREE_DETAILS_COLUMN=Detalles
-#[VideoSaverBuilderStrGui.java, GuiTree.java]
+#[SectorBasedVideoSaverBuilderGui.java, GuiTree.java]
GUI_TREE_SAVE_COLUMN=Guardar
-#[VideoSaverBuilderStrGui.java, GuiTree.java]
+#[SectorBasedVideoSaverBuilderGui.java, GuiTree.java]
GUI_TREE_INDEX_NUMBER_COLUMN=N.\u00BA
#[IndexId.java]
@@ -603,15 +589,16 @@ FAILED_TO_READ_1_SECTOR=Error al leer al menos un sector entero.
#[SerializedDiscItem.java]
EMPTY_SERIALIZED_STRING=Cadena serializada vac\u00EDa
-#[SerializedDiscItem.java]
-#
#String badNumber
SERIALIZATION_FAILED_TO_CONVERT_TO_INT=Error al convertir el campo serializado a integral\: {0}
+#String badNumber
+SERIALIZATION_FAILED_TO_CONVERT_TO_LONG=Error al convertir el campo serializado a longitud\: {0}
+
#[SerializedDiscItem.java]
#
#String badNumber
-SERIALIZATION_FAILED_TO_CONVERT_TO_LONG=Error al convertir el campo serializado a longitud\: {0}
+SERIALIZATION_FAILED_TO_CONVERT_TO_NUMBER=Error al convertir el texto a un valor num\u00E9rico\: {0}
#[SerializedDiscItem.java]
#
@@ -636,7 +623,7 @@ SERIALIZATION_FIELD_NOT_FOUND=Campo {0} no encontrado.
#[DiscIndex.java]
#
#String actualFormatDescription,String expectedFormatDescription
-CD_FORMAT_MISMATCH=El formato de disco no coincide con lo que dice el \u00EDndice \u00AB{0}\u00BB \!\= \u00AB{1}\u00BB.
+CD_FORMAT_MISMATCH=El formato de disco \u00AB{0}\u00BB no coincide el formato indicado en el \u00EDndice \u00AB{1}\u00BB.
#[DiscIndex.java]
INDEX_HEADER_MISSING=El encabezado del \u00EDndice no es correcto.
@@ -650,11 +637,12 @@ INDEX_SECTOR_CORRUPTED=Corrupci\u00F3n detectada en el sector {0,number,\#}. Pod
#[DiscIndex.java]
#
+#int sectorNumber
+INDEX_SECTOR_CORRUPTED_AT=Corrupci\u00F3n detectada en el sector {0,number,\#}. Podr\u00EDa afectar a la identificaci\u00F3n y conversi\u00F3n.
+
#int previousSectorNumber,int currentSectorNumber
INDEX_SECTOR_HEADER_NUM_BREAK=N\u00FAmero de encabezado del sector no continuo\: {0,number,\#} -> {1,number,\#}
-#[DiscIndex.java]
-#
#int sectorNumber
INDEX_MODE1_AMONG_MODE2=El sector {0,number,\#} es un Modo 1 encontrado entre sectores en Modo 2
@@ -663,7 +651,7 @@ INDEX_MODE1_AMONG_MODE2=El sector {0,number,\#} es un Modo 1 encontrado entre se
#[DiscIndex.java]
#
#String lineFromIndexFile,ILocalizedMessage localizedErrorMessage
-INDEX_PARSE_LINE_FAIL=No se ha podido analizar "{0}". Raz\u00F3n\: "{1}"
+INDEX_PARSE_LINE_FAIL=No se ha podido analizar {0}. Raz\u00F3n\: {1}
#[DiscIndex.java]
#
@@ -728,20 +716,25 @@ ITEM_TYPE_SOUND=clip de sonido
#[DiscItem.java]
ITEM_TYPE_SOUND_APPLY=clips de sonido
-#[DiscItemCrusader.java]
+#[DiscItemPacketBasedVideoStream.java]
+#
+#int videoWidth,int videoHeight,int frameCount,double framesPerSecond,java.util.Date duration
+GUI_PACKET_BASED_VID_DETAILS={0,number,\#}x{1,number,\#}, {2,number,\#} fotogramas, {3,number,\#} fps \= {4,time,m\:ss}
+
+#[DiscItemPacketBasedVideoStream.java]
#
-#int videoWidth,int videoHeight,int frameCount,int framesPerSecond,java.util.Date duration
-GUI_CRUSADER_VID_DETAILS={0,number,\#}x{1,number,\#}, {2,number,\#} fotogramas, {3,number,\#} fps \= {4,time,m\:ss}
+#int videoWidth,int videoHeight,int frameCount,double framesPerSecond,java.util.Date duration,int audioHz
+GUI_PACKET_BASED_VID_DETAILS_WITH_AUDIO={0,number,\#}x{1,number,\#}, {2,number,\#} fotogramas, {3,number,\#} fps \= {4,time,m\:ss}, {5,number,\#} Hz
#java.util.Date duration,int sampleRate
GUI_SQUARE_AUDIO_DETAILS={0,time,m\:ss}, {1,number,\#} Hz, est\u00E9reo
-#[DiscItemStrVideoStream.java]
+#[DiscItemSectorBasedVideoStream.java]
#
#int videoWidth,int videoHeight,int frameCount,double doubleSpeedFramesPerSecond,java.util.Date doubleSpeedDuration,double singleSpeedFramesPerSecond,java.util.Date singleSpeedDuration
GUI_STR_VIDEO_DETAILS_UNKNOWN_FPS={0,number,\#}x{1,number,\#}, {2,number,\#} fotogramas, {3,number,\#.\#\#\#} fps \= {4,time,m\:ss} (o {5,number,\#.\#\#\#} fps \= {6,time,m\:ss})
-#[DiscItemStrVideoStream.java]
+#[DiscItemSectorBasedVideoStream.java]
#
#int videoWidth,int videoHeight,int frameCount,double framesPerSecond,java.util.Date duration
GUI_STR_VIDEO_DETAILS={0,number,\#}x{1,number,\#}, {2,number,\#} fotogramas, {3,number,\#.\#\#\#} fps \= {4,time,m\:ss}
@@ -754,7 +747,7 @@ GUI_ISOFILE_DETAILS={0} bytes
#[DiscItemISO9660File.java]
#
#int rawBytesPerSector
-CMD_ISOFILE_ISO_HELP=-raw guardar {0,number,\#} bytes/sector (valor en bruto, el valor predeterminado es de 2048 bytes/sector)
+CMD_ISOFILE_ISO_HELP=-raw guardar en bruto usando {0,number,\#} bytes/sector (el valor predeterminado es de 2048 bytes/sector)
#[DiscItemISO9660File.java]
CMD_ISOFILE_HELP_NO_OPTIONS=[no hay opciones disponibles]
@@ -762,10 +755,10 @@ CMD_ISOFILE_HELP_NO_OPTIONS=[no hay opciones disponibles]
#[DiscItemISO9660File.java]
#
#int rawBytesPerSector
-CMD_ISOFILE_SAVING_RAW=Guardar en bruto ({0,number,\#} bytes/sector)
+CMD_ISOFILE_SAVING_RAW=Guardar en bruto usando {0,number,\#} bytes/sector
#[DiscItemISO9660File.java]
-CMD_ISOFILE_SAVING_2048=Guardar de forma normal (2048 bytes/sector)
+CMD_ISOFILE_SAVING_2048=Guardar de forma normal usando 2048 bytes/sector
#[DiscItemISO9660File.java]
GUI_ISOFILE_SAVE_2048=Normal (2048 bytes/sector)
@@ -822,18 +815,16 @@ CMD_AUDIO_VOL=-vol <0-100>
#int defaultVolumeLevel
CMD_AUDIO_VOL_HELP=Ajustar volumen (predeterminado {0,number,\#}).
-#[AudioSaverBuilder.java, SpuSaverBuilder.java]
+#[SpuSaverBuilder.java]
#
#String invalidFormatName
CMD_IGNORING_INVALID_FORMAT=Ignorando formato no v\u00E1lido {0}
-#[AudioSaverBuilder.java, SpuSaverBuilder.java]
+#[SpuSaverBuilder.java]
#
#String invalidVolume
CMD_IGNORING_INVALID_VOLUME=Ignorando volumen no v\u00E1lido {0}
-#[VideoSaverBuilder.java]
-#
#String badDiscSpeed
CMD_IGNORING_INVALID_DISC_SPEED=Ignorando velocidad de disco no v\u00E1lida {0}
@@ -970,57 +961,57 @@ QUALITY_PSX_DESCRIPTION=Emular (baja) calidad de PSX
#[MdecDecodeQuality.java]
QUALITY_PSX_COMMAND=psx
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BICUBIC_DESCRIPTION=Bic\u00FAbica
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BICUBIC_CMDLINE=Bic\u00FAbica
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BELL_DESCRIPTION=Bell
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BELL_CMDLINE=Bell
#We shouldn't translate this string, as it doesn't really have a proper translation and nobody would be able to understand it!
#
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_NEAR_NEIGHBOR_DESCRIPTION=Nearest Neighbor
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_NEAR_NEIGHBOR_CMDLINE=NearestNeighbor
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_LANCZOS3_DESCRIPTION=Lanczos3
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_LANCZOS3_CMDLINE=Lanczos3
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_MITCHELL_DESCRIPTION=Mitchell
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_MITCHELL_CMDLINE=Mitchell
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_HERMITE_DESCRIPTION=Hermite
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_HERMITE_CMDLINE=Hermite
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BSPLINE_DESCRIPTION=BSpline
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BSPLINE_CMDLINE=BSpline
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BILINEAR_DESCRIPTION=Bilineal
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BILINEAR_CMDLINE=Bilineal
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
#
#ILocalizedMessage commandLineId,ILocalizedMessage interplationName
CHROMA_UPSAMPLE_CMDLINE_HELP={0} ({1})
@@ -1065,10 +1056,12 @@ CMD_UNABLE_TO_IDENTIFY_FRAME_TYPE=No se ha podido identificar el tipo de fotogra
#[ReplaceFrameFull.java, ReplaceFramePartial.java]
#
#String frameNumber,int maxSize
-CMD_UNABLE_TO_COMPRESS_FRAME_SMALL_ENOUGH=\u00A1\u00A1No se ha podido comprimir el fotograma {0} de forma que ocupe {1,number,\#} bytes\!\!
+CMD_UNABLE_TO_COMPRESS_FRAME_SMALL_ENOUGH=No se ha podido comprimir el fotograma {0} de forma que ocupe {1,number,\#} bytes
#[ReplaceFramePartial.java]
-CMD_NO_DIFFERENCE_SKIPPING=No se han encontrado diferencias, omitiendo.
+#
+#String frameNumber
+CMD_NO_DIFFERENCE_SKIPPING=No se han encontrado diferencias en el fotograma {0}, omitiendo.
#[ReplaceFramePartial.java]
#
@@ -1084,7 +1077,9 @@ CMD_ENTIRE_FRAME_DIFFERENT=Advertencia\: Todo el fotograma es distinto.
REPLACE_UNABLE_READ_IMAGE=No se puede cargar {0} como una imagen.
#[ReplaceFramePartial.java]
-REPLACE_FRAME_DIMENSIONS_TOO_SMALL=Las dimensiones del fotograma sustituto son m\u00E1s peque\u00F1as que las del fotograma de origen.
+#
+#int newWidth,int newHeight,int existingWidth,int existingHeight
+REPLACE_FRAME_DIMENSIONS_TOO_SMALL=Las dimensiones del fotograma sustituto ({0,number,\#}x{1,number,\#}) son m\u00E1s peque\u00F1as que las del fotograma de origen ({2,number,\#}x{3,number,\#}).
#[ReplaceFrames.java]
#
@@ -1117,18 +1112,19 @@ REPLACE_FRAME_TYPE_NOT_IKI=El tipo de fotograma no es Iki.
FRAME_NOT_IKI=El fotograma no est\u00E1 en el formato iki.
-#[BitStreamUncompressor_Lain.java]
FRAME_NOT_LAIN=El fotograma no est\u00E1 en el formato Lain.
-#[BitStreamUncompressor_STRv1.java]
FRAME_NOT_STRV1=El fotograma no est\u00E1 en el formato STRv1.
-#[BitStreamUncompressor_STRv2.java]
FRAME_NOT_STRV2=El fotograma no est\u00E1 en el formato STRv2.
-#[BitStreamUncompressor_STRv3.java]
FRAME_NOT_STRV3=El fotograma no est\u00E1 en el formato STRv3.
+#[*]
+#
+#String frameFormatName
+FRAME_IS_NOT_BITSTREAM_FORMAT=El fotograma no est\u00E1 en el formato {0}.
+
#[SectorIkiVideo.java]
#
#int sourceWidth,int sourceHeight,int replaceWidth,int replaceHeight
@@ -1142,19 +1138,17 @@ UNEXPECTED_END_OF_AUDIO=Fin inesperado de los datos de audio
#[BitStreamUncompressor_Iki.java]
#
#int macroBlockX,int macroBlockY,int quantizationScale
-IKI_REDUCING_QSCALE_OF_MB_TO_VAL=Intentando reducir el Qscale de ({0,number,\#},{1,number,\#}) a {2,number,\#}
+IKI_REDUCING_QSCALE_OF_MB_TO_VAL=Intentando reducir la escala de cuantificaci\u00F3n del macrobloque ({0,number,\#},{1,number,\#}) a {2,number,\#}.
#We should try to translate all that's possible to translate, the closest of demux could be extraer.
#
-#[BitStreamUncompressor_Iki.java]
-#
#String frameNumber,int demuxSize,int sourceSize
IKI_NEW_FRAME_GT_SRC_STOPPING=El tama\u00F1o del fotograma nuevo {0} al descomprimir ({1,number,\#}) es superior al tama\u00F1o m\u00E1ximo del origen {2,number,\#}, deteniendo
#[BitStreamUncompressor_Iki.java, BitStreamUncompressor_Lain.java, BitStreamUncompressor_STRv2.java]
#
#String frameNumber,int demuxSize,int sourceSize
-NEW_FRAME_FITS=El tama\u00F1o del fotograma nuevo {0} al descomprimir ({1,number,\#}) es igual o inferior al tama\u00F1o m\u00E1ximo del origen {2,number,\#}
+NEW_FRAME_FITS=El tama\u00F1o del fotograma nuevo {0} ({1,number,\#}) entra en el tama\u00F1o disponible {2,number,\#}.
#[BitStreamUncompressor_Iki.java, BitStreamUncompressor_STRv2.java]
#
@@ -1166,17 +1160,17 @@ END_OF_STREAM=Fin del flujo de datos
#[BitStreamUncompressor_Lain.java]
#
#int lumaQuantizationScale,int chromaQuantizationScale
-TRYING_LUMA_CHROMA=Probando luma {0,number,\#} croma {1,number,\#}
+TRYING_LUMA_CHROMA=Intentando comprimir usando la escala de cuantificaci\u00F3n de luminancia {0,number,\#} y la escala de cuantificaci\u00F3n de croma {1,number,\#}.
#[BitStreamUncompressor_Iki.java, BitStreamUncompressor_Lain.java, BitStreamUncompressor_STRv2.java, ReplaceFrameFull.java]
#
#String frameNumber,int newFrameSize,int sourceFrameSize
-NEW_FRAME_DOES_NOT_FIT=\u00A1\u00A1El tama\u00F1o del fotograma nuevo {0} al descomprimir ({1,number,\#}) es superior al tama\u00F1o m\u00E1ximo del origen {2,number,\#}\!\!
+NEW_FRAME_DOES_NOT_FIT=El tama\u00F1o del fotograma nuevo {0} ({1,number,\#}) no entra en el tama\u00F1o disponible {2,number,\#}.
#[BitStreamUncompressor_Lain.java]
#
#String frameNumber
-COMPRESS_TOO_MUCH_ENERGY=El formato de v\u00EDdeo no admite el tama\u00F1o de los datos nuevos del fotograma {0}
+COMPRESS_TOO_MUCH_ENERGY=El fotograma sustituto {0} tiene demasiados detalles y no puede ser comprimida correctamente.
#int currentWidth,int newWidth
INCONSISTENT_WIDTH=Ancho inconsistente {0,number,\#} \!\= {1,number,\#}
@@ -1184,37 +1178,36 @@ INCONSISTENT_WIDTH=Ancho inconsistente {0,number,\#} \!\= {1,number,\#}
#int currentHeight,int newHeight
INCONSISTENT_HEIGHT=Altura inconsistente {0,number,\#} \!\= {1,number,\#}
-#[VideoSaverBuilderCrusader.java]
+#[PacketBasedVideoSaverBuilder.java]
#
#int audioSampleRate
-EMBEDDED_CRUSADER_AUDIO_HZ=Audio de Crusader incrustado a {0,number,\#} Hz
+CMD_EMBEDDED_PACKET_BASED_AUDIO_HZ=Audio incrustado a {0,number,\#} Hz
CRUSADER_VIDEO_CORRUPTED=V\u00EDdeo de Crusader\: No Remorse corrompido
+#[DiscIndexerPolicenauts.java, SectorClaimToPolicenauts.java]
+POLICENAUTS_DATA_CORRUPTION=Datos de Policenauts corrompidos
+
CRUSADER_AUDIO_CORRUPTED=Audio de Crusader\: No Remorse corrompido
#String frameNumber,int chunkNumber
MISSING_CHUNK=Falta el trozo {1,number,\#} del fotograma {0}.
-#[SectorFrameBuilder.java]
-#
#int sectorNumber,int currentChunkCount,int newChunkCount
DEMUX_FRAME_CHUNKS_CHANGED_FROM_TO=Trozos del fotograma del sector {0,number,\#} cambiados de {1,number,\#} a {2,number,\#}
-#[SectorFrameBuilder.java]
-#
#int sectorNumber,int chunkNumber,int chunksInFrame
DEMUX_CHUNK_NUM_GTE_CHUNKS_IN_FRAME=Trozo del sector {0,number,\#} n\u00FAmero {1,number,\#} >\= trozos en fotograma {2,number,\#}
-#[SectorFrameBuilder.java]
+#[SectorBasedFrameBuilder.java]
#
#int frameStartSector,int frameEndSector,int chunkNumber
MISSING_CHUNK_FRAME_IN_SECTORS=El fotograma de los sectores {0,number,\#}-{1,number,\#} no contiene el trozo {2,number,\#}
#[DemuxedCrusaderFrame.java, SectorBasedFrameReplace.java]
-CMD_FRAME_TO_REPLACE_MISSING_CHUNKS=\u00BFIntentas sustituir un fotograma con trozos incompletos?
+CMD_FRAME_TO_REPLACE_MISSING_CHUNKS=Intentando sustituir un fotograma corrompido.
-#[VDP.java, ReplaceFrameFull.java, ReplaceFramePartial.java]
+#[VDP.java, ReplaceFrameFull.java, ReplaceFramePartial.java, SectorBasedFrameBuilder.java]
#
#String frameNumber
FRAME_NUM_CORRUPTED=Error en el fotograma {0}\: El fotograma est\u00E1 corrompido
@@ -1241,12 +1234,12 @@ UNABLE_TO_DETERMINE_FRAME_TYPE=Error\: No se ha podido determinar el tipo de fot
#[VDP.java]
#
#String frameNumber,int frameCount
-FRAME_NUM_AHEAD_OF_READING=El fotograma {0} se ha adelantado a su lectura por {1,number,\#} {1,choice,1\#fotograma|2\#fotogramas}.
+FRAME_NUM_AHEAD_OF_READING=El fotograma {0} del archivo de v\u00EDdeo aparecer\u00E1 {1,number,\#} {1,choice,1\#fotograma|2\#fotogramas} por delante de su momento original.
#[VDP.java]
#
#int frameCount
-FRAME_AHEAD_OF_READING=El fotograma se ha adelantado a su lectura por {0,number,\#} {0,choice,1\#fotograma|2\#fotogramas}.
+FRAME_AHEAD_OF_READING=El fotograma del archivo de v\u00EDdeo aparecer\u00E1 {0,number,\#} {0,choice,1\#fotograma|2\#fotogramas} por delante de su momento original.
#[VDP.java]
#
@@ -1270,7 +1263,12 @@ JPEG_ENCODER_FRAME_FAIL_NO_FRAME=El codificador JPEG sencillo de jPSXdec no pued
#[VDP.java]
#
#int frameCount
-WRITING_BLANK_FRAMES_TO_ALIGN_AV=Escribiendo {0,number,\#} fotograma(s) en blanco para sincronizar la reproducci\u00F3n de audio y v\u00EDdeo.
+WRITING_BLANK_FRAMES_TO_ALIGN_AV=Escribiendo {0,number,\#} {0,choice,1\#fotograma|2\#fotogramas} en blanco para sincronizar la reproducci\u00F3n de audio y v\u00EDdeo.
+
+#[VDP.java]
+#
+#int frameCount
+WRITING_DUP_FRAMES_TO_ALIGN_AV=Escribiendo {0,number,\#} {0,choice,1\#fotograma|2\#fotogramas} duplicados para sincronizar la reproducci\u00F3n de audio y v\u00EDdeo.
#[VDP.java]
#
@@ -1373,7 +1371,7 @@ CMD_EMULATE_PSX_AV_SYNC_NY=Emular sincron\u00EDa audio/v\u00EDdeo de PSX\: {0,ch
#[VideoSaverBuilder.java]
CMD_NO_AUDIO=Sin sonido
-#[VideoSaverBuilder.java]
+#[VideoSaverBuilder.java, Command_Static.java]
#
#String upsampleDescription
CMD_UPSAMPLE_QUALITY=Interpolaci\u00F3n de croma\: {0}
@@ -1398,6 +1396,16 @@ CMD_FRAME_RANGE_AFTER=Omitir fotogramas posteriores a {0}
#int willCrop
CMD_CROPPING=Recorte\: {0,choice,0\#No|1\#S\u00ED}
+#[VideoSaverBuilder.java]
+#
+#String videoFormatDescription
+CMD_VIDEO_MUST_HAVE_EVEN_DIMS=Las dimensiones del v\u00EDdeo deben ser n\u00FAmeros pares para poder guardarlo como {0}, incrementando su tama\u00F1o en 1 p\u00EDxel.
+
+#[VideoSaverBuilder.java]
+#
+#int width,int height
+CMD_DIMENSIONS=Dimensiones\: {0,number,\#}x{1,number,\#}
+
AVI_CLOSE_ERR=Error al cerrar el archivo AVI
#[VideoSaverBuilder.java]
@@ -1426,13 +1434,9 @@ CMD_VIDEO_UP_HELP=M\u00E9todo para interpolar el croma\n(por defecto {0}). Opcio
#Was reading "Invalid decoding..." instead of "Invalid upsample." Fixing.
#
-#[VideoSaverBuilder.java]
-#
#String badQualityName
CMD_UPSAMPLE_QUALITY_INVALID=Calidad de interpolaci\u00F3n no v\u00E1lida {0}
-#[VideoSaverBuilder.java]
-#
#String badQualityName
CMD_DECODE_QUALITY_INVALID=Calidad de decodificaci\u00F3n no v\u00E1lida {0}
@@ -1450,13 +1454,11 @@ CMD_VIDEO_NOCROP=-nocrop
#[VideoSaverBuilder.java]
CMD_VIDEO_NOCROP_HELP=No recortar los bordes no utilizados en fotogramas.
-#[VideoSaverBuilder.java]
-#
#String badFrameNumberType
CMD_FRAME_NUMBER_TYPE_INVALID=Tipo {0} de n\u00FAmero de fotograma no v\u00E1lido
#[VideoSaverBuilder.java]
-CMD_VIDEO_FRAMES=-frame,-frames \# o \#-\#
+CMD_VIDEO_FRAMES=-start \#, -end \#
#[VideoSaverBuilder.java]
CMD_VIDEO_FRAMES_HELP=Procesa solo los fotogramas en el rango.
@@ -1469,8 +1471,6 @@ CMD_VIDEO_NUM=-num
#ILocalizedMessage frameNumberType
CMD_VIDEO_NUM_HELP=N\u00FAmero de fotogramas para usar al guardar la secuencia\nde im\u00E1genes (por defecto {0}). Opciones\:
-#[VideoSaverBuilder.java]
-#
#String badFormatString
CMD_VIDEO_FORMAT_INVALID=Formato de v\u00EDdeo no v\u00E1lido {0}
@@ -1488,13 +1488,13 @@ CMD_VIDEO_HEADER_FRAME_NUMBER_UNSUPPORTED=El v\u00EDdeo no admite el indexado de
#String badFrameNumberString
CMD_FRAME_RANGE_INVALID=Fotograma(s) no v\u00E1lido(s) {0}
-#[VideoSaverBuilderCrusader.java, VideoSaverBuilderStr.java]
+#[PacketBasedVideoSaverBuilder.java, SectorBasedVideoSaverBuilder.java]
CMD_VIDEO_NOAUD=-noaud
-#[VideoSaverBuilderCrusader.java, VideoSaverBuilderStr.java]
+#[PacketBasedVideoSaverBuilder.java, SectorBasedVideoSaverBuilder.java]
CMD_VIDEO_NOAUD_HELP=No guardar el audio.
-#[VideoSaverBuilderCrusaderGui.java]
+#[PacketBasedVideoSaverBuilderGui.java]
GUI_SAVE_AUDIO_LABEL=Guardar audio\:
#[VideoSaverPanel.java]
@@ -1543,16 +1543,16 @@ GUI_CROP_CHECKBOX=Recorte
#[VideoSaverPanel.java]
GUI_CHROMA_UPSAMPLING_LABEL=Interpolaci\u00F3n de croma\:
-#[VideoSaverBuilderStr.java]
+#[SectorBasedVideoSaverBuilder.java]
CMD_VIDEO_PSXAV=-psxav
-#[VideoSaverBuilderStr.java]
+#[SectorBasedVideoSaverBuilder.java]
CMD_VIDEO_PSXAV_HELP=Emular ritmo de audio/v\u00EDdeo de PSX.
-#[VideoSaverBuilderStrGui.java]
+#[SectorBasedVideoSaverBuilderGui.java]
GUI_EMULATE_PSX_AV_SYNC_LABEL=Emular sincron\u00EDa audio/v\u00EDdeo de PSX\:
-#[VideoSaverBuilderStrGui.java]
+#[SectorBasedVideoSaverBuilderGui.java]
GUI_VID_AUDIO_SAVE_ID_COLUMN=
#[TimPaletteSelector.java]
@@ -1568,13 +1568,9 @@ CMD_PALETTE_IMAGE_SAVE_FAIL=Imposible escribir imagen {0} con la paleta {1,numbe
#String fileFormat
CMD_TIM_SAVE_FORMAT=Formato\: {0}
-#[TimSaverBuilder.java]
-#
#String badFileFormat
CMD_TIM_SAVE_FORMAT_INVALID=Formato {0} no v\u00E1lido
-#[TimSaverBuilder.java]
-#
#String badPaletteList
CMD_TIM_PALETTE_LIST_INVALID=Lista de paletas no v\u00E1lida {0}
@@ -1631,6 +1627,16 @@ TIM_INCOMPATIBLE=El formato del TIM "{0}" no coincide con el formato ya existent
TIM_REPLACE_MULTI_CLUT_UNABLE=No se puede sustituir una imagen TIM multipaleta con una imagen sencilla.
+#[*]
+#
+#String invalidValue,String command
+CMD_INVALID_VALUE_FOR_CMD=Valor {0} no v\u00E1lido para {1}.
+
+#[*]
+#
+#String invalidValue,String command
+CMD_IGNORING_INVALID_VALUE_FOR_CMD=Ignorando valor no v\u00E1lido {0} para {1}.
+
#[*]
#
#String fileName
diff --git a/jpsxdec/src/jpsxdec/i18n/Translations_it.properties b/jpsxdec/src/jpsxdec/i18n/Translations_it.properties
new file mode 100644
index 0000000..b8eda6f
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/i18n/Translations_it.properties
@@ -0,0 +1,1686 @@
+# jPSXdec Translations
+# Copyright (c) 2015-2019
+# Michael Sabin, Víctor González, Sergi Medina, Gianluigi "Infrid" Cusimano
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#[CommandLine.java, DebugFormatter.java, Gui.java, GuiSettings.java, Mdec2Jpeg.java, UserFriendlyLogger.java]
+#
+#String versionNumber
+JPSXDEC_VERSION_NON_COMMERCIAL=jPSXdec\: PSX media decoder (software non commerciale) v{0}
+
+#[Command.java]
+#
+#java.io.File sourceFileName
+CMD_USING_SRC_FILE=Lettura file sorgente {0}
+
+#[Command.java]
+CMD_NEED_INPUT_OR_INDEX=Dovresti indicare un file da analizzare e/o un indice da caricare.
+
+#[Command.java]
+CMD_DISC_FILE_REQUIRED=Per questo comando \u00E8 necessario fornire una immagine del disco.
+
+#[Command.java]
+CMD_INPUT_FILE_REQUIRED=File input richiesto per questo comando.
+
+#[Command.java]
+#
+#int itemCount
+CMD_ITEMS_LOADED={0,number,\#} file caricati.
+
+#[Command.java]
+#
+#String fileName
+CMD_READING_INDEX_FILE=Lettura indice {0}
+
+#[Command.java]
+#
+#java.io.File fileName
+CMD_INPUT_FILE_NOT_FOUND=File non trovato {0}
+
+#String badItemNumber
+CMD_ITEM_NUMBER_INVALID=Numero voce non valido\: {0}
+
+#String badItemIdentifier
+CMD_ITEM_ID_INVALID=Identificativo voce non valido\: {0}
+
+#da rivedere
+#
+#[Command_Items.java]
+#
+#String discItemType
+CMD_NO_ITEMS_OF_TYPE=Spiacente, non \u00E8 stato possibile trovare alcuna voce sul disco di tipo {0}
+
+CMD_DISC_ITEM_NOT_AUDIO_VIDEO_NO_PLAYER=Impossibile riprodurre la voce, non sembra essere un audio o video.
+
+#[Command_Items.java]
+CMD_DISC_ITEM_NOT_VIDEO=La voce non \u00E8 un video
+
+#[Command_Items.java]
+CMD_DISC_ITEM_NOT_XA=La voce non \u00E8 una traccia XA.
+
+#[Command_Items.java]
+CMD_DISC_ITEM_NOT_TIM=La voce non \u00E8 una immagine TIM.
+
+#[Command_Items.java]
+#
+#int discItemIndex
+CMD_DISC_ITEM_NOT_FOUND_NUM=Impossibile trovare la voce {0,number,\#}
+
+#[Command_Items.java]
+#
+#String discItemId
+CMD_DISC_ITEM_NOT_FOUND_STR=Impossibile trovare la voce {0}
+
+#[Command_Items.java]
+CMD_DETAILED_HELP_FOR=Informazioni dettagliate per
+
+#[Command_Items.java]
+#
+#String discItemDescription
+CMD_SAVING=Salvataggio in corso per {0}
+
+#[Command_Items.java]
+CMD_ITEM_COMPLETE=File completato.
+
+#[Command_Items.java]
+CMD_ALL_ITEMS_COMPLETE=Tutti le voci nell'indice sono stati processate.
+
+#[Command_Items.java]
+CMD_PROCESS_COMPLETE=Decodifica/estrazione del disco completata.
+
+#[Command_Items.java, DiscIndex.java]
+#
+#double durationInSeconds
+PROCESS_TIME=Tempo\: {0,number,\#.\#\#} s
+
+#[Command_Items.java, Command_Static.java]
+#
+#int fileCount
+CMD_NUM_FILES_CREATED={0,choice,0\#Nessun file creato|1\#1 un file creato|2\#'{0,number,\#}' file sono stati creati}
+
+#[Command_Items.java]
+CMD_REOPENING_DISC_WRITE_ACCESS=Riapertura immagine disco in scrittura.
+
+#[Command_Items.java]
+CMD_BACKUP_DISC_IMAGE_WARNING=Assicurati di avere una copia di backup, questa operazione \u00E8 irreversibile.
+
+#[Command_Items.java]
+#
+#String badItemNumber
+CMD_XA_REPLACE_BAD_ITEM_NUM=Numero voce {0} XA non valido o mancante.
+
+CMD_CREATING_PLAYER=Creazione player per
+
+CMD_PLAYER_ERR=Errore di riproduzione
+
+#[Command_Items.java]
+#
+#String patchIndexFileName
+CMD_XA_REPLACE_OPENING_PATCH_IDX=Apertura indice patch {0}
+
+#[Command_Items.java, SavingGuiTask.java]
+SAVE_LOG_FILE_BASE_NAME=salvataggi
+
+#[Command.java, CommandLine.java, Gui.java]
+INDEX_LOG_FILE_BASE_NAME=indici
+
+#[Command_Items.java]
+REPLACE_LOG_FILE_BASE_NAME=sostituzioni
+
+#[UserFriendlyLogger.java]
+#
+#String logLevel,String logMessage
+USER_LOG_MESSAGE=[{0}] {1}
+
+#String logLevel,String logMessage,String exceptionName
+USER_LOG_MESSAGE_EXCEPTION=[{0}] {1} {2}
+
+#String logLevel,String logMessage,String exceptionName,String exceptionMessage
+USER_LOG_MESSAGE_EXCEPTION_MSG=[{0}] {1} {2} \: {3}
+
+#String logLevel,String exceptionName
+USER_LOG_EXCEPTION=[{0}] {1}
+
+#String logLevel,String exceptionName,String exceptionMessage
+USER_LOG_EXCEPTION_MSG=[{0}] {1} \: {2}
+
+#String badSectorRangeString
+CMD_SECTOR_RANGE_INVALID=Intervallo settori non valido\: {0}
+
+#[Command_CopySect.java]
+#
+#int startSector,int endSector,String destinationFile
+CMD_COPYING_SECTOR=Copia settori da {0,number,\#} - {1,number,\#} a {2} in corso
+
+#[Command_SectorDump.java]
+CMD_GENERATING_SECTOR_LIST=Generazione lista settori
+
+#[Command_Static.java]
+CMD_DIM_OPTION_REQURIED=opzione -dim richiesta
+
+#String badDimensionsString
+CMD_INVALID_DIMENSIONS=Dimensioni non valice\: {0}
+
+#String badQuality
+CMD_QUALITY_INVALID=Livello di qualit\u00E0 non valido {0}
+
+#[Command_Static.java]
+#
+#ILocalizedMessage qualityName
+CMD_USING_QUALITY=Qualit\u00E0 selezionata {0}
+
+#[Command_Static.java]
+CMD_NOT_TIM=Errore\: non sembra essere una immagine TIM
+
+#ILocalizedMessage upsampleDescription
+CMD_USING_UPSAMPLING=Uso l''interpolazione {0}
+
+#[Command_Static.java]
+CMD_TIM_IO_ERR=Errore di lettura/scrittura file TIM
+
+#String badFormat
+CMD_FORMAT_INVALID=Formato non valido {0}
+
+#[Command_Static.java]
+CMD_ASSERT_DISABLED_NO_DEBUG=Impossibile abilitare la decodifica debug per via delle asserzioni disabilitate.
+
+#[Command_Static.java]
+CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA=Avvia java usando gli switch -ea
+
+#[Command_Static.java]
+#
+#java.io.File timFileName
+CMD_READING_TIM=Lettura file TIM {0}
+
+#String badStaticTypeName
+CMD_STATIC_TYPE_INVALID=Tipo statico non valido\: {0}
+
+#[Command_Static.java]
+CMD_FRAME_CONVERT_OK=Fotogramma convertito correttamente.
+
+#[Command_Static.java]
+#
+#java.io.File fileName
+CMD_READING_STATIC_FILE=Lettura file statico {0}
+
+#[Command_Static.java]
+CMD_IMAGE_CONVERT_OK=Immagine convertita correttamente
+
+#[Command_Static.java, VideoSaverBuilder.java]
+#
+#java.io.File fileName
+CMD_SAVING_AS=Salvataggio in corso\: {0}
+
+#[Command_Visualize.java]
+CMD_GENERATING_VISUALIZATION=Generazione visualizzazione
+
+#[Command_Visualize.java]
+CMD_VISUALIZATION_ERR=Errore durante la lettura/scritta della visualizzazione
+
+#[Command.java]
+#
+#ILocalizedMessage localizedDetails
+ERR_LOADING_INDEX_FILE_REASON=Errore caricamento file indice\: {0}
+
+#[CommandLine.java]
+#
+#int itemCount
+CMD_NUM_ITEMS_FOUND={0,number,\#} file trovati
+
+#[CommandLine.java]
+CMD_BUILDING_INDEX=Creazione indice
+
+CMD_DISC_READ_ERROR=Errore lettura disco.
+
+#String badVerbosityLevel
+CMD_VERBOSE_LVL_INVALID_STR=Livello verbosit\u00E0 non valido {0}
+
+#int badVerbosityNumber
+CMD_VERBOSE_LVL_INVALID_NUM=Livello di verbosit\u00E0 non valido {0,number,\#}
+
+#[CommandLine.java]
+#
+#String fileName
+CMD_SAVING_INDEX=Salvataggio indice come {0}
+
+#[CommandLine.java]
+CMD_TRY_HELP=Prova -? per aiuto.
+
+#[CommandLine.java]
+CMD_NOT_SAVING_EMPTY_INDEX=Nessun voce trovata, inutile creare un indice
+
+#[CommandLine.java, Command_Items.java]
+#
+#java.lang.Throwable errorMessage,String exceptionType
+CMD_ERR_EX_CLASS=ERRORE\: {0} ({1})
+
+#[CommandLine.java]
+CMD_NEED_MAIN_COMMAND=Necessito un comando principale.
+
+#[CommandLine.java]
+#
+#ILocalizedMessage discFormatDescription
+CMD_DISC_IDENTIFIED=Identificato come {0}
+
+#[CommandLine.java]
+CMD_COMMAND_NEEDS_DISC=Il comando ha bisogno di un file disco
+
+#[CommandLine.java]
+CMD_TOO_MANY_MAIN_COMMANDS=Troppi comandi principali.
+
+#String fileName
+CMD_FILE_NOT_FOUND_FILE=File non trovato {0}
+
+#[CommandLine.java, IndexingGui.java]
+#
+#String cdFileDescription
+CMD_GUI_INDEXING=Indicizzando {0}
+
+#[ConsoleProgressLogger.java]
+#
+#String progressBar,double percentComplete,int warningCount,int errorCount
+CMD_PROGRESS=[{0}] {1,number,\#%}{2,choice,0\#|1\# '{2,number,\#}' '{2,choice,0\#avvertimenti|1\#avvertimento|1 {1,number,\#}
+
+#int sectorNumber
+INDEX_MODE1_AMONG_MODE2=Il settore {0,number,\#} Mode 1 \u00E8 stato trovato insieme a settori Mode 2
+
+#[DiscIndex.java]
+#
+#String lineFromIndexFile,ILocalizedMessage localizedErrorMessage
+INDEX_PARSE_LINE_FAIL=Impossibile interpretare "{0}" per via di "{1}"
+
+#[DiscIndex.java]
+#
+#String lineFromIndexFile
+INDEX_UNHANDLED_LINE=Linea non rinosciuta {0}
+
+#[DiscIndex.java]
+#
+#String discFileIdentifier
+INDEX_MULTIPLE_CD=L''indice contiene molte righe che iniziano per "{0}"
+
+#[DiscIndex.java]
+#
+#String discFileIdentifier
+INDEX_NO_CD=L''indice manca di una riga che inizia per "{0}", nessun file sorgente \u00E8 stato fornito.
+
+#[DiscIndex.java]
+INDEX_INCONSTSTENCIES=Trovate inconsistenze nell'indice, per caso \u00E8 stato modificato?
+
+#[DiscIndex.java]
+#
+#int currentSectorNumber,int totalSectorCount,int itemsFound
+INDEX_SECTOR_ITEM_PROGRESS=Settore {0,number,\#} / {1,number,\#} {2,number,\#} voci trovate
+
+#[DiscIndex.java]
+#
+#String lineCommentCharacter
+INDEX_COMMENT={0} Le righe che iniziano per {0} verranno ignorate
+
+#[DiscIndexerXaAudio.java]
+#
+#int sectorNumber,int channelNumber
+IGNORING_SILENT_XA_SECTOR=Ignoro la traccia audio XA muta che dura per un intero settore {0,number,\#}, canale {1,number,\#}
+
+#[DiscItem.java]
+ITEM_TYPE_VIDEO=Video
+
+#[DiscItem.java]
+ITEM_TYPE_VIDEO_APPLY=Video
+
+#[DiscItem.java]
+ITEM_TYPE_FILE=File
+
+#[DiscItem.java]
+ITEM_TYPE_FILE_APPLY=File (tutti)
+
+#[DiscItem.java]
+ITEM_TYPE_AUDIO=Audio
+
+#[DiscItem.java]
+ITEM_TYPE_AUDIO_APPLY=Audio (tutti)
+
+#[DiscItem.java]
+ITEM_TYPE_IMAGE=Immagine
+
+#[DiscItem.java]
+ITEM_TYPE_IMAGE_APPLY=Immagini
+
+#[DiscItem.java]
+ITEM_TYPE_SOUND=Clip audio
+
+#[DiscItem.java]
+ITEM_TYPE_SOUND_APPLY=Clip audio (tutti)
+
+#[DiscItemPacketBasedVideoStream.java]
+#
+#int videoWidth,int videoHeight,int frameCount,double framesPerSecond,java.util.Date duration
+GUI_PACKET_BASED_VID_DETAILS={0,number,\#}x{1,number,\#}, {2,number,\#} fotogrammi, {3,number,\#} fps \= {4,time,m\:ss}
+
+#[DiscItemPacketBasedVideoStream.java]
+#
+#int videoWidth,int videoHeight,int frameCount,double framesPerSecond,java.util.Date duration,int audioHz
+GUI_PACKET_BASED_VID_DETAILS_WITH_AUDIO={0,number,\#}x{1,number,\#}, {2,number,\#} fotogrammi, {3,number,\#.\#\#\#} fps \= {4,time,m\:ss}, {5,number,\#} Hz
+
+#java.util.Date duration,int sampleRate
+GUI_SQUARE_AUDIO_DETAILS={0,time,m\:ss}, {1,number,\#} Hz Stereo
+
+#[DiscItemSectorBasedVideoStream.java]
+#
+#int videoWidth,int videoHeight,int frameCount,double doubleSpeedFramesPerSecond,java.util.Date doubleSpeedDuration,double singleSpeedFramesPerSecond,java.util.Date singleSpeedDuration
+GUI_STR_VIDEO_DETAILS_UNKNOWN_FPS={0,number,\#}x{1,number,\#}, {2,number,\#} fotogrammi, {3,number,\#.\#\#\#} fps \= {4,time,m\:ss} (or {5,number,\#.\#\#\#} fps \= {6,time,m\:ss})
+
+#[DiscItemSectorBasedVideoStream.java]
+#
+#int videoWidth,int videoHeight,int frameCount,double framesPerSecond,java.util.Date duration
+GUI_STR_VIDEO_DETAILS={0,number,\#}x{1,number,\#}, {2,number,\#} fotogrammi, {3,number,\#.\#\#\#} fps \= {4,time,m\:ss}
+
+#[DiscItemISO9660File.java]
+#
+#long fileSize
+GUI_ISOFILE_DETAILS={0} byte
+
+#[DiscItemISO9660File.java]
+#
+#int rawBytesPerSector
+CMD_ISOFILE_ISO_HELP=-raw salva come dati grezzi {0,number,\#} byte/settore (2048 \u00E8 il valore predefinito)
+
+#[DiscItemISO9660File.java]
+CMD_ISOFILE_HELP_NO_OPTIONS=[nessuna opzione disponibile]
+
+#[DiscItemISO9660File.java]
+#
+#int rawBytesPerSector
+CMD_ISOFILE_SAVING_RAW=Salvataggio raw {0,number,\#} byte/settore
+
+#[DiscItemISO9660File.java]
+CMD_ISOFILE_SAVING_2048=Salvataggio col normale 2048 byte/settore
+
+#[DiscItemISO9660File.java]
+GUI_ISOFILE_SAVE_2048=Normale 2048 byte/settore
+
+#[DiscItemISO9660File.java]
+GUI_ISOFILE_SAVE_RAW=Raw
+
+#[DiscItemISO9660File.java]
+#
+#int rawSectorSize
+GUI_ISOFILE_SAVE_RAW_SIZE=Raw {0,number,\#} byte/settore
+
+#[DiscIndex.java, DiscIndexerISO9660.java, DiscItemISO9660File.java]
+#
+#String itemDescription
+NOT_CONTAINED_IN_DISC={0} non \u00E8 completamente dentro i limiti del formato CD/file, l''estrazione comportet\u00E0 errori.
+
+#[DiscIndexerISO9660.java]
+#
+#String fileName
+ISO_FILE_CORRUPTED_IGNORING=Le informazioni del file disco {0} sono corrotte, ignoro
+
+#[DiscItemISO9660File.java, AudioSaverBuilderGui.java, SpuSaverBuilderGui.java, TimSaverBuilderGui.java, VideoSaverPanel.java]
+GUI_SAVE_AS_LABEL=Salva come\:
+
+#[AudioSaverBuilder.java, SpuSaverBuilder.java]
+#
+#ILocalizedMessage audioFormat
+CMD_AUDIO_FORMAT=Formato\: {0}
+
+#[AudioSaverBuilder.java, SpuSaverBuilder.java]
+#
+#double volumeLevelPercent
+CMD_VOLUME_PERCENT=Volume\: {0,number,\#%}%
+
+#[AudioSaverBuilder.java, SpuSaverBuilder.java]
+#
+#java.io.File fileName
+CMD_FILENAME=Nome file\: {0}
+
+#[AudioSaverBuilder.java, SpuSaverBuilder.java]
+CMD_AUDIO_AF=-audfmt,-af
+
+#[AudioSaverBuilder.java, SpuSaverBuilder.java]
+#
+#String defaultAudioFormatName
+CMD_AUDIO_AF_HELP=Formato output audio (default {0}). Opzioni\:
+
+#[AudioSaverBuilder.java, SpuSaverBuilder.java]
+CMD_AUDIO_VOL=-vol <0-100>
+
+#[AudioSaverBuilder.java, SpuSaverBuilder.java]
+#
+#int defaultVolumeLevel
+CMD_AUDIO_VOL_HELP=Regola volume (default {0,number,\#}).
+
+#[SpuSaverBuilder.java]
+#
+#String invalidFormatName
+CMD_IGNORING_INVALID_FORMAT=Ignoro formato non valido {0}
+
+#[SpuSaverBuilder.java]
+#
+#String invalidVolume
+CMD_IGNORING_INVALID_VOLUME=Ignoro valore volume non valido {0}
+
+#String badDiscSpeed
+CMD_IGNORING_INVALID_DISC_SPEED=Ignoro velocit\u00E0 di lettura non valida {0}
+
+GUI_VOLUME_LABEL=Volume\:
+
+AVI_FILE_IS_CLOSED=File AVI chiuso
+
+#[DiscItemXaAudioStream.java, SquareAudioSectorPair.java]
+#
+#long startOfSamples,String sectorDescription
+WRITING_SAMPLES_TO_SECTOR=Scrittura campioni da {0,number,\#} al settore {1}
+
+#[DiscItemSquareAudioStream.java, DiscItemXaAudioStream.java]
+#
+#int sectorNumber
+CMD_PATCHING_SECTOR_NUMBER=Applico la patch al settore {0,number,\#}
+
+#[DiscItemXaAudioStream.java]
+#
+#String sectorDescription
+CMD_PATCHING_SECTOR_DESCRIPTION=Applico la patch al settore {0}
+
+#[DiscItemXaAudioStream.java]
+#
+#String otherSectorDescription
+CMD_PATCHING_WITH_SECTOR_DESCRIPTION=con questo settore {0}
+
+#[DiscItemXaAudioStream.java]
+#
+#String fieldName,int badFieldNumberValue
+FIELD_HAS_INVALID_VALUE_NUM=il campo {0} ha un valore non valido\: {1,number,\#}
+
+#[DiscItemXaAudioStream.java, SerializedDiscItem.java]
+#
+#String fieldName,String badFieldStringValue
+FIELD_HAS_INVALID_VALUE_STR=Il campo {0} ha un valore non valido\: {1}
+
+#[SectorXaAudioToAudioPacket.java]
+#
+#int sectorNumber,long firstBadSample
+XA_AUDIO_CORRUPTED=audio XA corrotto al settore {0,number,\#}, i campionamenti dopo {1,number,\#} saranno afflitti
+
+#[CrusaderPacketToFrameAndAudio.java, SquareAudioSectorPairToAudioPacket.java]
+#
+#int approximateSectorNumber,long firstBadSample
+SPU_ADPCM_CORRUPTED=Audio corrotto vicino al settore {0,number,\#}, i campionamenti dopo {1,number,\#} saranno afflitti
+
+#[DiscItemSquareAudioStream.java, DiscItemXaAudioStream.java]
+#
+#java.util.Date duration,int audioSampleRate,int audioChannelCount
+GUI_AUDIO_DESCRIPTION={0,time,m\:ss}, {1,number,\#} Hz {2,choice,1\#Mono|2\#Stereo}
+
+#[DiscItemXaAudioStream.java]
+#
+#String discItemDescription
+CMD_PATCHING_DISC_ITEM=Applico la patch {0}
+
+#[DiscItemXaAudioStream.java]
+#
+#String otherDiscItemDescription
+CMD_PATCHING_WITH_DISC_ITEM=con {0}
+
+#[DiscItemXaAudioStream.java]
+#
+#int newBitsPerSample,long newSampleCount,int newChannelCount,int newSamplesPerSecond,int existingBitsPerSample,long existingSampleCount,int existingChannelCount,int existingSamplesPerSecond
+XA_REPLACE_FORMAT_MISMATCH=Discrepanza audio XA\: nuova traccia audio XA ({0,number,\#} bit/campione, {1,number} {2,choice,1\#Mono|2\#Stereo} frequenza {3,number}Hz) non corrisponde alla traccia esistente ({4,number,\#} bit/campione, {5,number} {6,choice,1\#Mono|2\#Stereo} frequenza {7,number}Hz)
+
+#[DiscItemSquareAudioStream.java, DiscItemXaAudioStream.java]
+#
+#long newSampleCount,int newChannelCount,float newSampleRate,long existingSamleCount,int existingChannelCount,int existingSampleRate
+AUDIO_REPLACE_FORMAT_MISMATCH=Discrepanza audio\: nuovo audio ({0,number,\#} {1,choice,1\#Mono|2\#Stereo} campionato a {2,number,\#.\#}Hz) non corrisponde all''audio esistente ({3,number,\#} {4,choice,1\#Mono|2\#Stereo} campionamento a {5,number,\#.\#}Hz)
+
+#float incompatibleAudioSampleRate,int xaAudioSampleRate
+XA_COPY_REPLACE_SAMPLE_RATE_MISMATCH=La frequenza di campionamneto {0} non corrisponde a quella della traccia XA {1}
+
+#int replaceChannelCount,int sourceChannelCount
+XA_COPY_REPLACE_CHANNEL_MISMATCH=Il file audio \u00E8 {0,choice,1\#Mono|2\#Stereo} mentre la traccia XA ha invece {1,choice,1\#Mono|2\#Stereo}
+
+XA_ENCODE_REPLACE_SRC_AUDIO_EXHAUSTED=La traccia audio \u00E8 terminata, continuo usando il silenzio.
+
+#[DiscItemXaAudioStream.java]
+XA_COPY_REPLACE_SRC_XA_EXHAUSTED=Fine del file XA di origine, completamento in corso
+
+#[FrameLookup.java, FrameNumberNumber.java]
+#
+#String badFrameNumberString
+FRAME_NUM_INVALID=Numero fotogramma non valido {0}
+
+#[FrameNumber.java]
+FRAME_NUM_FORMAT_INDEX=Indice
+
+#[FrameNumber.java]
+FRAME_NUM_FORMAT_SECTOR=Settore
+
+#[FrameNumber.java]
+FRAME_NUM_FORMAT_HEADER=Header
+
+#[FrameNumber.java]
+#
+#String formattedSectorNumber
+FRAME_NUM_FORMATTER_SECTOR=Settore {0}
+
+#[FrameNumber.java]
+#
+#String formattedFrameNumber
+FRAME_NUM_FORMATTER_FRAME=Fotogramma {0}
+
+#String badFrameNumberFormat
+FRAME_NUM_FORMAT_INVALID=Formato numero frame non valido {0}
+
+#[VideoSaver.java]
+#
+#int frameNumber
+FRAME_MISSING_FRAME_NUMBER_HEADER=Il fotogramma {0,number,\#} manca di informazioni riguardo il numero
+
+#[HeaderFrameNumber.java, IndexSectorFrameNumber.java, VideoFileNameFormatter.java]
+FRAMES_UNEXPECTED_NUMBER=Sono stati trovati un numero inaspettato di fotogrammi, questi potrebbero essere salvati in ordine incostitente.
+
+#[MdecDecodeQuality.java]
+QUALITY_HIGH_DESCRIPTION=Alta qualit\u00E0 (pi\u00F9 lento)
+
+#[MdecDecodeQuality.java]
+QUALITY_HIGH_COMMAND=alta
+
+#[MdecDecodeQuality.java]
+QUALITY_FAST_DESCRIPTION=Veloce (bassa qualit\u00E0)
+
+#[MdecDecodeQuality.java]
+QUALITY_FAST_COMMAND=bassa
+
+#[MdecDecodeQuality.java]
+QUALITY_PSX_DESCRIPTION=Emula la qualit\u00E0 della PSX (bassa)
+
+#[MdecDecodeQuality.java]
+QUALITY_PSX_COMMAND=psx
+
+#[ChromaUpsample.java]
+CHROMA_UPSAMPLE_BICUBIC_DESCRIPTION=Bicubico
+
+#[ChromaUpsample.java]
+CHROMA_UPSAMPLE_BICUBIC_CMDLINE=Bicubico
+
+#[ChromaUpsample.java]
+CHROMA_UPSAMPLE_BELL_DESCRIPTION=Gaussiana
+
+#[ChromaUpsample.java]
+CHROMA_UPSAMPLE_BELL_CMDLINE=Gaussiana
+
+#[ChromaUpsample.java]
+CHROMA_UPSAMPLE_NEAR_NEIGHBOR_DESCRIPTION=Nearest Neighbor
+
+#[ChromaUpsample.java]
+CHROMA_UPSAMPLE_NEAR_NEIGHBOR_CMDLINE=NearestNeighbor
+
+#[ChromaUpsample.java]
+CHROMA_UPSAMPLE_LANCZOS3_DESCRIPTION=Lanczos3
+
+#[ChromaUpsample.java]
+CHROMA_UPSAMPLE_LANCZOS3_CMDLINE=Lanczos3
+
+#[ChromaUpsample.java]
+CHROMA_UPSAMPLE_MITCHELL_DESCRIPTION=Mitchell
+
+#[ChromaUpsample.java]
+CHROMA_UPSAMPLE_MITCHELL_CMDLINE=Mitchell
+
+#[ChromaUpsample.java]
+CHROMA_UPSAMPLE_HERMITE_DESCRIPTION=Hermite
+
+#[ChromaUpsample.java]
+CHROMA_UPSAMPLE_HERMITE_CMDLINE=Hermite
+
+#[ChromaUpsample.java]
+CHROMA_UPSAMPLE_BSPLINE_DESCRIPTION=BSpline
+
+#[ChromaUpsample.java]
+CHROMA_UPSAMPLE_BSPLINE_CMDLINE=BSpline
+
+#[ChromaUpsample.java]
+CHROMA_UPSAMPLE_BILINEAR_DESCRIPTION=Bilineare
+
+#[ChromaUpsample.java]
+CHROMA_UPSAMPLE_BILINEAR_CMDLINE=Bilineare
+
+#[ChromaUpsample.java]
+#
+#ILocalizedMessage commandLineId,ILocalizedMessage interplationName
+CHROMA_UPSAMPLE_CMDLINE_HELP={0} ({1})
+
+#[ReplaceFrameFull.java]
+#
+#String imageFile,int sourceWidth,int sourceHeight,int replaceWidth,int replaceHeight
+REPLACE_FRAME_DIMENSIONS_MISMATCH=Il fotogramma di rimpiazzo {0} ha una risoluzione di {1,number,\#}x{2,number,\#} e non combacia con quello di destinazione {3,number,\#}x{4,number,\#}
+
+#[ReplaceFrameFull.java]
+#
+#java.io.File bitstreamFile
+REPLACE_BITSTREAM_MISMATCH=Il tipo di fotogramma del file {0} non corrisponde a quello esistente
+
+#[ReplaceFrameFull.java]
+#
+#String mdecFileName,String frameNumber
+REPLACE_INCOMPATIBLE_MDEC=File mdec {0} non compatibile per il fotogramma {1}
+
+#[ReplaceFrameFull.java]
+#
+#String mdecFileName,String frameNumber
+REPLACE_INCOMPLETE_MDEC=File mdec {0} non completo per il fotogramma {1}
+
+#[ReplaceFrameFull.java]
+#
+#String mdecFileName,String frameNumber
+REPLACE_CORRUPTED_MDEC=File mdec {0} corrotto per il fotogramma {1}
+
+#[ReplaceFrameFull.java]
+#
+#String badFormatName
+REPLACE_INVALID_IMAGE_FORMAT=Formato file dell''immagine di rimpiazzo non valido {0}
+
+#[ReplaceFrameFull.java]
+#
+#java.io.File fileName
+REPLACE_FILE_NOT_JAVA_IMAGE=Impossibile leggere {0} come una immagine. Per caso hai dimenticato di specificare il formato nelle opzioni del file XML?
+
+CMD_UNABLE_TO_IDENTIFY_FRAME_TYPE=Impossibile identificare il tipo di fotogramma
+
+#[ReplaceFrameFull.java, ReplaceFramePartial.java]
+#
+#String frameNumber,int maxSize
+CMD_UNABLE_TO_COMPRESS_FRAME_SMALL_ENOUGH=Impossibile comprimere oltre il fotogramma {0} per farlo stare entro {1,number,\#} byte\!
+
+#[ReplaceFramePartial.java]
+#
+#String frameNumber
+CMD_NO_DIFFERENCE_SKIPPING=Nessuna differenza trovata {0}, salto.
+
+#[ReplaceFramePartial.java]
+#
+#int differenceCount
+CMD_REPLACE_FOUND_DIFFERENT_MACRO_BLOCKS=Trovato un numero differente di macroblocchi {0,number,\#} invece che 16x16
+
+#[ReplaceFramePartial.java]
+CMD_ENTIRE_FRAME_DIFFERENT=Attenzione\: L'intero fotogramma \u00E8 differente
+
+#[ReplaceFramePartial.java]
+#
+#String fileName
+REPLACE_UNABLE_READ_IMAGE=Impossibile caricare {0} come immagine
+
+#[ReplaceFramePartial.java]
+#
+#int newWidth,int newHeight,int existingWidth,int existingHeight
+REPLACE_FRAME_DIMENSIONS_TOO_SMALL=La dimensione del fotogramma di rimpiazzo {0,number,\#}x{1,number,\#} \u00E8 pi\u00F9 piccola di quella della sorgente {2,number,\#}x{3,number,\#}
+
+#[ReplaceFrames.java]
+#
+#String frameNumber,java.io.File fileName
+CMD_REPLACING_FRAME_WITH_FILE=Sostizione fotogramma {0} con {1}
+
+#[ReplaceFrames.java]
+#
+#String xmlErrorInEnglish
+REPLACE_FRAME_XML_ERROR=Errore sul file XML del fotogramma di rimpiazzo\: {0}
+
+#[ReplaceFrames.java]
+#
+#String xmlRootNodeName
+CMD_REPLACE_XML_INVALID_ROOT_NODE=Elemento radice non valido {0}
+
+#[ReplaceFrames.java]
+#
+#String versionNumber
+CMD_REPLACE_XML_INVALID_VERSION=Versione non valida {0}
+
+#[SectorStrVideo.java]
+REPLACE_FRAME_TYPE_NOT_V2_V3=Il tipo di fotogramma non \u00E8 SRTv2 o STRv3
+
+#[SectorFF9.java]
+REPLACE_FRAME_TYPE_NOT_V2=Il tipo di fotogramma non \u00E8 STRv2
+
+#[SectorIkiVideo.java]
+REPLACE_FRAME_TYPE_NOT_IKI=Il tipo di fotogramma non \u00E8 Iki
+
+FRAME_NOT_IKI=Il fotogramma non \u00E8 in formato Iki
+
+FRAME_NOT_LAIN=Il fotogramma non in formato Lain
+
+FRAME_NOT_STRV1=Il fotogramma non in formato STRv1
+
+FRAME_NOT_STRV2=Il fotogramma non in formato STRv2
+
+FRAME_NOT_STRV3=Il fotogramma non in formato STRv3
+
+#[*]
+#
+#String frameFormatName
+FRAME_IS_NOT_BITSTREAM_FORMAT=Il fotogramma non \u00E8 in formato {0}
+
+#[SectorIkiVideo.java]
+#
+#int sourceWidth,int sourceHeight,int replaceWidth,int replaceHeight
+REPLACE_FRAME_IKI_DIMENSIONS_MISMATCH=Dimensioni fotogramma iki non corrisponde alla dimensione del settore\: {0,number,\#}x{1,number,\#} \!\= {2,number,\#}x{3,number,\#}
+
+#[SectorLainVideo.java]
+REPLACE_FRAME_TYPE_NOT_LAIN=Dati incompatibili con Lain
+
+UNEXPECTED_END_OF_AUDIO=Inaspettata fine dei dati audio
+
+#[BitStreamUncompressor_Iki.java]
+#
+#int macroBlockX,int macroBlockY,int quantizationScale
+IKI_REDUCING_QSCALE_OF_MB_TO_VAL=Provo a ridurre la scala dei macroblocchi da ({0,number,\#},{1,number,\#}) a {2,number,\#}
+
+#String frameNumber,int demuxSize,int sourceSize
+IKI_NEW_FRAME_GT_SRC_STOPPING=Nuovo fotogramma {0} demux size {1,number,\#} maggiore del max source {2,number,\#}, interruzione.
+
+#[BitStreamUncompressor_Iki.java, BitStreamUncompressor_Lain.java, BitStreamUncompressor_STRv2.java]
+#
+#String frameNumber,int demuxSize,int sourceSize
+NEW_FRAME_FITS=La dimensione {1,number,\#} del nuovo fotogramma {0} entra nello spazio disponibile {2,number,\#}.
+
+#[BitStreamUncompressor_Iki.java, BitStreamUncompressor_STRv2.java]
+#
+#int quantizationScale
+TRYING_QSCALE=Provo {0,number,\#}
+
+END_OF_STREAM=Fine dello stream dati
+
+#[BitStreamUncompressor_Lain.java]
+#
+#int lumaQuantizationScale,int chromaQuantizationScale
+TRYING_LUMA_CHROMA=Provo a comprimere la luminanza con un fattore di quantizzazione {0,number,\#} e crominanza {1,number,\#}
+
+#[BitStreamUncompressor_Iki.java, BitStreamUncompressor_Lain.java, BitStreamUncompressor_STRv2.java, ReplaceFrameFull.java]
+#
+#String frameNumber,int newFrameSize,int sourceFrameSize
+NEW_FRAME_DOES_NOT_FIT=La dimensione {1,number,\#} del nuovo fotogramma {0} NON entra nello spazio disponibile {2,number,\#}.
+
+#[BitStreamUncompressor_Lain.java]
+#
+#String frameNumber
+COMPRESS_TOO_MUCH_ENERGY=Il formato video non pu\u00F2 gestire la complessit\u00E0 dei nuovi dati per il frame {0}
+
+#int currentWidth,int newWidth
+INCONSISTENT_WIDTH=Larghezza discrepante {0,number,\#} \u00E8 diverso da {1,number,\#}
+
+#int currentHeight,int newHeight
+INCONSISTENT_HEIGHT=Altezza discrepante\: {0,number,\#} \u00E8 diverso da {1,number,\#}
+
+#[PacketBasedVideoSaverBuilder.java]
+#
+#int audioSampleRate
+CMD_EMBEDDED_PACKET_BASED_AUDIO_HZ=Audio Embedded {0,number,\#} Hz
+
+CRUSADER_VIDEO_CORRUPTED=Video corrotto per "Crusader\: No Remorse"
+
+#[DiscIndexerPolicenauts.java, SectorClaimToPolicenauts.java]
+POLICENAUTS_DATA_CORRUPTION=Corruzione dati per Policenauts
+
+CRUSADER_AUDIO_CORRUPTED=Audio corrotto per "Crusader\: No Remorse"
+
+#String frameNumber,int chunkNumber
+MISSING_CHUNK=Al fotogramma {0} manca la parte {1,number,\#}.
+
+#int sectorNumber,int currentChunkCount,int newChunkCount
+DEMUX_FRAME_CHUNKS_CHANGED_FROM_TO=Sector {0,number,\#} chunks in frame changed from {1,number,\#} to {2,number,\#}
+
+#int sectorNumber,int chunkNumber,int chunksInFrame
+DEMUX_CHUNK_NUM_GTE_CHUNKS_IN_FRAME=Sector {0,number,\#} chunk number {1,number,\#} >\= chunks in frame {2,number,\#}
+
+#[SectorBasedFrameBuilder.java]
+#
+#int frameStartSector,int frameEndSector,int chunkNumber
+MISSING_CHUNK_FRAME_IN_SECTORS=Fotogramma in settori {0,number,\#}-{1,number,\#} manca di un pezzo {2,number,\#}
+
+#[DemuxedCrusaderFrame.java, SectorBasedFrameReplace.java]
+CMD_FRAME_TO_REPLACE_MISSING_CHUNKS=Provo a rimpiazzare un fotogramma corrotto esistente
+
+#[VDP.java, ReplaceFrameFull.java, ReplaceFramePartial.java, SectorBasedFrameBuilder.java]
+#
+#String frameNumber
+FRAME_NUM_CORRUPTED=Errore col fotogramma {0}\: Pare sia corrotto
+
+#[VDP.java]
+FRAME_CORRUPTED=Errore\: fotogramma corrotto
+
+#[ReplaceFrameFull.java, ReplaceFramePartial.java, VDP.java]
+#
+#String frameNumber
+FRAME_NUM_INCOMPLETE=Errore col fotogramma {0}\: Pare sia incompleto
+
+#[VDP.java]
+FRAME_INCOMPLETE=Erroe\: Fotogramma incompleto
+
+#[ReplaceFrameFull.java, ReplaceFramePartial.java, VDP.java]
+#
+#String frameNumber
+UNABLE_TO_DETERMINE_FRAME_TYPE_FRM=Errore col fotogramma {0}\: Impossibile determinare il tipo.
+
+#[VDP.java]
+UNABLE_TO_DETERMINE_FRAME_TYPE=Errore\: Impossibile determinare il tipo di fotogramma.
+
+#[VDP.java]
+#
+#String frameNumber,int frameCount
+FRAME_NUM_AHEAD_OF_READING=Fotogramma {0} \u00E8 in anticipo sulla lettura di {1,number,\#} {1,choice,1\#frame|2\#frames}.
+
+#[VDP.java]
+#
+#int frameCount
+FRAME_AHEAD_OF_READING=Fotogramma in anticipo sulla lettura di {0,number,\#} {0,choice,1\#frame|2\#frames}.
+
+#[VDP.java]
+#
+#String fileName,String frameNumber
+FRAME_FILE_WRITE_UNABLE=Impossibile scrivere il file {0} per il fotogramma {1}
+
+#String formatIdentifier
+VIDEO_FMT_IDENTIFIED=Formato video identificato come {0}
+
+#String frameNumber
+FRAME_UNCOMPRESS_ERR=Errore decompressione del fotogramma {0}
+
+#[VDP.java]
+#
+#String frameNumber
+JPEG_ENCODER_FRAME_FAIL=jPSXdec non pu\u00F2 gestire la codifica JPEG per il fotogramma {0}. Si prega di usare un altro formato.
+
+#[VDP.java]
+JPEG_ENCODER_FRAME_FAIL_NO_FRAME=jPSXdec non pu\u00F2 gestire la codifica JPEG per il fotogramma. Si prega di usare un altro formato.
+
+#[VDP.java]
+#
+#int frameCount
+WRITING_BLANK_FRAMES_TO_ALIGN_AV=Scrittura di {0,number,\#} {0,choice,1\#fotogramma vuoto|2\#fotogrammi vuoti} per poter sincronizzare audio/video.
+
+#[VDP.java]
+#
+#int frameCount
+WRITING_DUP_FRAMES_TO_ALIGN_AV=Scrittura {0,number,\#} {0,choice,1\#fotogramma duplicato|2\#fotogrammi duplicati} per sincronizzare audio/video.
+
+#[VDP.java]
+#
+#java.io.File fileName,String frameNumber
+FRAME_WRITE_ERR=Errore salvataggio del file {0} per il fotogramma {1}
+
+#[VDP.java]
+#
+#long sampleCount
+WRITING_SILECE_TO_SYNC_AV=Scrittura di {0,number,\#} campioni audio muti per poter sincronizzare audio/video.
+
+#[VDP.java]
+#
+#long sampleCount
+WRITING_SILENCE_TO_KEEP_AV_SYNCED=Aggiungo {0,number,\#} campioni audio vuoti per tenere la sincronizzazione.
+
+#[VideoFormat.java]
+VID_IMG_SEQ_PNG_DESCRIPTION=Sequenza immagini\: PNG
+
+#[VideoFormat.java]
+VID_IMG_SEQ_PNG_COMMAND=png
+
+#[VideoFormat.java]
+VID_AVI_MJPG_DESCRIPTION=AVI\: Compressione MJPG
+
+#[VideoFormat.java]
+VID_AVI_MJPG_COMMAND=avi\:mjpg
+
+#[VideoFormat.java]
+VID_AVI_RGB_DESCRIPTION=AVI\: Non compresso in RGB
+
+#[VideoFormat.java]
+VID_AVI_RGB_COMMAND=avi\:rgb
+
+#[VideoFormat.java]
+VID_IMG_SEQ_BMP_DESCRIPTION=Sequenza immagini\: BMP
+
+#[VideoFormat.java]
+VID_IMG_SEQ_BMP_COMMAND=bmp
+
+#[VideoFormat.java]
+VID_IMG_SEQ_MDEC_DESCRIPTION=Sequenza immagini\: mdec
+
+#[VideoFormat.java]
+VID_IMG_SEQ_MDEC_COMMAND=mdec
+
+#[VideoFormat.java]
+VID_AVI_JYUV_DESCRIPTION=AVI\: YUV con raggio 0-255
+
+#[VideoFormat.java]
+VID_AVI_JYUV_COMMAND=avi\:jyuv
+
+#[VideoFormat.java]
+VID_IMG_SEQ_JPG_DESCRIPTION=Sequenza immagini\: JPG
+
+#[VideoFormat.java]
+VID_IMG_SEQ_JPG_COMMAND=jpg
+
+#[VideoFormat.java]
+VID_IMG_SEQ_BS_DESCRIPTION=Sequenza immagini\: bitstream
+
+#[VideoFormat.java]
+VID_IMG_SEQ_BS_COMMAND=bs
+
+#[VideoFormat.java]
+VID_AVI_YUV_DESCRIPTION=AVI\: YUV con raggio 0-255
+
+#[VideoFormat.java]
+VID_AVI_YUV_COMMAND=avi\:yuv
+
+#[VideoSaverBuilder.java]
+#
+#java.io.File startFileName,java.io.File endFileName
+VID_RANGE_OF_FILES_TO_SAVE={0}-{1}
+
+#[SpuSaverBuilder.java]
+SPU_EXTENSION_DESCRIPTION=.spu (vag senza intestazione \= raw SPU data)
+
+#[SpuSaverBuilder.java]
+VAG_EXTENSION_DESCRIPTION=.vag (formato 'Very Audio Good')
+
+#[VideoSaverBuilder.java]
+#
+#String qualityDescription
+CMD_DECODE_QUALITY=Qualit\u00E0 decodifica\: {0}
+
+#[VideoSaverBuilder.java]
+#
+#java.io.File startFileName,java.io.File endFileName
+CMD_OUTPUT_FILES=Output file\: {0}-{1}
+
+#[VideoSaverBuilder.java]
+CMD_SAVING_WITH_AUDIO_ITEMS=Con file audio\:
+
+#[VideoSaverBuilder.java]
+#
+#int willEmulate
+CMD_EMULATE_PSX_AV_SYNC_NY=Emula sincronizzazione PSX audio/videoEmulate PSX audio/video sync\: {0,choice,0\#No|1\#Si}
+
+#[VideoSaverBuilder.java]
+CMD_NO_AUDIO=Senza sonoro
+
+#[VideoSaverBuilder.java, Command_Static.java]
+#
+#String upsampleDescription
+CMD_UPSAMPLE_QUALITY=Sovracampionamento crominanza\: {0}
+
+#[VideoSaverBuilder.java]
+#
+#String videoFormatDescription
+CMD_VIDEO_FORMAT=Formato video\: {0}
+
+#[VideoSaverBuilder.java]
+#
+#String startFrame
+CMD_FRAME_RANGE_BEFORE=Salta fotogrammi prima di {0}
+
+#[VideoSaverBuilder.java]
+#
+#String endFrame
+CMD_FRAME_RANGE_AFTER=Salta fotogrammi dopo {0}
+
+#[VideoSaverBuilder.java]
+#
+#int willCrop
+CMD_CROPPING=Crop\: {0,choice,0\#No|1\#Si}
+
+#[VideoSaverBuilder.java]
+#
+#String videoFormatDescription
+CMD_VIDEO_MUST_HAVE_EVEN_DIMS=La risoluzione del video {0} deve essere un numero pari, sistemo incrementando di un pixel
+
+#[VideoSaverBuilder.java]
+#
+#int width,int height
+CMD_DIMENSIONS=Risoluzione\: {0,number,\#}x{1,number,\#}
+
+AVI_CLOSE_ERR=Errore chiusura AVI
+
+#[VideoSaverBuilder.java]
+#
+#java.io.File fileName
+CMD_OUTPUT_FILE=File di destinazione\: {0}
+
+#[VideoSaverBuilder.java]
+#
+#int discSpeed,double framesPerSecond
+CMD_DISC_SPEED=Velocit\u00E0 disco\: {0,choice,1\#1x|2\#2x} ({1,number,\#.\#\#\#} fps)
+
+#[VideoSaverBuilder.java]
+CMD_VIDEO_DS=-ds
+
+#[VideoSaverBuilder.java]
+CMD_VIDEO_DS_HELP=Specifica 1 o 2 se la velocit\u00E0 del disco \u00E8 ignota.
+
+#[VideoSaverBuilder.java]
+CMD_VIDEO_UP=-up
+
+#[VideoSaverBuilder.java]
+#
+#ILocalizedMessage defaultUpsamplingMethod
+CMD_VIDEO_UP_HELP=Metodo di sovracampionamento crominanza\n(predefinito {0}). Opzioni\:
+
+#String badQualityName
+CMD_UPSAMPLE_QUALITY_INVALID=Qualit\u00E0 di sovracampionamento non valida {0}
+
+#String badQualityName
+CMD_DECODE_QUALITY_INVALID=Valore di qualit\u00E0 di decodifica non valido {0}
+
+#[VideoSaverBuilder.java]
+CMD_VIDEO_QUALITY=-quality,-q
+
+#[VideoSaverBuilder.java]
+#
+#ILocalizedMessage defaultQuality
+CMD_VIDEO_QUALITY_HELP=Qualit\u00E0 di decodifica (predefinito {0}). Opzioni\:
+
+#[VideoSaverBuilder.java]
+CMD_VIDEO_NOCROP=-nocrop
+
+#String badFrameNumberType
+CMD_FRAME_NUMBER_TYPE_INVALID=Numero tipo fotoramma non valido {0}
+
+#[VideoSaverBuilder.java]
+CMD_VIDEO_FRAMES=-start \#, -end \#
+
+#[VideoSaverBuilder.java]
+CMD_VIDEO_FRAMES_HELP=Processa solo fotogrammi nel raggio.
+
+#[VideoSaverBuilder.java]
+CMD_VIDEO_NUM=-num
+
+#[VideoSaverBuilder.java]
+#
+#ILocalizedMessage frameNumberType
+CMD_VIDEO_NUM_HELP=Numero fotogrammi da usare durante il salvataggio\ndella sequenza immagini (predefinito {0}). Opzioni\:
+
+#String badFormatString
+CMD_VIDEO_FORMAT_INVALID=Formato video non valido {0}
+
+#[VideoSaverBuilder.java]
+CMD_VIDEO_VF=-vidfmt,-vf
+
+#[VideoSaverBuilder.java]
+#
+#ILocalizedMessage defaultVideoFormat
+CMD_VIDEO_VF_HELP=Formato di destinazione (predefinito {0}).\nOpzioni\:
+
+#[VideoSaverBuilder.java]
+CMD_VIDEO_HEADER_FRAME_NUMBER_UNSUPPORTED=Il video non supporta l'indicizzazione dei fotogrammi attraverso il numero di intestazione, -start -end -num verranno ignorati
+
+#String badFrameNumberString
+CMD_FRAME_RANGE_INVALID=Fotogrammi non validi {0}
+
+#[PacketBasedVideoSaverBuilder.java, SectorBasedVideoSaverBuilder.java]
+CMD_VIDEO_NOAUD=-noaud
+
+#[PacketBasedVideoSaverBuilder.java, SectorBasedVideoSaverBuilder.java]
+CMD_VIDEO_NOAUD_HELP=Non salva l'audio
+
+#[PacketBasedVideoSaverBuilderGui.java]
+GUI_SAVE_AUDIO_LABEL=Salva audio\:
+
+#[VideoSaverPanel.java]
+GUI_DECODE_QUALITY_LABEL=Qualit\u00E0 decodifica\:
+
+#[VideoSaverPanel.java]
+#
+#long framesPerSecond
+GUI_FPS_LABLE_WHOLE_NUMBER={0,number,\#} fps
+
+#[VideoSaverPanel.java]
+#
+#double decimalFramesPerSecond,long framesPerSecondNumerator,long framesPerSecondDenominator
+GUI_FPS_LABEL_FRACTION={0,number,\#.\#\#\#} ({1,number,\#}/{2,number,\#}) fps
+
+#[VideoSaverPanel.java]
+GUI_DIMENSIONS_LABEL=Risoluzione\:
+
+#[VideoSaverPanel.java]
+#
+#int width,int height
+GUI_DIMENSIONS_WIDTH_X_HEIGHT_LABEL={0,number,\#}x{1,number,\#}
+
+#[VideoSaverPanel.java]
+#
+#java.io.File startFileName,java.io.File endFileName
+GUI_OUTPUT_VIDEO_FILE_RANGE={0}\na\: {1}
+
+#[VideoSaverPanel.java]
+GUI_DISC_SPEED_LABEL=Velocit\u00E0 disco\:
+
+#[VideoSaverPanel.java]
+DISC_SPEED_1X=1x
+
+#[VideoSaverPanel.java]
+DISC_SPEED_2X=2x
+
+GUI_AUDIO_VOLUME_LABEL=Volume audio\:
+
+#[VideoSaverPanel.java]
+GUI_VIDEO_FORMAT_LABEL=Formato video\:
+
+#[VideoSaverPanel.java]
+GUI_CROP_CHECKBOX=Ritaglio
+
+#[VideoSaverPanel.java]
+GUI_CHROMA_UPSAMPLING_LABEL=Sovracampionamento crominanza\:
+
+#[SectorBasedVideoSaverBuilder.java]
+CMD_VIDEO_PSXAV=-psxav
+
+#[SectorBasedVideoSaverBuilder.java]
+CMD_VIDEO_PSXAV_HELP=Emula il timing audio/video della PSX.
+
+#[SectorBasedVideoSaverBuilderGui.java]
+GUI_EMULATE_PSX_AV_SYNC_LABEL=Emula la sincronizzazione audio/video della PSX\:
+
+#[TimPaletteSelector.java]
+GUI_COPY_TO_CLIPBOARD_TOOLTIP=Copia negli appunti
+
+#[TimSaverBuilder.java]
+#
+#java.io.File outputFile,int paletteIndex
+CMD_PALETTE_IMAGE_SAVE_FAIL=Impossibile scrivere il file immagine {0} per la tavolozza colori {1,number,\#}
+
+#[TimSaverBuilder.java]
+#
+#String fileFormat
+CMD_TIM_SAVE_FORMAT=Formato\: {0}
+
+#String badFileFormat
+CMD_TIM_SAVE_FORMAT_INVALID=Formato non valido\: {0}
+
+#String badPaletteList
+CMD_TIM_PALETTE_LIST_INVALID=Lista tavolozza colori non valida {0}
+
+#[TimSaverBuilder.java]
+CMD_TIM_PAL=-pal <\#,\#-\#>
+
+#[TimSaverBuilder.java]
+CMD_TIM_PAL_HELP=Tavolozza colori da salvare (tutti se non specificato)
+
+#[TimSaverBuilder.java]
+CMD_TIM_IF=-imgfmt,-if
+
+#[TimSaverBuilder.java]
+#
+#String defaultImageFormat
+CMD_TIM_IF_HELP=Formato destinazione immagine (predefinito {0}). Opzioni\:
+
+#ILocalizedMessage ouputFiles
+CMD_TIM_PALETTE_FILES=File tavolozza colori\: {0}
+
+#[TimSaverBuilder.java]
+#
+#int fileCount,String startFileName,String endFileName
+TIM_OUTPUT_FILES={0,number,\#} file tra {1}-{2}
+
+#[TimSaverBuilder.java]
+TIM_OUTPUT_FILES_NONE=Nessuno
+
+#[TimSaverBuilder.java]
+TIM_DATA_NOT_FOUND=Dati immagine TIM non trovati
+
+#[TimSaverBuilderGui.java]
+GUI_TIM_SAVE_FORMAT_LABEL=Formato\:
+
+#[TimSaverBuilderGui.java]
+#
+#String listOfSourceCodeLineNumbers
+GUI_TIM_ERR_READING_PREVIEW=Errore lettura anteprima TIM\n{0}
+
+#[DiscItemTim.java]
+#
+#int byteCount,int sectorNumber
+CMD_TIM_REPLACE_SECTOR_BYTES=Scrittura {0,number,\#} di byte per il settore {1,number,\#}
+
+#[DiscItemTim.java]
+#
+#int timWidth,int timHeight,int paletteCount
+GUI_TIM_IMAGE_DETAILS={0,number,\#}x{1,number,\#}, Tavolozza colori\: {2,number,\#}
+
+#[DiscItemTim.java]
+#
+#String newTimFormatDescription,String existingFormatDescription
+TIM_INCOMPATIBLE=Nuovo formato TIM "{0}" non corrisponde a quello esistente "{1}"
+
+TIM_REPLACE_MULTI_CLUT_UNABLE=Impossibile rimpiazzare una TIM multi-palette con una semplice immagine
+
+#[*]
+#
+#String invalidValue,String command
+CMD_INVALID_VALUE_FOR_CMD=Valore non valido "{0}" per {1}
+
+#[*]
+#
+#String invalidValue,String command
+CMD_IGNORING_INVALID_VALUE_FOR_CMD=Ignoro valore non valido "{0}" per {1}
+
+#[*]
+#
+#String fileName
+IO_OPENING_FILE=Apertura file {0}
+
+#[*]
+IO_OPENING_FILE_NOT_FOUND=File non trovato
+
+#[*]
+#
+#String fileName
+IO_OPENING_FILE_NOT_FOUND_NAME=File non trovato {0}
+
+#[*]
+IO_OPENING_FILE_ERROR=Apertura file fallita
+
+#[*]
+#
+#String fileName
+IO_OPENING_FILE_ERROR_NAME=Apertura file fallita {0}
+
+#[*]
+IO_READING_FILE_ERROR=Errore lettura file
+
+#[*]
+#
+#String fileName
+IO_READING_FILE_ERROR_NAME=Errore lettura file {0}
+
+#[*]
+IO_READING_FROM_FILE_ERROR=Errore lettura dal file
+
+#[*]
+#
+#String fileName
+IO_READING_FROM_FILE_ERROR_NAME=Errore lettura dal file {0}
+
+#[*]
+#
+#String fileName
+IO_WRITING_FILE=Scrittura file {0}
+
+#[*]
+IO_WRITING_FILE_ERROR=Errore scrittura file
+
+#[*]
+#
+#String fileName
+IO_WRITING_FILE_ERROR_NAME=Errore scrittura file {0}
+
+#[*]
+IO_WRITING_TO_FILE_ERROR=Errore scrittura sul file
+
+#[*]
+#
+#String fileName
+IO_WRITING_TO_FILE_ERROR_NAME=Errore scrittura sul file {0}
+
+#[IO.java]
+#
+#java.io.File existingFileName
+CANNOT_CREATE_DIR_OVER_FILE=Impossibile creare una cartella per il file {0}
+
+#[IO.java]
+#
+#java.io.File directoryName
+UNABLE_TO_CREATE_DIR=Impossibile creare la cartella {0}
+
+#String directoryName
+DIR_DOES_NOT_EXIST=La cartella {0} non esiste.
diff --git a/jpsxdec/src/jpsxdec/i18n/Translations_ja.properties b/jpsxdec/src/jpsxdec/i18n/Translations_ja.properties
index dc480d2..b01e632 100644
--- a/jpsxdec/src/jpsxdec/i18n/Translations_ja.properties
+++ b/jpsxdec/src/jpsxdec/i18n/Translations_ja.properties
@@ -1,5 +1,6 @@
# jPSXdec Translations
-# Copyright (c) 2015-2017 Michael Sabin, Víctor González, Sergi Medina
+# Copyright (c) 2015-2019
+# Michael Sabin, Víctor González, Sergi Medina, Gianluigi "Infrid" Cusimano
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -47,13 +48,9 @@ CMD_READING_INDEX_FILE=\u8AAD\u307F\u51FA\u3057\u30A4\u30F3\u30C7\u30C3\u30AF\u3
#java.io.File fileName
CMD_INPUT_FILE_NOT_FOUND=\u5165\u529B\u30D5\u30A1\u30A4\u30EB{0}\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093
-#[Command_Items.java]
-#
#String badItemNumber
CMD_ITEM_NUMBER_INVALID=\u7121\u52B9\u9805\u76EE\u756A\u53F7\uFF1A{0}
-#[Command_Items.java]
-#
#String badItemIdentifier
CMD_ITEM_ID_INVALID=\u7121\u52B9\u306A\u30A2\u30A4\u30C6\u30E0\u8B58\u5225\u5B50\uFF1A{0}
@@ -105,7 +102,7 @@ CMD_PROCESS_COMPLETE=\u30C7\u30A3\u30B9\u30AF\u306E\u30C7\u30B3\u30FC\u30C7\u30A
#double durationInSeconds
PROCESS_TIME=\u6642\u9593\uFF1A{0,number,\#.\#\#}\u79D2
-#[Command_Items.java]
+#[Command_Items.java, Command_Static.java]
#
#int fileCount
CMD_NUM_FILES_CREATED={0,number,\#}\u500B\u306E\u30D5\u30A1\u30A4\u30EB\u306E\u4F5C\u6210
@@ -114,7 +111,7 @@ CMD_NUM_FILES_CREATED={0,number,\#}\u500B\u306E\u30D5\u30A1\u30A4\u30EB\u306E\u4
CMD_REOPENING_DISC_WRITE_ACCESS=\u66F8\u304D\u8FBC\u307F\u30A2\u30AF\u30BB\u30B9\u3067\u30C7\u30A3\u30B9\u30AF\u30A4\u30E1\u30FC\u30B8\u3092\u518D\u30AA\u30FC\u30D7\u30F3\u3002
#[Command_Items.java]
-CMD_BACKUP_DISC_IMAGE_WARNING=\u3053\u308C\u306F\u4E0D\u53EF\u9006\u7684\u3067\u3042\u308B\u306E\u3067\u3001\u3042\u306A\u305F\u306E\u30C7\u30A3\u30B9\u30AF\u30A4\u30E1\u30FC\u30B8\u3092\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u3059\u308B\u9858\u3063\u3066\u3044\u307E\u3059\u3002
+CMD_BACKUP_DISC_IMAGE_WARNING=\u3053\u308C\u306F\u4E0D\u53EF\u9006\u7684\u3067\u3059\u306E\u3067\u3001\u3042\u306A\u305F\u306E\u30C7\u30A3\u30B9\u30AF\u30A4\u30E1\u30FC\u30B8\u3092\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u3059\u308B\u9858\u3063\u3066\u3044\u307E\u3059\u3002
#[Command_Items.java]
#
@@ -131,7 +128,7 @@ CMD_PLAYER_ERR=\u30D7\u30EC\u30FC\u30E4\u30FC\u306E\u30A8\u30E9\u30FC
CMD_XA_REPLACE_OPENING_PATCH_IDX=\u958B\u53E3\u30D1\u30C3\u30C1\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9{0}
#[Command_Items.java, SavingGuiTask.java]
-SAVE_LOG_FILE_BASE_NAME=\u30BB\u30FC\u30D6
+SAVE_LOG_FILE_BASE_NAME=\u4FDD\u5B58\u3059\u308B
#[Command.java, CommandLine.java, Gui.java]
INDEX_LOG_FILE_BASE_NAME=\u6307\u6570
@@ -156,8 +153,6 @@ USER_LOG_EXCEPTION=[{0}] {1}
#String logLevel,String exceptionName,String exceptionMessage
USER_LOG_EXCEPTION_MSG=[{0}] {1} {2}
-#[Command_CopySect.java]
-#
#String badSectorRangeString
CMD_SECTOR_RANGE_INVALID=\u7121\u52B9\u30BB\u30AF\u30BF\u306E\u7BC4\u56F2\uFF1A{0}
@@ -172,8 +167,6 @@ CMD_GENERATING_SECTOR_LIST=\u30BB\u30AF\u30BF\u30EA\u30B9\u30C8\u3092\u4F5C\u621
#[Command_Static.java]
CMD_DIM_OPTION_REQURIED=-dim\u30AA\u30D7\u30B7\u30E7\u30F3\u304C\u5FC5\u8981
-#[Command_Static.java]
-#
#String badQuality
CMD_QUALITY_INVALID=\u7121\u52B9\u54C1\u8CEA{0}
@@ -185,16 +178,12 @@ CMD_USING_QUALITY=\u8CEA\u3092\u4F7F\u7528\u3057\u3066{0}
#[Command_Static.java]
CMD_NOT_TIM=\u30A8\u30E9\u30FC\uFF1A\u306A\u3044\u30C6\u30A3\u30E0\u306E\u753B\u50CF
-#[Command_Static.java]
-#
#ILocalizedMessage upsampleDescription
CMD_USING_UPSAMPLING=\u30A2\u30C3\u30D7\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0\u3092\u4F7F\u7528\u3057\u3066{0}
#[Command_Static.java]
CMD_TIM_IO_ERR=\u8AAD\u307F\u8FBC\u307F\u30A8\u30E9\u30FC\u307E\u305F\u306FTIM\u30D5\u30A1\u30A4\u30EB\u3092\u66F8\u304D\u307E\u3059
-#[Command_Static.java]
-#
#String badFormat
CMD_FORMAT_INVALID=\u7121\u52B9\u306A\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8\u30BF\u30A4\u30D7{0}
@@ -209,8 +198,6 @@ CMD_ASSERT_DISABLED_NO_DEBUG_USE_EA=-ea\u30AA\u30D7\u30B7\u30E7\u30F3\u3092\u4F7
#java.io.File timFileName
CMD_READING_TIM=\u8AAD\u307F\u53D6\u308ATIM\u30D5\u30A1\u30A4\u30EB{0}
-#[Command_Static.java]
-#
#String badStaticTypeName
CMD_STATIC_TYPE_INVALID=\u7121\u52B9\u306A\u9759\u7684\u578B\uFF1A{0}
@@ -225,11 +212,6 @@ CMD_READING_STATIC_FILE=\u9759\u7684\u30D5\u30A1\u30A4\u30EB{0}\u3092\u8AAD\u307
#[Command_Static.java]
CMD_IMAGE_CONVERT_OK=\u753B\u50CF\u306F\u6B63\u5E38\u306B\u5909\u63DB\u3057\u307E\u3057\u305F
-#[Command_Static.java]
-#
-#String badUpsamplingName
-CMD_UPSAMPLING_INVALID=\u7121\u52B9\u306A\u30A2\u30C3\u30D7\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0{0}
-
#[Command_Static.java, VideoSaverBuilder.java]
#
#java.io.File fileName
@@ -256,13 +238,9 @@ CMD_BUILDING_INDEX=\u30D3\u30EB\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9
CMD_DISC_READ_ERROR=\u30C7\u30A3\u30B9\u30AF\u306F\u8AAD\u307F\u8FBC\u307F\u30A8\u30E9\u30FC\u3002
-#[CommandLine.java]
-#
#String badVerbosityLevel
CMD_VERBOSE_LVL_INVALID_STR=\u7121\u52B9\u306A\u5197\u9577\u30EC\u30D9\u30EB{0}
-#[CommandLine.java]
-#
#int badVerbosityNumber
CMD_VERBOSE_LVL_INVALID_NUM=\u7121\u52B9\u306A\u5197\u9577\u30EC\u30D9\u30EB{0,number,\#}
@@ -381,7 +359,7 @@ GUI_EXPAND_ALL_BTN=\u3059\u3079\u3066\u5C55\u958B
GUI_SAVE_ALL_SELECTED_BTN=\u3059\u3079\u3066\u306E\u9078\u629E\u3092\u4FDD\u5B58
#[Gui.java]
-GUI_NOTHING_IS_MARKED_FOR_SAVING=\u4F55\u3082\u4FDD\u5B58\u7528\u306B\u30DE\u30FC\u30AF\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002
+GUI_NOTHING_IS_MARKED_FOR_SAVING=\u4F55\u3082\u4FDD\u5B58\u3059\u308B\u305F\u3081\u306B\u30DE\u30FC\u30AF\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002
#[Gui.java]
#
@@ -403,7 +381,7 @@ GUI_SAVE_INDEX_PROMPT_TITLE=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u3092\u4FDD\u5B
GUI_PLAY_TAB=\u00A0\u00A0\u00A0\u00A0\u904A\u3073\u307E\u3059\u00A0\u00A0\u00A0\u00A0
#[Gui.java]
-GUI_SAVE_TAB=\u00A0\u00A0\u00A0\u00A0\u30BB\u30FC\u30D6\u00A0\u00A0\u00A0\u00A0
+GUI_SAVE_TAB=\u00A0\u00A0\u00A0\u00A0\u4FDD\u5B58\u3059\u308B\u00A0\u00A0\u00A0\u00A0
#[Gui.java]
GUI_PAUSE_BTN=\u4F11\u6B62
@@ -441,7 +419,7 @@ GUI_SECTORS_COLUMN=\u30BB\u30AF\u30BF\u30FC
GUI_TREE_TYPE_COLUMN=\u30BF\u30A4\u30D7
#[GuiTree.java]
-GUI_SELECT_NONE=\u306A\u3057
+GUI_SELECT_NONE=\u7121\u3057
#[GuiTree.java]
GUI_SELECT_ALL_VIDEO=\u5168\u3066\u306E\u30D3\u30C7\u30AA
@@ -461,13 +439,13 @@ GUI_SELECT_ALL_IMAGES=\u3059\u3079\u3066\u306E\u753B\u50CF
#[GuiTree.java]
GUI_SELECT_ALL_SOUNDS=\u3059\u3079\u3066\u306E\u30B5\u30A6\u30F3\u30C9\u30AF\u30EA\u30C3\u30D7
-#[VideoSaverBuilderStrGui.java, GuiTree.java]
+#[SectorBasedVideoSaverBuilderGui.java, GuiTree.java]
GUI_TREE_DETAILS_COLUMN=\u7D30\u90E8
-#[VideoSaverBuilderStrGui.java, GuiTree.java]
-GUI_TREE_SAVE_COLUMN=\u30BB\u30FC\u30D6
+#[SectorBasedVideoSaverBuilderGui.java, GuiTree.java]
+GUI_TREE_SAVE_COLUMN=\u4FDD\u5B58\u3059\u308B
-#[VideoSaverBuilderStrGui.java, GuiTree.java]
+#[SectorBasedVideoSaverBuilderGui.java, GuiTree.java]
GUI_TREE_INDEX_NUMBER_COLUMN=\uFF03
#[IndexId.java]
@@ -588,13 +566,9 @@ FAILED_TO_READ_1_SECTOR=\u5C11\u306A\u304F\u3068\u30821\u30BB\u30AF\u30BF\u5168\
#[SerializedDiscItem.java]
EMPTY_SERIALIZED_STRING=\u7A7A\u306E\u30B7\u30EA\u30A2\u30E9\u30A4\u30BA\u3055\u308C\u305F\u6587\u5B57\u5217
-#[SerializedDiscItem.java]
-#
#String badNumber
SERIALIZATION_FAILED_TO_CONVERT_TO_INT=int\u306B\u30B7\u30EA\u30A2\u30EB\u5316\u3055\u308C\u305F\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u5909\u63DB\u3059\u308B\u305F\u3081\u306B\u5931\u6557\u3057\u307E\u3057\u305F\uFF1A{0}
-#[SerializedDiscItem.java]
-#
#String badNumber
SERIALIZATION_FAILED_TO_CONVERT_TO_LONG=long\u306B\u30B7\u30EA\u30A2\u30E9\u30A4\u30BA\u30D5\u30A3\u30FC\u30EB\u30C9\u306E\u5909\u63DB\u306B\u5931\u6557\u3057\u307E\u3057\u305F\uFF1A{0}
@@ -621,7 +595,7 @@ SERIALIZATION_FIELD_NOT_FOUND={0}\u30D5\u30A3\u30FC\u30EB\u30C9\u304C\u898B\u306
#[DiscIndex.java]
#
#String actualFormatDescription,String expectedFormatDescription
-CD_FORMAT_MISMATCH=\u30C7\u30A3\u30B9\u30AF\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8\u306F\u3001 "{0}"\uFF01\= "{1}" \u8A00\u3046\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u4E00\u81F4\u3057\u3066\u3044\u307E\u305B\u3093\u3002
+CD_FORMAT_MISMATCH=\u30C7\u30A3\u30B9\u30AF\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8\u300C{0}\u300D\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u30D5\u30A1\u30A4\u30EB\u306E\u5F62\u5F0F\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u300C{1}\u300D
#[DiscIndex.java]
INDEX_HEADER_MISSING=\u9069\u5207\u306A\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u30D8\u30C3\u30C0\u304C\u3042\u308A\u307E\u305B\u3093\u3002
@@ -633,13 +607,9 @@ INDEXING_ERROR=\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u305
#int sectorNumber
INDEX_SECTOR_CORRUPTED=\u30BB\u30AF\u30BF{0,number,\#}\u306E\u7834\u640D\u3092\u691C\u51FA\u3057\u307E\u3057\u305F\u3002\u3053\u308C\u306F\u3001\u8B58\u5225\u304A\u3088\u3073\u5909\u63DB\u306B\u5F71\u97FF\u3092\u4E0E\u3048\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002
-#[DiscIndex.java]
-#
#int previousSectorNumber,int currentSectorNumber
INDEX_SECTOR_HEADER_NUM_BREAK=\u975E\u9023\u7D9A\u7684\u306A\u30BB\u30AF\u30BF\u30D8\u30C3\u30C0\u756A\u53F7\uFF1A{0,number,\#} - > {1,number,\#}
-#[DiscIndex.java]
-#
#int sectorNumber
INDEX_MODE1_AMONG_MODE2=\u30BB\u30AF\u30BF\u306F\u3001{0,number,\#}\u304C\u30E2\u30FC\u30C91\u3001\u30E2\u30FC\u30C92\u306E\u30BB\u30AF\u30BF\u9593\u3067\u898B\u51FA\u3055\u308C\u307E\u3059
@@ -787,18 +757,16 @@ CMD_AUDIO_VOL=-vol <0-100>
#int defaultVolumeLevel
CMD_AUDIO_VOL_HELP=\u97F3\u91CF\u8ABF\u6574\uFF08\u30C7\u30D5\u30A9\u30EB\u30C8\u306E{0,number,\#}\uFF09\u3002
-#[AudioSaverBuilder.java, SpuSaverBuilder.java]
+#[SpuSaverBuilder.java]
#
#String invalidFormatName
CMD_IGNORING_INVALID_FORMAT=\u7121\u52B9\u306A\u5F62\u5F0F\u3092\u7121\u8996{0}
-#[AudioSaverBuilder.java, SpuSaverBuilder.java]
+#[SpuSaverBuilder.java]
#
#String invalidVolume
CMD_IGNORING_INVALID_VOLUME=\u7121\u52B9\u4F53\u7A4D\u3092\u7121\u8996{0}
-#[VideoSaverBuilder.java]
-#
#String badDiscSpeed
CMD_IGNORING_INVALID_DISC_SPEED=\u7121\u52B9\u306A\u30C7\u30A3\u30B9\u30AF\u901F\u5EA6\u3092\u7121\u8996{0}
@@ -917,55 +885,55 @@ QUALITY_PSX_DESCRIPTION=PSX\uFF08\u4F4E\u3044\uFF09\u54C1\u8CEA\u3092\u30A8\u30D
#[MdecDecodeQuality.java]
QUALITY_PSX_COMMAND=PSX
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BICUBIC_DESCRIPTION=\u30D0\u30A4\u30AD\u30E5\u30FC\u30D3\u30C3\u30AF
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BICUBIC_CMDLINE=\u30D0\u30A4\u30AD\u30E5\u30FC\u30D3\u30C3\u30AF
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BELL_DESCRIPTION=\u30D9\u30EB
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BELL_CMDLINE=\u30D9\u30EB
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_NEAR_NEIGHBOR_DESCRIPTION=\u6700\u8FD1\u508D
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_NEAR_NEIGHBOR_CMDLINE=NearestNeighbor
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_LANCZOS3_DESCRIPTION=Lanczos3
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_LANCZOS3_CMDLINE=Lanczos3
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_MITCHELL_DESCRIPTION=\u30DF\u30C3\u30C1\u30A7\u30EB
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_MITCHELL_CMDLINE=\u30DF\u30C3\u30C1\u30A7\u30EB
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_HERMITE_DESCRIPTION=\u30A8\u30EB\u30DF\u30FC\u30C8
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_HERMITE_CMDLINE=\u30A8\u30EB\u30DF\u30FC\u30C8
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BSPLINE_DESCRIPTION=B\u30B9\u30D7\u30E9\u30A4\u30F3
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BSPLINE_CMDLINE=B\u30B9\u30D7\u30E9\u30A4\u30F3
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BILINEAR_DESCRIPTION=\u30D0\u30A4\u30EA\u30CB\u30A2
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
CHROMA_UPSAMPLE_BILINEAR_CMDLINE=\u30D0\u30A4\u30EA\u30CB\u30A2
-#[MdecDecoder_double_interpolate.java]
+#[ChromaUpsample.java]
#
#ILocalizedMessage commandLineId,ILocalizedMessage interplationName
CHROMA_UPSAMPLE_CMDLINE_HELP={0}\uFF08{1}\uFF09
@@ -1010,10 +978,12 @@ CMD_UNABLE_TO_IDENTIFY_FRAME_TYPE=\u30D5\u30EC\u30FC\u30E0\u30BF\u30A4\u30D7\u30
#[ReplaceFrameFull.java, ReplaceFramePartial.java]
#
#String frameNumber,int maxSize
-CMD_UNABLE_TO_COMPRESS_FRAME_SMALL_ENOUGH=\u30D5\u30EC\u30FC\u30E0\u3092\u5727\u7E2E\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u305B\u3093{0} {1,number,\#}\u30D0\u30A4\u30C8\u306B\u53CE\u307E\u308B\u307B\u3069\u306E\u5C0F\u3055\u306A\!\!\!
+CMD_UNABLE_TO_COMPRESS_FRAME_SMALL_ENOUGH={1,number,\#}\u30D0\u30A4\u30C8\u306B\u53CE\u307E\u308B\u3088\u3046\u306B\u5341\u5206{0}\u5C0F\u3055\u306A\u30D5\u30EC\u30FC\u30E0\u3092\u5727\u7E2E\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u305B\u3093
#[ReplaceFramePartial.java]
-CMD_NO_DIFFERENCE_SKIPPING=\u5DEE\u7570\u306F\u30B9\u30AD\u30C3\u30D7\u3057\u3001\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002
+#
+#String frameNumber
+CMD_NO_DIFFERENCE_SKIPPING=\u30D5\u30EC\u30FC\u30E0\u306B\u898B\u3089\u308C\u308B\u5DEE\u7570{0}\u3001\u30B9\u30AD\u30C3\u30D7\u3002
#[ReplaceFramePartial.java]
#
@@ -1029,7 +999,9 @@ CMD_ENTIRE_FRAME_DIFFERENT=\u8B66\u544A\uFF1A\u5168\u4F53\u306E\u30D5\u30EC\u30F
REPLACE_UNABLE_READ_IMAGE=\u753B\u50CF\u3068\u3057\u3066{0}\u3092\u30ED\u30FC\u30C9\u3067\u304D\u307E\u305B\u3093
#[ReplaceFramePartial.java]
-REPLACE_FRAME_DIMENSIONS_TOO_SMALL=\u30BD\u30FC\u30B9\u30D5\u30EC\u30FC\u30E0\u3088\u308A\u5C0F\u3055\u3044\u4EA4\u63DB\u30D5\u30EC\u30FC\u30E0\u5BF8\u6CD5
+#
+#int newWidth,int newHeight,int existingWidth,int existingHeight
+REPLACE_FRAME_DIMENSIONS_TOO_SMALL=\u4EA4\u63DB\u30D5\u30EC\u30FC\u30E0\u5BF8\u6CD5{0,number,\#} X {1,number,\#}\u30BD\u30FC\u30B9\u30D5\u30EC\u30FC\u30E0{2,number,\#} X {3,number,\#}\u3088\u308A\u3082\u5C0F\u3055\u3044\u3067\u3059
#[ReplaceFrames.java]
#
@@ -1062,16 +1034,12 @@ REPLACE_FRAME_TYPE_NOT_IKI=\u30D5\u30EC\u30FC\u30E0\u30BF\u30A4\u30D7\u306F\u58F
FRAME_NOT_IKI=\u30D5\u30EC\u30FC\u30E0\u306F\u3001\u58F1\u5C90\u306E\u5F62\u5F0F\u3067\u306F\u3042\u308A\u307E\u305B\u3093
-#[BitStreamUncompressor_Lain.java]
FRAME_NOT_LAIN=\u30D5\u30EC\u30FC\u30E0\u306F\u3001\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8\u3092\u30EC\u30A4\u30F3\u308C\u3066\u3044\u307E\u305B\u3093
-#[BitStreamUncompressor_STRv1.java]
FRAME_NOT_STRV1=\u30D5\u30EC\u30FC\u30E0\u306FSTRv1\u5F62\u5F0F\u3067\u306F\u3042\u308A\u307E\u305B\u3093
-#[BitStreamUncompressor_STRv2.java]
FRAME_NOT_STRV2=\u30D5\u30EC\u30FC\u30E0\u306FSTRv2\u5F62\u5F0F\u3067\u306F\u3042\u308A\u307E\u305B\u3093
-#[BitStreamUncompressor_STRv3.java]
FRAME_NOT_STRV3=\u30D5\u30EC\u30FC\u30E0\u306FSTRv3\u5F62\u5F0F\u3067\u306F\u3042\u308A\u307E\u305B\u3093
#[SectorIkiVideo.java]
@@ -1087,17 +1055,15 @@ UNEXPECTED_END_OF_AUDIO=\u30AA\u30FC\u30C7\u30A3\u30AA\u30C7\u30FC\u30BF\u306E\u
#[BitStreamUncompressor_Iki.java]
#
#int macroBlockX,int macroBlockY,int quantizationScale
-IKI_REDUCING_QSCALE_OF_MB_TO_VAL={2,number,\#}\u3068\u306EQscale\uFF08{0,number,\#}\u3001{1,number,\#}\uFF09\u3092\u4F4E\u6E1B\u3057\u3088\u3046\u3068\u3057
+IKI_REDUCING_QSCALE_OF_MB_TO_VAL={2,number,\#}\u306B\uFF08{1,number,\#}\u3001{0,number,\#}\uFF09\u30DE\u30AF\u30ED\u30D6\u30ED\u30C3\u30AF\u306E\u91CF\u5B50\u5316\u30B9\u30B1\u30FC\u30EB\u3092\u4F4E\u6E1B\u3057\u3088\u3046\u3068
-#[BitStreamUncompressor_Iki.java]
-#
#String frameNumber,int demuxSize,int sourceSize
IKI_NEW_FRAME_GT_SRC_STOPPING=\u65B0\u3057\u3044\u30D5\u30EC\u30FC\u30E0{0} DEMUX\u30B5\u30A4\u30BA{1,number,\#}> max\u306E\u30BD\u30FC\u30B9{2,number,\#}\u3001\u305D\u3046\u505C\u6B62
#[BitStreamUncompressor_Iki.java, BitStreamUncompressor_Lain.java, BitStreamUncompressor_STRv2.java]
#
#String frameNumber,int demuxSize,int sourceSize
-NEW_FRAME_FITS=\u65B0\u3057\u3044\u30D5\u30EC\u30FC\u30E0{0} DEMUX\u30B5\u30A4\u30BA{1,number,\#} <\= max\u306E\u30BD\u30FC\u30B9{2,number,\#}
+NEW_FRAME_FITS=\u65B0\u3057\u3044\u30D5\u30EC\u30FC\u30E0{0}\u4EA4\u63DB\u30B5\u30A4\u30BA{1,number,\#}\u65E2\u5B58\u306E\u5229\u7528\u53EF\u80FD\u306A\u30B5\u30A4\u30BA\u5185\u306B\u53CE\u307E\u308B{2,number,\#}
#[BitStreamUncompressor_Iki.java, BitStreamUncompressor_STRv2.java]
#
@@ -1109,25 +1075,25 @@ END_OF_STREAM=\u30B9\u30C8\u30EA\u30FC\u30E0\u306E\u7D42\u308F\u308A
#[BitStreamUncompressor_Lain.java]
#
#int lumaQuantizationScale,int chromaQuantizationScale
-TRYING_LUMA_CHROMA=\u30EB\u30DE{0,number,\#}\u30AF\u30ED\u30DE{1,number,\#}\u3057\u3088\u3046
+TRYING_LUMA_CHROMA=\u30EB\u30DE\u91CF\u5B50\u5316\u30B9\u30B1\u30FC\u30EB{0,number,\#}\u304A\u3088\u3073\u30AF\u30ED\u30DE\u91CF\u5B50\u5316\u30B9\u30B1\u30FC\u30EB{1,number,\#}\u3067\u5727\u7E2E\u3057\u3088\u3046\u3068\u3057\u307E\u3059
#[BitStreamUncompressor_Iki.java, BitStreamUncompressor_Lain.java, BitStreamUncompressor_STRv2.java, ReplaceFrameFull.java]
#
#String frameNumber,int newFrameSize,int sourceFrameSize
-NEW_FRAME_DOES_NOT_FIT=\!\!\!\u65B0\u3057\u3044\u30D5\u30EC\u30FC\u30E0{0} DEMUX\u30B5\u30A4\u30BA{1,number,\#}> max\u306E\u30BD\u30FC\u30B9{2,number,\#}\uFF01
+NEW_FRAME_DOES_NOT_FIT=\u65B0\u3057\u3044\u30D5\u30EC\u30FC\u30E0{0}\u4EE3\u66FF\u30B5\u30A4\u30BA{1,number,\#}\u65E2\u5B58\u306E\u5229\u7528\u53EF\u80FD\u30B5\u30A4\u30BA\u306B\u53CE\u307E\u3089\u306A\u3044{2,number,\#}
#[BitStreamUncompressor_Lain.java]
#
#String frameNumber
-COMPRESS_TOO_MUCH_ENERGY=\u30D3\u30C7\u30AA\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8\u306F\u3001\u30D5\u30EC\u30FC\u30E0\u306E\u305F\u3081\u306E\u65B0\u305F\u306A\u30C7\u30FC\u30BF\u306E\u5927\u304D\u3055\u3092\u6271\u3046\u3053\u3068\u304C\u3067\u304D\u306A\u3044{0}
+COMPRESS_TOO_MUCH_ENERGY=\u30D5\u30EC\u30FC\u30E0{0}\u306E\u7F6E\u63DB\u753B\u50CF\u3092\u5727\u7E2E\u3059\u308B\u306B\u306F\u3042\u307E\u308A\u306B\u3082\u8A73\u7D30\u3067\u3059
#int currentWidth,int newWidth
INCONSISTENT_WIDTH=\u77DB\u76FE\u5E45{0,number,\#}\uFF01\= {1,number,\#}
-#[VideoSaverBuilderCrusader.java]
+#[PacketBasedVideoSaverBuilder.java]
#
#int audioSampleRate
-EMBEDDED_CRUSADER_AUDIO_HZ=\u57CB\u3081\u8FBC\u307F\u5341\u5B57\u8ECD\u30AA\u30FC\u30C7\u30A3\u30AA{0,number,\#}\u30D8\u30EB\u30C4
+CMD_EMBEDDED_PACKET_BASED_AUDIO_HZ=\u57CB\u3081\u8FBC\u307E\u308C\u305F\u30AA\u30FC\u30C7\u30A3\u30AA{0,number,\#}\u30D8\u30EB\u30C4
CRUSADER_VIDEO_CORRUPTED=\u30AF\u30EB\u30BB\u30A4\u30C0\u30FC\uFF1A\u3044\u3044\u3048\u5F8C\u6094\u30D3\u30C7\u30AA\u304C\u7834\u640D\u3057\u3066\u3044\u307E\u305B\u3093
@@ -1136,25 +1102,21 @@ CRUSADER_AUDIO_CORRUPTED=\u30AF\u30EB\u30BB\u30A4\u30C0\u30FC\uFF1A\u3044\u3044\
#String frameNumber,int chunkNumber
MISSING_CHUNK=\u30D5\u30EC\u30FC\u30E0{0}\u30C1\u30E3\u30F3\u30AF{1,number,\#}\u6B20\u843D\u3002
-#[SectorFrameBuilder.java]
-#
#int sectorNumber,int currentChunkCount,int newChunkCount
DEMUX_FRAME_CHUNKS_CHANGED_FROM_TO=\u30D5\u30EC\u30FC\u30E0\u5185\u306E\u30BB\u30AF\u30BF{0,number,\#}\u30C1\u30E3\u30F3\u30AF\u306F\u3001{2,number,\#}\u306B{1,number,\#}\u306B\u5909\u66F4\u3057\u307E\u3057\u305F
-#[SectorFrameBuilder.java]
-#
#int sectorNumber,int chunkNumber,int chunksInFrame
DEMUX_CHUNK_NUM_GTE_CHUNKS_IN_FRAME=\u30BB\u30AF\u30BF\u30FC\u30D5\u30EC\u30FC\u30E0\u306B\u304A\u3051\u308B{0,number,\#}\u30C1\u30E3\u30F3\u30AF\u756A\u53F7{1,number,\#}> \=\u30C1\u30E3\u30F3\u30AF{2,number,\#}
-#[SectorFrameBuilder.java]
+#[SectorBasedFrameBuilder.java]
#
#int frameStartSector,int frameEndSector,int chunkNumber
MISSING_CHUNK_FRAME_IN_SECTORS=\u30BB\u30AF\u30BF\u5185\u306E\u30D5\u30EC\u30FC\u30E0{0,number,\#} - {1,number,\#}\u6B20\u843D\u3057\u3066\u3044\u308B\u30C1\u30E3\u30F3\u30AF{2,number,\#}
#[DemuxedCrusaderFrame.java, SectorBasedFrameReplace.java]
-CMD_FRAME_TO_REPLACE_MISSING_CHUNKS=\u30C1\u30E3\u30F3\u30AF\u304C\u6B20\u843D\u3057\u3066\u30D5\u30EC\u30FC\u30E0\u3092\u4EA4\u63DB\u3057\u3088\u3046\u3068\u3059\u308B\u3068\uFF1F
+CMD_FRAME_TO_REPLACE_MISSING_CHUNKS=\u65E2\u5B58\u306E\u7834\u640D\u3057\u305F\u30D5\u30EC\u30FC\u30E0\u3092\u4EA4\u63DB\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059
-#[VDP.java, ReplaceFrameFull.java, ReplaceFramePartial.java]
+#[VDP.java, ReplaceFrameFull.java, ReplaceFramePartial.java, SectorBasedFrameBuilder.java]
#
#String frameNumber
FRAME_NUM_CORRUPTED=\u30D5\u30EC\u30FC\u30E0{0}\u306E\u30A8\u30E9\u30FC\uFF1A\u30D5\u30EC\u30FC\u30E0\u304C\u7834\u640D\u3057\u3066\u3044\u307E\u3059
@@ -1205,7 +1167,7 @@ JPEG_ENCODER_FRAME_FAIL_NO_FRAME=\u30B7\u30F3\u30D7\u30EBjPSXdec JPEG\u30A8\u30F
#[VDP.java]
#
#int frameCount
-WRITING_BLANK_FRAMES_TO_ALIGN_AV=\u30AA\u30FC\u30C7\u30A3\u30AA/\u30D3\u30C7\u30AA\u518D\u751F\u3092\u6574\u5217\u3055\u305B\u308B\u305F\u3081\u306B\u3001{0,number,\#}\u30D6\u30E9\u30F3\u30AF\u30D5\u30EC\u30FC\u30E0\uFF08\u8907\u6570\u53EF\uFF09\u3092\u66F8\u304D\u8FBC\u307F\u307E\u3059\u3002
+WRITING_BLANK_FRAMES_TO_ALIGN_AV=\u30AA\u30FC\u30C7\u30A3\u30AA/\u30D3\u30C7\u30AA\u518D\u751F\u3092\u6574\u5217\u3055\u305B\u308B\u305F\u3081\u306B\u3001{0,number,\#}\u30D6\u30E9\u30F3\u30AF\u30D5\u30EC\u30FC\u30E0\u3092\u66F8\u304D\u8FBC\u307F\u307E\u3059\u3002
#[VDP.java]
#
@@ -1303,7 +1265,7 @@ CMD_SAVING_WITH_AUDIO_ITEMS=\u30AA\u30FC\u30C7\u30A3\u30AA\u9805\u76EE\u3092\uFF
#[VideoSaverBuilder.java]
CMD_NO_AUDIO=\u30AA\u30FC\u30C7\u30A3\u30AA\u304C\u805E\u3053\u3048\u307E\u305B\u3093\u3002
-#[VideoSaverBuilder.java]
+#[VideoSaverBuilder.java, Command_Static.java]
#
#String upsampleDescription
CMD_UPSAMPLE_QUALITY=\u30AF\u30ED\u30DE\u30A2\u30C3\u30D7\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0\uFF1A{0}
@@ -1344,13 +1306,9 @@ CMD_VIDEO_UP=-up <\u30A2\u30C3\u30D7\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0>
#ILocalizedMessage defaultUpsamplingMethod
CMD_VIDEO_UP_HELP=\u30AF\u30ED\u30DE\u30A2\u30C3\u30D7\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0\u65B9\u6CD5\n\uFF08\u30C7\u30D5\u30A9\u30EB\u30C8{0}\uFF09\u3002\u30AA\u30D7\u30B7\u30E7\u30F3\uFF1A
-#[VideoSaverBuilder.java]
-#
#String badQualityName
CMD_UPSAMPLE_QUALITY_INVALID=\u7121\u52B9\u306A\u30A2\u30C3\u30D7\u30B5\u30F3\u30D7\u30EB\u54C1\u8CEA{0}
-#[VideoSaverBuilder.java]
-#
#String badQualityName
CMD_DECODE_QUALITY_INVALID=\u7121\u52B9\u30C7\u30B3\u30FC\u30C9\u54C1\u8CEA{0}
@@ -1368,13 +1326,11 @@ CMD_VIDEO_NOCROP=-nocrop
#[VideoSaverBuilder.java]
CMD_VIDEO_NOCROP_HELP=\u672A\u4F7F\u7528\u306E\u30D5\u30EC\u30FC\u30E0\u306E\u30A8\u30C3\u30B8\u306E\u5468\u308A\u306E\u30C7\u30FC\u30BF\u3092\u30AF\u30ED\u30C3\u30D7\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
-#[VideoSaverBuilder.java]
-#
#String badFrameNumberType
CMD_FRAME_NUMBER_TYPE_INVALID=\u7121\u52B9\u306A\u30D5\u30EC\u30FC\u30E0\u756A\u53F7\u306E\u30BF\u30A4\u30D7{0}
#[VideoSaverBuilder.java]
-CMD_VIDEO_FRAMES=-frame\u306F\u3001\uFF03\u307E\u305F\u306F\uFF03\u3092-frames - \uFF03
+CMD_VIDEO_FRAMES=-start \#, -end \#
#[VideoSaverBuilder.java]
CMD_VIDEO_FRAMES_HELP=\u30D7\u30ED\u30BB\u30B9\u306F\u3001\u7BC4\u56F2\u5185\u306E\u30D5\u30EC\u30FC\u30E0\u3002
@@ -1387,8 +1343,6 @@ CMD_VIDEO_NUM=-num <\u30BF\u30A4\u30D7>
#ILocalizedMessage frameNumberType
CMD_VIDEO_NUM_HELP=\u30A4\u30E1\u30FC\u30B8\u30B7\u30FC\u30B1\u30F3\u30B9\u3092\u4FDD\u5B58\u3059\u308B\u3068\u304D\u306B\u30D5\u30EC\u30FC\u30E0\u756A\u53F7\u3092\u4F7F\u7528\u3059\u308B\u306B\u306F\n\uFF08\u30C7\u30D5\u30A9\u30EB\u30C8{0}\uFF09\u3002\u30AA\u30D7\u30B7\u30E7\u30F3\uFF1A
-#[VideoSaverBuilder.java]
-#
#String badFormatString
CMD_VIDEO_FORMAT_INVALID=\u7121\u52B9\u306A\u30D3\u30C7\u30AA\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8{0}
@@ -1406,13 +1360,13 @@ CMD_VIDEO_HEADER_FRAME_NUMBER_UNSUPPORTED=\u30D3\u30C7\u30AA\u306F\u3001\u30D8\u
#String badFrameNumberString
CMD_FRAME_RANGE_INVALID=\u7121\u52B9\u30D5\u30EC\u30FC\u30E0\uFF08S\uFF09{0}
-#[VideoSaverBuilderCrusader.java, VideoSaverBuilderStr.java]
+#[PacketBasedVideoSaverBuilder.java, SectorBasedVideoSaverBuilder.java]
CMD_VIDEO_NOAUD=-noaud
-#[VideoSaverBuilderCrusader.java, VideoSaverBuilderStr.java]
+#[PacketBasedVideoSaverBuilder.java, SectorBasedVideoSaverBuilder.java]
CMD_VIDEO_NOAUD_HELP=\u30AA\u30FC\u30C7\u30A3\u30AA\u3092\u4FDD\u5B58\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
-#[VideoSaverBuilderCrusaderGui.java]
+#[PacketBasedVideoSaverBuilderGui.java]
GUI_SAVE_AUDIO_LABEL=\u30AA\u30FC\u30C7\u30A3\u30AA\u3092\u4FDD\u5B58\u3057\u307E\u3059\u3002
#[VideoSaverPanel.java]
@@ -1461,13 +1415,13 @@ GUI_CROP_CHECKBOX=\u53CE\u7A6B
#[VideoSaverPanel.java]
GUI_CHROMA_UPSAMPLING_LABEL=\u30AF\u30ED\u30DE\u30A2\u30C3\u30D7\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0\uFF1A
-#[VideoSaverBuilderStr.java]
+#[SectorBasedVideoSaverBuilder.java]
CMD_VIDEO_PSXAV=-psxav
-#[VideoSaverBuilderStr.java]
+#[SectorBasedVideoSaverBuilder.java]
CMD_VIDEO_PSXAV_HELP=PSX\u30AA\u30FC\u30C7\u30A3\u30AA/\u30D3\u30C7\u30AA\u30FB\u30BF\u30A4\u30DF\u30F3\u30B0\u3092\u30A8\u30DF\u30E5\u30EC\u30FC\u30C8\u3057\u307E\u3059\u3002
-#[VideoSaverBuilderStrGui.java]
+#[SectorBasedVideoSaverBuilderGui.java]
GUI_EMULATE_PSX_AV_SYNC_LABEL=PSX\u306EA / V\u540C\u671F\u3092\u30A8\u30DF\u30E5\u30EC\u30FC\u30C8\uFF1A
#[TimPaletteSelector.java]
@@ -1483,13 +1437,9 @@ CMD_PALETTE_IMAGE_SAVE_FAIL=\u30D1\u30EC\u30C3\u30C8{1,number,\#}\u306E\u753B\u5
#String fileFormat
CMD_TIM_SAVE_FORMAT=\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8\uFF1A{0}
-#[TimSaverBuilder.java]
-#
#String badFileFormat
CMD_TIM_SAVE_FORMAT_INVALID=\u7121\u52B9\u306A\u5F62\u5F0F{0}
-#[TimSaverBuilder.java]
-#
#String badPaletteList
CMD_TIM_PALETTE_LIST_INVALID=\u30D1\u30EC\u30C3\u30C8\u306E\u7121\u52B9\u30EA\u30B9\u30C8{0}
@@ -1516,7 +1466,7 @@ CMD_TIM_PALETTE_FILES=\u30D1\u30EC\u30C3\u30C8\u30D5\u30A1\u30A4\u30EB\uFF1A{0}
TIM_OUTPUT_FILES=\u9593{0,number,\#}\u500B\u306E\u30D5\u30A1\u30A4\u30EB{1} - {2}
#[TimSaverBuilder.java]
-TIM_OUTPUT_FILES_NONE=\u306A\u3057
+TIM_OUTPUT_FILES_NONE=\u7121\u3057
#[TimSaverBuilder.java]
TIM_DATA_NOT_FOUND=TIM\u306E\u753B\u50CF\u30C7\u30FC\u30BF\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093
diff --git a/jpsxdec/src/jpsxdec/i18n/main_cmdline_help.dat b/jpsxdec/src/jpsxdec/i18n/main_cmdline_help.dat
index 0efcb4f..006f6c0 100644
--- a/jpsxdec/src/jpsxdec/i18n/main_cmdline_help.dat
+++ b/jpsxdec/src/jpsxdec/i18n/main_cmdline_help.dat
@@ -28,9 +28,6 @@ java -jar jpsxdec.jar [ -x ] [ -f ]
-help/-h/-?
Display help about the index item
- -play
- Show real-time player for index item (audio/video items only)
-
(see manual or item's help for full list of possible commands)
-visualize
@@ -65,9 +62,4 @@ java -jar jpsxdec.jar -f
-debug
Show detailed decoding steps (needs Java started with -ea)
-Universal option (optional):
- -verbose/-v #
- How much info to print:
- 0 = none, 1 = only errors, 2 = errors & warnings, 3 = normal, 4 = extra
-
For all command-line options, see the manual.
\ No newline at end of file
diff --git a/jpsxdec/src/jpsxdec/i18n/main_cmdline_help_es.dat b/jpsxdec/src/jpsxdec/i18n/main_cmdline_help_es.dat
index 2244259..83252ba 100644
--- a/jpsxdec/src/jpsxdec/i18n/main_cmdline_help_es.dat
+++ b/jpsxdec/src/jpsxdec/i18n/main_cmdline_help_es.dat
@@ -32,10 +32,6 @@ java -jar jpsxdec.jar [ -x ] [ -f ]
-help/-h/-?
Muestra la ayuda del objeto del indice.
- -play
- Muestra el reproductor para el objeto del indice
- (solo videos y/o sonidos)
-
(ver el manual o la ayuda del objeto para revisar la lista completa de
comandos disponibles)
@@ -73,10 +69,4 @@ java -jar jpsxdec.jar -f
Muestra los pasos detallados de decodificaciĂłn
(necesita que Java esté iniciado con -ea).
-Opcion universal (opcional):
- -verbose/-v #
- Cuanta informacion se debe escribir:
- 0 = nada, 1 = solo errores, 2 = errores y advertencias,
- 3 = normal, 4 = extra
-
Revisa el manual para conocer todos los comandos disponibles.
\ No newline at end of file
diff --git a/jpsxdec/src/jpsxdec/i18n/main_cmdline_help_it.dat b/jpsxdec/src/jpsxdec/i18n/main_cmdline_help_it.dat
new file mode 100644
index 0000000..8c93f3e
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/i18n/main_cmdline_help_it.dat
@@ -0,0 +1,69 @@
+
+java -jar jpsxdec.jar [ or ]
+ Mostra l'interfaccia grafica, anche durante l'apertura di
+ o (rilevamento automatico)
+
+java -jar jpsxdec.jar <-?, -h, -help>
+ Mostra questo aiuto
+
+java -jar jpsxdec.jar -f -x
+ Crea un indice di per salvarlo come
+
+java -jar jpsxdec.jar [ -x ] [ -f ]
+
+ Comando principale dove è richiesto un file indice.
+ Usa un esistente (ignorando anche il indicato
+ al suo interno) oppure crea un indice al volo per (salvandolo
+ eventualmente come ) ed eseguendo uno dei seguenti comando
+
+
+ -item/-i <#, id>
+ -all/-a
+ Esegue su una voce dell'indice,
+ oppure su tutte le voci di un unico tipo (audio, video, file, immagine)
+
+ Se nessun altro comando è specificato:
+ Estrate la voce dall'indice processandola con i parametri facoltativi
+ (usa la funzione di aiuto sulla voce per conoscere i parametri)
+
+ -help/-h/-?
+ Mostra informazioni di aiuto riguardo la voce dell'indice
+
+ (consulta il manuale o la funzione di aiuto sulla voce interessata,
+ per una lista di possibili comandi)
+
+ -visualize
+ Mostra la disposizione dei settori e delle voci dell'indice
+
+java -jar jpsxdec.jar -f
+ Comando principale dove è richiesto solo un file in ingresso.
+
+ -copysect <#, #-#>
+ Copia settori su un altro file
+
+ -sectordump
+ Genera una lista in dei tipi di settori rilevati
+ (utile per fare debug)
+
+ -static
+ Per bs o mdec (nessun parametro aggiuntivo richiesto per file TIM):
+
+ -dim x
+ Risoluzione del fotogramma (parametro obbligatorio)
+
+ -quality/-q
+ QualitĂ di decodifica (valore predefinito "alto").
+
+ -fmt
+ Formato di destinazione (tipo predefinito PNG).
+
+ -up
+ Medoto per sovracampionare la crominanza (metodo predefinito Bicubic)
+ Opzioni: NearestNeighbor, Bilinear, Bicubic, Bell,
+ Mitchell, BSpline, Lanczos3, Hermite
+
+ -debug
+ Mostra informazioni dettagliate sul processo di decodifica
+ (Java deve essere avviato col parametro -ea)
+
+Per ulteriori dettagli sui comandi, consulta il manuale.
\ No newline at end of file
diff --git a/jpsxdec/src/jpsxdec/indexing/DiscIndex.java b/jpsxdec/src/jpsxdec/indexing/DiscIndex.java
index 99d248e..cdf9ef4 100644
--- a/jpsxdec/src/jpsxdec/indexing/DiscIndex.java
+++ b/jpsxdec/src/jpsxdec/indexing/DiscIndex.java
@@ -73,7 +73,6 @@
import jpsxdec.modules.sharedaudio.DiscItemAudioStream;
import jpsxdec.modules.strvideo.DiscItemStrVideoStream;
import jpsxdec.util.IO;
-import jpsxdec.util.IOException6;
import jpsxdec.util.Misc;
import jpsxdec.util.TaskCanceledException;
@@ -101,7 +100,7 @@ public IndexNotFoundException(@Nonnull File file, FileNotFoundException ex) {
}
}
- public static class IndexReadException extends IOException6 {
+ public static class IndexReadException extends IOException {
@Nonnull
private final File _file;
@@ -599,8 +598,10 @@ public void indexingSectorRead(@Nonnull CdSector cdSector) {
int iNewSectNumber = h.calculateSectorNumber();
if (iNewSectNumber != -1) {
if (_iCurrentHeaderSectorNumber >= 0) {
- if (_iCurrentHeaderSectorNumber + 1 != iNewSectNumber)
- _log.log(Level.WARNING, I.INDEX_SECTOR_HEADER_NUM_BREAK(_iCurrentHeaderSectorNumber, iNewSectNumber));
+ if (_iCurrentHeaderSectorNumber + 1 != iNewSectNumber) {
+ _log.log(Level.WARNING, I.INDEX_SECTOR_CORRUPTED_AT(cdSector.getSectorIndexFromStart()));
+ LOG.log(Level.WARNING, "Non-continuous sector header number: {0} -> {1}", new Object[]{_iCurrentHeaderSectorNumber, iNewSectNumber});
+ }
}
_iCurrentHeaderSectorNumber = iNewSectNumber;
} else {
@@ -612,8 +613,10 @@ public void indexingSectorRead(@Nonnull CdSector cdSector) {
switch (cdSector.getType()) {
case MODE1:
- if (_iMode1Count < _iMode2Count)
- _log.log(Level.WARNING, I.INDEX_MODE1_AMONG_MODE2(cdSector.getSectorIndexFromStart()));
+ if (_iMode1Count < _iMode2Count) {
+ _log.log(Level.WARNING, I.INDEX_SECTOR_CORRUPTED_AT(cdSector.getSectorIndexFromStart()));
+ LOG.log(Level.WARNING, "Sector {0} is Mode 1 found among Mode 2 sectors", new Object[]{cdSector.getSectorIndexFromStart()});
+ }
_iMode1Count++;
break;
case UNKNOWN2048:
diff --git a/jpsxdec/src/jpsxdec/indexing/DiscIndexer.java b/jpsxdec/src/jpsxdec/indexing/DiscIndexer.java
index 1901ef5..e293590 100644
--- a/jpsxdec/src/jpsxdec/indexing/DiscIndexer.java
+++ b/jpsxdec/src/jpsxdec/indexing/DiscIndexer.java
@@ -55,8 +55,10 @@
import jpsxdec.modules.crusader.DiscIndexerCrusader;
import jpsxdec.modules.dredd.DiscIndexerDredd;
import jpsxdec.modules.iso9660.DiscIndexerISO9660;
+import jpsxdec.modules.policenauts.DiscIndexerPolicenauts;
+import jpsxdec.modules.roadrash.DiscIndexerRoadRash;
import jpsxdec.modules.spu.DiscIndexerSpu;
-import jpsxdec.modules.square.DiscIndexerSquare;
+import jpsxdec.modules.square.DiscIndexerSquareAudio;
import jpsxdec.modules.strvideo.DiscIndexerStrVideo;
import jpsxdec.modules.tim.DiscIndexerTim;
import jpsxdec.modules.xa.DiscIndexerXaAudio;
@@ -71,13 +73,15 @@ public abstract class DiscIndexer {
public static @Nonnull List createIndexers(@Nonnull ILocalizedLogger log) {
DiscIndexer[] coreIndexers = new DiscIndexer[] {
new DiscIndexerISO9660(log),
- new DiscIndexerSquare(log),
+ new DiscIndexerSquareAudio(log),
new DiscIndexerTim(),
new DiscIndexerStrVideo(log),
new DiscIndexerAceCombat3Video(log),
new DiscIndexerXaAudio(log),
+ new DiscIndexerPolicenauts(),
new DiscIndexerCrusader(log),
new DiscIndexerDredd(log),
+ new DiscIndexerRoadRash(),
};
ArrayList indexers = new ArrayList(Arrays.asList(coreIndexers));
diff --git a/jpsxdec/src/jpsxdec/modules/IdentifiedSector.java b/jpsxdec/src/jpsxdec/modules/IdentifiedSector.java
index 368f5c9..354179a 100644
--- a/jpsxdec/src/jpsxdec/modules/IdentifiedSector.java
+++ b/jpsxdec/src/jpsxdec/modules/IdentifiedSector.java
@@ -86,6 +86,7 @@ final public int getProbability() {
}
/** Returns a string description of the sector type. */
+ @Override
public String toString() {
return _sourceCdSector.toString();
}
diff --git a/jpsxdec/src/jpsxdec/modules/SectorClaimSystem.java b/jpsxdec/src/jpsxdec/modules/SectorClaimSystem.java
index 8e66331..8010b57 100644
--- a/jpsxdec/src/jpsxdec/modules/SectorClaimSystem.java
+++ b/jpsxdec/src/jpsxdec/modules/SectorClaimSystem.java
@@ -50,6 +50,8 @@
import jpsxdec.modules.crusader.SectorClaimToSectorCrusader;
import jpsxdec.modules.dredd.SectorClaimToDreddFrame;
import jpsxdec.modules.iso9660.SectorClaimToSectorISO9660;
+import jpsxdec.modules.policenauts.SectorClaimToPolicenauts;
+import jpsxdec.modules.roadrash.SectorClaimToRoadRash;
import jpsxdec.modules.square.SectorClaimToSquareAudioSector;
import jpsxdec.modules.strvideo.SectorClaimToStrVideoSector;
import jpsxdec.modules.xa.SectorClaimToSectorXaAudio;
@@ -96,6 +98,8 @@ public class SectorClaimSystem {
scs.addClaimer(new SectorClaimToSectorAc3Video());
scs.addClaimer(new SectorClaimToSectorCrusader());
scs.addClaimer(new SectorClaimToDreddFrame());
+ scs.addClaimer(new SectorClaimToPolicenauts());
+ scs.addClaimer(new SectorClaimToRoadRash());
scs.addClaimer(new SectorClaimToUnidentifiedSector());
return scs;
}
@@ -111,9 +115,10 @@ public static abstract class SectorClaimer {
abstract public void sectorRead(@Nonnull ClaimableSector cs,
@Nonnull IOIterator peekIt,
@Nonnull ILocalizedLogger log)
- throws IOException;
+ throws IOException, ClaimerFailure;
- abstract public void endOfSectors(@Nonnull ILocalizedLogger log);
+ abstract public void endOfSectors(@Nonnull ILocalizedLogger log)
+ throws ClaimerFailure;
final public void setRangeLimit(int iStartSector, int iEndSectorInclusive) {
_iStartSector = iStartSector;
@@ -166,6 +171,12 @@ public String toString() {
}
}
+ public static class ClaimerFailure extends RuntimeException {
+ public ClaimerFailure(Throwable cause) {
+ super(cause);
+ }
+ }
+
/** The final sector after being processed by all claimers. */
public static class ClaimedSector {
@Nonnull
@@ -214,12 +225,13 @@ private SectorClaimSystem(@Nonnull CdFileSectorReader cd, int iStartSector,
_outerMostIterator = new BufferedIOIterator(core);
}
- public void addClaimer(@Nonnull SectorClaimer claimer) {
+ void addClaimer(@Nonnull SectorClaimer claimer) {
SectorClaimInception wrapping = new SectorClaimInception(_outerMostIterator, claimer);
_outerMostIterator = new BufferedIOIterator(wrapping);
_iterators.add(wrapping);
}
+ @SuppressWarnings("unchecked")
public @Nonnull T getClaimer(@Nonnull Class clazz) {
for (SectorClaimInception iterator : _iterators) {
if (iterator._claimer.getClass() == clazz) {
@@ -239,7 +251,9 @@ public boolean hasNext() {
return _outerMostIterator.hasNext();
}
- public @Nonnull ClaimedSector next(@Nonnull ILocalizedLogger log) throws CdFileSectorReader.CdReadException {
+ public @Nonnull ClaimedSector next(@Nonnull ILocalizedLogger log)
+ throws CdFileSectorReader.CdReadException, ClaimerFailure
+ {
try {
_log = log;
ClaimableSector next;
diff --git a/jpsxdec/src/jpsxdec/modules/ac3/DemuxedAc3Frame.java b/jpsxdec/src/jpsxdec/modules/ac3/DemuxedAc3Frame.java
index 2416ba7..49f959e 100644
--- a/jpsxdec/src/jpsxdec/modules/ac3/DemuxedAc3Frame.java
+++ b/jpsxdec/src/jpsxdec/modules/ac3/DemuxedAc3Frame.java
@@ -47,6 +47,7 @@
import jpsxdec.modules.video.IDemuxedFrame;
import jpsxdec.modules.video.framenumber.FrameNumber;
import jpsxdec.modules.video.sectorbased.SectorBasedFrameReplace;
+import jpsxdec.psxvideo.mdec.MdecInputStream;
import jpsxdec.util.DemuxedData;
import jpsxdec.util.Fraction;
@@ -86,6 +87,10 @@ void setFrame(@Nonnull FrameNumber frameNumber) {
return _frameNumber;
}
+ public @CheckForNull MdecInputStream getCustomFrameMdecStream() {
+ return null;
+ }
+
public int getWidth() { return _iWidth; }
public int getHeight() { return _iHeight; }
public int getStartSector() { return _demux.getStartSector(); }
diff --git a/jpsxdec/src/jpsxdec/modules/ac3/DiscIndexerAceCombat3Video.java b/jpsxdec/src/jpsxdec/modules/ac3/DiscIndexerAceCombat3Video.java
index cf8adb5..b7da693 100644
--- a/jpsxdec/src/jpsxdec/modules/ac3/DiscIndexerAceCombat3Video.java
+++ b/jpsxdec/src/jpsxdec/modules/ac3/DiscIndexerAceCombat3Video.java
@@ -47,6 +47,7 @@
import jpsxdec.discitems.DiscItem;
import jpsxdec.discitems.SerializedDiscItem;
import jpsxdec.i18n.exception.LocalizedDeserializationFail;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.indexing.DiscIndex;
import jpsxdec.indexing.DiscIndexer;
@@ -129,7 +130,7 @@ public Ac3Channel(@Nonnull DiscIndexerAceCombat3Video indexer, int iChannel) {
_sac3v2dac3frame = new SectorAc3VideoToDemuxedAc3Frame(iChannel, this);
}
- public void feedSector(@Nonnull SectorAceCombat3Video vidSector) {
+ public void feedSector(@Nonnull SectorAceCombat3Video vidSector) throws LoggedFailure {
Ac3AddResult result = _sac3v2dac3frame.feedSector(vidSector, _indexer._errLog);
if (result == Ac3AddResult.WrongChannel)
throw new RuntimeException("AC3 sector was not accepted for some reason.");
@@ -183,6 +184,7 @@ public void attachToSectorClaimer(@Nonnull SectorClaimSystem scs) {
public Ac3AddResult feedSector(@Nonnull SectorAceCombat3Video vidSector,
@Nonnull ILocalizedLogger log)
+ throws LoggedFailure
{
Integer oiChannel = vidSector.getChannel();
Ac3Channel channel = _activeStreams.get(oiChannel);
diff --git a/jpsxdec/src/jpsxdec/modules/ac3/DiscItemAceCombat3VideoStream.java b/jpsxdec/src/jpsxdec/modules/ac3/DiscItemAceCombat3VideoStream.java
index 13e219b..ee39ea1 100644
--- a/jpsxdec/src/jpsxdec/modules/ac3/DiscItemAceCombat3VideoStream.java
+++ b/jpsxdec/src/jpsxdec/modules/ac3/DiscItemAceCombat3VideoStream.java
@@ -46,6 +46,7 @@
import jpsxdec.discitems.DiscItem;
import jpsxdec.discitems.SerializedDiscItem;
import jpsxdec.i18n.exception.LocalizedDeserializationFail;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.DebugLogger;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.IIdentifiedSector;
@@ -112,6 +113,11 @@ public DiscItemAceCombat3VideoStream(@Nonnull CdFileSectorReader cd,
return TYPE_ID;
}
+ @Override
+ public boolean hasIndependentBitstream() {
+ return true;
+ }
+
@Override
public int getParentRating(@Nonnull DiscItem child) {
if (!(child instanceof DiscItemXaAudioStream))
@@ -221,7 +227,7 @@ public void setFrameListener(@Nonnull IDemuxedFrame.Listener listener) {
_listener = listener;
}
- public void frameComplete(@Nonnull DemuxedAc3Frame frame, @Nonnull ILocalizedLogger log) {
+ public void frameComplete(@Nonnull DemuxedAc3Frame frame, @Nonnull ILocalizedLogger log) throws LoggedFailure {
FrameNumber fn = _frameNumberFormatter.next(frame.getStartSector(),
_iEndFrameNumber - frame.getInvertedHeaderFrameNumber(),
log);
diff --git a/jpsxdec/src/jpsxdec/modules/ac3/SectorAc3VideoToDemuxedAc3Frame.java b/jpsxdec/src/jpsxdec/modules/ac3/SectorAc3VideoToDemuxedAc3Frame.java
index 863a5d5..5702247 100644
--- a/jpsxdec/src/jpsxdec/modules/ac3/SectorAc3VideoToDemuxedAc3Frame.java
+++ b/jpsxdec/src/jpsxdec/modules/ac3/SectorAc3VideoToDemuxedAc3Frame.java
@@ -39,6 +39,7 @@
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
/** Collects Ace Combat 3 sectors and generates frames.
@@ -47,7 +48,8 @@
public class SectorAc3VideoToDemuxedAc3Frame implements SectorClaimToSectorAc3Video.Listener {
public static interface Listener {
- void frameComplete(@Nonnull DemuxedAc3Frame frame, @Nonnull ILocalizedLogger log);
+ void frameComplete(@Nonnull DemuxedAc3Frame frame, @Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
}
private final int _iChannel;
@@ -70,6 +72,7 @@ public void setListener(@CheckForNull Listener listener) {
public @Nonnull Ac3AddResult feedSector(@Nonnull SectorAceCombat3Video vidSector,
@Nonnull ILocalizedLogger log)
+ throws LoggedFailure
{
if (vidSector.getChannel() != _iChannel)
return Ac3AddResult.WrongChannel;
@@ -89,7 +92,7 @@ public void setListener(@CheckForNull Listener listener) {
return Ac3AddResult.Same;
}
- public void endOfSectors(@Nonnull ILocalizedLogger log) {
+ public void endOfSectors(@Nonnull ILocalizedLogger log) throws LoggedFailure {
if (_currentFrame == null)
return;
if (_listener != null)
diff --git a/jpsxdec/src/jpsxdec/modules/ac3/SectorClaimToSectorAc3Video.java b/jpsxdec/src/jpsxdec/modules/ac3/SectorClaimToSectorAc3Video.java
index 6758543..3abe06d 100644
--- a/jpsxdec/src/jpsxdec/modules/ac3/SectorClaimToSectorAc3Video.java
+++ b/jpsxdec/src/jpsxdec/modules/ac3/SectorClaimToSectorAc3Video.java
@@ -41,6 +41,7 @@
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import jpsxdec.cdreaders.CdSector;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.SectorClaimSystem;
import jpsxdec.util.IOIterator;
@@ -50,8 +51,10 @@ public class SectorClaimToSectorAc3Video extends SectorClaimSystem.SectorClaimer
public interface Listener {
@Nonnull Ac3AddResult feedSector(@Nonnull SectorAceCombat3Video vidSector,
- @Nonnull ILocalizedLogger log);
- void endOfSectors(@Nonnull ILocalizedLogger log);
+ @Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
+ void endOfSectors(@Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
}
public static @CheckForNull SectorAceCombat3Video id(@Nonnull CdSector sector) {
@@ -75,7 +78,7 @@ public void setListener(@CheckForNull Listener listener) {
public void sectorRead(@Nonnull SectorClaimSystem.ClaimableSector cs,
@Nonnull IOIterator peekIt,
@Nonnull ILocalizedLogger log)
- throws IOException
+ throws IOException, SectorClaimSystem.ClaimerFailure
{
if (cs.isClaimed())
return;
@@ -84,13 +87,25 @@ public void sectorRead(@Nonnull SectorClaimSystem.ClaimableSector cs,
return;
cs.claim(vidSect);
- if (_listener != null && sectorIsInRange(cs.getSector().getSectorIndexFromStart()))
- _listener.feedSector(vidSect, log);
+ if (_listener != null && sectorIsInRange(cs.getSector().getSectorIndexFromStart())) {
+ try {
+ _listener.feedSector(vidSect, log);
+ } catch (LoggedFailure ex) {
+ throw new SectorClaimSystem.ClaimerFailure(ex);
+ }
+ }
}
- public void endOfSectors(@Nonnull ILocalizedLogger log) {
- if (_listener != null)
- _listener.endOfSectors(log);
+ public void endOfSectors(@Nonnull ILocalizedLogger log)
+ throws SectorClaimSystem.ClaimerFailure
+ {
+ if (_listener != null) {
+ try {
+ _listener.endOfSectors(log);
+ } catch (LoggedFailure ex) {
+ throw new SectorClaimSystem.ClaimerFailure(ex);
+ }
+ }
}
}
diff --git a/jpsxdec/src/jpsxdec/modules/dredd/DreddFrameToFrame.java b/jpsxdec/src/jpsxdec/modules/aconcagua/AconcaguaDemuxer.java
similarity index 63%
rename from jpsxdec/src/jpsxdec/modules/dredd/DreddFrameToFrame.java
rename to jpsxdec/src/jpsxdec/modules/aconcagua/AconcaguaDemuxer.java
index af55869..af0c037 100644
--- a/jpsxdec/src/jpsxdec/modules/dredd/DreddFrameToFrame.java
+++ b/jpsxdec/src/jpsxdec/modules/aconcagua/AconcaguaDemuxer.java
@@ -1,6 +1,6 @@
/*
* jPSXdec: PlayStation 1 Media Decoder/Converter in Java
- * Copyright (C) 2017-2019 Michael Sabin
+ * Copyright (C) 2019 Michael Sabin
* All rights reserved.
*
* Redistribution and use of the jPSXdec code or any derivative works are
@@ -35,39 +35,38 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package jpsxdec.modules.dredd;
+package jpsxdec.modules.aconcagua;
-import javax.annotation.CheckForNull;
+import java.util.List;
import javax.annotation.Nonnull;
+import jpsxdec.modules.video.sectorbased.*;
import jpsxdec.i18n.log.ILocalizedLogger;
-import jpsxdec.modules.video.IDemuxedFrame;
-/** Converts a Dredd frame to a generic frame.
- * Necessary to capture details about a Dredd frame before
- * passing it off as a generic frame. */
-public class DreddFrameToFrame implements SectorClaimToDreddFrame.Listener {
- @CheckForNull
- private IDemuxedFrame.Listener _listener;
+public class AconcaguaDemuxer extends VideoSectorWithFrameNumberDemuxer {
- public DreddFrameToFrame() {
- }
- public DreddFrameToFrame(@Nonnull IDemuxedFrame.Listener listener) {
- _listener = listener;
- }
- public void setListener(@CheckForNull IDemuxedFrame.Listener listener) {
- _listener = listener;
- }
+ private final int _iQuantizationScale;
- public void frameComplete(@Nonnull DemuxedDreddFrame frame, @Nonnull ILocalizedLogger log) {
- if (_listener != null)
- _listener.frameComplete(frame);
+ public AconcaguaDemuxer(@Nonnull SectorAconcaguaVideo firstChunk,
+ @Nonnull ILocalizedLogger log)
+ {
+ super(firstChunk, log);
+ _iQuantizationScale = firstChunk.getQuantizationScale();
}
- public void videoBreak(@Nonnull ILocalizedLogger log) {
+ @Override
+ public boolean addSectorIfPartOfFrame(@Nonnull ISelfDemuxingVideoSector sector) {
+ if (!(sector instanceof SectorAconcaguaVideo))
+ return false;
+ if (((SectorAconcaguaVideo)sector).getQuantizationScale() != _iQuantizationScale)
+ return false;
+ return super.addSectorIfPartOfFrame(sector);
}
- public void endOfSectors(@Nonnull ILocalizedLogger log) {
+ @Override
+ public DemuxedAconcaguaFrame finishFrame(@Nonnull ILocalizedLogger log) {
+ @SuppressWarnings("unchecked")
+ List s = (List)getNonNullChunks(log);
+ return new DemuxedAconcaguaFrame(getWidth(), getHeight(), getHeaderFrameNumber(), s, _iQuantizationScale);
}
-
}
diff --git a/jpsxdec/src/jpsxdec/modules/aconcagua/BitStreamUncompressor_Aconcagua.java b/jpsxdec/src/jpsxdec/modules/aconcagua/BitStreamUncompressor_Aconcagua.java
new file mode 100644
index 0000000..53bc253
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/aconcagua/BitStreamUncompressor_Aconcagua.java
@@ -0,0 +1,530 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.aconcagua;
+
+import javax.annotation.Nonnull;
+import jpsxdec.psxvideo.bitstreams.BitStreamDebugging;
+import jpsxdec.psxvideo.mdec.MdecBlock;
+import jpsxdec.psxvideo.mdec.MdecCode;
+import jpsxdec.psxvideo.mdec.MdecContext;
+import jpsxdec.psxvideo.mdec.MdecException;
+import jpsxdec.psxvideo.mdec.MdecInputStream;
+import jpsxdec.util.IO;
+import jpsxdec.util.Misc;
+
+/**
+ * The Aconcagua video bitstream decoder.
+ *
+ * nnnn##+++++++++++++++++++*;:,:;*znnnzzz#################zzzzzzzzz*;,` ``...`` `.,:,,.```.,:i*+znzznnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+ * nnnn#####++++++++++++++++*;:,:;*znnnnzzz###############zzzzzzzzn#*:.` ``.,.` `.,,,.`````.:;i+znnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnxnnnnnn
+ * nnnn####+++++++++++++++++*;:,:;*znnnnzzz###############zzzzzzznn#i:.` `.,,.` `.,,.`` ``.,;i*#nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+ * nnnn####+++++++++++++++++*;:,:;*znnnnzz###############zzzzz#####+i:...``.,,,.` `.,,.`` `..,:;i+++nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+ * nnnn####+++++++++++++++++*;:,:;*znnnnzz###########zzzzzzzz+**i*++*****#zzzz+i,` ``.:,.````..;::ii;:+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+ * nnnn####+++++++++++++++++*;:,:;*znnnnzz##########z#zzzzz#**;;i*+zxMM@W@@@@WWWni.` ``,:,,.```.;;i;ii;;;+nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+ * nnnn####+++++++++++++++++*;:,:;*znnnnzzz#########zzzzzz#+*;:;i#nMMW@@W@@@@@@@@Wx+.``,::,.```.*iii***;;i*nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+ * nnnn###++++++++++++++++++*;:,:;*znnnnzz#####z####z+zzzz+*;::innMMWMWxM@####@@@@@Wx+::::,.``,.*+*ii;;*i;i+nnznnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+ * nnnn#++++++++++++++++++++*;:,:;*znnnnzz###;;*###zi;;*z#*i:;*xxMWMWWWWW#@@@@@@@@@@WWMzi:,.`;;;:+#*ii;;ii;iznnzznnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+ * nnnn#++++++++++++++++++++*;:::;*znnnnzz#z;;;i#z+:;;;iz+i;;+MxxMMW@W@W@@@@@@@@@@@@@WMMx+:.`+;;;i*++*ii;;i:inznzzzzznnnnzzzzznnnnnnnnnnnnnnnnnnnnnnznnnn
+ * nnnn#++++++++++++++++++++*i::;;*znnnnzzz*i;i*+;i*;;i*z+i#znMMxWW@@##@@####@@#@#@@@@WWWWn:`**i;;i*+z+*i;;i:*nzzzzzzzzzzzzzzznnnnnnnnnnnnnzzznnnnnnznnnn
+ * nnnn#++++++++++++++++++++*i;;;;*#nnnnzz#**;*#+*ii;i*#nnxxxxWW@@@#@#@@####@@@@@@@@@@@@WW@M;.##ii;ii*++*i::i;inzzzzzzzzzzzzzzznznnnnnnnnnzzzznnnnnnznnnn
+ * nnnn#+++++++++++++++++++++i;::;i+znnnzz**i*#+*i;;**#Wz+M@@@W@@@@#@@@@@@@@@@@@@@@@@@W@@WMWM*.i#+*;;ii*++i::iizzzzzzzzzzzzzzzzzznnnnnnnzzzzznnnnnnnnnnnn
+ * nnnn#+++++++++++++++++++++i;,,:;*znnnn#+ii+**iiii*zM+;:+@@@@@@@##@####@@@@@@@##@@@@@@WMMMWM*..i#*i;;ii+#*;i*+zzzzzzzzzzzzzzzzzzzzznnzzzzzzzznnnnnnnnnn
+ * nnnn##++++++++++++++++++++i:,.,:i#nnnz+**++ii;i*+zzi;;;*@@@##########@@#####@@@@@@@@@WxxMMxxz,`:#*;;:;i++i;*inzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzznnnnznnnn
+ * nnnn##+++++++++++++++++++*;,...,i#nnn#****i;:;i+z+iii;i#@@########@##########@@@@@@@@@WMWMMxxz,.:#+i;:;i++ii*zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzznnnn
+ * nnnn#++++++++++++++++++++*;,``.,;#nn#*iiii;:;*+#*i;;;i+M@###################@#@#@@@@#@@@W@WMMW*..:++*;;i*+*i*+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzznnnn
+ * nnnn###++++++++++++++++++*;,```,;+nz**i*i;:;**#*i;;;i#W#####################@@@@##@@##@@@W@WW@x:,,;+#*;i*++***nzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzznnnn
+ * nnnn###++++++++++++++++++*;,```,i#n++*+ii:;+#+i;;;i*z@##################@@@@@@@@@###@@@@@@@@@@@+.,:i+#i;i*+***zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzznnnn
+ * nnnn###++++++++++++++++++*;,``.,i#z+++*i;;+z*i;:;i+M@##########################@##@@@@@@@@#@@@@M:,:;**+i;*****zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzznnnn
+ * nnnn###++++++++++++++++++*;,.`.:i#+++**;;*#*i;::i*M#######################@@###@##@@@#@@@@MznW@@*,:;**+*;i****+zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzznnnn
+ * nnnn####+++++++++++++++++*;,...:*z+***i:*+*i;::i*n@######@#############@@@@##@@###@#@@@@#@z::;i*+:,;*++*;i*****nzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzznnnn
+ * nnnn####+++++++++++++++++*;,..,;+#+**i;i#*i;::i*n@########@@########@@@###@@@@#@@@@@@@@@##n::;i;iii;*z+*i;i***izzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzznnnn
+ * nnnn####+++++++++++++++++*;,,,,i#+++*;;#++i;;i+n@#@#####@@@@@@######@@@#@##@@#@@@#@@##@@##W+i;;;;i;i*+z*i;ii*+**zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzznnnn
+ * nnnn##+++++++++++++++++++*;,,,:i+***i;*#*ii;i*z@@@###Wxn@@WWWW###@@@@@@@@@@@@@@@@@#@#######Wz*iii;;;ii*+*;;i*i*izzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzznnnn
+ * nnnn###+++++++++++++++++++;,,,,i*+**ii#*i;;i*iM@##Wx#;::x@WWMWW@@@@@@####@@#@@@@#@@@########@Wz*ii;;;i*+*i;;*i;i*zz#zzzzzzzzzzzzzzzzzzzzzzzzzzzzzznnnn
+ * nnnn##+++++++++++++++++++*;,,,,;****;++i;;;*i+@#@xiii:::nWWWMMMW@@@##@@@@@@@@@@@@@@###########@Wzii;ii****i;i**ii#zz#z#z########zzzzzzzzzzzzzzzzzznnnn
+ * nnnn#+++++++++++++++++++++;,,,,i+*iii+ii;;**ix#W#i;;;;;iMWMMMMxMWW@@@@@@@@@@@@@@@@@@###########@@W#*iiii***ii***iiz#zz#############zzzzzzzzzzzzzzznnnn
+ * nnnn#+++++++++++++++++++++;,,.:+*iii+*i;;*+*#Wni;i;;;;*x@WWWMxznxxWWW@@@@@@@@#@@@@@@@@##########@@M++*i;ii***ii*i;*z#z##########zzzzz##zzzzzzzzzzznnnn
+ * nnnn#++++++++++++++++++++*;,.,*iiiii*ii;i+*#z*i;:iiii#W@WWWWxn#zzznnxMM@@@@@@@@@@@##@@@###########@;*+*iiiii******izz###################zzzzzzzzzznnnn
+ * nnnn#++++++++++++++++++++*;,.iii*i**i;;;i**+*ii:;;i+M@@@@@WWWz+#nn###xxMW@@@@@@@@@@#@@#@########@@#ziz#*i;i*i****ii*z#####################zzzzzzzznnnn
+ * nnnn#+++#++++++++++++++++*;,:******iii;ii+**iii;;;#@@@@@@WWMMnz##zzz++zxMWWW@@@@@@@@@WMWW@@@###@@@@M*z+i;;;ii*ii*ii;######################zzzzzzzznnnn
+ * nnnn#++++++++++++++++++++*;,;***i**ii;;;**iiii;;;z@@#@@@@@WMnnz#+####++##xWWWWW@@W@@@WxnnxxW######@W*##*;;;ii*iii+*ii#####################zzzzzzzznnnn
+ * nnnn#++++++++++++++++++++*i:******iiiii**ii;;;i*x@@@#@@@@WMnnnz+*+#++*iii++xxnM@WMnMMzzzzznn@@@@@##@+*++i;;iiiiii*+i:+###################zzzzzzzzznnnn
+ * nnnn#++++++++++++++++++++*ii**+i*iii***ii;;;;iin###@@@@@@Mxxzznz#+++iiii;+iinz#nMnz#z#znnnnnM@@@@##@##Mn+;;;iiiiii**:;###################zzzzzzzzznnnn
+ * nnnn#+++++++++++++++++++++i+****i***ii;;;;;ii*x@###@#@@WMnnnzznnz#*#+**+i+i:++*##zznznxxxnnnx@@@@##@#xWxn+i;iiiiiiiii;*#############zzz#zzzzzzzzzznnnn
+ * nnnn#+++++++++++++++++++++*********ii;;;;;i*zW@######@Wxzzznzzznnzzxnznz*+i;*#i+zzxMMnnxnn#nnW#@@####M@Wzi;;;iiiiii*i*;###############zzzzzzzzzzzznnnn
+ * nnnn#++++++++++++++++++++++*+**i+*iii;;;;;;*M######@@WMzzznnzz#z#zxnnnz##+*ii#++znnnnnnnzz#znM@#####zn@@n*;;;;ii;;ii*ii+#############zzzzzzzzzzzzznnnn
+ * nnnn#++++++++++++++++++++***+*i**iiii;;;;ii#@#####@@@Wnzzznz####znn##++zz##+**#z#+iiii*#zz#znx@#####z#nWM*i;;;;iii;i***i+z###z#####zzzzzzzzzzzzzzznnnn
+ * nnnn#++++++++++++++++++++**+*i**iiiiii;;;i*W#######@Wxzzzzn#####+ii*+**++#+ii*#+i*#zz###+z#znx@####@z#zzx#i;;:;ii;;ii*++i#z#zzz###zzzzzzzzzzzzzzzznnnn
+ * nnnn#+++++++++++++++++++*******ii;;;;;;;;ix@######@@Mnzzzzz###+*+znnxn##+#+ii+#++znxW@WMn###nnW####W#z#zz+ii;;;i;;;iiii;iizz###zzzzzzzzzzzzzzzzzznnnnn
+ * nnnn#++++++++++++++++++*******i;;;;ii;;i+M########@@Mnzzzzz+++#xMW@Wzxz+++#***##*z#+#z#zx###nzW####x#zzzz#iii;;;;i;;;;ii,:*z#z#zzzzzzzzzzzzzzzzzznnnnn
+ * nnnn##+++++++++++++++++**+***ii;;;;;;;;;*@########@@xzz##z#+++nz+++**++**##+**#z*+++**i+#z##zzM###@##zzzzz+*iii;;;;;i;;i;,:+zzzzzzzzzzzzzzzzzzzzzznnnn
+ * nnnn####++++++++++++++*i*+**iii;;;;;;;;i+W########@Wxz#####+##+*iii*+##++#+***#z#*+*++*+++#+zzM###W+#zzzzz#iii;;;;;;;;;;i:::+nzzzzzzzzzzzzzzzznnnnnnnn
+ * nnnn####++++++++++++++*****i;;;;;;;;;;i*#M#########Wxzzz###+++**********+#+***###*iiii****++#zM##@x+#zzzzzz*iii;ii;;;:;;;i;;;+nzzzzzzznzzzzznnnnnnnnnn
+ * nnnn####+++++++++++++*i***ii;;;;;;;;;;i+#z@#######@Mnzz###+++***iiiiiii*+++***+##+*iiii**+++##x##@#+##zzzzz#****i;;;:::;;;*i;;#nzzzzznnnnnnnnnnnnnnnnn
+ * nnnn####++++++++++++*i**iiii;;;;;;;;;i*###@#@@####@xnz####+++***iiiiii*+++++**###+***iiii*++##x#@@*+##zzzzzz#**iii;;::::;;iii;;znnnzznnnnnnnnnnnnnnnnn
+ * nnnn##++++++++++++++***iii;;;;;;;;;;ii*##+x#@@@##@@xnz###++***iii;ii*****+++**+##++***iiii*+##x##@i+zzzzzzzzz#*++*i;:::;;;;ii;:;nnznnnnnnnnnnnnnnnnnnn
+ * nnnn#+++++++++++++*i*i*i;i;;;;;;;;;;i*###+z@@@@@@@@xnz####**iii;;i***iii+++*ii*+#+****iii***##x##x;+zzzzzzzzzzz#++i;:::;:;;i*i::innnnnnnnnnnnnnnnnnnnn
+ * nnnn##+++++++++++i****iii;;;;;;;;;;i**###++W#@@@@@@xzz####+*i;;;iiiiiii*++*ii;i*##*i*iiii*++##x#W+i##zzzzzzzzzzz##*;;;:::;;ii*i;;innnnnnnnnnnnnnnnnnnn
+ * nnnn##++++++++++i****i;;;;;;;;;;;;i**+z##++n@WMW@@WMzzz#+#+*ii;;;;iiiii+#+*i;:;*+##*ii;ii*++##xW#;i+zzzzzzzzzzzzz#+ii;;:::;;;iii;:*nznnnnnnnnnnnnnnnnn
+ * nnnn##+++++++++******i;;;;;;;;;;i***+zz##++z@WMW@@Wxzz####+**i;;;;;ii;*#++*;;;;i+##+iiiii*+#####i:i#zzzzzzzzzzzzzz#+*;;;;:;;;i;i;;:+nnnnnnnnnnnnnnnnnn
+ * nnnn##+++++++#+*****i;;;;;;;;;;ii**+zzz##+++WMWWWWMnz#####++**i;;;;;;*#+***iiii*++##*iiii*+###z+::i#zzzzzzzzzzzzzn##+i;;::;;;;i;;;::znnnxnnnnnnnnnnnnn
+ * nnnn###+++++#+*i****i;;;::;;;iii**+znzz##+++xMMWWWzzz#####++***ii;;;i+#+****iii*#++#+ii***+####+,:i#zzzzzzzzzzzzzzz#+*i;;;;;;;;i;;;::#+;;*nnxnnnnnnnnn
+ * nnnn###+##+#+ii****i;;;;;;;;;***++znzz###++*#MxW@W#zzz#####++**iiiii**+##xM#+*+zMn#++*i***+##zii,:i#zzzzzzzzzzzzzznz++i;;;;;;;;;i;;::;+i;:i:*#nnnnnnnn
+ * nnnn####i##+******ii;;;;;;;ii+##+zzzzzz##++*ixxMMWn#zz#z#++++***iiii*ii+##zzzz##zz#+*****+#+##*:.:i#zzzzzzzzzzzzzzzn#++i;;;;;;;;ii;;;:+#i:;:ii*#nnnnnn
+ * nnnn##+:,i+*i****ii;;;;;;;;i*#i:*#zzzzz##++*;zMxxnzz#zzz##++++**iii*iii*****++**+++++****+#+##*;.,i+zzzzzzzzzzzzzzznz++*ii;;;;;;;ii;;;+nx*:;;:;+nznnnn
+ * nnnn#+*ii:+i*****i;;;;;;;;i*#+,:i#nzzzz##++i;*Mxn+#z#zzz#+++++***i*iiii*****ii**+++*++**++###++:`,;+zzzzzzzzzzzzzzzzz#+**i;;;;;;;;ii;;+zxzii;:;znznnnn
+ * nnnn#+;i+n#****ii;;;;;;;;i*+#,,:i#zzzzz##++i;;Mxz+##zzz##++*++*****iiii*****iii*+++*++++++#+#+*``,;+#zzzzzzzzzzzzzzznz+**ii;;;;;;;iiii+#nx+ii;innnnnnn
+ * nnnn##*;i#+****i;;;;;;;;ii*#;,,:*#nnzzz##+*i;:x@z+##z#####+**+******iii*i*******++++++++++#+#i` `.:*#zzzzzzzzzzzzzzzzz#++*iii;;;;;iii*+zz#i:;ii#nnnnnn
+ * nnnn##**;++++*ii;;;;;;;;i*++::,:*#zzzzz##+*i;,##@xnMx###z#+**********ii***++**+#+++++#+++++##,` `.:i#zzzzzzzzzzzzzzzzzz+***iii;;;;;;i;*;;,;ii*;;nznnnn
+ * nnnn#i;i+;*#+*ii;;;;;;ii*++i,,,:i#zzzzz##+*i:,*@##@@Mzz#z#+*****i***+ii**+########+*+#+++++#+,` `,;+zzzzzzzzzzzzzzzzzn#**ii;i;,:;i:;,;;,:::;ii:+nnnnn
+ * nnnni;ii*i*#+*i;;;;;;ii*+++;,..,;+zzzzz##+*i::;W@##@xz#z##++*********ii*#zznnzxnzz#++++++++#*:. `.:+zzzzzzzzzzzzzzzzz+;i+**i;*ii:iii*;:,::;;ii;;znnnn
+ * nnnnii;iii+#+**i;;;;ii**++*;,..,:*#zzzz##+*i:,,z##@Mxzzzz#++***********#nxnnxxxnnn##+++++++#i:,. `.:*#zzzzzzzzzzzzzzzz*ii#*i***+ii;**;;;;;;;;;;i:#nnnn
+ * nnnn*i**iiz#++*i;;;ii**+++*;,``.:i#zzzz##+*i;,,;W#@zzzzz##++**********+*+z#+###+#z+#+++++++#n;,,` `,;+zzzzzzzzzzzzzzzzzz+*********i*ii:;;;;iii;;;#nnnn
+ * nnnn***;:*##+***i;iii*++++*:.```,i#nzzz##+*i;:,,+#+i+zzz####*******ii**++##+***+##+++++++++xx+,..``.:*#zzzzzzzzzzzzzzzzz+i*ii*******;;;;;::;;iiii#nnnn
+ * nnnn**i:i+#+++**iii**+++++*:.` `,;#nzzz##+*i;:,,,,,:*#zz####++******ii**++###+###+*+++++++#@M#i,:.``,;*#zzzzzzz#########+iiii******ii;;i;:;;;;;ii#nnnn
+ * nnnn+i;i*;+++******+++++*+*:.```,;#nzzz##+*i;:,,,,,;i+zzz####+****+*******+#zzz#++*+++++++M@Mz#;:,` `,;*+###+++****iiiiiii*iii******iii;;;;;iiii*#nnnn
+ * nnnn*;i*ii*******+++++#*i+*;.```,i#nzzz##+*i;::,::;*i+########+*+++********+###+**++++#++#@@Mz#*:,,` `,,;ii;::;;;:::,,::;*iiiii******iiii;;;;;;;iznnnn
+ * nnnniiiiii;;****+++++#i*i+*;,...:i#nnzz##+*i;;:;i++*i;########++++#+***+**+*+++*++++*++++n@@xz#+i,.````,;;;;;::;;:,...,:;iii*ii*******iii;ii;i;;;znnnn
+ * nnnn*ii;;ii*+*iiii+***+*++*;,...:*znzzzz##**;;i*++*i*;+########+*+#+***++***i******+*+#+#M@@xz#++;``.`:i;i*;;;iii;:::;i*+iii*ii****+***ii;;;;i;i;#nnnn
+ * nnnn*i;;;;i*+#+i**++##+#++*;,..,;+znnn###+*i:i**#+iii*i+#+#####+++#+****i*iii;ii**i**+#+#M@Wx###+i,..;*i***ii;i;i;:;**++z*iiiiiii*++***iiiiii;;ii#nnnn
+ * nnnn*i;;iii****++###z++#++*;,,,:i#nnzi;;:;;;*z+++*;i**i;+####z##++##+ii*iiiiii;ii*i**###zM@Mn##++;::.i+*+++ii;;ii;i+++#nn*i;;iiii*******i;;;i;;;;#nnnn
+ * nnnn*;;;iii*i*++*++++*i*++*;:::::;#z**+ii;;i+n#*+;;i**iii*#######+##+*iii;;;;i;;ii*++###zWWxz###*i;::;*++#+**;i+*i*#++#n*ii;;;iii***i****ii;;;;;;#nnnn
+ * nnnniiiiiii***+*+*+*+*i::;:,:::;:::i+z#*+**i+z#*+;i****ii;i+#########+*iiiiiiiii***++###zWMnz###*;;i;i+#+++i**i#+i*z+#n**z*i;;;;iii**i+*ii;;;i;;;#nnnn
+ * nnnnii;i**ii*++***+***+i::;;;;iii*i:izz++#+*i+#+*i*******i;i*zz####+#++************+####zMMn####*;;i**+++++***;z+i+z+n+*#z*i;;;;;ii**i**iii;;;;;;#nnnn
+ * nnnni;;ii***+****++***#*;:;;ii******;*n#*+z+i;#+*i*ii******i*#zz######+++********++####zzxMz#+++iiiii#++zz+***i##i#zzz*#+++ii;;;;;iii*i*iiiiii;;;#nnnn
+ * nnnn*i;iii**++***++***#*i;:;i*+**+++ii+z++z#i;i++**i******ii+i#znzz##+#+#++**+++++####zz#nnn#+++ii;i*ii+#z*****#z*z#n++++z#iiii;iiiiii**i*ii;;;;;#nznn
+ * nnnnii;ii*+******+****n*ii;:;i****++**i+#+z#*i;i++*iii***+***i*#nnzzz##++++++*++++#####z+z#z#++i;ii+*i**+zii***#z*zz++++#+**iii;;iii*i**i*ii**iii#nnnn
+ * nnnniiii***i****++****x+ii*i;:i***+++*i+++z#+i;;i+*ii;ii*++**iiznnz########++##+######z*#####++ii**+***++#i;*i*+n*zz*+++**+i*i;;;;iiii****iiiiii;#nnnn
+ * nnnni;;i*i******+***+*x#*i*+*i;***+++*i**+#z#+i;i***iii;****+*;*+xn#########zz####+##zi;z#####+i;i*+**+*++;:i*i*z+z#*++*+***i*;;i;;iii*****;ii;;i#nnnn
+ * nnnn*ii**i***+*+***i**x#*i****i***+++*i****z#+i;;i*i;ii;;i****;i+zxzzz######++######+;,*z++#++*ii+nz**+*+*;;i***+#z+****+*++iii;;i;i*******i*ii;;#nnnn
+ * nnnn*ii*ii*i+*++******x#*i*********++****i*#z#+i;ii;;iii;;iii*i+++nz##++++**++++++*;..:+#+++*iii*++*,**i+i;;:****##***++***+*i**;iii;***++*ii;;;i#znnn
+ * nnnn*****i**+*+******+W#*i*********#+**i**++##+*;;i;;;;ii;;ii;i#z###+#####++*i;:.```..i++**;;ii*iii:.:*i+*;;;ii**#z+***+***##i*ii;iiii**+****i;;;#nnnn
+ * nnnn+****+*+*++*****i+@z*i*********#+*ii****+#+i;;ii;;;iii;iii;+*;........```` ```..,iiii;i;iiiiii:.:***i;;i**i*+n+**++**+#+**iiiiiiiii*+***iiii#nnnn
+ * nnnn***++****++*****i+Wz*i**i+*i***##**i*****+*ii;;i;;;;;iii;i;+*:.` ``..,,;i;i;;i;iiii:.i***iii;i*i*+n#**+***++******ii;iiiii*+**iii#nnnn
+ * nnnn********++***+***+xz**+*******+##*i*i**i***ii;;ii;;;i;iii;i*+:. ``...`,iii;;;ii;ii*:.i*iii;i;i+ii*zz*********i****i**i;ii*******i#nnnn
+ * nnnn*ii**ii**********+nz+*********+##***i**ii;i*i;:;i;;;iii;ii*zz#i.` `````````````:ii;;;;;;;iii:.i**iiii;;*i;*#n****i++*iii*******iii********zznnn
+ * nnnn*;;;:ii*;;i;**i;;;i#+******i**+z#**i;i*i;;iii;;;ii;;;;i;;;*++#*:.`` ` ``````ii;;;;i;;;;ii:,***iiii;i*i;i+n+******iiiiii*i*************iznnnn
+ * nnnn+;;;,i;;i;:;;i;;:;*z*i*****i**+z+*i;;i*i;;iiii;;;i;::;iiiii;;;:.`` `````.*;;;;;:;;iii;,,i***ii;;;**;;inz******;;;iiiiiii*********+*i#nnnn
+ * nnnn*ii**+**ii**i;i+ii+z+***i*****+z+*i;;;*i;;;iii;:;i;:;i;;iiiiii,..``` `` ``..*;i;;;:;;;ii;,,***ii;::;**i;;#n*+***i;;;iii;ii;iii*****++**#nnnn
+ * nnnnii*++++****iii****+z+***i*****+z+;ii;i;;i;;ii*;;;ii;;;;i;;i;ii,.,.`` `` ` .`.;i;::;;:;;ii;:;****ii::;**i;:ix+****i;i;iiii;;i;;ii*i*i**++zznnn
+ *
+ *
+ * For each block
+ * - Read the DC code (normal)
+ * - The bits either point to a predefined VLC lookup table (normal)
+ * - Or there is an escape code indicating the DC value is in the
+ * biitstream itself (normal)
+ * - The chroma DC values are relative to prior chroma values (normal)
+ * - The luma DC values are relative to prior luma DC values (normal)
+ * - The choice of crisscrossing which luma block DC codes are relative
+ * to others is... (odd)
+ * - Now you must read an instruction code that tells us how we are going to
+ * decode this block (wait... what?)
+ * - There are only 64 predefined list of instructions, and there is no
+ * escape code to offer an alternative number (that would mean.. how?)
+ * - The instruction will tell us how many AC VLC codes to read from 3
+ * more different tables (and 3 more??)
+ * - So you follow the instructions, and read X VLC codes using the first
+ * table, Y codes using the second table, and Z codes using
+ * the third table (uh, sure)
+ * - Each table comes with it's own escape code to allow for entries not
+ * in the lookup table (back to some normalcy)
+ * - After following the instructions, the block is over (ok)
+ * - The bit reader used for reading the bit stream is actually pretty cool.
+ * The bits are read backwards from how normal bitstreams work, which makes
+ * the reader extremely simple and likely pretty fast. (cool)
+ * - And after reading one vertical column of macroblocks, you reset all the
+ * DC values to 0 (alright, that's fairly reasonable)
+ * and you skip up to 4 bytes in the original bitstream (4 bytes just
+ * wasted??)
+ *
+ * What even.......
+ *
+ * There's no escape code to do some unique number of table lookups among the
+ * three tables. You're stuck with them. Which means there will be cases where
+ * you really don't need to read N values from a table--too bad, because you're
+ * reading that preset count no matter what. Or maybe it would be better to read
+ * more from one of the tables to save some bits--nope! Or maybe you need to
+ * read only N number of codes in a block, but there is no X+Y+Z=N. What do you
+ * even do???
+ *
+ * Now consider this from the perspective of the insane encoder someone had to
+ * write. How do you choose how many values need to be read from each table. And
+ * even more insane, how were the final instruction table values chosen in the
+ * first place????? And why are there 3 tables to read from???? Why not 2? Or
+ * 4? And how were the values of those tables even chosen as well????????
+ *
+ * Now let's say maybe all this somehow actually saved some space in the frame
+ * to allow for a better quality image. Those few *BIT* savings are completely
+ * blown away by wasting at least a dozen *BYTES* per frame.
+ *
+ * And all this insanity is compounded by the fact that there is the standard
+ * PlayStation bitsream formats that
+ * - are readily available
+ * - encode better
+ * - are better quality
+ * - decode faster
+ * - and the decoding logic is already written for you
+ * - and so is the encoder!!
+ *
+ * Having said all that, we all make poor design decisions in our lives. Trying
+ * to spin up your own version of some other program because you could do it
+ * better--only to be wrong, but you're stuck with it now. It happens to all of
+ * us. I'm sure someone in the devolpment team wished they could go back and do
+ * it differently.
+ */
+public class BitStreamUncompressor_Aconcagua implements MdecInputStream {
+
+ private static final int MACROBLOCK_HEIGHT = 13; // 208 / 16
+
+ private final int _iQuantizationScale;
+ @Nonnull
+ private final MdecContext _context;
+
+ private int _iBlocksLeftInColumn = MACROBLOCK_HEIGHT * 6;
+
+ public BitStreamUncompressor_Aconcagua(int iMacroblockHeight, int iQuantizationScale, @Nonnull byte[] abBitstream) {
+ _iQuantizationScale = iQuantizationScale;
+ _bitstream = new AconcaguaBitReader(abBitstream, 0);
+ _context = new MdecContext(iMacroblockHeight);
+ }
+
+ // -------------------------------------------------------------------------
+ @Nonnull
+ private final AconcaguaBitReader _bitstream;
+ private int _iPreviousDcCr = 0;
+ private int _iPreviousDcCb = 0;
+ private int _iPreviousDcSetInY1UsedInY2Y3 = 0;
+ private int _iPreviousDcSetInY3UsedInY1Y4 = 0;
+
+ private int _iTable1Reads = -1;
+ private int _iTable2Reads = -1;
+ private int _iTable3Reads = -1;
+
+ private void resetColumn() {
+ _iPreviousDcCr = 0;
+ _iPreviousDcCb = 0;
+ _iPreviousDcSetInY1UsedInY2Y3 = 0;
+ _iPreviousDcSetInY3UsedInY1Y4 = 0;
+ _bitstream.resetColumn();
+ _iBlocksLeftInColumn = MACROBLOCK_HEIGHT * 6;
+ }
+ // -------------------------------------------------------------------------
+
+ private static final int BOTTOM_3_BITS = 0x0007;
+ private static final int BOTTOM_8_BITS = 0x00ff;
+ private static final int BOTTOM_9_BITS = 0x01ff;
+ private static final int BOTTOM_10_BITS = 0x03ff;
+ private static final int BOTTOM_11_BITS = 0x07ff;
+ private static final int BOTTOM_14_BITS = 0x3fff;
+ private static final int BIT9 = 0x0100;
+ private static final int BIT10 = 0x0200;
+
+ public boolean readMdecCode(@Nonnull MdecCode code) throws MdecException.EndOfStream, MdecException.ReadCorruption {
+ if (_context.atStartOfBlock()) {
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.println(_context.toString());
+ if (_iBlocksLeftInColumn == 0)
+ resetColumn();
+ _iBlocksLeftInColumn--;
+
+ int iNext32Bits = _bitstream.getBits();
+ int iBitsToSkip = readDc(_context.getCurrentBlock(), code, iNext32Bits);
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.println(String.format("%d bits qscale/dc %s", iBitsToSkip, code));
+ _bitstream.skipBits(iBitsToSkip);
+ _context.nextCode();
+ return false;
+ } else {
+ if (_context.getMdecCodesReadInCurrentBlock() == 1) {
+
+ int iInstructionCode = _bitstream.getBits() & BOTTOM_10_BITS;
+ InstructionTable.InstructionCode instruction = InstructionTable.lookup(iInstructionCode);
+ _bitstream.skipBits(instruction.getBitCodeLen());
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.println(String.format("%d bits %s", instruction.getBitCodeLen(), instruction));
+
+ _iTable1Reads = instruction.getTable1Count();
+ _iTable2Reads = instruction.getTable2Count();
+ _iTable3Reads = instruction.getTable3Count();
+ }
+
+ if (_iTable1Reads > 0) {
+ int iNext32Bits = _bitstream.getBits();
+ int iBitsToSkip = readTable1(code, iNext32Bits);
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.println(String.format("%d bits %s", iBitsToSkip, code));
+ _bitstream.skipBits(iBitsToSkip);
+ _iTable1Reads--;
+ _context.nextCode();
+ return false;
+ }
+
+ if (_iTable2Reads > 0) {
+ int iNext32Bits = _bitstream.getBits();
+ int iBitsToSkip = readTable2(code, iNext32Bits);
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.println(String.format("%d bits %s", iBitsToSkip, code));
+ _bitstream.skipBits(iBitsToSkip);
+ _iTable2Reads--;
+ _context.nextCode();
+ return false;
+ }
+
+ if (_iTable3Reads > 0) {
+ int iNext32Bits = _bitstream.getBits();
+ int iBitsToSkip = readTable3(code, iNext32Bits);
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.println(String.format("%d bits %s", iBitsToSkip, code));
+ _bitstream.skipBits(iBitsToSkip);
+ _iTable3Reads--;
+ _context.nextCode();
+ return false;
+ }
+
+ code.setToEndOfData();
+ _context.nextCodeEndBlock();
+ return true;
+ }
+ }
+
+ private int readDc(@Nonnull MdecBlock block, @Nonnull MdecCode code, int iNext32Bits) throws MdecException.ReadCorruption {
+ boolean blnIsDcEscapeCode = (iNext32Bits & BOTTOM_3_BITS) == 0;
+
+ int iDcFromEscapeCode = -1;
+ int iRelativeDcFromTable = -1;
+ int iBitsToSkip;
+
+ if (blnIsDcEscapeCode) {
+ iDcFromEscapeCode = (iNext32Bits >> 3) & BOTTOM_10_BITS;
+ iBitsToSkip = 3 + 10; // 3 zeros + 10 bits for DC
+ } else {
+ DcTable.DcCode entry = DcTable.lookup(iNext32Bits & BOTTOM_11_BITS);
+ iRelativeDcFromTable = entry.getRelativeDcCoefficient();
+ iBitsToSkip = entry.getBitCodeLen();
+ }
+
+ int iFinalDc;
+
+ switch (block) {
+ case Cr:
+ if (blnIsDcEscapeCode)
+ iFinalDc = iDcFromEscapeCode;
+ else
+ iFinalDc = iRelativeDcFromTable + _iPreviousDcCr;
+ _iPreviousDcCr = iFinalDc;
+ break;
+ case Cb:
+ if (blnIsDcEscapeCode)
+ iFinalDc = iDcFromEscapeCode;
+ else
+ iFinalDc = iRelativeDcFromTable + _iPreviousDcCb;
+ _iPreviousDcCb = iFinalDc;
+ break;
+ case Y1:
+ if (blnIsDcEscapeCode)
+ iFinalDc = iDcFromEscapeCode;
+ else
+ iFinalDc = iRelativeDcFromTable + _iPreviousDcSetInY3UsedInY1Y4;
+ _iPreviousDcSetInY1UsedInY2Y3 = iFinalDc;
+ break;
+ case Y2:
+ if (blnIsDcEscapeCode)
+ iFinalDc = iDcFromEscapeCode;
+ else
+ iFinalDc = iRelativeDcFromTable + _iPreviousDcSetInY1UsedInY2Y3;
+ break;
+ case Y3:
+ if (blnIsDcEscapeCode)
+ iFinalDc = iDcFromEscapeCode;
+ else
+ iFinalDc = iRelativeDcFromTable + _iPreviousDcSetInY1UsedInY2Y3;
+ _iPreviousDcSetInY3UsedInY1Y4 = iFinalDc;
+ break;
+ case Y4: default:
+ if (blnIsDcEscapeCode)
+ iFinalDc = iDcFromEscapeCode;
+ else
+ iFinalDc = iRelativeDcFromTable + _iPreviousDcSetInY3UsedInY1Y4;
+ break;
+ }
+
+ code.set((_iQuantizationScale << 10) | (iFinalDc & BOTTOM_10_BITS));
+
+ return iBitsToSkip;
+ }
+
+ private static int readTable1(@Nonnull MdecCode code, int iNext32Bits) throws MdecException.ReadCorruption {
+ if ((iNext32Bits & BOTTOM_8_BITS) == 0) {
+ // escape code
+
+ int iMdecCode;
+ int iVlcCodeLength;
+ if ((iNext32Bits & BIT9) != 0) {
+ // positive
+ iMdecCode = iNext32Bits >> 9;
+ iVlcCodeLength = 25;
+ } else {
+ // negative
+ int iSignExtendAc = (iNext32Bits << 16) >> 25;
+ iMdecCode = iSignExtendAc & BOTTOM_10_BITS;
+ iVlcCodeLength = 16;
+ }
+
+ code.set(iMdecCode);
+ return iVlcCodeLength;
+
+ } else {
+ ZeroRunLengthAcTables.AcCode ac = ZeroRunLengthAcTables.lookupTable1(iNext32Bits & BOTTOM_14_BITS);
+ ac.setMdec(code);
+ return ac._sBits.length();
+ }
+ }
+
+ private static int readTable2(@Nonnull MdecCode code, int iNext32Bits) throws MdecException.ReadCorruption {
+ if ((iNext32Bits & BOTTOM_9_BITS) == 0) {
+ // escape code
+
+ int iMdecCode;
+ int iVlcCodeLength;
+ if ((iNext32Bits & BIT10) != 0) {
+ // positive
+ iMdecCode = iNext32Bits >> 10;
+ iVlcCodeLength = 26;
+ } else {
+ // negative
+ int iSignExtendAc = (iNext32Bits << 17) >> 27;
+ int iZeroRunLength = (iNext32Bits >> 5) & 0x1c00;
+ iMdecCode = (iSignExtendAc & BOTTOM_10_BITS) | iZeroRunLength;
+ iVlcCodeLength = 18;
+ }
+
+ code.set(iMdecCode);
+ return iVlcCodeLength;
+
+ } else {
+ ZeroRunLengthAcTables.AcCode ac = ZeroRunLengthAcTables.lookupTable2(iNext32Bits & BOTTOM_14_BITS);
+ ac.setMdec(code);
+ return ac._sBits.length();
+ }
+ }
+
+ private static int readTable3(@Nonnull MdecCode code, int iNext32Bits) throws MdecException.ReadCorruption {
+ if ((iNext32Bits & BOTTOM_9_BITS) == 0) {
+ // escape code
+
+ int iMdecCode;
+ int iVlcCodeLength;
+ if ((iNext32Bits & BIT10) != 0) {
+ // positive
+ iMdecCode = iNext32Bits >> 10;
+ iVlcCodeLength = 26;
+ } else {
+ // negative
+ int iSignExtendAc = (iNext32Bits << 18) >> 28;
+ int iZeroRunLength = (iNext32Bits >> 4) & 0x3c00;
+ iMdecCode = (iSignExtendAc & BOTTOM_10_BITS) | iZeroRunLength;
+ iVlcCodeLength = 18;
+ }
+
+ code.set(iMdecCode);
+ return iVlcCodeLength;
+
+ } else {
+ ZeroRunLengthAcTables.AcCode ac = ZeroRunLengthAcTables.lookupTable3(iNext32Bits & BOTTOM_14_BITS);
+ ac.setMdec(code);
+ return ac._sBits.length();
+ }
+ }
+
+ /**
+ * This bit reader is actually pretty clever. It works backwards from the
+ * normal bistream approach, which I think might make it faster. But then
+ * again, the mpeg1 spec chose its bitstream style for a reason.
+ */
+ private static class AconcaguaBitReader {
+
+ private int _iFrontBits;
+ private int _iMidBits;
+ private int _iBackBits;
+ private int _iBitsRemaining;
+ @Nonnull
+ private final byte[] _abBitstream;
+ private int _iPos = -4; // meh workaround so I can call resetColumn() in the constructor
+
+ public AconcaguaBitReader(@Nonnull byte[] abBitstream, int iStartPos) {
+ _abBitstream = abBitstream;
+ resetColumn();
+ }
+
+ final public void resetColumn() {
+ _iBitsRemaining = 32;
+ _iPos = _iPos + 4;
+ _iFrontBits = IO.readSInt32LE(_abBitstream, _iPos);
+ _iMidBits = IO.readSInt32LE(_abBitstream, _iPos + 4);
+ _iBackBits = IO.readSInt32LE(_abBitstream, _iPos + 8);
+ }
+
+ public int getBits() {
+ return _iFrontBits;
+ }
+
+ public void skipBits(int iNumBits) {
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.println(String.format("Skip %d bits %s", iNumBits, Misc.bitsToString(_iFrontBits, iNumBits)));
+ _iFrontBits = _iFrontBits >>> iNumBits;
+ _iBitsRemaining = _iBitsRemaining - iNumBits;
+ int i = _iMidBits << (32 - iNumBits);
+ _iMidBits = _iMidBits >>> iNumBits;
+ _iFrontBits = _iFrontBits | i;
+
+ if (_iBitsRemaining < 0)
+ loadMoreBits();
+ }
+
+ public void loadMoreBits() {
+ _iMidBits = _iBackBits;
+ if (_iPos + 12 < _abBitstream.length)
+ _iBackBits = IO.readSInt32LE(_abBitstream, _iPos + 12);
+ else
+ _iBackBits = 0;
+ _iBitsRemaining = _iBitsRemaining + 32;
+ int rTemp = _iMidBits << _iBitsRemaining;
+ _iFrontBits = _iFrontBits | rTemp;
+ rTemp = 32 - _iBitsRemaining;
+ _iMidBits = _iMidBits >>> rTemp;
+
+ _iPos+=4;
+ }
+
+ }
+
+}
diff --git a/jpsxdec/src/jpsxdec/modules/aconcagua/DcTable.java b/jpsxdec/src/jpsxdec/modules/aconcagua/DcTable.java
new file mode 100644
index 0000000..bec3706
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/aconcagua/DcTable.java
@@ -0,0 +1,366 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.aconcagua;
+
+import javax.annotation.Nonnull;
+import jpsxdec.psxvideo.mdec.MdecException;
+import jpsxdec.util.Misc;
+
+/** Pretty standard variable length code bit reading mapped to DC codes.
+ * This is for the Aconcagua opening FMV. The ending FMV seems to be different. */
+public class DcTable {
+
+
+ public static class DcCode {
+ @Nonnull
+ private final String _sBits;
+ private final int _iRelativeDcCoefficient;
+
+ protected DcCode(@Nonnull String sBits, int iRelativeDcCoefficient) {
+ _sBits = sBits;
+ _iRelativeDcCoefficient = iRelativeDcCoefficient;
+ }
+
+ public int getBitCodeLen() {
+ return _sBits.length();
+ }
+
+ public int getRelativeDcCoefficient() {
+ return _iRelativeDcCoefficient;
+ }
+
+ @Override
+ public String toString() {
+ return make();
+ }
+
+ public @Nonnull String make() {
+ return String.format("new DcCode(%13s, %5d),",
+ "\""+_sBits+"\"", _iRelativeDcCoefficient);
+ }
+ }
+
+ public static @Nonnull DcCode lookup(int iBottom11Bits) throws MdecException.ReadCorruption {
+ DcCode code = LOOKUP[iBottom11Bits & BOTTOM_11_BITS];
+ if (code == null)
+ throw new MdecException.ReadCorruption(Misc.bitsToString(iBottom11Bits, BIT_LENGTH));
+ return code;
+ }
+
+ private static final int BIT_LENGTH = 11;
+ private static final int ENTRY_COUNT = 2048;
+ private static final int BOTTOM_11_BITS = 0x7FF;
+ private static void buildLookup() {
+ for (DcCode dc : DC_CODES) {
+ int iBits = Integer.parseInt(dc._sBits, 2);
+ int iMax = BOTTOM_11_BITS >>> dc._sBits.length();
+
+ for (int i = 0; i <= iMax; i++) {
+ int j = (i << dc._sBits.length()) | iBits;
+ if (LOOKUP[j] != null)
+ throw new RuntimeException("Wrong logic");
+ LOOKUP[j] = dc;
+ }
+ }
+ }
+
+ static final DcCode[] LOOKUP = new DcCode[ENTRY_COUNT];
+
+ private static final DcCode[] DC_CODES = {
+ new DcCode( "100", -1024),
+ new DcCode( "0011", 1),
+ new DcCode( "1101", 1023),
+ new DcCode( "01110", -2),
+ new DcCode( "10111", -3),
+ new DcCode( "11110", -1022),
+ new DcCode( "11111", -1021),
+ new DcCode( "001001", 1020),
+ new DcCode( "100001", 4),
+ new DcCode( "110001", 516),
+ new DcCode( "111011", 5),
+ new DcCode( "0000010", -5),
+ new DcCode( "0000110", -6),
+ new DcCode( "0001010", -1018),
+ new DcCode( "0100110", -1017),
+ new DcCode( "1000101", -1016),
+ new DcCode( "1011001", -7),
+ new DcCode( "1011011", -1015),
+ new DcCode( "1110101", -8),
+ new DcCode( "00001111", 1004),
+ new DcCode( "00100010", 1015),
+ new DcCode( "00101010", 11),
+ new DcCode( "00101111", 1001),
+ new DcCode( "00111010", 12),
+ new DcCode( "01001010", 1011),
+ new DcCode( "01010001", 15),
+ new DcCode( "01011010", 1012),
+ new DcCode( "01100010", 10),
+ new DcCode( "01110010", 1014),
+ new DcCode( "01111010", 1010),
+ new DcCode( "10000001", 13),
+ new DcCode( "10000101", 1006),
+ new DcCode( "10001011", 1003),
+ new DcCode( "10001111", 20),
+ new DcCode( "10101011", 1005),
+ new DcCode( "10101111", 18),
+ new DcCode( "10110110", 1008),
+ new DcCode( "11000111", 19),
+ new DcCode( "11001011", 17),
+ new DcCode( "11010001", 1009),
+ new DcCode( "11010101", 14),
+ new DcCode( "11101010", 1013),
+ new DcCode( "11101011", 1007),
+ new DcCode( "11111001", 16),
+ new DcCode( "000000001", -34),
+ new DcCode( "000000101", -983),
+ new DcCode( "000010001", -36),
+ new DcCode( "000010010", -28),
+ new DcCode( "000010101", -55),
+ new DcCode( "000010110", -30),
+ new DcCode( "000100101", -984),
+ new DcCode( "000100111", -963),
+ new DcCode( "000101011", -51),
+ new DcCode( "000110110", -992),
+ new DcCode( "001001111", -960),
+ new DcCode( "001010010", -997),
+ new DcCode( "001010110", -985),
+ new DcCode( "001100101", -976),
+ new DcCode( "001100111", -965),
+ new DcCode( "001101001", -990),
+ new DcCode( "001111001", -41),
+ new DcCode( "010010101", -972),
+ new DcCode( "010011011", -57),
+ new DcCode( "010100010", -1003),
+ new DcCode( "010100111", -974),
+ new DcCode( "010101001", -38),
+ new DcCode( "010101010", -1001),
+ new DcCode( "010110010", -24),
+ new DcCode( "010111001", -977),
+ new DcCode( "011000110", -33),
+ new DcCode( "011001111", -52),
+ new DcCode( "011100010", -999),
+ new DcCode( "011100101", -44),
+ new DcCode( "011100111", -59),
+ new DcCode( "011101001", -979),
+ new DcCode( "011110010", -1000),
+ new DcCode( "011110110", -991),
+ new DcCode( "011111010", -37),
+ new DcCode( "100000001", -989),
+ new DcCode( "100000111", -53),
+ new DcCode( "100001011", -54),
+ new DcCode( "100010001", -35),
+ new DcCode( "100010010", -25),
+ new DcCode( "100010101", -46),
+ new DcCode( "100010110", -39),
+ new DcCode( "100101011", -45),
+ new DcCode( "100110010", -26),
+ new DcCode( "100110110", -31),
+ new DcCode( "100111001", -981),
+ new DcCode( "101000001", -988),
+ new DcCode( "101000111", -967),
+ new DcCode( "101001011", -47),
+ new DcCode( "101001111", -50),
+ new DcCode( "101010101", -986),
+ new DcCode( "101100101", -40),
+ new DcCode( "101100111", -962),
+ new DcCode( "101101010", -998),
+ new DcCode( "101101011", -975),
+ new DcCode( "101101111", -970),
+ new DcCode( "101111001", -980),
+ new DcCode( "110000111", -969),
+ new DcCode( "110010001", -982),
+ new DcCode( "110010101", -987),
+ new DcCode( "110010110", -995),
+ new DcCode( "110011001", -48),
+ new DcCode( "110011010", -29),
+ new DcCode( "110011011", -43),
+ new DcCode( "110100101", -978),
+ new DcCode( "110100111", -968),
+ new DcCode( "110101010", -1002),
+ new DcCode( "110110101", -42),
+ new DcCode( "111000010", -22),
+ new DcCode( "111000110", -993),
+ new DcCode( "111011010", -994),
+ new DcCode( "111100111", -49),
+ new DcCode( "111110010", -27),
+ new DcCode( "111110110", -32),
+ new DcCode( "111111010", -996),
+ new DcCode( "0000000111", 111),
+ new DcCode( "0000001011", 909),
+ new DcCode( "0000011001", 901),
+ new DcCode( "0000011010", 946),
+ new DcCode( "0000011011", 120),
+ new DcCode( "0000101001", 936),
+ new DcCode( "0000110010", 69),
+ new DcCode( "0000110101", 903),
+ new DcCode( "0000111001", 90),
+ new DcCode( "0001000001", 941),
+ new DcCode( "0001000110", 67),
+ new DcCode( "0001000111", 121),
+ new DcCode( "0001001011", 898),
+ new DcCode( "0001010101", 920),
+ new DcCode( "0001100110", 940),
+ new DcCode( "0001101010", 58),
+ new DcCode( "0001101011", 912),
+ new DcCode( "0001101111", 126),
+ new DcCode( "0001110110", 926),
+ new DcCode( "0010000111", 914),
+ new DcCode( "0010010001", 103),
+ new DcCode( "0010010010", 77),
+ new DcCode( "0010010110", 948),
+ new DcCode( "0010011001", 107),
+ new DcCode( "0010011010", 957),
+ new DcCode( "0010100101", 100),
+ new DcCode( "0010110101", 109),
+ new DcCode( "0010111010", 951),
+ new DcCode( "0011000001", 89),
+ new DcCode( "0011000010", 962),
+ new DcCode( "0011001010", 958),
+ new DcCode( "0011010010", 963),
+ new DcCode( "0011010110", 942),
+ new DcCode( "0011011010", 97),
+ new DcCode( "0011100110", 76),
+ new DcCode( "0011101111", 907),
+ new DcCode( "0100000101", 110),
+ new DcCode( "0100011001", 98),
+ new DcCode( "0100011010", 82),
+ new DcCode( "0100011011", 128),
+ new DcCode( "0100100101", 932),
+ new DcCode( "0100100111", 119),
+ new DcCode( "0100101001", 928),
+ new DcCode( "0100110101", 911),
+ new DcCode( "0101000010", 53),
+ new DcCode( "0101000110", 74),
+ new DcCode( "0101010010", 68),
+ new DcCode( "0101010110", 947),
+ new DcCode( "0101100110", 86),
+ new DcCode( "0101101001", 931),
+ new DcCode( "0101110110", 952),
+ new DcCode( "0110010010", 961),
+ new DcCode( "0110100010", 960),
+ new DcCode( "0110101001", 927),
+ new DcCode( "0110110010", 944),
+ new DcCode( "0110111001", 915),
+ new DcCode( "0110111010", 956),
+ new DcCode( "0111000001", 91),
+ new DcCode( "0111001010", 65),
+ new DcCode( "0111001111", 108),
+ new DcCode( "0111010010", 968),
+ new DcCode( "0111010110", 938),
+ new DcCode( "0111100010", 954),
+ new DcCode( "0111100101", 96),
+ new DcCode( "0111100110", 935),
+ new DcCode( "0111101001", 923),
+ new DcCode( "0111101111", 886),
+ new DcCode( "1000000111", 906),
+ new DcCode( "1000001011", 890),
+ new DcCode( "1000011001", 102),
+ new DcCode( "1000011010", 950),
+ new DcCode( "1000011011", 114),
+ new DcCode( "1000101001", 917),
+ new DcCode( "1000110010", 66),
+ new DcCode( "1000110101", 99),
+ new DcCode( "1000111001", 908),
+ new DcCode( "1001000001", 930),
+ new DcCode( "1001000010", 964),
+ new DcCode( "1001000110", 93),
+ new DcCode( "1001000111", 904),
+ new DcCode( "1001001011", 106),
+ new DcCode( "1001010101", 916),
+ new DcCode( "1001100110", 81),
+ new DcCode( "1001101010", 87),
+ new DcCode( "1001101011", 895),
+ new DcCode( "1001101111", 118),
+ new DcCode( "1001110110", 922),
+ new DcCode( "1010000111", 132),
+ new DcCode( "1010010001", 929),
+ new DcCode( "1010010010", 70),
+ new DcCode( "1010010110", 924),
+ new DcCode( "1010011001", 92),
+ new DcCode( "1010011010", 84),
+ new DcCode( "1010100101", 918),
+ new DcCode( "1010110101", 105),
+ new DcCode( "1010111010", 85),
+ new DcCode( "1011000001", 905),
+ new DcCode( "1011000010", 966),
+ new DcCode( "1011001010", 955),
+ new DcCode( "1011010010", 80),
+ new DcCode( "1011010110", 79),
+ new DcCode( "1011011010", 75),
+ new DcCode( "1011100110", 71),
+ new DcCode( "1011101111", 896),
+ new DcCode( "1100000101", 101),
+ new DcCode( "1100011001", 72),
+ new DcCode( "1100011010", 943),
+ new DcCode( "1100011011", 104),
+ new DcCode( "1100100101", 115),
+ new DcCode( "1100100111", 910),
+ new DcCode( "1100101001", 925),
+ new DcCode( "1100110101", 899),
+ new DcCode( "1101000110", 933),
+ new DcCode( "1101010010", 60),
+ new DcCode( "1101010110", 937),
+ new DcCode( "1101100110", 94),
+ new DcCode( "1101101001", 913),
+ new DcCode( "1101110110", 83),
+ new DcCode( "1110010010", 949),
+ new DcCode( "1110100010", 959),
+ new DcCode( "1110101001", 921),
+ new DcCode( "1110110010", 63),
+ new DcCode( "1110111001", 939),
+ new DcCode( "1110111010", 934),
+ new DcCode( "1111000001", 88),
+ new DcCode( "1111001010", 945),
+ new DcCode( "1111001111", 893),
+ new DcCode( "1111010010", 78),
+ new DcCode( "1111010110", 953),
+ new DcCode( "1111100010", 51),
+ new DcCode( "1111100101", 919),
+ new DcCode( "1111100110", 73),
+ new DcCode( "1111101001", 95),
+ new DcCode( "1111101111", 116),
+ new DcCode("00001000010", -156),
+ new DcCode("01101000010", -879),
+ new DcCode("10001000010", -912),
+ new DcCode("11101000010", -124),
+ };
+
+ static {
+ buildLookup();
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/modules/aconcagua/DemuxedAconcaguaFrame.java b/jpsxdec/src/jpsxdec/modules/aconcagua/DemuxedAconcaguaFrame.java
new file mode 100644
index 0000000..4bcaffb
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/aconcagua/DemuxedAconcaguaFrame.java
@@ -0,0 +1,60 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.aconcagua;
+
+import java.util.List;
+import javax.annotation.Nonnull;
+import jpsxdec.modules.video.sectorbased.DemuxedFrameWithNumberAndDims;
+import jpsxdec.psxvideo.mdec.Calc;
+
+
+public class DemuxedAconcaguaFrame extends DemuxedFrameWithNumberAndDims {
+
+ private final int _iQuantizationScale;
+
+ public DemuxedAconcaguaFrame(int iWidth, int iHeight, int iHeaderFrameNumber, @Nonnull List sectors, int iQuantizationScale) {
+ super(iWidth, iHeight, iHeaderFrameNumber, sectors);
+ _iQuantizationScale = iQuantizationScale;
+ }
+
+ @Override
+ public @Nonnull BitStreamUncompressor_Aconcagua getCustomFrameMdecStream() {
+ byte[] abFrameData = copyDemuxData();
+ return new BitStreamUncompressor_Aconcagua(Calc.macroblockDim(getHeight()), _iQuantizationScale, abFrameData);
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/modules/aconcagua/InstructionTable.java b/jpsxdec/src/jpsxdec/modules/aconcagua/InstructionTable.java
new file mode 100644
index 0000000..3c4ffa0
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/aconcagua/InstructionTable.java
@@ -0,0 +1,200 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.aconcagua;
+
+import javax.annotation.Nonnull;
+import jpsxdec.psxvideo.mdec.MdecException;
+import jpsxdec.util.Misc;
+
+/** The "instruction" table, as I call it, indicates how many codes to read
+ * from each of the three zero-run length AC tables for the current block.
+ * This is for the Aconcagua opening FMV. The ending FMV seems to be different.
+ * What even.. */
+public class InstructionTable {
+
+ public static class InstructionCode {
+ @Nonnull
+ private final String _sBits;
+ private final int _iTable1Count;
+ private final int _iTable2Count;
+ private final int _iTable3Count;
+
+ protected InstructionCode(@Nonnull String sBits, int iTable1Count, int iTable2Count, int iTable3Count) {
+ _sBits = sBits;
+ _iTable1Count = iTable1Count;
+ _iTable2Count = iTable2Count;
+ _iTable3Count = iTable3Count;
+ }
+
+ public int getTable1Count() {
+ return _iTable1Count;
+ }
+
+ public int getTable2Count() {
+ return _iTable2Count;
+ }
+
+ public int getTable3Count() {
+ return _iTable3Count;
+ }
+
+ public int getBitCodeLen() {
+ return _sBits.length();
+ }
+
+ public String getBits() {
+ return _sBits;
+ }
+
+ @Override
+ public String toString() {
+ return make();
+ }
+
+ public @Nonnull String make() {
+ return String.format("new InstructionCode(%12s, %2d, %2d, %2d),",
+ "\""+_sBits+"\"", _iTable1Count, _iTable2Count, _iTable3Count);
+ }
+ }
+
+ private static final int BOTTOM_10_BITS = 0x03ff;
+ public static @Nonnull InstructionCode lookup(int iBottom10Bits) throws MdecException.ReadCorruption {
+ iBottom10Bits &= BOTTOM_10_BITS;
+ int iOnesCount;
+ int b = iBottom10Bits;
+ for (iOnesCount = 0; iOnesCount < 9; iOnesCount++) {
+ if ((b & 1) == 0)
+ break;
+ b >>>= 1;
+ }
+
+ if (iOnesCount <= 3) {
+ return INSTRUCTIONS[iOnesCount];
+ } else if (iOnesCount < 7) {
+ InstructionCode code = PARTIAL_LOOKUP[(iBottom10Bits >>> 4)];
+ if (code == null)
+ throw new MdecException.ReadCorruption("Aconcagua lookup table bits " + Misc.bitsToString(iBottom10Bits, 10));
+ return code;
+ } else if (iOnesCount <= 9) {
+ return INSTRUCTIONS[4 + ((iBottom10Bits >>> 7) & 3)];
+ }
+ throw new MdecException.ReadCorruption("Aconcagua lookup table bits " + Misc.bitsToString(iBottom10Bits, 10));
+ }
+
+ private static void buildLookup() {
+ for (int i = 8; i < INSTRUCTIONS.length; i++) {
+ InstructionCode code = INSTRUCTIONS[i];
+ int iLookupPos = Integer.parseInt(code._sBits, 2);
+ PARTIAL_LOOKUP[iLookupPos >>> 4] = code;
+ }
+ }
+
+ private static final int _111110b = 0x3E;
+ private static final InstructionCode[] PARTIAL_LOOKUP = new InstructionCode[_111110b + 1];
+
+ private static final InstructionCode[] INSTRUCTIONS = {
+ new InstructionCode( "0", 0, 0, 0),
+ new InstructionCode( "01", 0, 0, 1),
+ new InstructionCode( "011", 0, 0, 2),
+ new InstructionCode( "0111", 0, 0, 3),
+ new InstructionCode( "001111111", 0, 0, 4),
+ new InstructionCode( "011111111", 3, 1, 12),
+ new InstructionCode( "101111111", 3, 1, 14),
+ new InstructionCode( "111111111", 3, 1, 13),
+ new InstructionCode("0000001111", 5, 2, 19),
+ new InstructionCode("0000011111", 7, 43, 8),
+ new InstructionCode("0000101111", 10, 7, 25),
+ new InstructionCode("0000111111", 2, 0, 10),
+ new InstructionCode("0001001111", 1, 0, 8),
+ new InstructionCode("0001011111", 6, 27, 17),
+ new InstructionCode("0001101111", 8, 4, 22),
+ new InstructionCode("0010001111", 6, 3, 21),
+ new InstructionCode("0010011111", 1, 56, 5),
+ new InstructionCode("0010101111", 8, 16, 22),
+ new InstructionCode("0010111111", 1, 1, 9),
+ new InstructionCode("0011001111", 0, 1, 5),
+ new InstructionCode("0011011111", 9, 24, 19),
+ new InstructionCode("0011101111", 9, 5, 24),
+ new InstructionCode("0100001111", 0, 0, 5),
+ new InstructionCode("0100011111", 7, 44, 8),
+ new InstructionCode("0100101111", 9, 6, 25),
+ new InstructionCode("0100111111", 3, 0, 12),
+ new InstructionCode("0101001111", 1, 0, 9),
+ new InstructionCode("0101011111", 6, 25, 17),
+ new InstructionCode("0101101111", 7, 3, 22),
+ new InstructionCode("0110001111", 6, 2, 20),
+ new InstructionCode("0110011111", 8, 33, 14),
+ new InstructionCode("0110101111", 10, 9, 25),
+ new InstructionCode("0110111111", 2, 1, 10),
+ new InstructionCode("0111001111", 5, 1, 17),
+ new InstructionCode("0111011111", 8, 28, 17),
+ new InstructionCode("0111101111", 8, 5, 23),
+ new InstructionCode("1000001111", 6, 1, 20),
+ new InstructionCode("1000011111", 10, 34, 12),
+ new InstructionCode("1000101111", 8, 11, 24),
+ new InstructionCode("1000111111", 4, 1, 14),
+ new InstructionCode("1001001111", 1, 0, 7),
+ new InstructionCode("1001011111", 11, 24, 16),
+ new InstructionCode("1001101111", 8, 4, 23),
+ new InstructionCode("1010001111", 7, 3, 21),
+ new InstructionCode("1010011111", 0, 58, 5),
+ new InstructionCode("1010101111", 8, 18, 21),
+ new InstructionCode("1010111111", 4, 1, 16),
+ new InstructionCode("1011001111", 5, 1, 18),
+ new InstructionCode("1011011111", 2, 53, 5),
+ new InstructionCode("1011101111", 9, 6, 24),
+ new InstructionCode("1100001111", 5, 2, 18),
+ new InstructionCode("1100011111", 1, 54, 6),
+ new InstructionCode("1100101111", 9, 7, 25),
+ new InstructionCode("1100111111", 2, 1, 11),
+ new InstructionCode("1101001111", 4, 1, 17),
+ new InstructionCode("1101011111", 10, 20, 19),
+ new InstructionCode("1101101111", 7, 4, 22),
+ new InstructionCode("1110001111", 6, 3, 20),
+ new InstructionCode("1110011111", 15, 29, 13),
+ new InstructionCode("1110101111", 9, 12, 24),
+ new InstructionCode("1110111111", 4, 1, 15),
+ new InstructionCode("1111001111", 1, 0, 6),
+ new InstructionCode("1111011111", 8, 33, 13),
+ new InstructionCode("1111101111", 8, 6, 23),
+ };
+
+ static {
+ buildLookup();
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/modules/aconcagua/SectorAconcaguaVideo.java b/jpsxdec/src/jpsxdec/modules/aconcagua/SectorAconcaguaVideo.java
new file mode 100644
index 0000000..24be20a
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/aconcagua/SectorAconcaguaVideo.java
@@ -0,0 +1,172 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.aconcagua;
+
+import javax.annotation.Nonnull;
+import jpsxdec.cdreaders.CdSector;
+import jpsxdec.i18n.exception.LocalizedIncompatibleException;
+import jpsxdec.i18n.log.ILocalizedLogger;
+import jpsxdec.modules.IdentifiedSector;
+import jpsxdec.modules.video.sectorbased.ISelfDemuxingVideoSector;
+import jpsxdec.modules.video.sectorbased.IVideoSectorWithFrameNumber;
+import jpsxdec.modules.video.sectorbased.SectorBasedFrameReplace;
+import jpsxdec.util.DemuxedData;
+
+/** Video sector of the Aconcagua opening FMV. The ending FMV is different. */
+public class SectorAconcaguaVideo extends IdentifiedSector
+ implements DemuxedData.Piece, ISelfDemuxingVideoSector,
+ SectorBasedFrameReplace.IReplaceableVideoSector,
+ IVideoSectorWithFrameNumber
+{
+
+ private final static long MAGIC_NUMBER_BE = 0x60010200;
+
+ // Magic // 4 bytes @0
+ private int _iChunkNumber; // 2 bytes @4
+ private int _iChunksInFrame; // 2 bytes @6
+ private int _iFrameNumber; // 4 bytes @8
+ private int _iCodeCount; // 4 bytes @12
+ private int _iWidth; // 2 bytes @16
+ private int _iHeight; // 2 bytes @18
+ private int _iQuantizationScale; // 4 bytes @20
+ // Zeroes // 8 bytes @24
+
+ public SectorAconcaguaVideo(CdSector cdSector) {
+ super(cdSector);
+ if (isSuperInvalidElseReset()) return;
+
+ long lngMagic = cdSector.readUInt32BE(0);
+ if (lngMagic != MAGIC_NUMBER_BE)
+ return;
+
+ _iChunkNumber = cdSector.readSInt16LE(4);
+ if (_iChunkNumber < 0 || _iChunkNumber > 10)
+ return;
+ _iChunksInFrame = cdSector.readSInt16LE(6);
+ if (_iChunksInFrame <= 0 || _iChunksInFrame > 10)
+ return;
+ _iFrameNumber = cdSector.readSInt32LE(8);
+ if (_iFrameNumber < 0)
+ return;
+ _iCodeCount = cdSector.readSInt32LE(12);
+ if (_iCodeCount < 1)
+ return;
+ _iWidth = cdSector.readSInt16LE(16);
+ if (_iWidth < 16 || _iWidth > 400)
+ return;
+ _iHeight = cdSector.readSInt16LE(18);
+ if (_iHeight < 16 || _iHeight > 400)
+ return;
+ _iQuantizationScale = cdSector.readSInt32LE(20);
+ if (_iQuantizationScale < 1 || _iQuantizationScale > 64)
+ return;
+ for (int i = 24; i < 32; i++) {
+ if (cdSector.readUserDataByte(i) != 0)
+ return;
+ }
+
+ setProbability(100);
+ }
+
+ public String getTypeName() {
+ return "Aconcagua Video";
+ }
+
+ public int getWidth() {
+ return _iWidth;
+ }
+
+ public int getHeight() {
+ return _iHeight;
+ }
+
+ public int getHeaderFrameNumber() {
+ return _iFrameNumber;
+ }
+
+ public int getChunksInFrame() {
+ return _iChunksInFrame;
+ }
+
+ public int getChunkNumber() {
+ return _iChunkNumber;
+ }
+
+ public int getQuantizationScale() {
+ return _iQuantizationScale;
+ }
+
+ public int getVideoSectorHeaderSize() {
+ return 32;
+ }
+
+ public int getDemuxPieceSize() {
+ return getCdSector().getCdUserDataSize() - getVideoSectorHeaderSize();
+ }
+
+ public byte getDemuxPieceByte(int i) {
+ return getCdSector().readUserDataByte(i);
+ }
+
+ public void copyDemuxPieceData(@Nonnull byte[] abOut, int iOutPos) {
+ getCdSector().getCdUserDataCopy(getVideoSectorHeaderSize(),
+ abOut, iOutPos, getDemuxPieceSize());
+ }
+
+ public @Nonnull AconcaguaDemuxer createDemuxer(@Nonnull ILocalizedLogger log) {
+ return new AconcaguaDemuxer(this, log);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s %s frame:%d chunk:%d/%d %dx%d codes:%d qscale=%d",
+ getTypeName(),
+ super.cdToString(),
+ _iFrameNumber,
+ _iChunkNumber,
+ _iChunksInFrame,
+ _iWidth,
+ _iHeight,
+ _iCodeCount,
+ _iQuantizationScale);
+ }
+
+ public void replaceVideoSectorHeader(byte[] abNewDemuxData, int iNewUsedSize, int iNewMdecCodeCount, byte[] abCurrentVidSectorHeader) throws LocalizedIncompatibleException {
+ throw new UnsupportedOperationException("Not gonna support replacing Aconcagua video");
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/modules/aconcagua/ZeroRunLengthAcTables.java b/jpsxdec/src/jpsxdec/modules/aconcagua/ZeroRunLengthAcTables.java
new file mode 100644
index 0000000..795bbb7
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/aconcagua/ZeroRunLengthAcTables.java
@@ -0,0 +1,662 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.aconcagua;
+
+import javax.annotation.Nonnull;
+import jpsxdec.psxvideo.mdec.MdecCode;
+import jpsxdec.psxvideo.mdec.MdecException;
+import jpsxdec.util.Misc;
+
+/** Pretty standard variable length code bit reading mapped to MDEC codes.
+ * These are for the Aconcagua opening FMV. The ending FMV seems to be different. */
+public class ZeroRunLengthAcTables {
+
+ public static class AcCode {
+ @Nonnull
+ public final String _sBits;
+ @Nonnull
+ public final MdecCode _code;
+
+ protected AcCode(@Nonnull String sBits, @Nonnull MdecCode code) {
+ _sBits = sBits;
+ _code = code;
+ }
+
+ public @Nonnull MdecCode getMdecCodeCopy() {
+ return _code.copy();
+ }
+
+ public void setMdec(@Nonnull MdecCode code) {
+ code.setFrom(_code);
+ }
+
+ @Override
+ public String toString() {
+ return make();
+ }
+
+ public @Nonnull String make() {
+ return String.format("new AcCode(%16s, new MdecCode(%2d, %4d)),",
+ "\""+_sBits+"\"", _code.getTop6Bits(), _code.getBottom10Bits());
+ }
+
+ }
+
+ public static @Nonnull AcCode lookupTable1(int iBottom14Bits) throws MdecException.ReadCorruption {
+ return lookup(TABLE1_LOOKUP, iBottom14Bits);
+ }
+
+ public static @Nonnull AcCode lookupTable2(int iBottom14Bits) throws MdecException.ReadCorruption {
+ return lookup(TABLE2_LOOKUP, iBottom14Bits);
+ }
+
+ public static @Nonnull AcCode lookupTable3(int iBottom14Bits) throws MdecException.ReadCorruption {
+ return lookup(TABLE3_LOOKUP, iBottom14Bits);
+ }
+
+ private static @Nonnull AcCode lookup(@Nonnull AcCode[] aoTable, int iBottom14Bits)
+ throws MdecException.ReadCorruption
+ {
+ AcCode code = aoTable[iBottom14Bits & BOTTOM_14_BITS];
+ if (code == null)
+ throw new MdecException.ReadCorruption(Misc.bitsToString(iBottom14Bits, BIT_LENGTH));
+ return code;
+ }
+
+ private static final int BIT_LENGTH = 14;
+ private static final int ENTRY_COUNT = 16384;
+ private static final int BOTTOM_14_BITS = 0x3FFF;
+
+ static final AcCode[] TABLE1_LOOKUP = new AcCode[ENTRY_COUNT];
+ static final AcCode[] TABLE2_LOOKUP = new AcCode[ENTRY_COUNT];
+ static final AcCode[] TABLE3_LOOKUP = new AcCode[ENTRY_COUNT];
+
+ private static void buidLookup(@Nonnull AcCode[] table, @Nonnull AcCode[] lookup) {
+ for (AcCode ac : table) {
+ int iBits = Integer.parseInt(ac._sBits, 2);
+ int iMax = BOTTOM_14_BITS >>> ac._sBits.length();
+
+ for (int i = 0; i <= iMax; i++) {
+ int j = (i << ac._sBits.length()) | iBits;
+ if (j >= lookup.length)
+ System.out.println("");
+ if (lookup[j] != null)
+ throw new RuntimeException("Wrong logic");
+ lookup[j] = ac;
+ }
+ }
+ }
+
+ private static final AcCode[] TABLE1 = {
+ new AcCode( "0001", new MdecCode( 0, 2)),
+ new AcCode( "0010", new MdecCode( 0, 3)),
+ new AcCode( "0011", new MdecCode( 0, 1)),
+ new AcCode( "1100", new MdecCode( 0, -3)),
+ new AcCode( "1101", new MdecCode( 0, -1)),
+ new AcCode( "1110", new MdecCode( 0, -2)),
+ new AcCode( "00101", new MdecCode( 0, -5)),
+ new AcCode( "00111", new MdecCode( 0, -4)),
+ new AcCode( "01000", new MdecCode( 0, -7)),
+ new AcCode( "01010", new MdecCode( 0, 6)),
+ new AcCode( "01111", new MdecCode( 0, 4)),
+ new AcCode( "10110", new MdecCode( 0, -6)),
+ new AcCode( "11000", new MdecCode( 0, 7)),
+ new AcCode( "11011", new MdecCode( 0, 5)),
+ new AcCode( "000110", new MdecCode( 0, -10)),
+ new AcCode( "010100", new MdecCode( 0, -11)),
+ new AcCode( "100110", new MdecCode( 0, 10)),
+ new AcCode( "101001", new MdecCode( 0, -9)),
+ new AcCode( "110000", new MdecCode( 0, 12)),
+ new AcCode( "110100", new MdecCode( 0, 11)),
+ new AcCode( "110101", new MdecCode( 0, 9)),
+ new AcCode( "110111", new MdecCode( 0, -8)),
+ new AcCode( "111111", new MdecCode( 0, 8)),
+ new AcCode( "0001011", new MdecCode( 0, -13)),
+ new AcCode( "0011010", new MdecCode( 0, 15)),
+ new AcCode( "0011111", new MdecCode( 0, -12)),
+ new AcCode( "0100000", new MdecCode( 0, 16)),
+ new AcCode( "0111001", new MdecCode( 0, -14)),
+ new AcCode( "1000100", new MdecCode( 0, -15)),
+ new AcCode( "1001001", new MdecCode( 0, 14)),
+ new AcCode( "1001011", new MdecCode( 0, 13)),
+ new AcCode( "1011010", new MdecCode( 1, 1)),
+ new AcCode( "1100100", new MdecCode( 1, -1)),
+ new AcCode( "00000100", new MdecCode( 0, 21)),
+ new AcCode( "00010000", new MdecCode( 0, 22)),
+ new AcCode( "00010111", new MdecCode( 1, -2)),
+ new AcCode( "00011001", new MdecCode( 0, 20)),
+ new AcCode( "00101011", new MdecCode( 0, -18)),
+ new AcCode( "01000000", new MdecCode( 1, 4)),
+ new AcCode( "01010111", new MdecCode( 0, 17)),
+ new AcCode( "01100000", new MdecCode( 0, -21)),
+ new AcCode( "01101011", new MdecCode( 1, 2)),
+ new AcCode( "01111001", new MdecCode( 1, 3)),
+ new AcCode( "10000000", new MdecCode( 0, -16)),
+ new AcCode( "10011001", new MdecCode( 0, 19)),
+ new AcCode( "11010000", new MdecCode( 1, -4)),
+ new AcCode( "11010101", new MdecCode( 0, 18)),
+ new AcCode( "11011001", new MdecCode( 0, -19)),
+ new AcCode( "11011111", new MdecCode( 0, -17)),
+ new AcCode( "11111001", new MdecCode( 1, -3)),
+ new AcCode( "11111010", new MdecCode( 0, -20)),
+ new AcCode( "001010101", new MdecCode( 0, 24)),
+ new AcCode( "001011111", new MdecCode( 0, -22)),
+ new AcCode( "001111010", new MdecCode( 0, -25)),
+ new AcCode( "010000100", new MdecCode( 1, -6)),
+ new AcCode( "010001001", new MdecCode( 0, 25)),
+ new AcCode( "010010111", new MdecCode( 0, -23)),
+ new AcCode( "010111010", new MdecCode( 0, -26)),
+ new AcCode( "100001001", new MdecCode( 0, -24)),
+ new AcCode( "100010101", new MdecCode( 1, -5)),
+ new AcCode( "100100100", new MdecCode( 0, -27)),
+ new AcCode( "101010000", new MdecCode( 0, -28)),
+ new AcCode( "101011111", new MdecCode( 0, 23)),
+ new AcCode( "110000100", new MdecCode( 0, 26)),
+ new AcCode( "110101011", new MdecCode( 1, 5)),
+ new AcCode( "110111010", new MdecCode( 1, 6)),
+ new AcCode( "111100000", new MdecCode( 0, 27)),
+ new AcCode( "0000001001", new MdecCode( 2, -1)),
+ new AcCode( "0000010101", new MdecCode( 0, 31)),
+ new AcCode( "0001011001", new MdecCode( 2, 1)),
+ new AcCode( "0010010000", new MdecCode( 1, 9)),
+ new AcCode( "0010010101", new MdecCode( 0, -31)),
+ new AcCode( "0010101011", new MdecCode( 1, 7)),
+ new AcCode( "0011000000", new MdecCode( 1, -9)),
+ new AcCode( "0101011001", new MdecCode( 0, -32)),
+ new AcCode( "0110010111", new MdecCode( 0, 28)),
+ new AcCode( "0110100100", new MdecCode( 0, -35)),
+ new AcCode( "0111000000", new MdecCode( 0, -36)),
+ new AcCode( "0111010111", new MdecCode( 0, -29)),
+ new AcCode( "1000010101", new MdecCode( 0, 30)),
+ new AcCode( "1000100100", new MdecCode( 0, 33)),
+ new AcCode( "1000111010", new MdecCode( 1, -8)),
+ new AcCode( "1010010000", new MdecCode( 0, 35)),
+ new AcCode( "1010010101", new MdecCode( 0, -30)),
+ new AcCode( "1010100100", new MdecCode( 0, -34)),
+ new AcCode( "1010101011", new MdecCode( 1, -7)),
+ new AcCode( "1100111010", new MdecCode( 0, 32)),
+ new AcCode( "1101111010", new MdecCode( 0, -33)),
+ new AcCode( "1110001001", new MdecCode( 1, 8)),
+ new AcCode( "1110010111", new MdecCode( 0, 29)),
+ new AcCode( "1111000000", new MdecCode( 0, -37)),
+ new AcCode( "00000111010", new MdecCode( 0, -42)),
+ new AcCode( "00010100100", new MdecCode( 0, -43)),
+ new AcCode( "00011010111", new MdecCode( 0, 34)),
+ new AcCode( "00011100000", new MdecCode( 0, 40)),
+ new AcCode( "00011101011", new MdecCode( 0, 39)),
+ new AcCode( "00100111010", new MdecCode( 1, -12)),
+ new AcCode( "00101010101", new MdecCode( 0, -45)),
+ new AcCode( "00101111010", new MdecCode( 1, -11)),
+ new AcCode( "00110001001", new MdecCode( 0, 44)),
+ new AcCode( "00110010000", new MdecCode( 0, 45)),
+ new AcCode( "00110010101", new MdecCode( 0, -44)),
+ new AcCode( "01000001001", new MdecCode( 0, -41)),
+ new AcCode( "01101010101", new MdecCode( 2, -2)),
+ new AcCode( "01110010000", new MdecCode( 0, 42)),
+ new AcCode( "01110010101", new MdecCode( 0, -39)),
+ new AcCode( "01111010111", new MdecCode( 0, 38)),
+ new AcCode( "01111101011", new MdecCode( 1, 10)),
+ new AcCode( "10001010000", new MdecCode( 1, 12)),
+ new AcCode( "10010100100", new MdecCode( 0, -48)),
+ new AcCode( "10011100000", new MdecCode( 1, 11)),
+ new AcCode( "10011101011", new MdecCode( 1, -10)),
+ new AcCode( "10110010000", new MdecCode( 0, -46)),
+ new AcCode( "10111101011", new MdecCode( 0, 37)),
+ new AcCode( "11001011001", new MdecCode( 0, 41)),
+ new AcCode( "11011010111", new MdecCode( 0, 36)),
+ new AcCode( "11011101011", new MdecCode( 0, -38)),
+ new AcCode( "11110010101", new MdecCode( 0, -40)),
+ new AcCode( "11110100100", new MdecCode( 2, 3)),
+ new AcCode( "11111101011", new MdecCode( 2, 2)),
+ new AcCode( "000000100100", new MdecCode( 0, 48)),
+ new AcCode( "000111101011", new MdecCode( 2, -3)),
+ new AcCode( "001001010000", new MdecCode( 0, 56)),
+ new AcCode( "001011000000", new MdecCode( 1, 15)),
+ new AcCode( "001011010111", new MdecCode( 0, -47)),
+ new AcCode( "001011100000", new MdecCode( 0, -57)),
+ new AcCode( "001011101011", new MdecCode( 1, 13)),
+ new AcCode( "010000111010", new MdecCode( 1, -14)),
+ new AcCode( "010011010111", new MdecCode( 0, 46)),
+ new AcCode( "010101111010", new MdecCode( 0, 43)),
+ new AcCode( "010110001001", new MdecCode( 1, 14)),
+ new AcCode( "010110010101", new MdecCode( 0, -53)),
+ new AcCode( "011000001001", new MdecCode( 2, 4)),
+ new AcCode( "011001010000", new MdecCode( 0, 52)),
+ new AcCode( "011011100000", new MdecCode( 0, 50)),
+ new AcCode( "011101011001", new MdecCode( 3, 1)),
+ new AcCode( "100000100100", new MdecCode( 1, -15)),
+ new AcCode( "100001010000", new MdecCode( 3, -1)),
+ new AcCode( "100111101011", new MdecCode( 1, -13)),
+ new AcCode( "101001010000", new MdecCode( 1, 16)),
+ new AcCode( "101001011001", new MdecCode( 2, -4)),
+ new AcCode( "101011000000", new MdecCode( 0, 49)),
+ new AcCode( "101011010111", new MdecCode( 0, 47)),
+ new AcCode( "101011100000", new MdecCode( 0, 51)),
+ new AcCode( "110000100100", new MdecCode( 0, -56)),
+ new AcCode( "110101111010", new MdecCode( 0, -49)),
+ new AcCode( "110110001001", new MdecCode( 0, -52)),
+ new AcCode( "111011000000", new MdecCode( 1, -16)),
+ new AcCode( "111101011001", new MdecCode( 0, -50)),
+ new AcCode( "111111010111", new MdecCode( 0, -51)),
+ new AcCode( "0001101011001", new MdecCode( 0, 57)),
+ new AcCode( "0010000100100", new MdecCode( 0, 60)),
+ new AcCode( "0011011000000", new MdecCode( 1, -21)),
+ new AcCode( "0011101010101", new MdecCode( 0, 53)),
+ new AcCode( "0011110010000", new MdecCode( 1, 20)),
+ new AcCode( "0011111010111", new MdecCode( 0, -60)),
+ new AcCode( "0101101011001", new MdecCode( 1, 17)),
+ new AcCode( "0110000111010", new MdecCode( 0, -59)),
+ new AcCode( "0110011010111", new MdecCode( 2, 5)),
+ new AcCode( "0110100111010", new MdecCode( 3, -2)),
+ new AcCode( "0111000001001", new MdecCode( 0, 61)),
+ new AcCode( "0111011100000", new MdecCode( 1, -18)),
+ new AcCode( "0111101010101", new MdecCode( 0, 55)),
+ new AcCode( "0111110010000", new MdecCode( 1, 19)),
+ new AcCode( "1000001010000", new MdecCode( 3, 2)),
+ new AcCode( "1001110100100", new MdecCode( 0, 59)),
+ new AcCode( "1010100111010", new MdecCode( 0, 54)),
+ new AcCode( "1010101010101", new MdecCode( 0, -54)),
+ new AcCode( "1011011000000", new MdecCode( 0, 67)),
+ new AcCode( "1011110010000", new MdecCode( 0, 82)),
+ new AcCode( "1101011101011", new MdecCode( 0, -66)),
+ new AcCode( "1101101011001", new MdecCode( 0, -72)),
+ new AcCode( "1110000111010", new MdecCode( 2, 6)),
+ new AcCode( "1110100111010", new MdecCode( 2, -5)),
+ new AcCode( "1111000001001", new MdecCode( 1, -17)),
+ new AcCode( "1111001010000", new MdecCode( 0, -70)),
+ new AcCode( "1111101010101", new MdecCode( 0, -55)),
+ new AcCode( "1111110010000", new MdecCode( 1, 18)),
+ new AcCode("00000001010000", new MdecCode( 0, 69)),
+ new AcCode("00001001011001", new MdecCode( 1, 21)),
+ new AcCode("00001110100100", new MdecCode( 1, 27)),
+ new AcCode("00010100111010", new MdecCode( 3, 3)),
+ new AcCode("00010101010101", new MdecCode( 0, 66)),
+ new AcCode("00101011101011", new MdecCode( 0, 80)),
+ new AcCode("00101110100100", new MdecCode( 0, 63)),
+ new AcCode("00110101010101", new MdecCode( 0, 58)),
+ new AcCode("00110110010101", new MdecCode( 1, -20)),
+ new AcCode("00111001010000", new MdecCode( 1, -26)),
+ new AcCode("01001001011001", new MdecCode( 0, 109)),
+ new AcCode("01001101011001", new MdecCode( 0, -170)),
+ new AcCode("01010000100100", new MdecCode( 0, -68)),
+ new AcCode("01011101010101", new MdecCode( 1, 26)),
+ new AcCode("01011111010111", new MdecCode( 0, -58)),
+ new AcCode("01101110100100", new MdecCode( 0, 68)),
+ new AcCode("01110011010111", new MdecCode( 0, -69)),
+ new AcCode("01110101010101", new MdecCode( 2, 7)),
+ new AcCode("01110110010101", new MdecCode( 0, -61)),
+ new AcCode("01111011100000", new MdecCode( 0, 64)),
+ new AcCode("10000001010000", new MdecCode( 0, -85)),
+ new AcCode("10001001011001", new MdecCode( 0, -63)),
+ new AcCode("10001110100100", new MdecCode( 1, 22)),
+ new AcCode("10010100111010", new MdecCode( 0, -71)),
+ new AcCode("10010101010101", new MdecCode( 0, -67)),
+ new AcCode("10101011101011", new MdecCode( 0, 65)),
+ new AcCode("10101110100100", new MdecCode( 2, -7)),
+ new AcCode("10110101010101", new MdecCode( 1, -19)),
+ new AcCode("10110110010101", new MdecCode( 2, -6)),
+ new AcCode("10111001010000", new MdecCode( 0, 72)),
+ new AcCode("11001001011001", new MdecCode( 0, -122)),
+ new AcCode("11001101011001", new MdecCode( 3, -3)),
+ new AcCode("11010000100100", new MdecCode( 0, -86)),
+ new AcCode("11011101010101", new MdecCode( 0, 62)),
+ new AcCode("11011111010111", new MdecCode( 0, -62)),
+ new AcCode("11101110100100", new MdecCode( 0, -64)),
+ new AcCode("11110011010111", new MdecCode( 0, -94)),
+ new AcCode("11110101010101", new MdecCode( 0, -109)),
+ new AcCode("11110110010101", new MdecCode( 4, -1)),
+ new AcCode("11111011100000", new MdecCode( 0, -75)),
+ };
+
+ private static final AcCode[] TABLE2 = {
+ new AcCode( "001", new MdecCode( 0, 1)),
+ new AcCode( "110", new MdecCode( 0, -1)),
+ new AcCode( "0100", new MdecCode( 0, 4)),
+ new AcCode( "0101", new MdecCode( 0, 3)),
+ new AcCode( "0111", new MdecCode( 0, -2)),
+ new AcCode( "1000", new MdecCode( 0, -4)),
+ new AcCode( "1010", new MdecCode( 0, -3)),
+ new AcCode( "1111", new MdecCode( 0, 2)),
+ new AcCode( "01101", new MdecCode( 0, -5)),
+ new AcCode( "10000", new MdecCode( 0, -6)),
+ new AcCode( "11100", new MdecCode( 0, 6)),
+ new AcCode( "11101", new MdecCode( 0, 5)),
+ new AcCode( "000011", new MdecCode( 0, -7)),
+ new AcCode( "001011", new MdecCode( 1, -1)),
+ new AcCode( "100010", new MdecCode( 0, -8)),
+ new AcCode( "100011", new MdecCode( 1, 1)),
+ new AcCode( "101100", new MdecCode( 0, 8)),
+ new AcCode( "110011", new MdecCode( 0, 7)),
+ new AcCode( "0010010", new MdecCode( 0, -10)),
+ new AcCode( "0101011", new MdecCode( 0, -9)),
+ new AcCode( "0110010", new MdecCode( 1, 3)),
+ new AcCode( "0111011", new MdecCode( 1, -2)),
+ new AcCode( "1001100", new MdecCode( 0, 10)),
+ new AcCode( "1010010", new MdecCode( 1, -3)),
+ new AcCode( "1011011", new MdecCode( 0, 9)),
+ new AcCode( "1111011", new MdecCode( 1, 2)),
+ new AcCode( "00001100", new MdecCode( 0, -14)),
+ new AcCode( "00010011", new MdecCode( 0, -12)),
+ new AcCode( "00100000", new MdecCode( 2, -1)),
+ new AcCode( "01000000", new MdecCode( 0, 14)),
+ new AcCode( "01010011", new MdecCode( 1, -4)),
+ new AcCode( "01101011", new MdecCode( 1, 4)),
+ new AcCode( "10001100", new MdecCode( 0, 15)),
+ new AcCode( "10011011", new MdecCode( 0, 11)),
+ new AcCode( "10100000", new MdecCode( 2, 1)),
+ new AcCode( "11000010", new MdecCode( 0, 13)),
+ new AcCode( "11010011", new MdecCode( 0, -11)),
+ new AcCode( "11100000", new MdecCode( 0, -13)),
+ new AcCode( "11101011", new MdecCode( 0, 12)),
+ new AcCode( "000000010", new MdecCode( 0, 18)),
+ new AcCode( "000011011", new MdecCode( 1, 5)),
+ new AcCode( "001000010", new MdecCode( 2, -2)),
+ new AcCode( "001100000", new MdecCode( 0, 16)),
+ new AcCode( "001110010", new MdecCode( 2, 2)),
+ new AcCode( "010000000", new MdecCode( 1, -7)),
+ new AcCode( "010000010", new MdecCode( 0, -17)),
+ new AcCode( "010010011", new MdecCode( 0, -15)),
+ new AcCode( "100000000", new MdecCode( 1, -5)),
+ new AcCode( "100000010", new MdecCode( 0, -16)),
+ new AcCode( "101000010", new MdecCode( 0, 17)),
+ new AcCode( "101100000", new MdecCode( 0, 20)),
+ new AcCode( "101110010", new MdecCode( 1, 6)),
+ new AcCode( "111110010", new MdecCode( 1, -6)),
+ new AcCode( "0011110010", new MdecCode( 0, -20)),
+ new AcCode( "0100011011", new MdecCode( 0, -18)),
+ new AcCode( "0110000010", new MdecCode( 0, 23)),
+ new AcCode( "0110010011", new MdecCode( 1, 7)),
+ new AcCode( "1011110010", new MdecCode( 2, -3)),
+ new AcCode( "1100011011", new MdecCode( 0, 19)),
+ new AcCode( "1110010011", new MdecCode( 2, 3)),
+ new AcCode( "0111110000000", new MdecCode( 0, -19)),
+ new AcCode( "1111110000000", new MdecCode( 1, 8)),
+ new AcCode("00000011000000", new MdecCode( 0, -34)),
+ new AcCode("00000110000000", new MdecCode( 0, 42)),
+ new AcCode("00000111000000", new MdecCode( 0, -39)),
+ new AcCode("00001011000000", new MdecCode( 2, -7)),
+ new AcCode("00001110000000", new MdecCode( 0, -23)),
+ new AcCode("00001110000010", new MdecCode( 3, 2)),
+ new AcCode("00001111000000", new MdecCode( 0, 37)),
+ new AcCode("00010011000000", new MdecCode( 1, -12)),
+ new AcCode("00010110000000", new MdecCode( 0, -38)),
+ new AcCode("00010111000000", new MdecCode( 0, -24)),
+ new AcCode("00011011000000", new MdecCode( 0, -41)),
+ new AcCode("00011110000000", new MdecCode( 0, -76)),
+ new AcCode("00011110000010", new MdecCode( 0, 22)),
+ new AcCode("00011111000000", new MdecCode( 0, -29)),
+ new AcCode("00100011000000", new MdecCode( 1, 12)),
+ new AcCode("00100110000000", new MdecCode( 0, -68)),
+ new AcCode("00100111000000", new MdecCode( 3, -4)),
+ new AcCode("00101011000000", new MdecCode( 0, -92)),
+ new AcCode("00101110000000", new MdecCode( 3, 1)),
+ new AcCode("00101110000010", new MdecCode( 0, 27)),
+ new AcCode("00101111000000", new MdecCode( 0, -35)),
+ new AcCode("00110011000000", new MdecCode( 0, -40)),
+ new AcCode("00110110000000", new MdecCode( 1, -20)),
+ new AcCode("00110111000000", new MdecCode( 0, -26)),
+ new AcCode("00111011000000", new MdecCode( 0, 59)),
+ new AcCode("00111110000010", new MdecCode( 1, 9)),
+ new AcCode("00111111000000", new MdecCode( 0, 40)),
+ new AcCode("01000011000000", new MdecCode( 0, 55)),
+ new AcCode("01000110000000", new MdecCode( 2, -13)),
+ new AcCode("01000111000000", new MdecCode( 0, -32)),
+ new AcCode("01001011000000", new MdecCode( 1, 18)),
+ new AcCode("01001110000000", new MdecCode( 0, 21)),
+ new AcCode("01001110000010", new MdecCode( 2, 4)),
+ new AcCode("01001111000000", new MdecCode( 0, 30)),
+ new AcCode("01010011000000", new MdecCode( 1, -15)),
+ new AcCode("01010110000000", new MdecCode( 0, 43)),
+ new AcCode("01010111000000", new MdecCode( 0, 32)),
+ new AcCode("01011011000000", new MdecCode( 3, 4)),
+ new AcCode("01011110000000", new MdecCode( 0, 56)),
+ new AcCode("01011110000010", new MdecCode( 0, -25)),
+ new AcCode("01011111000000", new MdecCode( 3, -3)),
+ new AcCode("01100011000000", new MdecCode( 2, 7)),
+ new AcCode("01100110000000", new MdecCode( 0, 53)),
+ new AcCode("01100111000000", new MdecCode( 0, -33)),
+ new AcCode("01101011000000", new MdecCode( 1, 15)),
+ new AcCode("01101110000000", new MdecCode( 1, -8)),
+ new AcCode("01101110000010", new MdecCode( 0, 29)),
+ new AcCode("01101111000000", new MdecCode( 4, -1)),
+ new AcCode("01110011000000", new MdecCode( 2, -6)),
+ new AcCode("01110110000000", new MdecCode( 1, -13)),
+ new AcCode("01110111000000", new MdecCode( 0, 39)),
+ new AcCode("01111011000000", new MdecCode( 0, -43)),
+ new AcCode("01111110000010", new MdecCode( 0, -27)),
+ new AcCode("01111111000000", new MdecCode( 2, -5)),
+ new AcCode("10000011000000", new MdecCode( 1, -11)),
+ new AcCode("10000110000000", new MdecCode( 0, 58)),
+ new AcCode("10000111000000", new MdecCode( 0, 31)),
+ new AcCode("10001011000000", new MdecCode( 3, 5)),
+ new AcCode("10001110000000", new MdecCode( 0, -21)),
+ new AcCode("10001110000010", new MdecCode( 3, -2)),
+ new AcCode("10001111000000", new MdecCode( 0, 44)),
+ new AcCode("10010011000000", new MdecCode( 0, -37)),
+ new AcCode("10010110000000", new MdecCode( 2, 9)),
+ new AcCode("10010111000000", new MdecCode( 0, 41)),
+ new AcCode("10011011000000", new MdecCode( 0, -49)),
+ new AcCode("10011110000000", new MdecCode( 0, -114)),
+ new AcCode("10011110000010", new MdecCode( 2, -4)),
+ new AcCode("10011111000000", new MdecCode( 0, 36)),
+ new AcCode("10100011000000", new MdecCode( 4, 3)),
+ new AcCode("10100110000000", new MdecCode( 0, -71)),
+ new AcCode("10100111000000", new MdecCode( 3, 3)),
+ new AcCode("10101011000000", new MdecCode( 0, 50)),
+ new AcCode("10101110000000", new MdecCode( 0, -22)),
+ new AcCode("10101110000010", new MdecCode( 0, -28)),
+ new AcCode("10101111000000", new MdecCode( 1, -14)),
+ new AcCode("10110011000000", new MdecCode( 0, -44)),
+ new AcCode("10110110000000", new MdecCode( 2, -8)),
+ new AcCode("10110111000000", new MdecCode( 0, -30)),
+ new AcCode("10111011000000", new MdecCode( 1, -18)),
+ new AcCode("10111110000010", new MdecCode( 0, 24)),
+ new AcCode("10111111000000", new MdecCode( 1, 11)),
+ new AcCode("11000011000000", new MdecCode( 0, 57)),
+ new AcCode("11000110000000", new MdecCode( 0, 47)),
+ new AcCode("11000111000000", new MdecCode( 1, 10)),
+ new AcCode("11001011000000", new MdecCode( 4, 2)),
+ new AcCode("11001110000000", new MdecCode( 3, -1)),
+ new AcCode("11001110000010", new MdecCode( 0, 26)),
+ new AcCode("11001111000000", new MdecCode( 2, 6)),
+ new AcCode("11010011000000", new MdecCode( 0, 34)),
+ new AcCode("11010110000000", new MdecCode( 4, -2)),
+ new AcCode("11010111000000", new MdecCode( 1, -9)),
+ new AcCode("11011011000000", new MdecCode( 1, 14)),
+ new AcCode("11011110000000", new MdecCode( 0, -57)),
+ new AcCode("11011110000010", new MdecCode( 0, 25)),
+ new AcCode("11011111000000", new MdecCode( 4, 1)),
+ new AcCode("11100011000000", new MdecCode( 0, -42)),
+ new AcCode("11100110000000", new MdecCode( 0, -45)),
+ new AcCode("11100111000000", new MdecCode( 0, -36)),
+ new AcCode("11101011000000", new MdecCode( 2, 8)),
+ new AcCode("11101110000000", new MdecCode( 0, 33)),
+ new AcCode("11101110000010", new MdecCode( 0, -31)),
+ new AcCode("11101111000000", new MdecCode( 0, 35)),
+ new AcCode("11110011000000", new MdecCode( 0, 38)),
+ new AcCode("11110110000000", new MdecCode( 1, 13)),
+ new AcCode("11110111000000", new MdecCode( 2, 5)),
+ new AcCode("11111011000000", new MdecCode( 0, -56)),
+ new AcCode("11111110000010", new MdecCode( 0, 28)),
+ new AcCode("11111111000000", new MdecCode( 1, -10)),
+ };
+
+ private static final AcCode[] TABLE3 = {
+ new AcCode( "10", new MdecCode( 0, 1)),
+ new AcCode( "101", new MdecCode( 0, -1)),
+ new AcCode( "0001", new MdecCode( 1, -1)),
+ new AcCode( "0011", new MdecCode( 0, -2)),
+ new AcCode( "1011", new MdecCode( 0, 2)),
+ new AcCode( "1111", new MdecCode( 1, 1)),
+ new AcCode( "00100", new MdecCode( 0, 3)),
+ new AcCode( "01100", new MdecCode( 2, 1)),
+ new AcCode( "10100", new MdecCode( 0, -3)),
+ new AcCode( "11100", new MdecCode( 2, -1)),
+ new AcCode( "001000", new MdecCode( 1, 2)),
+ new AcCode( "010000", new MdecCode( 4, -1)),
+ new AcCode( "011001", new MdecCode( 3, 1)),
+ new AcCode( "100000", new MdecCode( 0, -4)),
+ new AcCode( "100111", new MdecCode( 3, -1)),
+ new AcCode( "101000", new MdecCode( 0, 4)),
+ new AcCode( "111000", new MdecCode( 1, -2)),
+ new AcCode( "0011000", new MdecCode( 0, -5)),
+ new AcCode( "0101001", new MdecCode( 4, 1)),
+ new AcCode( "0110000", new MdecCode( 6, 1)),
+ new AcCode( "1000000", new MdecCode( 6, -1)),
+ new AcCode( "1001001", new MdecCode( 5, -1)),
+ new AcCode( "1010111", new MdecCode( 0, 5)),
+ new AcCode( "1111001", new MdecCode( 5, 1)),
+ new AcCode( "00000111", new MdecCode( 1, -3)),
+ new AcCode( "00001001", new MdecCode( 7, -1)),
+ new AcCode( "01000111", new MdecCode( 0, 6)),
+ new AcCode( "01011000", new MdecCode( 8, -1)),
+ new AcCode( "01110111", new MdecCode( 0, -6)),
+ new AcCode( "10000111", new MdecCode( 1, 3)),
+ new AcCode( "10110111", new MdecCode( 2, -2)),
+ new AcCode( "10111001", new MdecCode( 7, 1)),
+ new AcCode( "11110111", new MdecCode( 2, 2)),
+ new AcCode( "001101001", new MdecCode( 9, 1)),
+ new AcCode( "010010111", new MdecCode( 3, 2)),
+ new AcCode( "011011000", new MdecCode( 3, -2)),
+ new AcCode( "011110000", new MdecCode( 1, -4)),
+ new AcCode( "100000000", new MdecCode( 8, 1)),
+ new AcCode( "100110111", new MdecCode(10, 1)),
+ new AcCode( "100111001", new MdecCode( 0, -7)),
+ new AcCode( "101101001", new MdecCode( 9, -1)),
+ new AcCode( "110000000", new MdecCode(11, 1)),
+ new AcCode( "110001001", new MdecCode( 0, 7)),
+ new AcCode( "111000111", new MdecCode(10, -1)),
+ new AcCode( "111011000", new MdecCode( 1, 4)),
+ new AcCode( "111110000", new MdecCode( 0, 8)),
+ new AcCode( "0000010111", new MdecCode( 0, -9)),
+ new AcCode( "0000110111", new MdecCode( 2, -3)),
+ new AcCode( "0000111001", new MdecCode(12, -1)),
+ new AcCode( "0011000111", new MdecCode(12, 1)),
+ new AcCode( "0011101001", new MdecCode(11, -1)),
+ new AcCode( "0110010111", new MdecCode( 4, 2)),
+ new AcCode( "1000010111", new MdecCode(13, 1)),
+ new AcCode( "1000110111", new MdecCode( 0, 9)),
+ new AcCode( "1010000000", new MdecCode( 1, 5)),
+ new AcCode( "1011000111", new MdecCode( 2, 3)),
+ new AcCode( "1011101001", new MdecCode( 0, -8)),
+ new AcCode( "1100010111", new MdecCode(13, -1)),
+ new AcCode( "1110010111", new MdecCode( 4, -2)),
+ new AcCode( "00010000000", new MdecCode( 0, -11)),
+ new AcCode( "00010001001", new MdecCode( 5, -2)),
+ new AcCode( "00100010111", new MdecCode(14, -1)),
+ new AcCode( "00111101001", new MdecCode( 1, -5)),
+ new AcCode( "01000111001", new MdecCode( 5, 2)),
+ new AcCode( "01010001001", new MdecCode( 0, -10)),
+ new AcCode( "10010000000", new MdecCode(14, 1)),
+ new AcCode( "10010001001", new MdecCode( 0, 10)),
+ new AcCode( "10100010111", new MdecCode( 0, 11)),
+ new AcCode( "11101110000", new MdecCode( 2, -4)),
+ new AcCode( "001111101001", new MdecCode( 3, -3)),
+ new AcCode( "010111101001", new MdecCode( 3, 3)),
+ new AcCode( "011000111001", new MdecCode( 7, 2)),
+ new AcCode( "011010001001", new MdecCode( 2, 4)),
+ new AcCode( "011111101001", new MdecCode( 6, 2)),
+ new AcCode( "101111101001", new MdecCode( 1, -6)),
+ new AcCode( "110111101001", new MdecCode( 1, 6)),
+ new AcCode( "111000111001", new MdecCode( 0, -12)),
+ new AcCode( "111010001001", new MdecCode( 0, 12)),
+ new AcCode( "111111101001", new MdecCode( 6, -2)),
+ new AcCode("00000001110000", new MdecCode( 2, 5)),
+ new AcCode("00000101110000", new MdecCode(19, -1)),
+ new AcCode("00001001110000", new MdecCode(11, -2)),
+ new AcCode("00001101110000", new MdecCode( 0, -13)),
+ new AcCode("00010001110000", new MdecCode( 0, -14)),
+ new AcCode("00010101110000", new MdecCode(21, -1)),
+ new AcCode("00011001110000", new MdecCode( 1, 8)),
+ new AcCode("00100001110000", new MdecCode(17, -1)),
+ new AcCode("00100101110000", new MdecCode( 1, 9)),
+ new AcCode("00101001110000", new MdecCode( 3, -5)),
+ new AcCode("00101101110000", new MdecCode(15, 1)),
+ new AcCode("00110001110000", new MdecCode( 3, 4)),
+ new AcCode("00110101110000", new MdecCode( 6, 3)),
+ new AcCode("00111001110000", new MdecCode(17, 1)),
+ new AcCode("01000001110000", new MdecCode(16, -1)),
+ new AcCode("01000101110000", new MdecCode( 4, 4)),
+ new AcCode("01001001110000", new MdecCode( 9, -2)),
+ new AcCode("01001101110000", new MdecCode( 7, -2)),
+ new AcCode("01010001110000", new MdecCode( 4, -3)),
+ new AcCode("01010101110000", new MdecCode( 2, 6)),
+ new AcCode("01011001110000", new MdecCode(16, 1)),
+ new AcCode("01100001110000", new MdecCode( 5, -3)),
+ new AcCode("01100101110000", new MdecCode( 4, -4)),
+ new AcCode("01101001110000", new MdecCode(10, 2)),
+ new AcCode("01101101110000", new MdecCode(15, -1)),
+ new AcCode("01110001110000", new MdecCode( 0, 14)),
+ new AcCode("01110101110000", new MdecCode( 0, -17)),
+ new AcCode("01111001110000", new MdecCode( 0, 16)),
+ new AcCode("10000001110000", new MdecCode(11, 2)),
+ new AcCode("10000101110000", new MdecCode(20, -1)),
+ new AcCode("10001001110000", new MdecCode( 0, 17)),
+ new AcCode("10001101110000", new MdecCode( 1, 7)),
+ new AcCode("10010001110000", new MdecCode( 8, -2)),
+ new AcCode("10010101110000", new MdecCode(20, 1)),
+ new AcCode("10011001110000", new MdecCode( 1, -8)),
+ new AcCode("10100001110000", new MdecCode( 5, 3)),
+ new AcCode("10100101110000", new MdecCode( 7, 3)),
+ new AcCode("10101001110000", new MdecCode(10, -2)),
+ new AcCode("10101101110000", new MdecCode( 8, 2)),
+ new AcCode("10110001110000", new MdecCode( 3, -4)),
+ new AcCode("10110101110000", new MdecCode( 0, 18)),
+ new AcCode("10111001110000", new MdecCode(19, 1)),
+ new AcCode("11000001110000", new MdecCode( 0, -15)),
+ new AcCode("11000101110000", new MdecCode( 6, -3)),
+ new AcCode("11001001110000", new MdecCode(18, 1)),
+ new AcCode("11001101110000", new MdecCode( 0, 13)),
+ new AcCode("11010001110000", new MdecCode( 4, 3)),
+ new AcCode("11010101110000", new MdecCode(18, -1)),
+ new AcCode("11011001110000", new MdecCode( 0, -16)),
+ new AcCode("11100001110000", new MdecCode( 0, 15)),
+ new AcCode("11100101110000", new MdecCode( 0, -18)),
+ new AcCode("11101001110000", new MdecCode( 2, -6)),
+ new AcCode("11101101110000", new MdecCode( 1, -7)),
+ new AcCode("11110001110000", new MdecCode( 2, -5)),
+ new AcCode("11110101110000", new MdecCode(12, -2)),
+ new AcCode("11111001110000", new MdecCode( 9, 2)),
+ };
+
+ static {
+ buidLookup(TABLE1, TABLE1_LOOKUP);
+ buidLookup(TABLE2, TABLE2_LOOKUP);
+ buidLookup(TABLE3, TABLE3_LOOKUP);
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/modules/crusader/CrusaderPacketHeaderReader.java b/jpsxdec/src/jpsxdec/modules/crusader/CrusaderPacketHeaderReader.java
index 4ffdce3..5f0d6c6 100644
--- a/jpsxdec/src/jpsxdec/modules/crusader/CrusaderPacketHeaderReader.java
+++ b/jpsxdec/src/jpsxdec/modules/crusader/CrusaderPacketHeaderReader.java
@@ -86,7 +86,7 @@ public VideoHeader(@Nonnull byte[] abHeader, int iRemainingPayloadSize)
private static final long AUDIO_ID = 0x08000200L;
public static class AudioHeader implements Header {
- private final int _iPresentationSample;
+ private final int _iPresentationSampleFrame;
private final int _iByteSize;
public AudioHeader(@Nonnull byte[] abHeader, int iRemainingPayloadSize)
@@ -97,8 +97,8 @@ public AudioHeader(@Nonnull byte[] abHeader, int iRemainingPayloadSize)
// always be sure the audio data is a multiple of 16*2
if (iRemainingPayloadSize % (SpuAdpcmSoundUnit.SIZEOF_SOUND_UNIT * 2) != 0)
throw new BinaryDataNotRecognized();
- _iPresentationSample = IO.readSInt32BE(abHeader, 8);
- if (_iPresentationSample < 0)
+ _iPresentationSampleFrame = IO.readSInt32BE(abHeader, 8);
+ if (_iPresentationSampleFrame < 0)
throw new BinaryDataNotRecognized();
final long lngAudioId = IO.readUInt32BE(abHeader, 12);
if (lngAudioId != AUDIO_ID)
@@ -106,7 +106,7 @@ public AudioHeader(@Nonnull byte[] abHeader, int iRemainingPayloadSize)
_iByteSize = iRemainingPayloadSize;
}
- public int getPresentationSample() { return _iPresentationSample; }
+ public int getPresentationSampleFrame() { return _iPresentationSampleFrame; }
/** Guaranteed to be a multiple of 16*2 (i.e. stereo SPU sound units). */
public int getByteSize() { return _iByteSize; }
}
diff --git a/jpsxdec/src/jpsxdec/modules/crusader/CrusaderPacketToFrameAndAudio.java b/jpsxdec/src/jpsxdec/modules/crusader/CrusaderPacketToFrameAndAudio.java
index 16711fb..0fadd40 100644
--- a/jpsxdec/src/jpsxdec/modules/crusader/CrusaderPacketToFrameAndAudio.java
+++ b/jpsxdec/src/jpsxdec/modules/crusader/CrusaderPacketToFrameAndAudio.java
@@ -47,6 +47,7 @@
import jpsxdec.adpcm.SpuAdpcmDecoder;
import jpsxdec.adpcm.SpuAdpcmSoundUnit;
import jpsxdec.i18n.I;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.sharedaudio.DecodedAudioPacket;
import jpsxdec.util.DemuxedData;
@@ -60,17 +61,19 @@ public class CrusaderPacketToFrameAndAudio implements CrusaderSectorToCrusaderPa
/** Equivalent to 15 fps. */
public static final int SECTORS_PER_FRAME = 10;
- public static final int CRUSADER_SAMPLES_PER_SECOND = 22050;
- public static final int SAMPLES_PER_SECTOR = CRUSADER_SAMPLES_PER_SECOND / 150;
+ public static final int CRUSADER_SAMPLE_FRAMES_PER_SECOND = 22050;
+ public static final int SAMPLE_FRAMES_PER_SECTOR = CRUSADER_SAMPLE_FRAMES_PER_SECOND / 150;
static {
- if (CRUSADER_SAMPLES_PER_SECOND % 150 != 0)
+ if (CRUSADER_SAMPLE_FRAMES_PER_SECOND % 150 != 0)
throw new RuntimeException("Crusader sample rate doesn't cleanly divide by sector rate");
}
- public static final AudioFormat CRUSADER_AUDIO_FORMAT = new AudioFormat(CRUSADER_SAMPLES_PER_SECOND, 16, 2, true, false);
+ public static final AudioFormat CRUSADER_AUDIO_FORMAT = new AudioFormat(CRUSADER_SAMPLE_FRAMES_PER_SECOND, 16, 2, true, false);
public interface FrameListener {
- void frameComplete(@Nonnull DemuxedCrusaderFrame frame, @Nonnull ILocalizedLogger log);
- void videoEnd(@Nonnull ILocalizedLogger log, int iStartSector, int iEndSector);
+ void frameComplete(@Nonnull DemuxedCrusaderFrame frame, @Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
+ void videoEnd(@Nonnull ILocalizedLogger log, int iStartSector, int iEndSector)
+ throws LoggedFailure;
}
@Nonnull
@@ -120,6 +123,7 @@ public void setAudioListener(@CheckForNull DecodedAudioPacket.Listener audioList
public void frame(@Nonnull CrusaderPacketHeaderReader.VideoHeader frameHeader,
@Nonnull DemuxedData demux,
@Nonnull ILocalizedLogger log)
+ throws LoggedFailure
{
int iPresentationSector = frameHeader.getFrameNumber() * SECTORS_PER_FRAME + _iAbsoluteInitialFramePresentationSector;
@@ -134,6 +138,7 @@ public void frame(@Nonnull CrusaderPacketHeaderReader.VideoHeader frameHeader,
public void audio(@Nonnull CrusaderPacketHeaderReader.AudioHeader audio,
@Nonnull DemuxedData demux,
@Nonnull ILocalizedLogger log)
+ throws LoggedFailure
{
// .. copy the audio data out of the sectors ...............
byte[] abAudioDemuxBuffer = demux.copyDemuxData();
@@ -162,11 +167,12 @@ public void audio(@Nonnull CrusaderPacketHeaderReader.AudioHeader audio,
log.log(Level.WARNING, I.SPU_ADPCM_CORRUPTED(demux.getStartSector(), _audDecoder.getSampleFramesWritten()));
if (_audioListener != null) {
- Fraction presentationSector = new Fraction(audio.getPresentationSample(), SAMPLES_PER_SECTOR)
+ Fraction presentationSector = new Fraction(audio.getPresentationSampleFrame(), SAMPLE_FRAMES_PER_SECTOR)
.add(_iAbsoluteInitialFramePresentationSector);
- _audioListener.audioPacketComplete(new DecodedAudioPacket(-1, CRUSADER_AUDIO_FORMAT,
- presentationSector,
- audioBuffer.toByteArray()), log);
+ DecodedAudioPacket packet = new DecodedAudioPacket(-1, CRUSADER_AUDIO_FORMAT,
+ presentationSector,
+ audioBuffer.toByteArray());
+ _audioListener.audioPacketComplete(packet, log);
}
diff --git a/jpsxdec/src/jpsxdec/modules/crusader/CrusaderSectorToCrusaderPacket.java b/jpsxdec/src/jpsxdec/modules/crusader/CrusaderSectorToCrusaderPacket.java
index 984ad37..623917e 100644
--- a/jpsxdec/src/jpsxdec/modules/crusader/CrusaderSectorToCrusaderPacket.java
+++ b/jpsxdec/src/jpsxdec/modules/crusader/CrusaderSectorToCrusaderPacket.java
@@ -43,6 +43,7 @@
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.util.BinaryDataNotRecognized;
import jpsxdec.util.DemuxPushInputStream;
@@ -62,11 +63,13 @@ public class CrusaderSectorToCrusaderPacket {
public interface PacketListener {
void frame(@Nonnull CrusaderPacketHeaderReader.VideoHeader frame,
@Nonnull DemuxedData demux,
- @Nonnull ILocalizedLogger log);
+ @Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
void audio(@Nonnull CrusaderPacketHeaderReader.AudioHeader audio,
@Nonnull DemuxedData demux,
- @Nonnull ILocalizedLogger log);
+ @Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
}
@CheckForNull
@@ -91,7 +94,7 @@ public void setListener(@CheckForNull PacketListener listener) {
/** Returns if the sector was accepted by this movie.
* A new {@link CrusaderSectorToCrusaderPacket} should be created for
* each movie. */
- public boolean sectorRead(@Nonnull SectorCrusader sector, @Nonnull ILocalizedLogger log) {
+ public boolean sectorRead(@Nonnull SectorCrusader sector, @Nonnull ILocalizedLogger log) throws LoggedFailure {
if (_iPrevCrusaderSector != -1) {
if (sector.getCrusaderSectorNumber() < _iPrevCrusaderSector)
return false;
@@ -120,13 +123,13 @@ private void addPiece(@Nonnull CrusaderDemuxPiece piece) {
}
/** Tells this to finish off the video and flush any remaining data. */
- public void endVideo(@Nonnull ILocalizedLogger log) {
+ public void endVideo(@Nonnull ILocalizedLogger log) throws LoggedFailure {
_stream.close();
read(log);
_stream = null;
}
- private void read(@Nonnull ILocalizedLogger log) {
+ private void read(@Nonnull ILocalizedLogger log) throws LoggedFailure {
try {
while (true) {
if (_header == null) {
diff --git a/jpsxdec/src/jpsxdec/modules/crusader/DemuxedCrusaderFrame.java b/jpsxdec/src/jpsxdec/modules/crusader/DemuxedCrusaderFrame.java
index 77ed558..294994b 100644
--- a/jpsxdec/src/jpsxdec/modules/crusader/DemuxedCrusaderFrame.java
+++ b/jpsxdec/src/jpsxdec/modules/crusader/DemuxedCrusaderFrame.java
@@ -50,6 +50,7 @@
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.video.IDemuxedFrame;
import jpsxdec.modules.video.framenumber.FrameNumber;
+import jpsxdec.psxvideo.mdec.MdecInputStream;
import jpsxdec.util.DemuxedData;
import jpsxdec.util.Fraction;
@@ -79,6 +80,10 @@ public DemuxedCrusaderFrame(int iWidth, int iHeight,
_iPresentationSector = iPresentationSector;
}
+ public @CheckForNull MdecInputStream getCustomFrameMdecStream() {
+ return null;
+ }
+
public @Nonnull byte[] copyDemuxData() {
return _demux.copyDemuxData();
}
@@ -141,6 +146,7 @@ public void printSectors(@Nonnull PrintStream ps) {
* @throws IllegalArgumentException
* if {@code abNewDemux.length > } {@link #getDemuxSize()}
*/
+ @Override
public void writeToSectors(@Nonnull byte[] abNewDemux,
int iUsedSize_ignore, int iMdecCodeCount_ignore,
@Nonnull CdFileSectorReader cd,
diff --git a/jpsxdec/src/jpsxdec/modules/crusader/DiscIndexerCrusader.java b/jpsxdec/src/jpsxdec/modules/crusader/DiscIndexerCrusader.java
index 069aae2..f098eec 100644
--- a/jpsxdec/src/jpsxdec/modules/crusader/DiscIndexerCrusader.java
+++ b/jpsxdec/src/jpsxdec/modules/crusader/DiscIndexerCrusader.java
@@ -52,6 +52,7 @@
import jpsxdec.discitems.DiscItem;
import jpsxdec.discitems.SerializedDiscItem;
import jpsxdec.i18n.exception.LocalizedDeserializationFail;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.indexing.DiscIndex;
import jpsxdec.indexing.DiscIndexer;
@@ -172,6 +173,7 @@ private static class VidBuilder implements CrusaderSectorToCrusaderPacket.Packet
public VidBuilder(@Nonnull ILocalizedLogger errLog,
@Nonnull SectorCrusader vidSect)
+ throws LoggedFailure
{
_errLog = errLog;
_iStartSector = _iEndSector = vidSect.getSectorNumber();
@@ -181,7 +183,7 @@ public VidBuilder(@Nonnull ILocalizedLogger errLog,
/** Returns if the supplied sector is part of this movie. If not,
* end this movie and start a new one. */
- public boolean feedSector(@Nonnull SectorCrusader sector) {
+ public boolean feedSector(@Nonnull SectorCrusader sector) throws LoggedFailure {
if (!_cs2cp.sectorRead(sector, _errLog)) {
return false;
}
@@ -230,7 +232,7 @@ public void audio(@Nonnull CrusaderPacketHeaderReader.AudioHeader audio,
// so pick an initial presentation sector a little before when the next
// frame should be presented (-60)
if (_iInitialFramePresentationSector < 0) {
- _iInitialFramePresentationSector = (audio.getPresentationSample() / CrusaderPacketToFrameAndAudio.SAMPLES_PER_SECTOR) - 60;
+ _iInitialFramePresentationSector = (audio.getPresentationSampleFrame() / CrusaderPacketToFrameAndAudio.SAMPLE_FRAMES_PER_SECTOR) - 60;
if (_iInitialFramePresentationSector < 0) // don't start before the start of the movie
_iInitialFramePresentationSector = 0;
else if (_iInitialFramePresentationSector > 0)
@@ -239,7 +241,9 @@ else if (_iInitialFramePresentationSector > 0)
_iSoundUnitCount += audio.getByteSize() / 2 / 16;
}
- public @CheckForNull DiscItemCrusader endOfMovie(@Nonnull CdFileSectorReader cd) {
+ public @CheckForNull DiscItemCrusader endOfMovie(@Nonnull CdFileSectorReader cd)
+ throws LoggedFailure
+ {
_cs2cp.endVideo(_errLog);
if (_indexSectorFrameNumberBuilder == null) // never received a frame
@@ -287,7 +291,9 @@ public void attachToSectorClaimer(@Nonnull SectorClaimSystem scs) {
s2cs.setListener(this);
}
- public void sectorRead(@Nonnull SectorCrusader vidSect, @Nonnull ILocalizedLogger log) {
+ public void sectorRead(@Nonnull SectorCrusader vidSect, @Nonnull ILocalizedLogger log)
+ throws LoggedFailure
+ {
if (_currentStream != null) {
boolean blnAccepted = _currentStream.feedSector(vidSect);
if (!blnAccepted) {
@@ -302,7 +308,7 @@ public void sectorRead(@Nonnull SectorCrusader vidSect, @Nonnull ILocalizedLogge
}
}
- public void endOfSectors(@Nonnull ILocalizedLogger log) {
+ public void endOfSectors(@Nonnull ILocalizedLogger log) throws LoggedFailure {
if (_currentStream != null) {
DiscItemCrusader vid = _currentStream.endOfMovie(getCd());
if (vid != null)
diff --git a/jpsxdec/src/jpsxdec/modules/crusader/DiscItemCrusader.java b/jpsxdec/src/jpsxdec/modules/crusader/DiscItemCrusader.java
index d1b2ebc..fdfa123 100644
--- a/jpsxdec/src/jpsxdec/modules/crusader/DiscItemCrusader.java
+++ b/jpsxdec/src/jpsxdec/modules/crusader/DiscItemCrusader.java
@@ -38,34 +38,29 @@
package jpsxdec.modules.crusader;
import java.util.Arrays;
-import java.util.Date;
import java.util.List;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.sound.sampled.AudioFormat;
import jpsxdec.cdreaders.CdFileSectorReader;
import jpsxdec.discitems.SerializedDiscItem;
-import jpsxdec.i18n.I;
-import jpsxdec.i18n.ILocalizedMessage;
import jpsxdec.i18n.exception.LocalizedDeserializationFail;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.SectorClaimSystem;
-import jpsxdec.modules.player.MediaPlayer;
import jpsxdec.modules.sharedaudio.DecodedAudioPacket;
-import jpsxdec.modules.sharedaudio.ISectorAudioDecoder;
import jpsxdec.modules.video.Dimensions;
-import jpsxdec.modules.video.DiscItemVideoStream;
import jpsxdec.modules.video.IDemuxedFrame;
-import jpsxdec.modules.video.ISectorClaimToDemuxedFrame;
import jpsxdec.modules.video.framenumber.FrameNumber;
import jpsxdec.modules.video.framenumber.HeaderFrameNumber;
import jpsxdec.modules.video.framenumber.IFrameNumberFormatterWithHeader;
import jpsxdec.modules.video.framenumber.IndexSectorFrameNumber;
+import jpsxdec.modules.video.packetbased.SectorClaimToAudioAndFrame;
+import jpsxdec.modules.video.packetbased.DiscItemPacketBasedVideoStream;
import jpsxdec.util.Fraction;
-import jpsxdec.util.player.PlayController;
/** Crusader: No Remorse audio/video stream. */
-public class DiscItemCrusader extends DiscItemVideoStream {
+public class DiscItemCrusader extends DiscItemPacketBasedVideoStream {
public static final String TYPE_ID = "Crusader";
private static final Fraction SECTORS_PER_FRAME = new Fraction(10);
@@ -75,11 +70,9 @@ public class DiscItemCrusader extends DiscItemVideoStream {
private final HeaderFrameNumber.Format _headerFrameNumberFormat;
private static final String INITIAL_PRES_SECTOR_KEY = "Initial presentation sector";
+ /** Should normally be 0 unless the first several sectors of the video are missing for some reason. */
private final int _iRelativeInitialFramePresentationSector;
- private static final String SOUND_UNIT_COUNT_KEY = "Sound unit count";
- private final int _iSoundUnitCount;
-
public DiscItemCrusader(@Nonnull CdFileSectorReader cd,
int iStartSector, int iEndSector,
@Nonnull Dimensions dim,
@@ -88,10 +81,9 @@ public DiscItemCrusader(@Nonnull CdFileSectorReader cd,
int iInitialPresentationSector,
int iSoundUnitCount)
{
- super(cd, iStartSector, iEndSector, dim, sectorIndexFrameNumberFormat);
+ super(cd, iStartSector, iEndSector, dim, sectorIndexFrameNumberFormat, iSoundUnitCount);
_headerFrameNumberFormat = headerFrameNumberFormat;
_iRelativeInitialFramePresentationSector = iInitialPresentationSector;
- _iSoundUnitCount = iSoundUnitCount;
}
public DiscItemCrusader(@Nonnull CdFileSectorReader cd, @Nonnull SerializedDiscItem fields)
@@ -99,7 +91,6 @@ public DiscItemCrusader(@Nonnull CdFileSectorReader cd, @Nonnull SerializedDiscI
{
super(cd, fields);
_headerFrameNumberFormat = new HeaderFrameNumber.Format(fields);
- _iSoundUnitCount = fields.getInt(SOUND_UNIT_COUNT_KEY);
_iRelativeInitialFramePresentationSector = fields.getInt(INITIAL_PRES_SECTOR_KEY);
}
@@ -107,7 +98,6 @@ public DiscItemCrusader(@Nonnull CdFileSectorReader cd, @Nonnull SerializedDiscI
public @Nonnull SerializedDiscItem serialize() {
SerializedDiscItem serial = super.serialize();
_headerFrameNumberFormat.serialize(serial);
- serial.addNumber(SOUND_UNIT_COUNT_KEY, _iSoundUnitCount);
serial.addNumber(INITIAL_PRES_SECTOR_KEY, _iRelativeInitialFramePresentationSector);
return serial;
}
@@ -117,6 +107,11 @@ public DiscItemCrusader(@Nonnull CdFileSectorReader cd, @Nonnull SerializedDiscI
return TYPE_ID;
}
+ @Override
+ public boolean hasIndependentBitstream() {
+ return true;
+ }
+
@Override
public @Nonnull FrameNumber getStartFrame() {
return _headerFrameNumberFormat.getStartFrame(_indexSectorFrameNumberFormat);
@@ -133,30 +128,18 @@ public FrameNumber getEndFrame() {
}
@Override
- public @Nonnull ILocalizedMessage getInterestingDescription() {
- int iFrames = getFrameCount();
- Date secs = new Date(0, 0, 0, 0, 0, Math.max(iFrames / FPS, 1));
- return I.GUI_CRUSADER_VID_DETAILS(getWidth() ,getHeight(), iFrames, FPS, secs);
+ protected double getPacketBasedFpsInterestingDescription() {
+ return FPS;
}
- @Override
- public @Nonnull VideoSaverBuilderCrusader makeSaverBuilder() {
- return new VideoSaverBuilderCrusader(this);
- }
-
- @Override
- public int getDiscSpeed() {
- return 2; // pretty sure it plays back at 2x
- }
-
@Override
public @Nonnull Fraction getSectorsPerFrame() {
return SECTORS_PER_FRAME;
}
@Override
- public int getAbsolutePresentationStartSector() {
- return getStartSector();
+ public int getAudioSampleFramesPerSecond() {
+ return CrusaderPacketToFrameAndAudio.CRUSADER_SAMPLE_FRAMES_PER_SECOND;
}
@Override
@@ -165,22 +148,15 @@ public double getApproxDuration() {
}
@Override
- public @Nonnull Demuxer makeDemuxer() {
- return makeDemuxer(1.0);
- }
-
- public @Nonnull Demuxer makeDemuxer(double dblVolume) {
+ public @Nonnull SectorClaimToAudioAndFrame makeAudioVideoDemuxer(double dblVolume) {
return new Demuxer(dblVolume, _headerFrameNumberFormat.makeFormatter(_indexSectorFrameNumberFormat));
}
- @Override
- public @Nonnull PlayController makePlayController() {
- Demuxer demuxer = makeDemuxer();
- return new PlayController(new MediaPlayer(this, demuxer, demuxer, getStartSector(), getEndSector()));
- }
-
- public class Demuxer implements ISectorClaimToDemuxedFrame, ISectorAudioDecoder,
- SectorClaimToSectorCrusader.Listener,
+ /* SectorClaimSystem -> CrusaderSectorToCrusaderPacket -> CrusaderPacketToFrameAndAudio -> IDemuxedFrame
+ * -> DecodedAudioPacket
+ */
+ public class Demuxer extends SectorClaimToAudioAndFrame
+ implements SectorClaimToSectorCrusader.Listener,
CrusaderPacketToFrameAndAudio.FrameListener
{
@@ -215,15 +191,17 @@ public void attachToSectorClaimer(@Nonnull SectorClaimSystem scs) {
s2cs.setRangeLimit(getStartSector(), getEndSector());
}
- public void sectorRead(@Nonnull SectorCrusader sector, @Nonnull ILocalizedLogger log) {
+ public void sectorRead(@Nonnull SectorCrusader sector, @Nonnull ILocalizedLogger log)
+ throws LoggedFailure
+ {
_cs2cp.sectorRead(sector, log);
}
- public void endOfSectors(@Nonnull ILocalizedLogger log) {
+ public void endOfSectors(@Nonnull ILocalizedLogger log) throws LoggedFailure {
_cs2cp.endVideo(log);
}
- public void frameComplete(@Nonnull DemuxedCrusaderFrame frame, @Nonnull ILocalizedLogger log) {
+ public void frameComplete(@Nonnull DemuxedCrusaderFrame frame, @Nonnull ILocalizedLogger log) throws LoggedFailure {
frame.setFrame(_frameNumberFormatter.next(frame.getStartSector(), frame.getHeaderFrameNumber(), log));
if (_listener != null)
_listener.frameComplete(frame);
@@ -260,7 +238,7 @@ public int getEndSector() {
}
public int getSampleFramesPerSecond() {
- return CrusaderPacketToFrameAndAudio.CRUSADER_SAMPLES_PER_SECOND;
+ return CrusaderPacketToFrameAndAudio.CRUSADER_SAMPLE_FRAMES_PER_SECOND;
}
public int getDiscSpeed() {
diff --git a/jpsxdec/src/jpsxdec/modules/crusader/SectorClaimToSectorCrusader.java b/jpsxdec/src/jpsxdec/modules/crusader/SectorClaimToSectorCrusader.java
index 988378e..564e2f5 100644
--- a/jpsxdec/src/jpsxdec/modules/crusader/SectorClaimToSectorCrusader.java
+++ b/jpsxdec/src/jpsxdec/modules/crusader/SectorClaimToSectorCrusader.java
@@ -40,6 +40,7 @@
import java.io.IOException;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.SectorClaimSystem;
import jpsxdec.util.IOIterator;
@@ -48,8 +49,10 @@
public class SectorClaimToSectorCrusader extends SectorClaimSystem.SectorClaimer {
public interface Listener {
- void sectorRead(@Nonnull SectorCrusader sector, @Nonnull ILocalizedLogger log);
- void endOfSectors(@Nonnull ILocalizedLogger log);
+ void sectorRead(@Nonnull SectorCrusader sector, @Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
+ void endOfSectors(@Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
}
@CheckForNull
@@ -67,7 +70,7 @@ public void setListener(@CheckForNull Listener listener) {
public void sectorRead(@Nonnull SectorClaimSystem.ClaimableSector cs,
@Nonnull IOIterator peekIt,
@Nonnull ILocalizedLogger log)
- throws IOException
+ throws IOException, SectorClaimSystem.ClaimerFailure
{
if (cs.isClaimed())
return;
@@ -77,13 +80,25 @@ public void sectorRead(@Nonnull SectorClaimSystem.ClaimableSector cs,
cs.claim(sector);
- if (_listener != null && sectorIsInRange(cs.getSector().getSectorIndexFromStart()))
- _listener.sectorRead(sector, log);
+ if (_listener != null && sectorIsInRange(cs.getSector().getSectorIndexFromStart())) {
+ try {
+ _listener.sectorRead(sector, log);
+ } catch (LoggedFailure ex) {
+ throw new SectorClaimSystem.ClaimerFailure(ex);
+ }
+ }
}
- public void endOfSectors(@Nonnull ILocalizedLogger log) {
- if (_listener != null)
- _listener.endOfSectors(log);
+ public void endOfSectors(@Nonnull ILocalizedLogger log)
+ throws SectorClaimSystem.ClaimerFailure
+ {
+ if (_listener != null) {
+ try {
+ _listener.endOfSectors(log);
+ } catch (LoggedFailure ex) {
+ throw new SectorClaimSystem.ClaimerFailure(ex);
+ }
+ }
}
}
diff --git a/jpsxdec/src/jpsxdec/modules/dredd/DemuxedDreddFrame.java b/jpsxdec/src/jpsxdec/modules/dredd/DemuxedDreddFrame.java
index 8a0b074..9063f64 100644
--- a/jpsxdec/src/jpsxdec/modules/dredd/DemuxedDreddFrame.java
+++ b/jpsxdec/src/jpsxdec/modules/dredd/DemuxedDreddFrame.java
@@ -46,6 +46,7 @@
import jpsxdec.modules.video.IDemuxedFrame;
import jpsxdec.modules.video.framenumber.FrameNumber;
import jpsxdec.modules.video.sectorbased.SectorBasedFrameReplace;
+import jpsxdec.psxvideo.mdec.MdecInputStream;
import jpsxdec.util.DemuxedData;
import jpsxdec.util.Fraction;
@@ -69,6 +70,10 @@ public DemuxedDreddFrame(@Nonnull DemuxedData demux, int iHeig
_iHeight = iHeight;
}
+ public @CheckForNull MdecInputStream getCustomFrameMdecStream() {
+ return null;
+ }
+
public int getHeight() {
return _iHeight;
}
diff --git a/jpsxdec/src/jpsxdec/modules/dredd/DiscItemDreddVideoStream.java b/jpsxdec/src/jpsxdec/modules/dredd/DiscItemDreddVideoStream.java
index 5ba2f7f..912c449 100644
--- a/jpsxdec/src/jpsxdec/modules/dredd/DiscItemDreddVideoStream.java
+++ b/jpsxdec/src/jpsxdec/modules/dredd/DiscItemDreddVideoStream.java
@@ -47,6 +47,7 @@
import jpsxdec.discitems.DiscItem;
import jpsxdec.discitems.SerializedDiscItem;
import jpsxdec.i18n.exception.LocalizedDeserializationFail;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.DebugLogger;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.IIdentifiedSector;
@@ -91,6 +92,11 @@ public DiscItemDreddVideoStream(@Nonnull CdFileSectorReader cd, @Nonnull Seriali
return TYPE_ID;
}
+ @Override
+ public boolean hasIndependentBitstream() {
+ return true;
+ }
+
@Override
public int getParentRating(@Nonnull DiscItem child) {
if (!(child instanceof DiscItemXaAudioStream))
@@ -191,7 +197,7 @@ public void setFrameListener(@Nonnull IDemuxedFrame.Listener listener) {
_listener = listener;
}
- public void frameComplete(@Nonnull DemuxedDreddFrame frame, @Nonnull ILocalizedLogger log) {
+ public void frameComplete(@Nonnull DemuxedDreddFrame frame, @Nonnull ILocalizedLogger log) throws LoggedFailure {
FrameNumber fn = _indexSectorFrameNumberFormatter.next(frame.getStartSector(), log);
frame.setFrame(fn);
if (_listener != null)
diff --git a/jpsxdec/src/jpsxdec/modules/dredd/DreddDemuxer.java b/jpsxdec/src/jpsxdec/modules/dredd/DreddDemuxer.java
index 74e4d6a..dba312e 100644
--- a/jpsxdec/src/jpsxdec/modules/dredd/DreddDemuxer.java
+++ b/jpsxdec/src/jpsxdec/modules/dredd/DreddDemuxer.java
@@ -48,6 +48,7 @@
import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor;
import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_STRv2;
import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_STRv3;
+import jpsxdec.psxvideo.bitstreams.StrHeader;
import jpsxdec.psxvideo.mdec.MdecException;
import jpsxdec.util.BinaryDataNotRecognized;
import jpsxdec.util.DemuxedData;
@@ -73,30 +74,30 @@ public class DreddDemuxer {
return null;
// only first chunk can we check for bitstream header
- BitStreamUncompressor.Type bsuType = hasBitstreamHeader(cdSector, 4);
+ StrHeader strHeader = hasBitstreamHeader(cdSector, 4);
int iFirstHeaderSize;
- if (bsuType != null) {
+ if (strHeader != null) {
iFirstHeaderSize = 4;
} else {
- bsuType = hasBitstreamHeader(cdSector, 44);
- if (bsuType != null)
+ strHeader = hasBitstreamHeader(cdSector, 44);
+ if (strHeader != null)
iFirstHeaderSize = 44;
else
return null;
}
- return new DreddDemuxer(bsuType, new SectorDreddVideo(cdSector, iChunk, iFirstHeaderSize));
+ return new DreddDemuxer(strHeader, new SectorDreddVideo(cdSector, iChunk, iFirstHeaderSize));
}
@Nonnull
- private final BitStreamUncompressor.Type _bsuType;
+ private final StrHeader _strHeader;
@Nonnull
private final ArrayList _sectors = new ArrayList(MAX_CHUNKS_PER_FRAME);
- public DreddDemuxer(@Nonnull BitStreamUncompressor.Type bsuType,
+ public DreddDemuxer(@Nonnull StrHeader strHeader,
@Nonnull SectorDreddVideo firstDreddFrameSector)
{
- _bsuType = bsuType;
+ _strHeader = strHeader;
_sectors.add(firstDreddFrameSector);
}
@@ -155,7 +156,7 @@ public FrameSectors(DemuxedDreddFrame frame, List sectors) {
}
byte[] abDemuxBuffer = baos.toByteArray();
- if (!checkHeight(abDemuxBuffer, _bsuType)) {
+ if (!checkHeight(abDemuxBuffer, _strHeader)) {
LOG.log(Level.WARNING, "Possible Dredd frame failed bitstream check starting with sector {0}",
_sectors.get(0));
return null;
@@ -199,26 +200,20 @@ private static boolean commonSectorCheck(@Nonnull CdSector cdSector) {
return true;
}
- /** Returns if this is a v2 or v3 frame. Be sure to keep in sync with
- * {@link jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_STRv2#checkHeader(byte[])}
- * and
- * {@link jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_STRv3#checkHeader(byte[])}.
- */
- private static @CheckForNull BitStreamUncompressor.Type hasBitstreamHeader(@Nonnull CdSector cdSector, int iOfs) {
+ /** Returns if this is a v2 or v3 frame. */
+ private static @CheckForNull StrHeader hasBitstreamHeader(@Nonnull CdSector cdSector, int iOfs) {
if (cdSector.getCdUserDataSize() + iOfs < 8)
return null;
byte[] abHeader = new byte[8];
cdSector.getCdUserDataCopy(iOfs, abHeader, 0, abHeader.length);
- BitStreamUncompressor_STRv2.StrV2Header v2 =
- new BitStreamUncompressor_STRv2.StrV2Header(abHeader, abHeader.length);
+ StrHeader v2 = new BitStreamUncompressor_STRv2.StrV2Header(abHeader, abHeader.length);
if (v2.isValid())
- return BitStreamUncompressor.Type.STRv2;
- BitStreamUncompressor_STRv3.StrV3Header v3 =
- new BitStreamUncompressor_STRv3.StrV3Header(abHeader, abHeader.length);
+ return v2;
+ StrHeader v3 = new BitStreamUncompressor_STRv3.StrV3Header(abHeader, abHeader.length);
if (v3.isValid())
- return BitStreamUncompressor.Type.STRv3;
+ return v3;
return null;
}
@@ -230,10 +225,10 @@ private static boolean commonSectorCheck(@Nonnull CdSector cdSector) {
/** Uncompresses the bitstream by a minium amount to ensure it is valid. */
private static boolean checkHeight(@Nonnull byte[] abFullFrame,
- @Nonnull BitStreamUncompressor.Type bsuType)
+ @Nonnull StrHeader strHeader)
{
try {
- BitStreamUncompressor bsu = bsuType.makeNew(abFullFrame);
+ BitStreamUncompressor bsu = strHeader.makeNew(abFullFrame);
bsu.skipMacroBlocks(FRAME_WIDTH, FRAME_HEIGHT_B);
return true;
} catch (MdecException.EndOfStream ex) {
diff --git a/jpsxdec/src/jpsxdec/modules/dredd/SectorClaimToDreddFrame.java b/jpsxdec/src/jpsxdec/modules/dredd/SectorClaimToDreddFrame.java
index 0e4416b..28f52e2 100644
--- a/jpsxdec/src/jpsxdec/modules/dredd/SectorClaimToDreddFrame.java
+++ b/jpsxdec/src/jpsxdec/modules/dredd/SectorClaimToDreddFrame.java
@@ -45,6 +45,7 @@
import javax.annotation.Nonnull;
import jpsxdec.cdreaders.CdSector;
import jpsxdec.cdreaders.CdSectorXaSubHeader;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.SectorClaimSystem;
import jpsxdec.util.IOIterator;
@@ -55,7 +56,8 @@ public class SectorClaimToDreddFrame extends SectorClaimSystem.SectorClaimer {
private static final Logger LOG = Logger.getLogger(SectorClaimToDreddFrame.class.getName());
public interface Listener {
- void frameComplete(@Nonnull DemuxedDreddFrame frame, @Nonnull ILocalizedLogger log);
+ void frameComplete(@Nonnull DemuxedDreddFrame frame, @Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
void videoBreak(@Nonnull ILocalizedLogger log);
void endOfSectors(@Nonnull ILocalizedLogger log);
}
@@ -118,9 +120,13 @@ public void setListener(@CheckForNull Listener listener) {
public void sectorRead(@Nonnull SectorClaimSystem.ClaimableSector cs,
@Nonnull IOIterator peekIt,
@Nonnull ILocalizedLogger log)
- throws IOException
+ throws IOException, SectorClaimSystem.ClaimerFailure
{
- beforeEofCheck(cs, peekIt, log);
+ try {
+ beforeEofCheck(cs, peekIt, log);
+ } catch (LoggedFailure ex) {
+ throw new SectorClaimSystem.ClaimerFailure(ex);
+ }
// after processing the current sector, always check the EOF flag
// the only way to know a video ends is by the EOF marker
CdSectorXaSubHeader sh = cs.getSector().getSubHeader();
@@ -137,7 +143,7 @@ public void sectorRead(@Nonnull SectorClaimSystem.ClaimableSector cs,
private void beforeEofCheck(@Nonnull SectorClaimSystem.ClaimableSector cs,
@Nonnull IOIterator peekIt,
@Nonnull ILocalizedLogger log)
- throws IOException
+ throws IOException, LoggedFailure
{
// claimed? ignore
if (cs.isClaimed())
diff --git a/jpsxdec/src/jpsxdec/modules/granturismo/GranTurismoDemuxer.java b/jpsxdec/src/jpsxdec/modules/granturismo/GranTurismoDemuxer.java
index 762b173..3563039 100644
--- a/jpsxdec/src/jpsxdec/modules/granturismo/GranTurismoDemuxer.java
+++ b/jpsxdec/src/jpsxdec/modules/granturismo/GranTurismoDemuxer.java
@@ -43,8 +43,8 @@
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import jpsxdec.i18n.log.ILocalizedLogger;
-import jpsxdec.modules.video.sectorbased.ISelfDemuxingVideoSector;
import jpsxdec.modules.video.sectorbased.DemuxedFrameWithNumberAndDims;
+import jpsxdec.modules.video.sectorbased.ISelfDemuxingVideoSector;
import jpsxdec.modules.video.sectorbased.SectorBasedFrameBuilder;
import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_Iki;
import jpsxdec.util.DemuxedData;
diff --git a/jpsxdec/src/jpsxdec/modules/granturismo/SectorGTVideo.java b/jpsxdec/src/jpsxdec/modules/granturismo/SectorGTVideo.java
index 30f48f4..6f9314c 100644
--- a/jpsxdec/src/jpsxdec/modules/granturismo/SectorGTVideo.java
+++ b/jpsxdec/src/jpsxdec/modules/granturismo/SectorGTVideo.java
@@ -90,13 +90,13 @@ public SectorGTVideo(@Nonnull CdSector cdSector) {
if (_header.lngMagic != GT_MAGIC)
return;
- if (!_header.isChunkNumberStandard())
+ if (!_header.hasStandardChunkNumber())
return;
- if (!_header.isChunksInFrameStandard())
+ if (!_header.hasStandardChunksInFrame())
return;
if (_header.iFrameNumber < 1)
return;
- if (!_header.isUsedDemuxSizeStandard())
+ if (!_header.hasStandardUsedDemuxSize())
return;
_iTotalFrames = cdSector.readSInt16LE(16);
if (_iTotalFrames < 1)
diff --git a/jpsxdec/src/jpsxdec/modules/iso9660/DiscItemISO9660File.java b/jpsxdec/src/jpsxdec/modules/iso9660/DiscItemISO9660File.java
index ac43a21..c1e8ab1 100644
--- a/jpsxdec/src/jpsxdec/modules/iso9660/DiscItemISO9660File.java
+++ b/jpsxdec/src/jpsxdec/modules/iso9660/DiscItemISO9660File.java
@@ -76,6 +76,7 @@
import jpsxdec.i18n.exception.LocalizedDeserializationFail;
import jpsxdec.i18n.exception.LocalizedFileNotFoundException;
import jpsxdec.i18n.exception.LoggedFailure;
+import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.i18n.log.ProgressLogger;
import jpsxdec.util.ArgParser;
import jpsxdec.util.IO;
@@ -317,6 +318,7 @@ public void startSave(@Nonnull ProgressLogger pl, @CheckForNull File outputDir)
throws LoggedFailure, TaskCanceledException
{
clearGeneratedFiles();
+ printSelectedOptions(pl);
File outputFile = new File(outputDir, getPath().getPath());
try {
@@ -364,11 +366,11 @@ public void startSave(@Nonnull ProgressLogger pl, @CheckForNull File outputDir)
pl.progressEnd();
}
- public void printSelectedOptions(@Nonnull FeedbackStream fbs) {
+ public void printSelectedOptions(@Nonnull ILocalizedLogger log) {
if (getSaveRaw())
- fbs.println(I.CMD_ISOFILE_SAVING_RAW(getRawSectorSize()));
+ log.log(Level.INFO, I.CMD_ISOFILE_SAVING_RAW(getRawSectorSize()));
else
- fbs.println(I.CMD_ISOFILE_SAVING_2048());
+ log.log(Level.INFO, I.CMD_ISOFILE_SAVING_2048());
}
}
diff --git a/jpsxdec/src/jpsxdec/modules/player/AudioPlayerSectorTimedWriter.java b/jpsxdec/src/jpsxdec/modules/player/AudioPlayerSectorTimedWriter.java
index 1ae5f09..40e8e38 100644
--- a/jpsxdec/src/jpsxdec/modules/player/AudioPlayerSectorTimedWriter.java
+++ b/jpsxdec/src/jpsxdec/modules/player/AudioPlayerSectorTimedWriter.java
@@ -37,49 +37,58 @@
package jpsxdec.modules.player;
+import java.io.IOException;
+import java.io.OutputStream;
import javax.annotation.Nonnull;
-import javax.sound.sampled.AudioFormat;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.sharedaudio.DecodedAudioPacket;
import jpsxdec.modules.video.save.AudioSync;
+import jpsxdec.util.IO;
-/** Receives audio packets and sends them to the inner {@link MediaPlayer}
+/** Receives audio packets and sends them to the inner {@link OutputStream}
* making sure to add silence if there is any gap in the packets.
* This ensures the audio stays in sync with the playback. */
public class AudioPlayerSectorTimedWriter implements DecodedAudioPacket.Listener {
@Nonnull
- private final MediaPlayer _player;
+ private final OutputStream _audioOut;
@Nonnull
private final AudioSync _audioSync;
private long _lngSampleFramesWritten = 0;
- public AudioPlayerSectorTimedWriter(@Nonnull MediaPlayer player, int iMovieStartSector,
- int iSectorsPerSecond, int iSamplesPerSecond)
+ public AudioPlayerSectorTimedWriter(@Nonnull OutputStream audioOutputStream,
+ int iMovieStartSector,
+ int iSectorsPerSecond,
+ int iSamplesPerSecond)
{
- _player = player;
- AudioFormat fmt = _player.getAudioFormat();
- if (fmt == null)
- throw new IllegalArgumentException("Media player without audio passed to AudioPlayerSectorTimedWriter");
+ _audioOut = audioOutputStream;
_audioSync = new AudioSync(iMovieStartSector, iSectorsPerSecond, iSamplesPerSecond);
}
public void audioPacketComplete(@Nonnull DecodedAudioPacket packet, @Nonnull ILocalizedLogger log) {
- // already confirmed that _player has an audio format
- if (!packet.getAudioFormat().matches(_player.getAudioFormat()))
- throw new IllegalArgumentException("Incompatable audio format.");
+ try {
+ long lngSampleFrameDiff = _audioSync.calculateAudioToCatchUp(packet.getPresentationSector(), _lngSampleFramesWritten);
+ if (lngSampleFrameDiff > 0) {
+ System.out.println("Audio out of sync " + lngSampleFrameDiff + " samples, adding silence.");
+ long lngSilentBytes = lngSampleFrameDiff * packet.getAudioFormat().getFrameSize();
+ while (lngSilentBytes > 0) {
+ int iToWrite = (int) Math.min((long)Integer.MAX_VALUE, lngSilentBytes);
+ IO.writeZeros(_audioOut, iToWrite);
+ lngSilentBytes -= iToWrite;
+ }
+ // TODO move this inside the loop in case there is an error it will keep the inner state correct
+ _lngSampleFramesWritten += lngSampleFrameDiff;
+ }
- long lngSampleFrameDiff = _audioSync.calculateAudioToCatchUp(packet.getPresentationSector(), _lngSampleFramesWritten);
- if (lngSampleFrameDiff > 0) {
- System.out.println("Audio out of sync " + lngSampleFrameDiff + " samples, adding silence.");
- _player.writeSilence(lngSampleFrameDiff);
- _lngSampleFramesWritten += lngSampleFrameDiff;
- }
-
- _lngSampleFramesWritten += packet.getSampleFrameCount();
+ _lngSampleFramesWritten += packet.getSampleFrameCount();
- byte[] abData = packet.getData();
- _player.writeAudio(abData, 0, abData.length);
+ byte[] abData = packet.getData();
+ //System.out.println("Sending " + abData.length + " bytes of audio");
+ _audioOut.write(abData);
+ } catch (IOException ex) {
+ // wrap the exception and have the MediaPlayer catch it outside the pipeline
+ throw new WrapIOException(ex);
+ }
}
}
diff --git a/jpsxdec/src/jpsxdec/modules/player/MediaPlayer.java b/jpsxdec/src/jpsxdec/modules/player/MediaPlayer.java
index a7803e9..a3c1516 100644
--- a/jpsxdec/src/jpsxdec/modules/player/MediaPlayer.java
+++ b/jpsxdec/src/jpsxdec/modules/player/MediaPlayer.java
@@ -37,10 +37,7 @@
package jpsxdec.modules.player;
-import java.util.logging.Logger;
-import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
-import javax.sound.sampled.AudioFormat;
import jpsxdec.cdreaders.CdFileSectorReader;
import jpsxdec.i18n.ILocalizedMessage;
import jpsxdec.i18n.exception.LoggedFailure;
@@ -53,40 +50,38 @@
import jpsxdec.modules.video.IDemuxedFrame;
import jpsxdec.modules.video.ISectorClaimToDemuxedFrame;
import jpsxdec.modules.video.framenumber.FormattedFrameNumber;
+import jpsxdec.modules.video.framenumber.FrameNumber;
+import jpsxdec.modules.video.save.AutowireVDP;
+import jpsxdec.modules.video.save.Frame2Bitstream;
import jpsxdec.modules.video.save.VDP;
import jpsxdec.psxvideo.mdec.MdecDecoder;
import jpsxdec.psxvideo.mdec.MdecDecoder_int;
import jpsxdec.psxvideo.mdec.idct.SimpleIDCT;
import jpsxdec.util.Fraction;
-import jpsxdec.util.player.AudioVideoReader;
-import jpsxdec.util.player.IDecodableFrame;
-import jpsxdec.util.player.ObjectPool;
+import jpsxdec.util.player.IFrameProcessor;
+import jpsxdec.util.player.IMediaDataReader;
+import jpsxdec.util.player.IPreprocessedFrameWriter;
+import jpsxdec.util.player.PlayController;
+import jpsxdec.util.player.StopPlayingException;
-/** Holds all the class implementations that the {@link jpsxdec.util.player}
+/** Holds all the class implementations that the {@link jpsxdec.util.player}
* framework needs to playback PlayStation audio and/or video. */
-public class MediaPlayer extends AudioVideoReader implements IDemuxedFrame.Listener {
-
- private static final Logger LOG = Logger.getLogger(MediaPlayer.class.getName());
-
- private static final boolean DEBUG = false;
+public class MediaPlayer implements IMediaDataReader {
private final int _iMovieStartSector;
private final int _iMovieEndSector;
@Nonnull
private final CdFileSectorReader _cdReader;
- private final double _dblDuration;
+
+ @Nonnull
+ private final PlayController _controller;
+
+ private final AutowireVDP _demuxAutowire = new AutowireVDP();
+ private final AutowireVDP _decodeAutowire = new AutowireVDP();
//----------------------------------------------------------
- @CheckForNull
- private final DiscItemVideoStream _vid;
- private int _iSectorsPerSecond;
- @CheckForNull
- private final VDP.Bitstream2Mdec _b2m;
- @CheckForNull
- private final VDP.Mdec2Decoded _m2d;
- @CheckForNull
- private final ISectorClaimToDemuxedFrame _demuxer;
+ private final int _iSectorsPerSecond;
public MediaPlayer(@Nonnull DiscItemVideoStream vid, @Nonnull ISectorClaimToDemuxedFrame demuxer) {
this(vid, demuxer, vid.getStartSector(), vid.getEndSector());
@@ -96,34 +91,11 @@ public MediaPlayer(@Nonnull DiscItemVideoStream vid, @Nonnull ISectorClaimToDemu
public MediaPlayer(@Nonnull DiscItemVideoStream vid, @Nonnull ISectorClaimToDemuxedFrame demuxer,
int iSectorStart, int iSectorEnd)
{
- _cdReader = vid.getSourceCd();
- _iMovieStartSector = iSectorStart;
- _iMovieEndSector = iSectorEnd;
- if (vid.getDiscSpeed() == 1) {
- _iSectorsPerSecond = 75;
- } else {
- // if disc speed is unknown, assume 2x
- _iSectorsPerSecond = 150;
- }
- _dblDuration = vid.getApproxDuration();
-
- _vid = vid;
- _m2d = new VDP.Mdec2Decoded(new MdecDecoder_int(new SimpleIDCT(),
- vid.getWidth(),
- vid.getHeight()),
- DebugLogger.Log);
- _b2m = new VDP.Bitstream2Mdec(_m2d);
- _demuxer = demuxer;
- _demuxer.setFrameListener(this);
+ this(vid, demuxer, null, iSectorStart, iSectorEnd);
}
//-----------------------------------------------------------------------
- @CheckForNull
- private ISectorAudioDecoder _audioDecoder;
- @CheckForNull
- private AudioPlayerSectorTimedWriter _audioOut;
-
public MediaPlayer(@Nonnull DiscItemAudioStream aud) {
_cdReader = aud.getSourceCd();
_iMovieStartSector = aud.getStartSector();
@@ -134,180 +106,159 @@ public MediaPlayer(@Nonnull DiscItemAudioStream aud) {
// if disc speed is unknown, assume 2x
_iSectorsPerSecond = 150;
}
- _dblDuration = aud.getApproxDuration();
+
+ ISectorAudioDecoder audioDecoder = aud.makeDecoder(1.0);
+ _demuxAutowire.setAudioDecoder(audioDecoder);
- _audioDecoder = aud.makeDecoder(1.0);
- _audioOut = new AudioPlayerSectorTimedWriter(this, _iMovieStartSector, _iSectorsPerSecond, _audioDecoder.getSampleFramesPerSecond());
- _audioDecoder.setAudioListener(_audioOut);
+ _controller = new PlayController(audioDecoder.getOutputFormat());
+ _controller.setReader(this);
+ audioDecoder.getAbsolutePresentationStartSector(); // <-- TODO check if it would be better to use this to align on initial presentation sector
- // ignore video
- _vid = null;
- _b2m = null;
- _m2d = null;
- _demuxer = null;
+ AudioPlayerSectorTimedWriter audioWriter = new AudioPlayerSectorTimedWriter(_controller.getAudioOutputStream(), _iMovieStartSector, _iSectorsPerSecond, audioDecoder.getSampleFramesPerSecond());
+ _demuxAutowire.setAudioPacketListener(audioWriter);
}
-
+
//----------------------------------------------------------
- public MediaPlayer(@Nonnull DiscItemVideoStream vid,
+ public MediaPlayer(@Nonnull DiscItemVideoStream vid,
@Nonnull ISectorClaimToDemuxedFrame demuxer,
- @Nonnull ISectorAudioDecoder audio,
+ @Nonnull ISectorAudioDecoder audioDecoder, // tell everyone this can't be null, but secretly allow it
int iSectorStart, int iSectorEnd)
{
// do the video init
- this(vid, demuxer, iSectorStart, iSectorEnd);
-
- if (audio.getDiscSpeed() == 1) {
+ _cdReader = vid.getSourceCd();
+ _iMovieStartSector = iSectorStart;
+ _iMovieEndSector = iSectorEnd;
+ if (vid.getDiscSpeed() == 1) {
_iSectorsPerSecond = 75;
} else {
// if disc speed is unknown, assume 2x
_iSectorsPerSecond = 150;
}
- // manually init the audio
- _audioDecoder = audio;
- _audioOut = new AudioPlayerSectorTimedWriter(this, _iMovieStartSector, _iSectorsPerSecond, _audioDecoder.getSampleFramesPerSecond());
- _audioDecoder.setAudioListener(_audioOut);
- }
+ _demuxAutowire.setMap(demuxer);
- public void demuxThread() {
+ if (audioDecoder == null) {
+ _controller = new PlayController(vid.getWidth(), vid.getHeight());
+ } else {
+ _controller = new PlayController(vid.getWidth(), vid.getHeight(), audioDecoder.getOutputFormat());
+
+ AudioPlayerSectorTimedWriter audioWriter = new AudioPlayerSectorTimedWriter(_controller.getAudioOutputStream(), _iMovieStartSector, _iSectorsPerSecond, audioDecoder.getSampleFramesPerSecond());
+ _demuxAutowire.setAudioDecoder(audioDecoder);
+ _demuxAutowire.setAudioPacketListener(audioWriter);
+ }
+
+ ProcessingThread pt = new ProcessingThread(vid.getWidth(), vid.getHeight());
+ _controller.setVidProcressor(pt);
+ _decodeAutowire.setMap(pt);
+ _decodeAutowire.setDecodedListener(pt);
+ _decodeAutowire.setMap(new VDP.Mdec2Decoded(new MdecDecoder_int(new SimpleIDCT(), vid.getWidth(), vid.getHeight()), DebugLogger.Log));
+ _decodeAutowire.setMap(new VDP.Bitstream2Mdec());
+ _decodeAutowire.autowire();
+
+ vid.getAbsolutePresentationStartSector(); // <-- TODO check if it would be better to align on initial presentation sector
+
+ _demuxAutowire.setFrameListener(new DemuxFrameToPlayerProcessor(_controller.getFrameWriter(), _iMovieStartSector, _iSectorsPerSecond));
+
+ _controller.setReader(this);
+ }
+ public void demuxThread(@Nonnull PlayController controller) throws StopPlayingException {
try {
final int iSectorLength = _iMovieEndSector - _iMovieStartSector + 1;
SectorClaimSystem it = SectorClaimSystem.create(_cdReader, _iMovieStartSector, _iMovieEndSector);
- if (_demuxer != null)
- _demuxer.attachToSectorClaimer(it);
- if (_audioDecoder != null)
- _audioDecoder.attachToSectorClaimer(it);
- for (int iSector = 0; it.hasNext() && stillPlaying(); iSector++)
+ _demuxAutowire.attachToSectorClaimer(it);
+ _demuxAutowire.autowire();
+
+ IIdentifiedSector identifiedSector;
+ for (int iSector = 0; it.hasNext() && !controller.isClosed(); iSector++)
{
- IIdentifiedSector identifiedSector = it.next(DebugLogger.Log).getClaimer();
- setReadProgress(iSector*100 / iSectorLength);
+ identifiedSector = it.next(DebugLogger.Log).getClaimer();
}
-
+ it.close(DebugLogger.Log);
+ } catch (WrapIOException ex) {
+ if (ex.getCause() instanceof StopPlayingException)
+ throw (StopPlayingException)ex.getCause();
+ else
+ throw new StopPlayingException(ex.getCause());
} catch (CdFileSectorReader.CdReadException ex) {
- throw new RuntimeException(ex);
+ throw new StopPlayingException(ex);
}
}
- public void frameComplete(@Nonnull IDemuxedFrame frame) {
- StrFrame strFrame = _framePool.borrow();
- strFrame.init(frame.getDemuxSize(), frame.getFrame().getIndexNumber(), frame.getPresentationSector().subtract(_iMovieStartSector).asInt());
- strFrame.__abDemuxBuf = frame.copyDemuxData();
- writeFrame(strFrame);
- }
-
- // #########################################################################
- // #########################################################################
-
- public @CheckForNull AudioFormat getAudioFormat() {
- if (_audioDecoder == null)
- return null;
- return _audioDecoder.getOutputFormat();
+ public @Nonnull PlayController getPlayController() {
+ return _controller;
}
+ private static class DemuxFrameToPlayerProcessor implements IDemuxedFrame.Listener {
+ @Nonnull
+ private final IPreprocessedFrameWriter _processor;
+ private final int _iAbsolutePresentationStartSector;
+ private final int _iSectorsPerSecond;
- // #########################################################################
- // #########################################################################
-
- private class DecodableFramePool extends ObjectPool {
-
- @Override
- protected StrFrame createNewObject() {
- if (DEBUG) System.err.println("Creating new pool object.");
- return new StrFrame();
+ public DemuxFrameToPlayerProcessor(@Nonnull IPreprocessedFrameWriter processor,
+ int iAbsolutePresentationStartSector,
+ int iSectorsPerSecond)
+ {
+ _processor = processor;
+ _iAbsolutePresentationStartSector = iAbsolutePresentationStartSector;
+ _iSectorsPerSecond = iSectorsPerSecond;
}
- }
- private final DecodableFramePool _framePool = new DecodableFramePool();
-
-
- public boolean hasVideo() {
- return _vid != null;
- }
+ @Override
+ public void frameComplete(@Nonnull IDemuxedFrame frame) {
- public int getVideoWidth() {
- if (_vid == null)
- throw new UnsupportedOperationException("Accessing video dimension for audio only player");
- return _vid.getWidth();
+ long lngPresentationNanos = (long) ((frame.getPresentationSector().asDouble() - _iAbsolutePresentationStartSector) / _iSectorsPerSecond * 1000000000.);
+ try {
+ _processor.writeFrame(frame, lngPresentationNanos);
+ } catch (StopPlayingException ex) {
+ throw new WrapIOException(ex);
+ }
+ }
}
- public int getVideoHeight() {
- if (_vid == null)
- throw new UnsupportedOperationException("Accessing video dimension for audio only player");
- return _vid.getHeight();
- }
- public double getDuration() {
- return _dblDuration;
- }
+ private static class ProcessingThread extends Frame2Bitstream implements IFrameProcessor, VDP.IDecodedListener {
- private class StrFrame implements IDecodableFrame, VDP.IDecodedListener {
+ private final int _iWidth, _iHeight;
- @CheckForNull
- public byte[] __abDemuxBuf;
- @CheckForNull
- private FormattedFrameNumber __frameNum;
- private int __iSectorFromStart;
- @CheckForNull
- private int[] __aiDrawHere;
-
- public void init(int iSize, @Nonnull FormattedFrameNumber frameNum, int iSectorFromStart) {
- __iSectorFromStart = iSectorFromStart;
- __frameNum = frameNum;
- }
+ private int[] _aiDrawHere;
- public long getPresentationTime() {
- return (__iSectorFromStart * 1000000000L / _iSectorsPerSecond);
+ public ProcessingThread(int iWidth, int iHeight) {
+ super(FrameNumber.Type.Index);
+ _iWidth = iWidth;
+ _iHeight = iHeight;
}
- public void decodeVideo(@Nonnull int[] drawHere) {
- // _md2 and _b2m should != null when processing frames
- // if not, bad stuff should happen
- _m2d.setDecoded(this);
- __aiDrawHere = drawHere;
+ @Override
+ public void processFrame(@Nonnull IDemuxedFrame frame, int[] drawHere) {
+ // ideally we would have a buffer in this class where the decoded frame is written, then copy that into drawHere
+ // but we don't want an extra copy, so use this workaround
+ _aiDrawHere = drawHere;
try {
- // This will call _m2d which in turn will call decoded()
- // __abDemuxBuf and __frameNum should have been initialied in init()
- // The presentation sector is passed here, but it is not used directly,
- // instead we use getPresentationTime()
- _b2m.bitstream(__abDemuxBuf, __abDemuxBuf.length, __frameNum, new Fraction(__iSectorFromStart));
+ frameComplete(frame);
} catch (LoggedFailure ex) {
- System.err.print("Frame "+__frameNum+' '+ex.getMessage());
- if (ex.getCause() != null && ex.getCause().getMessage() != null)
- System.err.println(": " + ex.getCause().getMessage());
- else
- System.err.println();
+ System.err.println("Frame "+frame.getFrame()+" "+ex.getMessage());
} finally {
- _m2d.setDecoded(null);
- __aiDrawHere = null;
+ _aiDrawHere = null;
}
}
- public void assertAcceptsDecoded(@Nonnull MdecDecoder decoder) {}
-
- public void decoded(@Nonnull MdecDecoder decoder,
- @Nonnull FormattedFrameNumber frameNumber,
- @Nonnull Fraction presentationSector_unused)
- {
- decoder.readDecodedRgb(getVideoWidth(), getVideoHeight(), __aiDrawHere);
+ @Override
+ public void decoded(@Nonnull MdecDecoder decoder, FormattedFrameNumber _ignoredFN, Fraction _ignoredPS) {
+ decoder.readDecodedRgb(_iWidth, _iHeight, _aiDrawHere);
}
- public void error(@Nonnull ILocalizedMessage errMsg,
- @Nonnull FormattedFrameNumber frameNumber,
- @Nonnull Fraction presentationSector_unused)
- {
+ @Override
+ public void error(ILocalizedMessage errMsg, FormattedFrameNumber frameNumber, Fraction presentationSector) {
System.err.println(errMsg.getEnglishMessage());
}
- public void returnToPool() {
- if (DEBUG) System.err.println("Returning object to pool.");
- _framePool.giveBack(this);
- }
-
+ @Override
+ public void assertAcceptsDecoded(MdecDecoder decoder) {}
}
}
diff --git a/jpsxdec/src/jpsxdec/modules/player/WrapIOException.java b/jpsxdec/src/jpsxdec/modules/player/WrapIOException.java
new file mode 100644
index 0000000..d4dbc07
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/player/WrapIOException.java
@@ -0,0 +1,54 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.player;
+
+import java.io.IOException;
+
+/** Catches an {@link IOException} and wraps it in a {@link RuntimeException}
+ * to be thrown later. */
+class WrapIOException extends RuntimeException {
+
+ public WrapIOException(IOException cause) {
+ super(cause);
+ }
+
+ @Override
+ public IOException getCause() {
+ return (IOException) super.getCause();
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/modules/policenauts/DemuxPolicenautsFrame.java b/jpsxdec/src/jpsxdec/modules/policenauts/DemuxPolicenautsFrame.java
new file mode 100644
index 0000000..b529349
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/policenauts/DemuxPolicenautsFrame.java
@@ -0,0 +1,116 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.policenauts;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import jpsxdec.cdreaders.CdFileSectorReader;
+import jpsxdec.i18n.exception.LoggedFailure;
+import jpsxdec.i18n.log.ILocalizedLogger;
+import jpsxdec.modules.video.IDemuxedFrame;
+import jpsxdec.modules.video.framenumber.FrameNumber;
+import jpsxdec.psxvideo.mdec.MdecInputStream;
+import jpsxdec.util.Fraction;
+
+
+public class DemuxPolicenautsFrame implements IDemuxedFrame {
+ private final int _iWidth, _iHeight;
+ private final SPacketData _data;
+ @Nonnull
+ private final FrameNumber _frameNumber;
+ @Nonnull
+ private final Fraction _presentationSector;
+
+ public DemuxPolicenautsFrame(int iWidth, int iHeight,
+ @Nonnull SPacketData data,
+ @Nonnull FrameNumber frameNumber,
+ @Nonnull Fraction presentationSector)
+ {
+ _iWidth = iWidth;
+ _iHeight = iHeight;
+ _data = data;
+ _frameNumber = frameNumber;
+ _presentationSector = presentationSector;
+ }
+
+ public int getWidth() {
+ return _iWidth;
+ }
+
+ public int getHeight() {
+ return _iHeight;
+ }
+
+ public @Nonnull FrameNumber getFrame() {
+ return _frameNumber;
+ }
+
+ public int getStartSector() {
+ return _data.getStartSector();
+ }
+
+ public int getEndSector() {
+ return _data.getEndSector();
+ }
+
+ public @Nonnull Fraction getPresentationSector() {
+ return _presentationSector;
+ }
+
+ public @CheckForNull MdecInputStream getCustomFrameMdecStream() {
+ return null;
+ }
+
+ public int getDemuxSize() {
+ return _data.getData().length;
+ }
+
+ public @Nonnull byte[] copyDemuxData() {
+ return Arrays.copyOfRange(_data.getData(), 0, getDemuxSize());
+ }
+
+ public void printSectors(PrintStream ps) {
+ // TODO?
+ }
+
+ public void writeToSectors(byte[] abNewDemux, int iNewUsedSize, int iNewMdecCodeCount, CdFileSectorReader cd, ILocalizedLogger log) throws LoggedFailure {
+ throw new UnsupportedOperationException("Replacing Policenauts frames is not supported");
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/modules/policenauts/DiscIndexerPolicenauts.java b/jpsxdec/src/jpsxdec/modules/policenauts/DiscIndexerPolicenauts.java
new file mode 100644
index 0000000..97c9ea3
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/policenauts/DiscIndexerPolicenauts.java
@@ -0,0 +1,165 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.policenauts;
+
+import java.util.Collection;
+import java.util.logging.Level;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import jpsxdec.discitems.DiscItem;
+import jpsxdec.discitems.SerializedDiscItem;
+import jpsxdec.i18n.I;
+import jpsxdec.i18n.exception.LocalizedDeserializationFail;
+import jpsxdec.i18n.log.ILocalizedLogger;
+import jpsxdec.indexing.DiscIndex;
+import jpsxdec.indexing.DiscIndexer;
+import jpsxdec.modules.SectorClaimSystem;
+import jpsxdec.modules.video.Dimensions;
+import jpsxdec.modules.video.framenumber.HeaderFrameNumber;
+import jpsxdec.modules.video.framenumber.IndexSectorFrameNumber;
+
+
+public class DiscIndexerPolicenauts extends DiscIndexer implements SectorClaimToPolicenauts.Listener {
+
+ @Override
+ public void attachToSectorClaimer(@Nonnull SectorClaimSystem scs) {
+ SectorClaimToPolicenauts sc = scs.getClaimer(SectorClaimToPolicenauts.class);
+ sc.setListener(this);
+ }
+
+ @Override
+ public @CheckForNull DiscItem deserializeLineRead(@Nonnull SerializedDiscItem fields) throws LocalizedDeserializationFail {
+ if (DiscItemPolicenauts.TYPE_ID.equals(fields.getType()))
+ return new DiscItemPolicenauts(getCd(), fields);
+ return null;
+ }
+
+ private class VidBuilder {
+ @Nonnull
+ private final Dimensions __dims;
+ private final int __iStartKlbsStartSector;
+ private int __iLastKlbsEndSector;
+ @CheckForNull
+ private IndexSectorFrameNumber.Format.Builder __indexSectorFrameNumberBuilder;
+ @CheckForNull
+ private HeaderFrameNumber.Format.Builder __headerFrameNumberBuilder;
+ private int __iSoundUnitCount = 0;
+
+ public VidBuilder(@Nonnull SPacketData firstPacket, Dimensions dims) {
+ __dims = dims;
+ __iStartKlbsStartSector = firstPacket.getKlbsStartSectorNum();
+ __iLastKlbsEndSector = firstPacket.getKlbsEndSectorNum();
+ addPacket(firstPacket);
+ }
+
+ final public void addPacket(@Nonnull SPacketData packet) {
+ __iLastKlbsEndSector = packet.getKlbsEndSectorNum();
+
+ if (packet.isAudio()) {
+ __iSoundUnitCount += packet.getSoundUnitCount();
+ } else if (packet.isVideo()) {
+ if (__headerFrameNumberBuilder == null)
+ __headerFrameNumberBuilder = new HeaderFrameNumber.Format.Builder(packet.getTimestamp());
+ else
+ __headerFrameNumberBuilder.addHeaderFrameNumber(packet.getTimestamp());
+
+ if (__indexSectorFrameNumberBuilder == null)
+ __indexSectorFrameNumberBuilder = new IndexSectorFrameNumber.Format.Builder(packet.getStartSector());
+ else
+ __indexSectorFrameNumberBuilder.addFrameStartSector(packet.getStartSector());
+ }
+ }
+
+ public void finishVid(ILocalizedLogger log) {
+ if (__indexSectorFrameNumberBuilder == null) {
+ log.log(Level.WARNING, I.POLICENAUTS_DATA_CORRUPTION());
+ return;
+ }
+ DiscItemPolicenauts di = new DiscItemPolicenauts(getCd(),
+ __iStartKlbsStartSector, __iLastKlbsEndSector, __dims,
+ __indexSectorFrameNumberBuilder.makeFormat(),
+ __headerFrameNumberBuilder.makeFormat(),
+ __iSoundUnitCount);
+ addDiscItem(di);
+ }
+ }
+
+ @CheckForNull
+ private VidBuilder _currentVid;
+ @CheckForNull
+ private Dimensions _dims;
+
+ @Override
+ public void videoStart(int iWidth, int iHeight, @Nonnull ILocalizedLogger log) {
+ if (_currentVid != null) {
+ _currentVid.finishVid(log);
+ _currentVid = null;
+ }
+ _dims = new Dimensions(iWidth, iHeight);
+ }
+
+ @Override
+ public void feedPacket(@Nonnull SPacketData packet, @Nonnull ILocalizedLogger log) {
+ if (_dims == null) {
+ log.log(Level.WARNING, I.POLICENAUTS_DATA_CORRUPTION());
+ return;
+ }
+ if (_currentVid == null)
+ _currentVid = new VidBuilder(packet, _dims);
+ else
+ _currentVid.addPacket(packet);
+ }
+
+ @Override
+ public void endOfSectors(@Nonnull ILocalizedLogger log) {
+ if (_currentVid != null) {
+ _currentVid.finishVid(log);
+ _currentVid = null;
+ _dims = null;
+ }
+ }
+
+ @Override
+ public void listPostProcessing(@Nonnull Collection allItems) {
+ }
+
+ @Override
+ public void indexGenerated(@Nonnull DiscIndex index) {
+ }
+
+}
diff --git a/jpsxdec/src/jpsxdec/modules/policenauts/DiscItemPolicenauts.java b/jpsxdec/src/jpsxdec/modules/policenauts/DiscItemPolicenauts.java
new file mode 100644
index 0000000..6cc006c
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/policenauts/DiscItemPolicenauts.java
@@ -0,0 +1,260 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.policenauts;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.sound.sampled.AudioFormat;
+import jpsxdec.adpcm.SpuAdpcmDecoder;
+import jpsxdec.cdreaders.CdFileSectorReader;
+import jpsxdec.discitems.SerializedDiscItem;
+import jpsxdec.i18n.exception.LocalizedDeserializationFail;
+import jpsxdec.i18n.exception.LoggedFailure;
+import jpsxdec.i18n.log.ILocalizedLogger;
+import jpsxdec.modules.SectorClaimSystem;
+import jpsxdec.modules.sharedaudio.DecodedAudioPacket;
+import jpsxdec.modules.video.Dimensions;
+import jpsxdec.modules.video.IDemuxedFrame;
+import jpsxdec.modules.video.framenumber.FrameNumber;
+import jpsxdec.modules.video.framenumber.HeaderFrameNumber;
+import jpsxdec.modules.video.framenumber.IFrameNumberFormatterWithHeader;
+import jpsxdec.modules.video.framenumber.IndexSectorFrameNumber;
+import jpsxdec.modules.video.packetbased.DiscItemPacketBasedVideoStream;
+import jpsxdec.modules.video.packetbased.SectorClaimToAudioAndFrame;
+import jpsxdec.util.Fraction;
+
+public class DiscItemPolicenauts extends DiscItemPacketBasedVideoStream {
+
+ public static final String TYPE_ID = "Policenauts";
+
+ @Nonnull
+ private final HeaderFrameNumber.Format _timestampFrameNumberFormat;
+
+ public DiscItemPolicenauts(@Nonnull CdFileSectorReader cd,
+ int iStartSector, int iEndSector,
+ @Nonnull Dimensions dim,
+ @Nonnull IndexSectorFrameNumber.Format sectorIndexFrameNumberFormat,
+ @Nonnull HeaderFrameNumber.Format timestampFrameNumberFormat,
+ int iSoundUnitCount)
+ {
+ super(cd, iStartSector, iEndSector, dim, sectorIndexFrameNumberFormat, iSoundUnitCount);
+ _timestampFrameNumberFormat = timestampFrameNumberFormat;
+ }
+
+ public DiscItemPolicenauts(@Nonnull CdFileSectorReader cd, @Nonnull SerializedDiscItem fields)
+ throws LocalizedDeserializationFail
+ {
+ super(cd, fields);
+ _timestampFrameNumberFormat = new HeaderFrameNumber.Format(fields);
+ }
+
+ @Override
+ public @Nonnull SerializedDiscItem serialize() {
+ SerializedDiscItem serial = super.serialize();
+ _timestampFrameNumberFormat.serialize(serial);
+ return serial;
+ }
+
+ @Override
+ public @Nonnull String getSerializationTypeId() {
+ return TYPE_ID;
+ }
+
+ @Override
+ public boolean hasIndependentBitstream() {
+ return false;
+ }
+
+ @Override
+ public @Nonnull FrameNumber getStartFrame() {
+ return _timestampFrameNumberFormat.getStartFrame(_indexSectorFrameNumberFormat);
+ }
+
+ @Override
+ public FrameNumber getEndFrame() {
+ return _timestampFrameNumberFormat.getEndFrame(_indexSectorFrameNumberFormat);
+ }
+
+ @Override
+ public @Nonnull List getFrameNumberTypes() {
+ return Arrays.asList(FrameNumber.Type.Index, FrameNumber.Type.Header, FrameNumber.Type.Sector);
+ }
+
+ @Override
+ protected double getPacketBasedFpsInterestingDescription() {
+ return SPacket.FRAMES_PER_SECOND.asDouble();
+ }
+
+ @Override
+ public @Nonnull Fraction getSectorsPerFrame() {
+ return SPacket.SECTORS150_PER_FRAME;
+ }
+
+ @Override
+ public double getApproxDuration() {
+ return getFrameCount() / SPacket.FRAMES_PER_SECOND.asDouble();
+ }
+
+ @Override
+ public int getAudioSampleFramesPerSecond() {
+ return SPacket.AUDIO_SAMPLE_FRAMES_PER_SECOND;
+ }
+
+ @Override
+ public @Nonnull SectorClaimToAudioAndFrame makeAudioVideoDemuxer(double dblVolume) {
+ return new Demuxer(getWidth(), getHeight(), getStartSector(), dblVolume,
+ _timestampFrameNumberFormat.makeFormatter(_indexSectorFrameNumberFormat));
+ }
+
+ public class Demuxer extends SectorClaimToAudioAndFrame
+ implements SectorClaimToPolicenauts.Listener
+ {
+ private final int _iWidth, _iHeight;
+ @Nonnull
+ private final IFrameNumberFormatterWithHeader _fnf;
+ private final int _iStartSector;
+
+ @CheckForNull
+ private IDemuxedFrame.Listener _frameListener;
+ @CheckForNull
+ private DecodedAudioPacket.Listener _audioListener;
+
+ @Nonnull
+ private final SpuAdpcmDecoder.Mono _audioDecoder;
+ private Fraction _zeroTimestampOffset = Fraction.ZERO;
+ private boolean _blnPrevTimestampWas0 = false;
+ private int _iPrevDuration = 0;
+
+ private final ByteArrayOutputStream _pcmOut = new ByteArrayOutputStream();
+
+ public Demuxer(int iWidth, int iHeight, int iStartSector, double dblVolume,
+ @Nonnull IFrameNumberFormatterWithHeader fnf)
+ {
+ _iWidth = iWidth;
+ _iHeight = iHeight;
+ _iStartSector = iStartSector;
+ _audioDecoder = new SpuAdpcmDecoder.Mono(dblVolume);
+ _fnf = fnf;
+ }
+
+ public void attachToSectorClaimer(@Nonnull SectorClaimSystem scs) {
+ SectorClaimToPolicenauts s2cs = scs.getClaimer(SectorClaimToPolicenauts.class);
+ s2cs.setListener(this);
+ s2cs.setRangeLimit(getStartSector(), getEndSector());
+ }
+
+ public void videoStart(int iWidth, int iHeight, ILocalizedLogger log) {
+ // not important here
+ }
+
+ @Override
+ public void feedPacket(@Nonnull SPacketData packet, @Nonnull ILocalizedLogger log) throws LoggedFailure {
+
+ if (packet.isAudio()) {
+ if (_audioListener != null) {
+ _pcmOut.reset();
+ // The audio timestamp is a pain
+ // The first 3 audio packets all start at 0 and are 156 long
+ // after that, the numbers add up correctly
+ if (_blnPrevTimestampWas0 && packet.getTimestamp() == 0) {
+ _zeroTimestampOffset = _zeroTimestampOffset.add(SPacket.SECTORS150_PER_TIMESTAMP.multiply(_iPrevDuration));
+ }
+ //System.out.println(_zeroTimestampOffset + " -------- " + packet);
+ Fraction close = SPacket.SECTORS150_PER_TIMESTAMP.multiply(packet.getTimestamp()).add(_iStartSector).add(_zeroTimestampOffset);
+ _blnPrevTimestampWas0 = packet.getTimestamp() == 0;
+ _iPrevDuration = packet.getDuration();
+ packet.decodeAudio(_audioDecoder, _pcmOut);
+ DecodedAudioPacket aup = new DecodedAudioPacket(0, SPacket.AUDIO_FORMAT, close, _pcmOut.toByteArray());
+ _audioListener.audioPacketComplete(aup, log);
+ }
+ } else if (packet.isVideo()) {
+ FrameNumber fn = _fnf.next(packet.getStartSector(), packet.getTimestamp(), log);
+ if (_frameListener != null) {
+ _frameListener.frameComplete(new DemuxPolicenautsFrame(_iWidth, _iHeight, packet, fn,
+ SPacket.SECTORS150_PER_TIMESTAMP.multiply(packet.getTimestamp()).add(_iStartSector)));
+ }
+ }
+ }
+
+ public void endOfSectors(ILocalizedLogger log) {
+ // not important here
+ }
+
+ public void setFrameListener(@CheckForNull IDemuxedFrame.Listener listener) {
+ _frameListener = listener;
+ }
+
+ public void setAudioListener(@Nonnull DecodedAudioPacket.Listener listener) {
+ _audioListener = listener;
+ }
+
+ public @Nonnull AudioFormat getOutputFormat() {
+ return SPacket.AUDIO_FORMAT;
+ }
+
+ public double getVolume() {
+ return _audioDecoder.getVolume();
+ }
+
+ public int getAbsolutePresentationStartSector() {
+ return DiscItemPolicenauts.this.getStartSector();
+ }
+
+ public int getStartSector() {
+ return DiscItemPolicenauts.this.getStartSector();
+ }
+
+ public int getEndSector() {
+ return DiscItemPolicenauts.this.getEndSector();
+ }
+
+ public int getSampleFramesPerSecond() {
+ return SPacket.AUDIO_SAMPLE_FRAMES_PER_SECOND;
+ }
+
+ public int getDiscSpeed() {
+ return 2;
+ }
+
+ }
+
+
+}
diff --git a/jpsxdec/src/jpsxdec/modules/policenauts/KlbsStreamReader.java b/jpsxdec/src/jpsxdec/modules/policenauts/KlbsStreamReader.java
new file mode 100644
index 0000000..44dfef2
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/policenauts/KlbsStreamReader.java
@@ -0,0 +1,149 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.policenauts;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.Nonnull;
+import jpsxdec.util.BinaryDataNotRecognized;
+import jpsxdec.util.DemuxPushInputStream;
+import jpsxdec.util.IO;
+
+
+public class KlbsStreamReader {
+
+ private static final int READ_HEADER = 1;
+ private static final int READ_PACKET = 2;
+ private static final int DONE = 3;
+
+ private final int _iEntryCount;
+ private final int _iKlbsStartSector;
+ private final int _iKlbsEndSectorInclusive;
+
+ @Nonnull
+ private final DemuxPushInputStream _sectorStream;
+
+ private List _sPackets;
+ private int _iNextRequiredBytes = 0;
+ private int _iState = READ_HEADER;
+ private int _iPacketDataRead = 0;
+
+ public KlbsStreamReader(@Nonnull SectorPN_KLBS klbsSector) {
+ _iEntryCount = klbsSector.getEntryCount();
+ _iKlbsStartSector = klbsSector.getSectorNumber();
+ _iKlbsEndSectorInclusive = klbsSector.getEndSectorInclusive();
+
+ _sectorStream = new DemuxPushInputStream(klbsSector);
+
+ try {
+ IO.skip(_sectorStream, SectorPN_KLBS.SIZEOF_KLBS_HEADER);
+ } catch (IOException ex) {
+ throw new RuntimeException("Should not happen", ex);
+ }
+
+ _iNextRequiredBytes = _iEntryCount * SPacket.SIZEOF;
+ }
+
+ public void addSector(@Nonnull SectorPolicenauts sector) {
+ _sectorStream.addPiece(sector);
+ }
+
+ public boolean allRead() {
+ return _iState == DONE;
+ }
+
+ public @Nonnull List readAllAvailablePackets() throws BinaryDataNotRecognized {
+ try {
+ return doReadAllAvailablePackets();
+ } catch (IOException ex) {
+ throw new RuntimeException("Should not happen", ex);
+ }
+ }
+
+ private @Nonnull List doReadAllAvailablePackets() throws BinaryDataNotRecognized, IOException {
+
+ List finishedPackets = null;
+
+ while (_sectorStream.available() >= _iNextRequiredBytes && _iState != DONE) {
+ switch (_iState) {
+ case READ_HEADER:
+ _sPackets = SPacketPos.readPackets(_sectorStream, _iEntryCount, _iKlbsStartSector, _iKlbsEndSectorInclusive);
+ _iNextRequiredBytes = _sPackets.get(0).getSize();
+ _iState = READ_PACKET;
+ break;
+
+ case READ_PACKET:
+ SPacketPos packetPos = _sPackets.get(_iPacketDataRead);
+ skipZeroes(packetPos.getPaddingBeforeThisPacket());
+
+ _sectorStream.mark(packetPos.getSize());
+ SPacketData packetData = packetPos.read(_sectorStream);
+ if (finishedPackets == null)
+ finishedPackets = new ArrayList(3);
+ finishedPackets.add(packetData);
+
+ _iPacketDataRead++;
+ if (_iPacketDataRead >= _sPackets.size()) {
+ _iState = DONE;
+ } else {
+ SPacketPos nextPacket = _sPackets.get(_iPacketDataRead);
+ _iNextRequiredBytes = nextPacket.getPaddingBeforeThisPacket() + nextPacket.getSize();
+ }
+ break;
+ }
+ }
+
+ if (finishedPackets == null)
+ finishedPackets = Collections.emptyList();
+ return finishedPackets;
+ }
+
+ private void skipZeroes(int iCount) throws IOException, BinaryDataNotRecognized {
+ while (iCount > 0) {
+ int iPos = _sectorStream.getOffsetInCurrentPiece();
+ int iByte = _sectorStream.read();
+ if (iByte != 0) {
+ throw new BinaryDataNotRecognized("Expected 0 at " + iPos + " in sector " + _sectorStream.getCurrentPiece() +" but got " + iByte);
+ }
+ iCount--;
+ }
+ }
+
+}
diff --git a/jpsxdec/src/jpsxdec/modules/policenauts/SPacket.java b/jpsxdec/src/jpsxdec/modules/policenauts/SPacket.java
new file mode 100644
index 0000000..e7c62e3
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/policenauts/SPacket.java
@@ -0,0 +1,166 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.policenauts;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.sound.sampled.AudioFormat;
+import jpsxdec.adpcm.SoundUnitDecoder;
+import jpsxdec.adpcm.SpuAdpcmSoundUnit;
+import jpsxdec.util.BinaryDataNotRecognized;
+import jpsxdec.util.Fraction;
+import jpsxdec.util.IO;
+import jpsxdec.util.Misc;
+
+/** Policenauts FMVs consist of several packets of data.
+ * All the packets have a type identifier, and all the identifiers start with
+ * the letter 'S'. */
+public class SPacket {
+
+ public static final int AUDIO_SAMPLE_FRAMES_PER_SECOND = 44100; // confirmed
+ public static final AudioFormat AUDIO_FORMAT = new AudioFormat(AUDIO_SAMPLE_FRAMES_PER_SECOND, 16, 1, true, false);
+ public static final Fraction AUDIO_SAMPLE_FRAMES_PER_TIMESTAMP =
+ new Fraction(16384 / SpuAdpcmSoundUnit.SIZEOF_SOUND_UNIT * SoundUnitDecoder.SAMPLES_PER_SOUND_UNIT, 156);
+ public static final Fraction TIMESTAMP_UNITS_PER_SECOND = Fraction.divide(AUDIO_SAMPLE_FRAMES_PER_SECOND, AUDIO_SAMPLE_FRAMES_PER_TIMESTAMP);
+ public static final Fraction SECONDS_PER_TIMESTAMP = Fraction.divide(1, TIMESTAMP_UNITS_PER_SECOND);
+
+ public static final int TIMESTAMP_UNITS_PER_FRAME = 20;
+ public static final Fraction FRAMES_PER_SECOND = TIMESTAMP_UNITS_PER_SECOND.divide(TIMESTAMP_UNITS_PER_FRAME);
+
+ public static final Fraction SECTORS150_PER_FRAME = Fraction.divide(150, FRAMES_PER_SECOND);
+ public static final Fraction SECTORS150_PER_TIMESTAMP = SECONDS_PER_TIMESTAMP.multiply(150);
+
+ public enum Type {
+ /** SPU ADPCM. */
+ SDNSSDTS("SDNSSDTS (audio)"),
+ /** Frame bitstream. */
+ SCIPPDTS("SCIPPDTS (video)"),
+ SDNSHDTS,
+ SCTELLEC,
+ SCTEGOLD,
+ SCTEGLEC,
+ SCTEMLEC;
+
+ @CheckForNull
+ private final String _sToString;
+
+ private Type() { _sToString = null; }
+ private Type(String sToString) { _sToString = sToString; }
+
+ @Override
+ public String toString() {
+ return _sToString == null ? super.toString() : _sToString;
+ }
+ }
+
+ public static final int SIZEOF = 48;
+
+ // Zeroes // 8 bytes @ 0
+ @Nonnull
+ private final Type _type; // 8 bytes @ 8
+ private final int _iTimestamp; // 4 bytes @ 16
+ private final int _iDuration; // 4 bytes @ 20
+ private final int _iOffset; // 4 bytes @ 24
+ private final int _iSize; // 4 bytes @ 28
+ // Zeroes // 16 bytes @ 32
+
+ public SPacket(@Nonnull InputStream is) throws EOFException, IOException, BinaryDataNotRecognized {
+
+ long lng8Zeroes = IO.readSInt64BE(is);
+ if (lng8Zeroes != 0)
+ throw new BinaryDataNotRecognized();
+
+ byte[] abTag = new byte[8];
+ IO.readByteArray(is, abTag);
+ try {
+ _type = Type.valueOf(Misc.asciiToString(abTag));
+ } catch (IllegalArgumentException ex) {
+ throw new BinaryDataNotRecognized(ex);
+ }
+ _iTimestamp = IO.readSInt32LE(is);
+ if (_iTimestamp < 0 || _iTimestamp > 63780)
+ throw new BinaryDataNotRecognized();
+ _iDuration = IO.readSInt32LE(is);
+ if (_iDuration < 0 || _iDuration > 156)
+ throw new BinaryDataNotRecognized();
+ _iOffset = IO.readSInt32LE(is);
+ if (_iOffset < 1)
+ throw new BinaryDataNotRecognized();
+ _iSize = IO.readSInt32LE(is);
+ if (_iSize < 5 || _iSize > 17000)
+ throw new BinaryDataNotRecognized();
+ lng8Zeroes = IO.readSInt64BE(is);
+ if (lng8Zeroes != 0)
+ throw new BinaryDataNotRecognized();
+ lng8Zeroes = IO.readSInt64BE(is);
+ if (lng8Zeroes != 0)
+ throw new BinaryDataNotRecognized();
+
+ if (_type == Type.SDNSSDTS && !(_iSize % SpuAdpcmSoundUnit.SIZEOF_SOUND_UNIT == 0))
+ throw new BinaryDataNotRecognized();
+ }
+
+ public @Nonnull Type getType() {
+ return _type;
+ }
+
+ public int getTimestamp() {
+ return _iTimestamp;
+ }
+
+ public int getDuration() {
+ return _iDuration;
+ }
+
+ public int getOffset() {
+ return _iOffset;
+ }
+
+ public int getSize() {
+ return _iSize;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s Time:%d Duration:%d Offset:%d Size:%d",
+ _type, _iTimestamp, _iDuration, _iOffset, _iSize);
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/modules/policenauts/SPacketData.java b/jpsxdec/src/jpsxdec/modules/policenauts/SPacketData.java
new file mode 100644
index 0000000..db94afd
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/policenauts/SPacketData.java
@@ -0,0 +1,113 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.policenauts;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import javax.annotation.Nonnull;
+import jpsxdec.adpcm.SpuAdpcmDecoder;
+import jpsxdec.adpcm.SpuAdpcmSoundUnit;
+
+
+public class SPacketData {
+
+ @Nonnull
+ private final SPacketPos _sPacketPos;
+ @Nonnull
+ private final byte[] _abData;
+
+ public SPacketData(@Nonnull SPacketPos sPacketPos, @Nonnull byte[] abData) {
+ _sPacketPos = sPacketPos;
+ _abData = abData;
+ }
+
+ public boolean isAudio() {
+ return _sPacketPos.isAudio();
+ }
+
+ public boolean isVideo() {
+ return _sPacketPos.isVideo();
+ }
+
+ public @Nonnull byte[] getData() {
+ return _abData;
+ }
+
+ public int getSoundUnitCount() {
+ return _abData.length / SpuAdpcmSoundUnit.SIZEOF_SOUND_UNIT;
+ }
+
+ public void decodeAudio(@Nonnull SpuAdpcmDecoder.Mono decoder, @Nonnull OutputStream pcmOut) {
+ ByteArrayInputStream spuIn = new ByteArrayInputStream(_abData);
+ try {
+ decoder.decode(spuIn, getSoundUnitCount(), pcmOut);
+ } catch (IOException ex) {
+ throw new RuntimeException("Should not happen", ex);
+ }
+ }
+
+ public int getKlbsStartSectorNum() {
+ return _sPacketPos.getKlbsStartSectorNum();
+ }
+
+ public int getKlbsEndSectorNum() {
+ return _sPacketPos.getKlbsEndSectorNum();
+ }
+
+ public int getStartSector() {
+ return _sPacketPos.getStartSector();
+ }
+
+ public int getEndSector() {
+ return _sPacketPos.getEndSector();
+ }
+
+ public int getTimestamp() {
+ return _sPacketPos.getTimestamp();
+ }
+
+ public int getDuration() {
+ return _sPacketPos.getDuration();
+ }
+
+ @Override
+ public String toString() {
+ return _sPacketPos.toString();
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/modules/policenauts/SPacketPos.java b/jpsxdec/src/jpsxdec/modules/policenauts/SPacketPos.java
new file mode 100644
index 0000000..102bf71
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/policenauts/SPacketPos.java
@@ -0,0 +1,195 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.policenauts;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.annotation.Nonnull;
+import jpsxdec.adpcm.SpuAdpcmSoundUnit;
+import jpsxdec.cdreaders.CdSector;
+import jpsxdec.util.BinaryDataNotRecognized;
+import jpsxdec.util.IO;
+
+/** Wraps a {@link SPacket} with information about its position of the data
+ * on the disk. */
+public class SPacketPos {
+
+ private static final Logger LOG = Logger.getLogger(SPacketPos.class.getName());
+
+
+ public static @Nonnull List readPackets(@Nonnull InputStream is, int iEntryCount,
+ int iKlbsStartSector, int iKlbsEndSectorInclusive)
+ throws IOException, BinaryDataNotRecognized
+ {
+ ArrayList _sPackets = new ArrayList();
+ for (int i = 0; i < iEntryCount; i++) {
+ SPacket packet = new SPacket(is);
+
+ SPacketPos packetPos = new SPacketPos(packet, iKlbsStartSector, iKlbsEndSectorInclusive, i);
+ if (i > 0) {
+ SPacketPos prev = _sPackets.get(i - 1);
+ prev.checkAgainstNextPacket(packetPos);
+ }
+ _sPackets.add(packetPos);
+ }
+ return _sPackets;
+ }
+
+
+ @Nonnull
+ private final SPacket _sPacket;
+
+ private final int _iKlbsStartSectorNum;
+ private final int _iKlbsEndSectorNumInclusive;
+ private final int _iIndexInKlbs;
+ private final int _iStartSector;
+ private final int _iStartOfs;
+
+ /** 1 FMV has an incorrect size, so we'll correct it later. */
+ private int _iCorrectedSize;
+
+ private int _iPaddingBeforeThisPacket = 0;
+ private int _iPaddingAfterThisPacket = 0;
+
+ public SPacketPos(@Nonnull SPacket sPacket, int iKlbsStartSectorNum, int iKlbsEndSectorNumInclusive, int iIndexInKlbs) {
+ _sPacket = sPacket;
+ _iKlbsStartSectorNum = iKlbsStartSectorNum;
+ _iKlbsEndSectorNumInclusive = iKlbsEndSectorNumInclusive;
+ _iIndexInKlbs = iIndexInKlbs;
+ _iStartSector = iKlbsStartSectorNum + (sPacket.getOffset() / CdSector.SECTOR_SIZE_2048_ISO);
+ _iStartOfs = sPacket.getOffset() % CdSector.SECTOR_SIZE_2048_ISO;
+
+ _iCorrectedSize = sPacket.getSize();
+ }
+
+ public int getSize() {
+ return _iCorrectedSize;
+ }
+
+ public int getPaddingBeforeThisPacket() {
+ return _iPaddingBeforeThisPacket;
+ }
+
+ public int getTimestamp() {
+ return _sPacket.getTimestamp();
+ }
+
+ public int getDuration() {
+ return _sPacket.getDuration();
+ }
+
+ public boolean isVideo() {
+ return _sPacket.getType() == SPacket.Type.SCIPPDTS;
+ }
+
+ public boolean isAudio() {
+ return _sPacket.getType() == SPacket.Type.SDNSSDTS;
+ }
+
+ public int getKlbsStartSectorNum() {
+ return _iKlbsStartSectorNum;
+ }
+
+ public int getKlbsEndSectorNum() {
+ return _iKlbsEndSectorNumInclusive;
+ }
+
+ public void checkAgainstNextPacket(@Nonnull SPacketPos nextPacket) throws BinaryDataNotRecognized {
+ if (nextPacket.getPacket().getOffset() < _sPacket.getOffset())
+ throw new BinaryDataNotRecognized();
+
+ // Some timestamps can be a little before the next one
+ if (nextPacket.getPacket().getTimestamp() < _sPacket.getTimestamp()) {
+ LOG.log(Level.INFO, "{0} < {1}", new Object[]{nextPacket, _sPacket});
+ if (nextPacket.getPacket().getTimestamp() + 15 < _sPacket.getTimestamp()) {
+ throw new BinaryDataNotRecognized("Next packet timestamp " + nextPacket.getPacket().getTimestamp() +
+ " < current packet timestamp " + _sPacket.getTimestamp());
+ }
+ }
+
+ int iBytesBetweenPacketStarts = nextPacket._sPacket.getOffset() - _sPacket.getOffset();
+ if (_sPacket.getSize() > iBytesBetweenPacketStarts) {
+ LOG.log(Level.WARNING, "{0} packet size exceeds room {1,number,#} (expected for MV000003.MOV on disc 2)",
+ new Object[]{this, iBytesBetweenPacketStarts});
+ if (isAudio() && !(iBytesBetweenPacketStarts % SpuAdpcmSoundUnit.SIZEOF_SOUND_UNIT == 0))
+ throw new BinaryDataNotRecognized();
+ _iCorrectedSize = iBytesBetweenPacketStarts;
+ }
+ _iPaddingAfterThisPacket = iBytesBetweenPacketStarts - _iCorrectedSize;
+ nextPacket._iPaddingBeforeThisPacket = _iPaddingAfterThisPacket;
+ }
+
+ /** Reads the packet data and returns a {@link SPacketData}. */
+ public @Nonnull SPacketData read(@Nonnull InputStream is) throws EOFException, IOException {
+ byte[] abData = IO.readByteArray(is, _iCorrectedSize);
+ return new SPacketData(this, abData);
+ }
+
+ public int getStartSector() {
+ return _iStartSector;
+ }
+
+ public int getEndSector() {
+ return _iStartSector + (_sPacket.getOffset() + _iCorrectedSize) / CdSector.SECTOR_SIZE_2048_ISO;
+ }
+
+ /** The packet data is padded to a 4 byte boundary, so there is often
+ * a few bytes between packets */
+ public int bytesToThisPacket(int iFromSector, int iFromOffset) {
+ int iSectorDiff = _iStartSector - iFromSector;
+ int iOfsDiff = _iStartOfs - iFromOffset;
+ int i = iSectorDiff * CdSector.SECTOR_SIZE_2048_ISO + iOfsDiff;
+ return i;
+ }
+
+ public @Nonnull SPacket getPacket() {
+ return _sPacket;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("Start %d [%d] sector.ofs %d.%d %s",
+ _iKlbsStartSectorNum, _iIndexInKlbs, _iStartSector, _iStartOfs, _sPacket);
+ }
+
+}
\ No newline at end of file
diff --git a/jpsxdec/src/jpsxdec/modules/policenauts/SectorClaimToPolicenauts.java b/jpsxdec/src/jpsxdec/modules/policenauts/SectorClaimToPolicenauts.java
new file mode 100644
index 0000000..ca8dbb9
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/policenauts/SectorClaimToPolicenauts.java
@@ -0,0 +1,186 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.policenauts;
+
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import jpsxdec.cdreaders.CdSector;
+import jpsxdec.i18n.I;
+import jpsxdec.i18n.exception.LoggedFailure;
+import jpsxdec.i18n.log.ILocalizedLogger;
+import jpsxdec.modules.SectorClaimSystem;
+import jpsxdec.util.BinaryDataNotRecognized;
+import jpsxdec.util.IOIterator;
+
+
+public class SectorClaimToPolicenauts extends SectorClaimSystem.SectorClaimer {
+
+ private static final Logger LOG = Logger.getLogger(SectorClaimToPolicenauts.class.getName());
+
+ public interface Listener {
+ void videoStart(int iWidth, int iHeight, @Nonnull ILocalizedLogger log);
+ void feedPacket(@Nonnull SPacketData packet, @Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
+ public void endOfSectors(@Nonnull ILocalizedLogger log);
+ }
+
+
+ private static class KlbsSectorRange {
+ /** Stream to read the packet data in this KLBS set of sectors.
+ * Once all are read, the stream ends, but we want to stick around to
+ * collect any more sectors in this KLBS. */
+ @CheckForNull
+ private KlbsStreamReader _stream;
+ private final int _iKlbsEndSectorInclusive;
+ private SectorPN_KLBS _klbsSector;
+ private boolean _blnAtEnd = false;
+
+ public KlbsSectorRange(@Nonnull SectorPN_KLBS klbsSector) {
+ _klbsSector = klbsSector;
+ _stream = new KlbsStreamReader(klbsSector);
+ _iKlbsEndSectorInclusive = klbsSector.getEndSectorInclusive();
+ }
+
+ public @Nonnull SectorPN_KLBS start(@Nonnull ILocalizedLogger log) {
+ SectorPN_KLBS klbsSector = _klbsSector;
+ _klbsSector = null; // free up the KLBS sector memory and underlying buffer
+ doRead(klbsSector, log);
+ return klbsSector;
+ }
+
+ public @Nonnull SectorPolicenauts addSector(@Nonnull CdSector cdSector, @Nonnull ILocalizedLogger log) {
+ _blnAtEnd = cdSector.getSectorIndexFromStart() >= _iKlbsEndSectorInclusive;
+ SectorPolicenauts pnSector = new SectorPolicenauts(cdSector, _blnAtEnd);
+ if (_stream != null) {
+ _stream.addSector(pnSector);
+ doRead(pnSector, log);
+ }
+ return pnSector;
+ }
+
+ public boolean atEnd() {
+ return _blnAtEnd;
+ }
+
+ private void doRead(SectorPolicenauts pnSector, @Nonnull ILocalizedLogger log) {
+ try {
+ List finishedPackets = _stream.readAllAvailablePackets();
+ if (_stream.allRead())
+ _stream = null;
+ pnSector.setPacketsEndingInThisSector(finishedPackets);
+ } catch (BinaryDataNotRecognized ex) {
+ log.log(Level.SEVERE, I.POLICENAUTS_DATA_CORRUPTION(), ex);
+ _stream = null;
+ }
+ }
+ }
+
+
+ @CheckForNull
+ private Listener _listener;
+ @CheckForNull
+ private KlbsSectorRange _currentKlbs;
+
+
+ public void setListener(@CheckForNull Listener listener) {
+ _listener = listener;
+ }
+
+ @Override
+ public void sectorRead(@Nonnull SectorClaimSystem.ClaimableSector cs,
+ @Nonnull IOIterator peekIt,
+ @Nonnull ILocalizedLogger log)
+ throws SectorClaimSystem.ClaimerFailure
+ {
+ if (cs.isClaimed()) {
+ checkCorruptionIfExistingKlbs(log);
+ return;
+ }
+
+ SectorPN_VMNK vmnkSector = new SectorPN_VMNK(cs.getSector());
+ if (vmnkSector.getProbability() == 100) {
+ checkCorruptionIfExistingKlbs(log);
+ cs.claim(vmnkSector);
+ if (_listener != null)
+ _listener.videoStart(vmnkSector.getWidth(), vmnkSector.getHeight(), log);
+ } else {
+ SectorPolicenauts pnSector = null;
+ SectorPN_KLBS klbsSector = new SectorPN_KLBS(cs.getSector());
+ if (klbsSector.getProbability() == 100) {
+ checkCorruptionIfExistingKlbs(log);
+ _currentKlbs = new KlbsSectorRange(klbsSector);
+ klbsSector = _currentKlbs.start(log);
+ cs.claim(klbsSector);
+ pnSector = klbsSector;
+ } else if (_currentKlbs != null) {
+ pnSector = _currentKlbs.addSector(cs.getSector(), log);
+ cs.claim(pnSector);
+ if (_currentKlbs.atEnd())
+ _currentKlbs = null;
+ }
+
+ if (_listener != null && pnSector != null) {
+ for (SPacketData sPacketData : pnSector) {
+ try {
+ _listener.feedPacket(sPacketData, log);
+ } catch (LoggedFailure ex) {
+ throw new SectorClaimSystem.ClaimerFailure(ex);
+ }
+ }
+ }
+ }
+ }
+
+ /** There should not already be an existing KLBS block we are tracking. */
+ private void checkCorruptionIfExistingKlbs(@Nonnull ILocalizedLogger log) {
+ if (_currentKlbs != null) {
+ log.log(Level.WARNING, I.POLICENAUTS_DATA_CORRUPTION());
+ _currentKlbs = null;
+ }
+ }
+
+ @Override
+ public void endOfSectors(@Nonnull ILocalizedLogger log) {
+ if (_listener != null)
+ _listener.endOfSectors(log);
+ }
+
+}
diff --git a/jpsxdec/src/jpsxdec/modules/policenauts/SectorPN_KLBS.java b/jpsxdec/src/jpsxdec/modules/policenauts/SectorPN_KLBS.java
new file mode 100644
index 0000000..c2e1a7b
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/policenauts/SectorPN_KLBS.java
@@ -0,0 +1,103 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.policenauts;
+
+import javax.annotation.Nonnull;
+import jpsxdec.cdreaders.CdSector;
+import jpsxdec.util.Misc;
+
+public class SectorPN_KLBS extends SectorPolicenauts {
+
+ public static final int SIZEOF_KLBS_HEADER = 32;
+ public static final int KLBS_SECTOR_COUNT = 128;
+
+ // Zeroes // 8 bytes @0
+ // "KLBS" // 4 bytes @8
+ private int _iSize; // 4 bytes @12 always = 262144 = 128 * 2048
+ private int _iEntryCount; // 4 bytes @16
+ // Entry count again // 4 bytes @20
+ // Zeroes // 8 bytes @24
+
+ public SectorPN_KLBS(@Nonnull CdSector cdSector) {
+ super(cdSector, false);
+ if (isSuperInvalidElseReset()) return;
+
+ for (int i = 0; i < 8; i++) {
+ if (cdSector.readUserDataByte(i) != 0) return;
+ }
+
+ byte[] abKlbs = new byte[4];
+ cdSector.getCdUserDataCopy(8, abKlbs, 0, 4);
+ String sKlbs = Misc.asciiToString(abKlbs);
+ if (!"KLBS".equals(sKlbs)) return;
+
+ _iSize = cdSector.readSInt32LE(12);
+ if (_iSize != KLBS_SECTOR_COUNT * CdSector.SECTOR_SIZE_2048_ISO /*262144*/) return;
+ _iEntryCount = cdSector.readSInt32LE(16);
+ if (_iEntryCount < 1 || _iEntryCount > 83) return;
+ int iEntryCount2 = cdSector.readSInt32LE(20);
+ if (iEntryCount2 != _iEntryCount) return;
+ for (int i = 24; i < SIZEOF_KLBS_HEADER; i++) {
+ if (cdSector.readUserDataByte(i) != 0) return;
+ }
+
+ setProbability(100);
+ }
+
+ public int getSectorLength() {
+ return KLBS_SECTOR_COUNT;
+ }
+
+ public int getEndSectorInclusive() {
+ return getSectorNumber() + KLBS_SECTOR_COUNT - 1;
+ }
+
+ public int getEntryCount() {
+ return _iEntryCount;
+ }
+
+ @Override
+ public String getTypeName() {
+ return "Policenauts KLBS";
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s %s size:%d entries:%d", getTypeName(), super.toString(), _iSize, _iEntryCount);
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/modules/policenauts/SectorPN_VMNK.java b/jpsxdec/src/jpsxdec/modules/policenauts/SectorPN_VMNK.java
new file mode 100644
index 0000000..1003135
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/policenauts/SectorPN_VMNK.java
@@ -0,0 +1,104 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.policenauts;
+
+import javax.annotation.Nonnull;
+import jpsxdec.cdreaders.CdSector;
+import jpsxdec.modules.IdentifiedSector;
+
+public class SectorPN_VMNK extends IdentifiedSector {
+
+ public static final int WIDTH = 288;
+ public static final int HEIGHT = 144;
+
+ // I don't know what these mean
+ private static final byte[] VMNK_HEADER = {
+ 'V', 'M', 'N', 'K',
+ (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0xF0, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x00,
+ (byte)0x10, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x10, (byte)0x00, (byte)0x00, (byte)0x00
+ };
+
+ private int _iWidth;
+ private int _iHeight;
+
+ public SectorPN_VMNK(@Nonnull CdSector cdSector) {
+ super(cdSector);
+ if (isSuperInvalidElseReset()) return;
+
+ for (int i = 0; i < VMNK_HEADER.length; i++) {
+ if (cdSector.readUserDataByte(i) != VMNK_HEADER[i])
+ return;
+ }
+
+ _iWidth = cdSector.readSInt32LE(28);
+ if (_iWidth != WIDTH)
+ return;
+ _iHeight = cdSector.readSInt32LE(32);
+ if (_iHeight != HEIGHT)
+ return;
+
+ for (int i = VMNK_HEADER.length + 8; i < cdSector.getCdUserDataSize(); i++) {
+ if (cdSector.readUserDataByte(i) != 0)
+ return;
+ }
+
+ setProbability(100);
+ }
+
+ public @Nonnull String getTypeName() {
+ return "Policenauts VMNK";
+ }
+
+ public int getWidth() {
+ return _iWidth;
+ }
+
+ public int getHeight() {
+ return _iHeight;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s %s %dx%d", getTypeName(), super.toString(), _iWidth, _iHeight);
+ }
+
+}
diff --git a/jpsxdec/src/jpsxdec/modules/policenauts/SectorPolicenauts.java b/jpsxdec/src/jpsxdec/modules/policenauts/SectorPolicenauts.java
new file mode 100644
index 0000000..d5ab3f9
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/policenauts/SectorPolicenauts.java
@@ -0,0 +1,108 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.policenauts;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import javax.annotation.Nonnull;
+import jpsxdec.cdreaders.CdSector;
+import jpsxdec.modules.IdentifiedSector;
+import jpsxdec.util.DemuxedData;
+
+/** Just a simple sector wrapper for Policenauts to claim sectors. */
+public class SectorPolicenauts extends IdentifiedSector implements Iterable, DemuxedData.Piece {
+
+ private boolean _blnIsEnd;
+
+ @Nonnull
+ private List _packetsEndingInThisSector = Collections.emptyList();
+
+ public SectorPolicenauts(@Nonnull CdSector cdSector, boolean blnIsEnd) {
+ super(cdSector);
+ if (isSuperInvalidElseReset()) return;
+ _blnIsEnd = blnIsEnd;
+ setProbability(100);
+ }
+
+ @Override
+ public String getTypeName() {
+ return "Policenauts";
+ }
+
+ void setPacketsEndingInThisSector(@Nonnull List packetsEndingInThisSector) {
+ _packetsEndingInThisSector = packetsEndingInThisSector;
+ }
+
+ @Override
+ public int getDemuxPieceSize() {
+ return getCdSector().getCdUserDataSize();
+ }
+
+ @Override
+ public byte getDemuxPieceByte(int i) {
+ return getCdSector().readUserDataByte(i);
+ }
+
+ @Override
+ public void copyDemuxPieceData(@Nonnull byte[] abOut, int iOutPos) {
+ getCdSector().getCdUserDataCopy(0, abOut, iOutPos, getDemuxPieceSize());
+ }
+
+ @Override
+ public @Nonnull Iterator iterator() {
+ return _packetsEndingInThisSector.iterator();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getTypeName()).append(' ')
+ .append(super.toString()).append(' ')
+ .append(_packetsEndingInThisSector.size()).append(" finished packets [");
+ for (int i = 0; i < _packetsEndingInThisSector.size(); i++) {
+ if (i > 0)
+ sb.append(", ");
+ sb.append(_packetsEndingInThisSector.get(i));
+ }
+ sb.append(']');
+ if (_blnIsEnd)
+ sb.append(" END");
+ return sb.toString();
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/modules/roadrash/BitStreamUncompressorRoadRash.java b/jpsxdec/src/jpsxdec/modules/roadrash/BitStreamUncompressorRoadRash.java
new file mode 100644
index 0000000..697afea
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/roadrash/BitStreamUncompressorRoadRash.java
@@ -0,0 +1,319 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.roadrash;
+
+import javax.annotation.Nonnull;
+import jpsxdec.psxvideo.bitstreams.ArrayBitReader;
+import jpsxdec.psxvideo.bitstreams.BitStreamCode;
+import jpsxdec.psxvideo.bitstreams.BitStreamCompressor;
+import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor;
+import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_STRv2;
+import jpsxdec.psxvideo.bitstreams.ZeroRunLengthAcLookup;
+
+public class BitStreamUncompressorRoadRash extends BitStreamUncompressor {
+
+ private final int _iQuantizationScale;
+
+ public BitStreamUncompressorRoadRash(@Nonnull byte[] abMdecPacketPayload,
+ @Nonnull ZeroRunLengthAcLookup lookupTable,
+ int iQuantizationScale)
+ {
+ super(
+ new ArrayBitReader(abMdecPacketPayload, abMdecPacketPayload.length, true),
+ lookupTable,
+ new BitStreamUncompressor_STRv2.QuantizationDc_STRv12(iQuantizationScale),
+ BitStreamUncompressor_STRv2.AC_ESCAPE_CODE_STR,
+ BitStreamUncompressor.FRAME_END_PADDING_BITS_NONE
+ );
+ _iQuantizationScale = iQuantizationScale;
+ }
+
+ @Override
+ public @Nonnull BitStreamCompressor makeCompressor() {
+ // Writing a Road Rashvideo encoder would be a significant amount of work.
+ // And that might be ok, except to properly replace Road Rash videos would
+ // require re-building all of the packets from start to finish.
+ // That is beyond the scope jPSXdec's functionality. Modders will have
+ // to handle that part on their own.
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + " qscale:" + _iQuantizationScale;
+ }
+
+ /**
+ * This MDEC code has special mean, it is treated as the escape code.
+ */
+ static final int BITSTREAM_ESCAPE_CODE = 0x7c1f;
+
+ /** The VLC0 packet contains a list of MDEC codes that are mapped to bit-codes in this order. */
+ static final BitStreamCode[] ROAD_RASH_BIT_CODE_ORDER = {
+ BitStreamCode._10_______________,
+ BitStreamCode._110______________,
+ BitStreamCode._111______________,
+ BitStreamCode._0110_____________,
+ BitStreamCode._0111_____________,
+ BitStreamCode._01000____________,
+ BitStreamCode._01001____________,
+ BitStreamCode._01010____________,
+ BitStreamCode._01011____________,
+ BitStreamCode._001010___________,
+ BitStreamCode._001011___________,
+ BitStreamCode._001110___________,
+ BitStreamCode._001111___________,
+ BitStreamCode._001100___________,
+ BitStreamCode._001101___________,
+ BitStreamCode._0001100__________,
+ BitStreamCode._0001101__________,
+ BitStreamCode._0001110__________,
+ BitStreamCode._0001111__________,
+ BitStreamCode._0001010__________,
+ BitStreamCode._0001011__________,
+ BitStreamCode._0001000__________,
+ BitStreamCode._0001001__________,
+ BitStreamCode._000001___________,
+ BitStreamCode._00001100_________,
+ BitStreamCode._00001101_________,
+ BitStreamCode._00001000_________,
+ BitStreamCode._00001001_________,
+ BitStreamCode._00001110_________,
+ BitStreamCode._00001111_________,
+ BitStreamCode._00001010_________,
+ BitStreamCode._00001011_________,
+ BitStreamCode._001001100________,
+ BitStreamCode._001001101________,
+ BitStreamCode._001000010________,
+ BitStreamCode._001000011________,
+ BitStreamCode._001001010________,
+ BitStreamCode._001001011________,
+ BitStreamCode._001001000________,
+ BitStreamCode._001001001________,
+ BitStreamCode._001001110________,
+ BitStreamCode._001001111________,
+ BitStreamCode._001000110________,
+ BitStreamCode._001000111________,
+ BitStreamCode._001000100________,
+ BitStreamCode._001000101________,
+ BitStreamCode._001000000________,
+ BitStreamCode._001000001________,
+ BitStreamCode._00000010100______,
+ BitStreamCode._00000010101______,
+ BitStreamCode._00000011000______,
+ BitStreamCode._00000011001______,
+ BitStreamCode._00000010110______,
+ BitStreamCode._00000010111______,
+ BitStreamCode._00000011110______,
+ BitStreamCode._00000011111______,
+ BitStreamCode._00000010010______,
+ BitStreamCode._00000010011______,
+ BitStreamCode._00000011100______,
+ BitStreamCode._00000011101______,
+ BitStreamCode._00000011010______,
+ BitStreamCode._00000011011______,
+ BitStreamCode._00000010000______,
+ BitStreamCode._00000010001______,
+ BitStreamCode._0000000111010____,
+ BitStreamCode._0000000111011____,
+ BitStreamCode._0000000110000____,
+ BitStreamCode._0000000110001____,
+ BitStreamCode._0000000100110____,
+ BitStreamCode._0000000100111____,
+ BitStreamCode._0000000100000____,
+ BitStreamCode._0000000100001____,
+ BitStreamCode._0000000110110____,
+ BitStreamCode._0000000110111____,
+ BitStreamCode._0000000101000____,
+ BitStreamCode._0000000101001____,
+ BitStreamCode._0000000111000____,
+ BitStreamCode._0000000111001____,
+ BitStreamCode._0000000100100____,
+ BitStreamCode._0000000100101____,
+ BitStreamCode._0000000111100____,
+ BitStreamCode._0000000111101____,
+ BitStreamCode._0000000101010____,
+ BitStreamCode._0000000101011____,
+ BitStreamCode._0000000100010____,
+ BitStreamCode._0000000100011____,
+ BitStreamCode._0000000111110____,
+ BitStreamCode._0000000111111____,
+ BitStreamCode._0000000110100____,
+ BitStreamCode._0000000110101____,
+ BitStreamCode._0000000110010____,
+ BitStreamCode._0000000110011____,
+ BitStreamCode._0000000101110____,
+ BitStreamCode._0000000101111____,
+ BitStreamCode._0000000101100____,
+ BitStreamCode._0000000101101____,
+ BitStreamCode._00000000110100___,
+ BitStreamCode._00000000110101___,
+ BitStreamCode._00000000110010___,
+ BitStreamCode._00000000110011___,
+ BitStreamCode._00000000110000___,
+ BitStreamCode._00000000110001___,
+ BitStreamCode._00000000101110___,
+ BitStreamCode._00000000101111___,
+ BitStreamCode._00000000101100___,
+ BitStreamCode._00000000101101___,
+ BitStreamCode._00000000101010___,
+ BitStreamCode._00000000101011___,
+ BitStreamCode._00000000101000___,
+ BitStreamCode._00000000101001___,
+ BitStreamCode._00000000100110___,
+ BitStreamCode._00000000100111___,
+ BitStreamCode._00000000100100___,
+ BitStreamCode._00000000100101___,
+ BitStreamCode._00000000100010___,
+ BitStreamCode._00000000100011___,
+ BitStreamCode._00000000100000___,
+ BitStreamCode._00000000100001___,
+ BitStreamCode._00000000111110___,
+ BitStreamCode._00000000111111___,
+ BitStreamCode._00000000111100___,
+ BitStreamCode._00000000111101___,
+ BitStreamCode._00000000111010___,
+ BitStreamCode._00000000111011___,
+ BitStreamCode._00000000111000___,
+ BitStreamCode._00000000111001___,
+ BitStreamCode._00000000110110___,
+ BitStreamCode._00000000110111___,
+ BitStreamCode._000000000111110__,
+ BitStreamCode._000000000111111__,
+ BitStreamCode._000000000111100__,
+ BitStreamCode._000000000111101__,
+ BitStreamCode._000000000111010__,
+ BitStreamCode._000000000111011__,
+ BitStreamCode._000000000111000__,
+ BitStreamCode._000000000111001__,
+ BitStreamCode._000000000110110__,
+ BitStreamCode._000000000110111__,
+ BitStreamCode._000000000110100__,
+ BitStreamCode._000000000110101__,
+ BitStreamCode._000000000110010__,
+ BitStreamCode._000000000110011__,
+ BitStreamCode._000000000110000__,
+ BitStreamCode._000000000110001__,
+ BitStreamCode._000000000101110__,
+ BitStreamCode._000000000101111__,
+ BitStreamCode._000000000101100__,
+ BitStreamCode._000000000101101__,
+ BitStreamCode._000000000101010__,
+ BitStreamCode._000000000101011__,
+ BitStreamCode._000000000101000__,
+ BitStreamCode._000000000101001__,
+ BitStreamCode._000000000100110__,
+ BitStreamCode._000000000100111__,
+ BitStreamCode._000000000100100__,
+ BitStreamCode._000000000100101__,
+ BitStreamCode._000000000100010__,
+ BitStreamCode._000000000100011__,
+ BitStreamCode._000000000100000__,
+ BitStreamCode._000000000100001__,
+ BitStreamCode._0000000000110000_,
+ BitStreamCode._0000000000110001_,
+ BitStreamCode._0000000000101110_,
+ BitStreamCode._0000000000101111_,
+ BitStreamCode._0000000000101100_,
+ BitStreamCode._0000000000101101_,
+ BitStreamCode._0000000000101010_,
+ BitStreamCode._0000000000101011_,
+ BitStreamCode._0000000000101000_,
+ BitStreamCode._0000000000101001_,
+ BitStreamCode._0000000000100110_,
+ BitStreamCode._0000000000100111_,
+ BitStreamCode._0000000000100100_,
+ BitStreamCode._0000000000100101_,
+ BitStreamCode._0000000000100010_,
+ BitStreamCode._0000000000100011_,
+ BitStreamCode._0000000000100000_,
+ BitStreamCode._0000000000100001_,
+ BitStreamCode._0000000000111110_,
+ BitStreamCode._0000000000111111_,
+ BitStreamCode._0000000000111100_,
+ BitStreamCode._0000000000111101_,
+ BitStreamCode._0000000000111010_,
+ BitStreamCode._0000000000111011_,
+ BitStreamCode._0000000000111000_,
+ BitStreamCode._0000000000111001_,
+ BitStreamCode._0000000000110110_,
+ BitStreamCode._0000000000110111_,
+ BitStreamCode._0000000000110100_,
+ BitStreamCode._0000000000110101_,
+ BitStreamCode._0000000000110010_,
+ BitStreamCode._0000000000110011_,
+ BitStreamCode._00000000000100110,
+ BitStreamCode._00000000000100111,
+ BitStreamCode._00000000000100100,
+ BitStreamCode._00000000000100101,
+ BitStreamCode._00000000000100010,
+ BitStreamCode._00000000000100011,
+ BitStreamCode._00000000000100000,
+ BitStreamCode._00000000000100001,
+ BitStreamCode._00000000000101000,
+ BitStreamCode._00000000000101001,
+ BitStreamCode._00000000000110100,
+ BitStreamCode._00000000000110101,
+ BitStreamCode._00000000000110010,
+ BitStreamCode._00000000000110011,
+ BitStreamCode._00000000000110000,
+ BitStreamCode._00000000000110001,
+ BitStreamCode._00000000000101110,
+ BitStreamCode._00000000000101111,
+ BitStreamCode._00000000000101100,
+ BitStreamCode._00000000000101101,
+ BitStreamCode._00000000000101010,
+ BitStreamCode._00000000000101011,
+ BitStreamCode._00000000000111110,
+ BitStreamCode._00000000000111111,
+ BitStreamCode._00000000000111100,
+ BitStreamCode._00000000000111101,
+ BitStreamCode._00000000000111010,
+ BitStreamCode._00000000000111011,
+ BitStreamCode._00000000000111000,
+ BitStreamCode._00000000000111001,
+ BitStreamCode._00000000000110110,
+ BitStreamCode._00000000000110111,
+ };
+
+ static {
+ if (ROAD_RASH_BIT_CODE_ORDER.length != BitStreamCode.getTotalCount())
+ throw new AssertionError("Road Rash VLC code count is wrong");
+ }
+
+}
diff --git a/jpsxdec/src/jpsxdec/modules/roadrash/DemuxedRoadRashFrame.java b/jpsxdec/src/jpsxdec/modules/roadrash/DemuxedRoadRashFrame.java
new file mode 100644
index 0000000..7cbd694
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/roadrash/DemuxedRoadRashFrame.java
@@ -0,0 +1,124 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.roadrash;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+import javax.annotation.Nonnull;
+import jpsxdec.cdreaders.CdFileSectorReader;
+import jpsxdec.i18n.exception.LoggedFailure;
+import jpsxdec.i18n.log.ILocalizedLogger;
+import jpsxdec.modules.video.IDemuxedFrame;
+import jpsxdec.modules.video.framenumber.FrameNumber;
+import jpsxdec.psxvideo.mdec.MdecInputStream;
+import jpsxdec.util.Fraction;
+
+
+public class DemuxedRoadRashFrame implements IDemuxedFrame {
+
+ @Nonnull
+ private final RoadRashPacketSectors _sectors;
+ @Nonnull
+ private final RoadRashPacket.MDEC _mdecPacket;
+ @Nonnull
+ private final RoadRashPacket.VLC0 _vlc;
+ @Nonnull
+ private final FrameNumber _frameNumber;
+ @Nonnull
+ private final Fraction _presentationSector;
+
+ public DemuxedRoadRashFrame(@Nonnull RoadRashPacketSectors sectors,
+ @Nonnull RoadRashPacket.MDEC mdecPacket,
+ @Nonnull RoadRashPacket.VLC0 vlc,
+ @Nonnull FrameNumber frameNumber,
+ @Nonnull Fraction presentationSector)
+ {
+ _sectors = sectors;
+ _mdecPacket = mdecPacket;
+ _vlc = vlc;
+ _frameNumber = frameNumber;
+ _presentationSector = presentationSector;
+ }
+
+
+ public int getWidth() {
+ return _mdecPacket.getWidth();
+ }
+
+ public int getHeight() {
+ return _mdecPacket.getHeight();
+ }
+
+ public @Nonnull MdecInputStream getCustomFrameMdecStream() {
+ return _vlc.makeFrameBitStreamUncompressor(_mdecPacket);
+ }
+
+ public @Nonnull FrameNumber getFrame() {
+ return _frameNumber;
+ }
+
+ public int getStartSector() {
+ return _sectors.iStartSector;
+ }
+
+ public int getEndSector() {
+ return _sectors.iEndSector;
+ }
+
+ public @Nonnull Fraction getPresentationSector() {
+ return _presentationSector;
+ }
+
+ public int getDemuxSize() {
+ return _mdecPacket.getPayload().length;
+ }
+
+ /** Not really useful, but why not. */
+ public @Nonnull byte[] copyDemuxData() {
+ return Arrays.copyOfRange(_mdecPacket.getPayload(), 0, getDemuxSize());
+ }
+
+ public void printSectors(PrintStream ps) {
+ // TODO?
+ }
+
+ public void writeToSectors(byte[] abNewDemux, int iNewUsedSize, int iNewMdecCodeCount, CdFileSectorReader cd, ILocalizedLogger log) throws LoggedFailure {
+ throw new UnsupportedOperationException("No support for replacing Road Rash frames");
+ }
+
+}
diff --git a/jpsxdec/src/jpsxdec/modules/roadrash/DiscIndexerRoadRash.java b/jpsxdec/src/jpsxdec/modules/roadrash/DiscIndexerRoadRash.java
new file mode 100644
index 0000000..1cf43ec
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/roadrash/DiscIndexerRoadRash.java
@@ -0,0 +1,195 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.roadrash;
+
+import java.util.Collection;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import jpsxdec.cdreaders.CdFileSectorReader;
+import jpsxdec.discitems.DiscItem;
+import jpsxdec.discitems.SerializedDiscItem;
+import jpsxdec.i18n.exception.LocalizedDeserializationFail;
+import jpsxdec.i18n.log.ILocalizedLogger;
+import jpsxdec.indexing.DiscIndex;
+import jpsxdec.indexing.DiscIndexer;
+import jpsxdec.modules.SectorClaimSystem;
+import jpsxdec.modules.video.Dimensions;
+import jpsxdec.modules.video.framenumber.HeaderFrameNumber;
+import jpsxdec.modules.video.framenumber.IndexSectorFrameNumber;
+import jpsxdec.util.BinaryDataNotRecognized;
+
+public class DiscIndexerRoadRash extends DiscIndexer implements SectorClaimToRoadRash.Listener {
+
+ private static final Logger LOG = Logger.getLogger(DiscIndexerRoadRash.class.getName());
+
+ @Override
+ public void attachToSectorClaimer(@Nonnull SectorClaimSystem scs) {
+ SectorClaimToRoadRash ui = scs.getClaimer(SectorClaimToRoadRash.class);
+ ui.setListener(this);
+ }
+
+ @Override
+ public @CheckForNull DiscItem deserializeLineRead(@Nonnull SerializedDiscItem fields) throws LocalizedDeserializationFail {
+ if (DiscItemRoadRash.TYPE_ID.equals(fields.getType()))
+ return new DiscItemRoadRash(getCd(), fields);
+ return null;
+ }
+
+ @Override
+ public void listPostProcessing(@Nonnull Collection allItems) {
+ }
+
+ @Override
+ public void indexGenerated(@Nonnull DiscIndex index) {
+ }
+
+ private static class VidBuilder {
+ @Nonnull
+ private final Dimensions _dims;
+ @Nonnull
+ private final IndexSectorFrameNumber.Format.Builder _indexSectorFrameNumberBuilder;
+ @Nonnull
+ private final HeaderFrameNumber.Format.Builder _headerFrameNumberBuilder;
+
+ public VidBuilder(@Nonnull RoadRashPacket.MDEC firstMdec, int iStartSector) {
+ _dims = new Dimensions(firstMdec.getWidth(), firstMdec.getHeight());
+ _indexSectorFrameNumberBuilder = new IndexSectorFrameNumber.Format.Builder(iStartSector);
+ _headerFrameNumberBuilder = new HeaderFrameNumber.Format.Builder(firstMdec.getFrameNumber());
+ }
+
+ public void addFrame(@Nonnull RoadRashPacket.MDEC mdec, int iStartSector) throws BinaryDataNotRecognized {
+ if (!_dims.equals(mdec.getWidth(), mdec.getHeight()) ||
+ mdec.getFrameNumber() < _headerFrameNumberBuilder.getLastFrameNumber())
+ throw new BinaryDataNotRecognized("Road Rash data corruption");
+
+ _headerFrameNumberBuilder.addHeaderFrameNumber(mdec.getFrameNumber());
+ _indexSectorFrameNumberBuilder.addFrameStartSector(iStartSector);
+ }
+
+ public HeaderFrameNumber.Format getFrameFormat() {
+ // some movies have the same frame number for all the frames
+ // if that is the case, then treat it like it has no header frame number
+ if (_headerFrameNumberBuilder.getStartFrameNumber() != _headerFrameNumberBuilder.getLastFrameNumber())
+ return _headerFrameNumberBuilder.makeFormat();
+ else
+ return null;
+
+ }
+ }
+
+ private static class MovieBuilder {
+ @CheckForNull
+ private VidBuilder _vidBuilder;
+ @Nonnull
+ private final RoadRashPacket.VLC0 _vlcPacket;
+ private int _iSpuSoundUnitPairCount = 0;
+ private final int _iStartSector;
+ private int _iEndSector;
+
+ public MovieBuilder(RoadRashPacket.VLC0 vlcPacket, int iStartSector) {
+ this._vlcPacket = vlcPacket;
+ _iStartSector = iStartSector;
+ _iEndSector = iStartSector;
+ }
+
+ public void addPacket(@Nonnull RoadRashPacketSectors packet, int iStartSector) throws BinaryDataNotRecognized {
+ _iEndSector = packet.iEndSector;
+ if (packet.packet instanceof RoadRashPacket.AU) {
+ RoadRashPacket.AU au = (RoadRashPacket.AU)packet.packet;
+ _iSpuSoundUnitPairCount += au.getSpuSoundUnitPairCount();
+ } else if (packet.packet instanceof RoadRashPacket.MDEC) {
+ if (_vidBuilder == null) {
+ _vidBuilder = new VidBuilder((RoadRashPacket.MDEC) packet.packet, packet.iStartSector);
+ } else {
+ _vidBuilder.addFrame((RoadRashPacket.MDEC) packet.packet, packet.iStartSector);
+ }
+ } else if (packet.packet instanceof RoadRashPacket.VLC0) {
+ throw new BinaryDataNotRecognized();
+ } else {
+ throw new RuntimeException("??");
+ }
+ }
+
+ public @Nonnull DiscItemRoadRash makeItem(@Nonnull CdFileSectorReader cd) throws BinaryDataNotRecognized {
+ if (_vidBuilder == null)
+ throw new BinaryDataNotRecognized();
+
+ DiscItemRoadRash item = new DiscItemRoadRash(cd, _iStartSector, _iEndSector,
+ _vidBuilder._dims,
+ _vidBuilder._indexSectorFrameNumberBuilder.makeFormat(),
+ _vidBuilder.getFrameFormat(),
+ _iSpuSoundUnitPairCount);
+ return item;
+ }
+ }
+
+ @CheckForNull
+ private MovieBuilder _movieBuilder;
+
+ public void feedPacket(@Nonnull RoadRashPacketSectors packet, @Nonnull ILocalizedLogger log) {
+
+ try {
+ if (_movieBuilder == null) {
+ if (!(packet.packet instanceof RoadRashPacket.VLC0)) {
+ throw new BinaryDataNotRecognized();
+ }
+ _movieBuilder = new MovieBuilder((RoadRashPacket.VLC0) packet.packet, packet.iStartSector);
+ } else {
+ _movieBuilder.addPacket(packet, 0);
+ }
+ } catch (BinaryDataNotRecognized ex) {
+ LOG.log(Level.SEVERE, "Road Rash data corruption", ex);
+ endVideo(log);
+ }
+ }
+
+ public void endVideo(@Nonnull ILocalizedLogger log) {
+ if (_movieBuilder != null) {
+ try {
+ DiscItemRoadRash item = _movieBuilder.makeItem(getCd());
+ addDiscItem(item);
+ } catch (BinaryDataNotRecognized ex) {
+ LOG.log(Level.SEVERE, "Road Rash data corruption", ex);
+ }
+ _movieBuilder = null;
+ }
+ }
+
+}
diff --git a/jpsxdec/src/jpsxdec/modules/roadrash/DiscItemRoadRash.java b/jpsxdec/src/jpsxdec/modules/roadrash/DiscItemRoadRash.java
new file mode 100644
index 0000000..b657b70
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/roadrash/DiscItemRoadRash.java
@@ -0,0 +1,276 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.roadrash;
+
+import java.util.Arrays;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.sound.sampled.AudioFormat;
+import jpsxdec.adpcm.SpuAdpcmDecoder;
+import jpsxdec.cdreaders.CdFileSectorReader;
+import jpsxdec.discitems.SerializedDiscItem;
+import jpsxdec.i18n.exception.LocalizedDeserializationFail;
+import jpsxdec.i18n.exception.LoggedFailure;
+import jpsxdec.i18n.log.ILocalizedLogger;
+import jpsxdec.modules.SectorClaimSystem;
+import jpsxdec.modules.sharedaudio.DecodedAudioPacket;
+import jpsxdec.modules.video.Dimensions;
+import jpsxdec.modules.video.IDemuxedFrame;
+import jpsxdec.modules.video.framenumber.FrameNumber;
+import jpsxdec.modules.video.framenumber.HeaderFrameNumber;
+import jpsxdec.modules.video.framenumber.IFrameNumberFormatter;
+import jpsxdec.modules.video.framenumber.IFrameNumberFormatterWithHeader;
+import jpsxdec.modules.video.framenumber.IndexSectorFrameNumber;
+import jpsxdec.modules.video.packetbased.DiscItemPacketBasedVideoStream;
+import jpsxdec.modules.video.packetbased.SectorClaimToAudioAndFrame;
+import jpsxdec.util.Fraction;
+
+/** A Road Rash audio/video stream. */
+public class DiscItemRoadRash extends DiscItemPacketBasedVideoStream {
+
+ public static final String TYPE_ID = "RoadRash";
+ private static final int SECTORS_PER_FRAME = 10;
+ private static final int FPS = 15;
+
+ /** Will be null if all the header frames were the same number. */
+ @CheckForNull
+ private final HeaderFrameNumber.Format _headerFrameNumberFormat;
+
+ public DiscItemRoadRash(@Nonnull CdFileSectorReader cd,
+ int iStartSector, int iEndSector,
+ @Nonnull Dimensions dim,
+ @Nonnull IndexSectorFrameNumber.Format sectorIndexFrameNumberFormat,
+ @CheckForNull HeaderFrameNumber.Format headerFrameNumberFormat,
+ int iSoundUnitCount)
+ {
+ super(cd, iStartSector, iEndSector, dim, sectorIndexFrameNumberFormat, iSoundUnitCount);
+ _headerFrameNumberFormat = headerFrameNumberFormat;
+ }
+
+ public DiscItemRoadRash(@Nonnull CdFileSectorReader cd, @Nonnull SerializedDiscItem fields)
+ throws LocalizedDeserializationFail
+ {
+ super(cd, fields);
+ if (fields.hasField(HeaderFrameNumber.Format.HEADER_FORMAT_KEY))
+ _headerFrameNumberFormat = new HeaderFrameNumber.Format(fields);
+ else
+ _headerFrameNumberFormat = null;
+ }
+
+ @Override
+ public @Nonnull SerializedDiscItem serialize() {
+ SerializedDiscItem serial = super.serialize();
+ if (_headerFrameNumberFormat != null)
+ _headerFrameNumberFormat.serialize(serial);
+ return serial;
+ }
+
+ @Override
+ public @Nonnull String getSerializationTypeId() {
+ return TYPE_ID;
+ }
+
+ @Override
+ public boolean hasIndependentBitstream() {
+ return false;
+ }
+
+ @Override
+ public @Nonnull FrameNumber getStartFrame() {
+ if (_headerFrameNumberFormat == null)
+ return _indexSectorFrameNumberFormat.getStartFrame();
+ else
+ return _headerFrameNumberFormat.getStartFrame(_indexSectorFrameNumberFormat);
+ }
+
+ @Override
+ public @Nonnull FrameNumber getEndFrame() {
+ if (_headerFrameNumberFormat == null)
+ return _indexSectorFrameNumberFormat.getEndFrame();
+ else
+ return _headerFrameNumberFormat.getEndFrame(_indexSectorFrameNumberFormat);
+ }
+
+ @Override
+ public @Nonnull List getFrameNumberTypes() {
+ if (_headerFrameNumberFormat == null)
+ return Arrays.asList(FrameNumber.Type.Index, FrameNumber.Type.Sector);
+ else
+ return Arrays.asList(FrameNumber.Type.Index, FrameNumber.Type.Header, FrameNumber.Type.Sector);
+ }
+
+ @Override
+ protected double getPacketBasedFpsInterestingDescription() {
+ return FPS;
+ }
+
+ @Override
+ public @Nonnull Fraction getSectorsPerFrame() {
+ return new Fraction(SECTORS_PER_FRAME);
+ }
+
+ @Override
+ public double getApproxDuration() {
+ return getFrameCount() / (double)FPS;
+ }
+
+ @Override
+ public int getAudioSampleFramesPerSecond() {
+ if (hasAudio())
+ return RoadRashPacket.SAMPLE_FRAMES_PER_SECOND;
+ else
+ return -1;
+ }
+
+ @Override
+ public @Nonnull SectorClaimToAudioAndFrame makeAudioVideoDemuxer(double dblVolume) {
+ if (_headerFrameNumberFormat != null)
+ return new Demuxer(dblVolume, _headerFrameNumberFormat.makeFormatter(_indexSectorFrameNumberFormat), null);
+ else
+ return new Demuxer(dblVolume, null, _indexSectorFrameNumberFormat.makeFormatter());
+ }
+
+ public class Demuxer extends SectorClaimToAudioAndFrame
+ implements SectorClaimToRoadRash.Listener
+ {
+ // only one of these two will not be null
+ @CheckForNull
+ private final IFrameNumberFormatterWithHeader _fnfwh;
+ @CheckForNull
+ private final IFrameNumberFormatter _fnf;
+ @Nonnull
+ private final SpuAdpcmDecoder.Stereo _audioDecoder;
+
+ @CheckForNull
+ private IDemuxedFrame.Listener _frameListener;
+ @CheckForNull
+ private DecodedAudioPacket.Listener _audioListener;
+
+ @CheckForNull
+ private RoadRashPacket.VLC0 _vlcPacket;
+
+ public Demuxer(double dblVolume,
+ @CheckForNull IFrameNumberFormatterWithHeader fnfwh,
+ @CheckForNull IFrameNumberFormatter fnf)
+ {
+ _audioDecoder = new SpuAdpcmDecoder.Stereo(dblVolume);
+ _fnfwh = fnfwh;
+ _fnf = fnf;
+ }
+
+ public void attachToSectorClaimer(@Nonnull SectorClaimSystem scs) {
+ SectorClaimToRoadRash s2cs = scs.getClaimer(SectorClaimToRoadRash.class);
+ s2cs.setListener(this);
+ s2cs.setRangeLimit(getStartSector(), getEndSector());
+ }
+
+ public void feedPacket(@Nonnull RoadRashPacketSectors packet, @Nonnull ILocalizedLogger log) throws LoggedFailure {
+ if (packet.packet instanceof RoadRashPacket.AU) {
+ RoadRashPacket.AU au = (RoadRashPacket.AU)packet.packet;
+ DecodedAudioPacket aup = au.decode(_audioDecoder);
+ if (_audioListener != null)
+ _audioListener.audioPacketComplete(aup, log);
+ } else if (packet.packet instanceof RoadRashPacket.MDEC) {
+ RoadRashPacket.MDEC mdecPacket = (RoadRashPacket.MDEC) packet.packet;
+
+ int iFrameNumber = mdecPacket.getFrameNumber();
+ FrameNumber fn;
+ if (_fnf != null) {
+ fn = _fnf.next(packet.iStartSector, log);
+ iFrameNumber = fn.getIndexNumber().getFrameValue();
+ } else {
+ fn = _fnfwh.next(packet.iStartSector, mdecPacket.getFrameNumber(), log);
+ }
+
+ if (_vlcPacket != null && _frameListener != null) {
+ // problem!!!: we don't have a frame number in some cases
+ // But is there anything we can really do about it?
+ // The location of the packet can't really tell us anything
+ // So I guess we're stuck just using the frame index :P
+ int iPresentationSector = iFrameNumber * SECTORS_PER_FRAME + DiscItemRoadRash.this.getAbsolutePresentationStartSector();
+ _frameListener.frameComplete(new DemuxedRoadRashFrame(packet, mdecPacket, _vlcPacket, fn, new Fraction(iPresentationSector)));
+ }
+ } else if (packet.packet instanceof RoadRashPacket.VLC0) {
+ _vlcPacket = (RoadRashPacket.VLC0)packet.packet;
+ }
+
+ }
+
+ public void endVideo(@Nonnull ILocalizedLogger log) {
+ // probably doesn't matter
+ }
+
+ public void setFrameListener(@CheckForNull IDemuxedFrame.Listener listener) {
+ _frameListener = listener;
+ }
+
+ public void setAudioListener(@CheckForNull DecodedAudioPacket.Listener listener) {
+ _audioListener = listener;
+ }
+
+ public @Nonnull AudioFormat getOutputFormat() {
+ return RoadRashPacket.ROAD_RASH_AUDIO_FORMAT;
+ }
+
+ public double getVolume() {
+ return _audioDecoder.getVolume();
+ }
+
+ public int getAbsolutePresentationStartSector() {
+ return DiscItemRoadRash.this.getStartSector();
+ }
+
+ public int getStartSector() {
+ return DiscItemRoadRash.this.getStartSector();
+ }
+
+ public int getEndSector() {
+ return DiscItemRoadRash.this.getEndSector();
+ }
+
+ public int getSampleFramesPerSecond() {
+ return RoadRashPacket.SAMPLE_FRAMES_PER_SECOND;
+ }
+
+ public int getDiscSpeed() {
+ return 2;
+ }
+
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/modules/roadrash/RoadRashPacket.java b/jpsxdec/src/jpsxdec/modules/roadrash/RoadRashPacket.java
new file mode 100644
index 0000000..c6f7dd5
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/roadrash/RoadRashPacket.java
@@ -0,0 +1,413 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.roadrash;
+
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.sound.sampled.AudioFormat;
+import jpsxdec.adpcm.SoundUnitDecoder;
+import jpsxdec.adpcm.SpuAdpcmDecoder;
+import jpsxdec.adpcm.SpuAdpcmSoundUnit;
+import static jpsxdec.modules.roadrash.BitStreamUncompressorRoadRash.ROAD_RASH_BIT_CODE_ORDER;
+import jpsxdec.modules.sharedaudio.DecodedAudioPacket;
+import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor;
+import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_STRv2;
+import jpsxdec.psxvideo.bitstreams.ZeroRunLengthAc;
+import jpsxdec.psxvideo.bitstreams.ZeroRunLengthAcLookup;
+import jpsxdec.psxvideo.mdec.MdecCode;
+import jpsxdec.util.Fraction;
+import jpsxdec.util.IO;
+
+/**
+ * Support for "Road Rash 3D" videos.
+ * Road Rash takes a unique approach to bitstreams, every movie has its own unique VLC table.
+ * There's a lot of big-endian data in here.
+ */
+public abstract class RoadRashPacket {
+
+ public static final int MIN_PACKET_SIZE = 456;
+ public static final int MAX_PACKET_SIZE = 14200;
+
+ public static final long MAGIC_VLC0 = 0x564c4330;
+ public static final long MAGIC_MDEC = 0x4d444543;
+ public static final long MAGIC_au00 = 0x61753030;
+ public static final long MAGIC_au01 = 0x61753031;
+
+ public static final int SAMPLE_FRAMES_PER_SECOND = 22050;
+ public static final int SAMPLE_FRAMES_PER_SECTOR = SAMPLE_FRAMES_PER_SECOND / 150;
+ static {
+ if (SAMPLE_FRAMES_PER_SECOND % 150 != 0)
+ throw new RuntimeException("Road Rash sample rate doesn't cleanly divide by sector rate");
+ }
+
+ public static final AudioFormat ROAD_RASH_AUDIO_FORMAT = new AudioFormat(SAMPLE_FRAMES_PER_SECOND, 16, 2, true, false);
+
+ // =========================================================================
+
+ public static @CheckForNull RoadRashPacket readPacket(@Nonnull InputStream is)
+ throws EOFException, IOException
+ {
+
+ long lngMagic = IO.readUInt32BE(is);
+ if (lngMagic != MAGIC_VLC0 &&
+ lngMagic != MAGIC_au00 &&
+ lngMagic != MAGIC_au01 &&
+ lngMagic != MAGIC_MDEC)
+ {
+ return null;
+ }
+
+ int iPacketSize = IO.readSInt32BE(is);
+ if (iPacketSize % 4 != 0)
+ throw new RuntimeException();
+ if (iPacketSize < MIN_PACKET_SIZE || iPacketSize > MAX_PACKET_SIZE)
+ throw new RuntimeException();
+ if (lngMagic == MAGIC_au00 || lngMagic == MAGIC_au01) {
+ return AU.readPacket(lngMagic, iPacketSize, is);
+ }
+ if (lngMagic == MAGIC_MDEC) {
+ return MDEC.readPacket(lngMagic, iPacketSize, is);
+ }
+ if (lngMagic == MAGIC_VLC0) {
+ return VLC0.readPacket(lngMagic, iPacketSize, is);
+ }
+
+ throw new RuntimeException("Should have been handled before this");
+ }
+
+ // =========================================================================
+
+ public static final int HEADER_SIZEOF = 8;
+
+ private final long _lngPacketType; // @0 4 bytes (BE)
+ private final int _iHeaderPacketSize; // @4 4 bytes BE
+
+ /** Only payload data that is actual payload,
+ * not including any additional payload sub-headers */
+ @Nonnull
+ private final byte[] _abPayloadAfterHeaders;
+
+ public RoadRashPacket(long lngPacketType, int iHeaderPacketSize,
+ @Nonnull byte[] abPayloadAfterHeaders)
+ {
+ _lngPacketType = lngPacketType;
+ _iHeaderPacketSize = iHeaderPacketSize;
+ _abPayloadAfterHeaders = abPayloadAfterHeaders;
+ }
+
+ public long getPacketType() {
+ return _lngPacketType;
+ }
+
+ public int getHeaderPacketSize() {
+ return _iHeaderPacketSize;
+ }
+
+ protected @Nonnull byte[] getPayload() {
+ return _abPayloadAfterHeaders;
+ }
+
+ // =========================================================================
+
+ /**
+ * "VLC" is known to mean "variable-length code/codes/coding".
+ * Huffman coding is the kind of VLC logic used in PlayStation games.
+ */
+ public static class VLC0 extends RoadRashPacket {
+
+ public static @CheckForNull VLC0 readPacket(long lngMagic, int iPacketSize, @Nonnull InputStream is)
+ throws EOFException, IOException
+ {
+ if (iPacketSize != (ROAD_RASH_BIT_CODE_ORDER.length * 2) + 8)
+ throw new RuntimeException();
+ byte[] abPacketPayload = IO.readByteArray(is, iPacketSize - 8);
+
+ ZeroRunLengthAcLookup.Builder bldr = new ZeroRunLengthAcLookup.Builder();
+ MdecCode[] aoVlcHeaderMdecCodesForReference = new MdecCode[ROAD_RASH_BIT_CODE_ORDER.length];
+
+ for (int i = 0; i < ROAD_RASH_BIT_CODE_ORDER.length; i++) {
+ int iMdec = IO.readUInt16LE(abPacketPayload, i * 2);
+ MdecCode mdecCode = new MdecCode(iMdec);
+ if (!mdecCode.isValid())
+ throw new RuntimeException();
+ aoVlcHeaderMdecCodesForReference[i] = mdecCode;
+
+ ZeroRunLengthAc bitCode = new ZeroRunLengthAc(ROAD_RASH_BIT_CODE_ORDER[i],
+ mdecCode.getTop6Bits(), mdecCode.getBottom10Bits(),
+ mdecCode.toMdecWord() == BitStreamUncompressorRoadRash.BITSTREAM_ESCAPE_CODE,
+ mdecCode.isEOD());
+
+ bldr.add(bitCode);
+ }
+
+ return new VLC0(lngMagic, iPacketSize, abPacketPayload, bldr.build(), aoVlcHeaderMdecCodesForReference);
+ }
+
+ @Nonnull
+ private final ZeroRunLengthAcLookup _vlcLookup;
+ @Nonnull
+ private final MdecCode[] _aoVlcHeaderMdecCodesForReference;
+
+ public VLC0(long lngPacketType, int iHeaderPacketSize,
+ @Nonnull byte[] abPayloadAfterHeaders,
+ @Nonnull ZeroRunLengthAcLookup vlcLookup,
+ @Nonnull MdecCode[] aoVlcHeaderMdecCodesForReference)
+ {
+ super(lngPacketType, iHeaderPacketSize, abPayloadAfterHeaders);
+ _vlcLookup = vlcLookup;
+ _aoVlcHeaderMdecCodesForReference = aoVlcHeaderMdecCodesForReference;
+ }
+
+ public @Nonnull BitStreamUncompressor makeFrameBitStreamUncompressor(@Nonnull MDEC mdecPacket) {
+ return new BitStreamUncompressorRoadRash(mdecPacket.getPayload(), _vlcLookup, mdecPacket.getQuantizationScale());
+ }
+
+ /** For debugging. */
+ public void printCodes() {
+ for (int i = 0; i < _aoVlcHeaderMdecCodesForReference.length; i++) {
+ MdecCode mdec = _aoVlcHeaderMdecCodesForReference[i];
+ System.out.format("%04X %-8s %s", mdec.toMdecWord(), mdec, ROAD_RASH_BIT_CODE_ORDER[i]);
+ if (mdec.toMdecWord() == BitStreamUncompressorRoadRash.BITSTREAM_ESCAPE_CODE)
+ System.out.println(" (escape code)");
+ else
+ System.out.println();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "VLC0";
+ }
+ }
+
+
+ // =========================================================================
+
+ public static class AU extends RoadRashPacket {
+
+ public static @CheckForNull AU readPacket(
+ long lngMagic, int iPacketSize, @Nonnull InputStream is)
+ throws EOFException, IOException
+ {
+ if (iPacketSize < 1576 || iPacketSize > 6348)
+ return null;
+
+ int iPresentationSampleFrame = IO.readSInt32BE(is);
+ if (iPresentationSampleFrame < 0 || iPresentationSampleFrame > 1312556)
+ throw new RuntimeException();
+
+ // I don't know what these values are, but they're always the same
+ int i2048 = IO.readSInt16BE(is);
+ if (i2048 != 2048)
+ throw new RuntimeException();
+ int i512 = IO.readSInt16BE(is);
+ if (i512 != 512)
+ throw new RuntimeException();
+
+ byte[] abPacketPayload = IO.readByteArray(is, iPacketSize - 8 - 8);
+ return new AU(lngMagic, iPacketSize, abPacketPayload, iPresentationSampleFrame);
+ }
+
+ private final int _iPresentationSampleFrame; // @8 4 bytes BE
+ // 2048 // @12 2 bytes BE
+ // 512 // @16 2 bytes BE
+
+ public AU(long lngPacketType, int iHeaderPacketSize,
+ @Nonnull byte[] abPayloadAfterHeaders, int iPresentationSampleFrame)
+ {
+ super(lngPacketType, iHeaderPacketSize, abPayloadAfterHeaders);
+ _iPresentationSampleFrame = iPresentationSampleFrame;
+ }
+
+ public boolean isLastAudioPacket() {
+ return getPacketType() == MAGIC_au01;
+ }
+
+ public int calcSampleFramesGenerated() {
+ return getSpuSoundUnitPairCount() * SoundUnitDecoder.SAMPLES_PER_SOUND_UNIT;
+ }
+
+ public int getSpuSoundUnitPairCount() {
+ int iSoundUnits = getPayload().length / 15;
+ return iSoundUnits / 2;
+ }
+
+ public @Nonnull DecodedAudioPacket decode(@Nonnull SpuAdpcmDecoder.Stereo decoder) {
+ List units = unpackSpu(getPayload());
+
+ // each audio packet is split in half: half for left channel, half for right
+ int iHalf = units.size() / 2;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ for (int iUnit = 0; iUnit < iHalf; iUnit++) {
+ try {
+ decoder.decode(units.get(iUnit), units.get(iHalf + iUnit), out);
+ } catch (IOException ex) {
+ throw new RuntimeException("Should nothappen", ex);
+ }
+ }
+
+ if (out.size() != calcSampleFramesGenerated() * 4)
+ throw new RuntimeException();
+
+ Fraction presentationSector = new Fraction(_iPresentationSampleFrame, SAMPLE_FRAMES_PER_SECTOR);
+
+ return new DecodedAudioPacket(0, ROAD_RASH_AUDIO_FORMAT, presentationSector, out.toByteArray());
+ }
+
+ @Override
+ public String toString() {
+ return String.format("au0%c start sample frame:%d sample frames:%d",
+ isLastAudioPacket() ? '1' : '0',
+ _iPresentationSampleFrame, calcSampleFramesGenerated());
+ }
+
+ }
+
+ /** I guess to make the audio 1/16 smaller they chose to remove the
+ * 2nd byte in each SPU sound unit, which is usually 0, but I found
+ * it can also be filled with other values, but haven't found where
+ * that logic lies. */
+ private static @Nonnull List unpackSpu(@Nonnull byte[] abPayload) {
+ List units = new ArrayList();
+
+ int iBytesUsed;
+ for (iBytesUsed = 0; iBytesUsed+14 < abPayload.length; iBytesUsed+=15) {
+ byte[] abSpuSoundUnit = new byte[16];
+ abSpuSoundUnit[0] = abPayload[iBytesUsed];
+ // this byte can sometimes be values other than 0
+ // I couldn't figure out how the game decides to make
+ // those changes. Where would the data come from?
+ // Maybe the leftover 2 bytes in some audio packets?
+ // Maybe the timestamp?
+ // More debugging is nedded
+ abSpuSoundUnit[1] = 0;
+ System.arraycopy(abPayload, iBytesUsed+1, abSpuSoundUnit, 2, 14);
+ units.add(new SpuAdpcmSoundUnit(abSpuSoundUnit));
+ }
+
+ return units;
+ }
+
+ // =========================================================================
+
+ public static class MDEC extends RoadRashPacket {
+
+ public static @CheckForNull MDEC readPacket(
+ long lngMagic, int iPacketSize, @Nonnull InputStream is)
+ throws EOFException, IOException
+ {
+ if (iPacketSize < 688 || iPacketSize > 14200)
+ throw new RuntimeException();
+
+ int iWidth = IO.readSInt16BE(is);
+ int iHeight = IO.readSInt16BE(is);
+
+ if ((iWidth != 144 || iHeight != 112) &&
+ (iWidth != 208 || iHeight != 144) &&
+ (iWidth != 320 || iHeight != 144) &&
+ (iWidth != 320 || iHeight != 224))
+ {
+ throw new RuntimeException();
+ }
+
+ int iFrameNumber = IO.readSInt32BE(is);
+ if ((iFrameNumber < 0 || iFrameNumber > 893) && iFrameNumber != 0x7fffad1c)
+ throw new RuntimeException();
+
+ byte[] abStrHeader = IO.readByteArray(is, BitStreamUncompressor_STRv2.StrV2Header.SIZEOF);
+
+ BitStreamUncompressor_STRv2.StrV2Header strHeader =
+ new BitStreamUncompressor_STRv2.StrV2Header(abStrHeader, abStrHeader.length);
+
+ if (!strHeader.isValid())
+ throw new RuntimeException();
+ if (strHeader.getQuantizationScale() < 1 || strHeader.getQuantizationScale() > 17)
+ throw new RuntimeException();
+
+ byte[] abPacketPayload = IO.readByteArray(is, iPacketSize - 8 - 8 - abStrHeader.length);
+ return new MDEC(lngMagic, iPacketSize, abPacketPayload, iWidth, iHeight, iFrameNumber, strHeader);
+ }
+
+ private final int _iWidth; // @8 2 bytes BE
+ private final int _iHeight; // @10 2 bytes BE
+ private final int _iFrameNumber; // @12 4 bytes
+ @Nonnull
+ private final BitStreamUncompressor_STRv2.StrV2Header _strHeader; // @16 8 bytes
+
+ public MDEC(long lngPacketType, int iHeaderPacketSize,
+ @Nonnull byte[] abPayloadAfterHeaders,
+ int iWidth, int iHeight, int iFrameNumber,
+ @Nonnull BitStreamUncompressor_STRv2.StrV2Header strHeader)
+ {
+ super(lngPacketType, iHeaderPacketSize, abPayloadAfterHeaders);
+ _iWidth = iWidth;
+ _iHeight = iHeight;
+ _iFrameNumber = iFrameNumber;
+ _strHeader = strHeader;
+ }
+
+ public int getWidth() {
+ return _iWidth;
+ }
+
+ public int getHeight() {
+ return _iHeight;
+ }
+
+ public int getFrameNumber() {
+ return _iFrameNumber;
+ }
+
+ public int getQuantizationScale() {
+ return _strHeader.getQuantizationScale();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("MDEC %dx%d frame:%d qscale:%d",
+ _iWidth, _iHeight, _iFrameNumber, _strHeader.getQuantizationScale());
+ }
+ }
+
+}
diff --git a/jpsxdec/src/jpsxdec/modules/roadrash/RoadRashPacketSectors.java b/jpsxdec/src/jpsxdec/modules/roadrash/RoadRashPacketSectors.java
new file mode 100644
index 0000000..c486aab
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/roadrash/RoadRashPacketSectors.java
@@ -0,0 +1,53 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.roadrash;
+
+import javax.annotation.Nonnull;
+
+/** Wraps a standard {@link RoadRashPacket} with the sectors it was found in. */
+public class RoadRashPacketSectors {
+ @Nonnull
+ public final RoadRashPacket packet;
+ public final int iStartSector, iEndSector;
+
+ public RoadRashPacketSectors(@Nonnull RoadRashPacket packet, int iStartSector, int iEndSector) {
+ this.packet = packet;
+ this.iStartSector = iStartSector;
+ this.iEndSector = iEndSector;
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/modules/roadrash/SectorClaimToRoadRash.java b/jpsxdec/src/jpsxdec/modules/roadrash/SectorClaimToRoadRash.java
new file mode 100644
index 0000000..bbec29a
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/roadrash/SectorClaimToRoadRash.java
@@ -0,0 +1,234 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.roadrash;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import jpsxdec.cdreaders.CdSector;
+import jpsxdec.i18n.exception.LoggedFailure;
+import jpsxdec.i18n.log.ILocalizedLogger;
+import jpsxdec.modules.CdSectorDemuxPiece;
+import jpsxdec.modules.SectorClaimSystem;
+import jpsxdec.util.DemuxPushInputStream;
+import jpsxdec.util.DemuxPushInputStream.NeedsMoreData;
+import jpsxdec.util.IO;
+import jpsxdec.util.IOIterator;
+
+public class SectorClaimToRoadRash extends SectorClaimSystem.SectorClaimer {
+
+ private static final Logger LOG = Logger.getLogger(SectorClaimToRoadRash.class.getName());
+
+ public interface Listener {
+ void feedPacket(@Nonnull RoadRashPacketSectors packet, @Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
+ void endVideo(@Nonnull ILocalizedLogger log);
+ }
+
+ @CheckForNull
+ private Listener _listener;
+
+ public SectorClaimToRoadRash() {
+ }
+ public SectorClaimToRoadRash(@Nonnull Listener listener) {
+ _listener = listener;
+ }
+ public void setListener(@CheckForNull Listener listener) {
+ _listener = listener;
+ }
+
+ @CheckForNull
+ private DemuxPushInputStream _sectorStream;
+ private boolean _blnVidEnd = false;
+
+ private @Nonnull List readAsManyPacketsAsPossible() {
+ List finishedPackets = new ArrayList();
+ if (_sectorStream == null) throw new IllegalStateException();
+
+ if (_sectorStream.available() < RoadRashPacket.MIN_PACKET_SIZE)
+ return finishedPackets;
+
+ while (true) {
+ _sectorStream.mark(RoadRashPacket.MAX_PACKET_SIZE);
+ int iStartSector = _sectorStream.getCurrentPiece().getSectorNumber();
+
+ try {
+ RoadRashPacket packet = RoadRashPacket.readPacket(_sectorStream);
+
+ if (packet != null) {
+ int iEndSector = _sectorStream.getCurrentPiece().getSectorNumber();
+ finishedPackets.add(new RoadRashPacketSectors(packet, iStartSector, iEndSector));
+ } else {
+
+ // possibly end of stream
+ _sectorStream.reset();
+
+ // check for 8 zeroes
+ int iIsZero = IO.readSInt32BE(_sectorStream);
+ if (iIsZero == 0) {
+ _sectorStream.mark(RoadRashPacket.MAX_PACKET_SIZE);
+ iIsZero = IO.readSInt32BE(_sectorStream);
+ if (iIsZero == 0) {
+ // 8 zeroes, definitely end of stream
+ _blnVidEnd = true;
+ return finishedPackets;
+ }
+
+ // so there were 4 zeroes, but now there is some non-zero data
+ // don't end the stream, but this is definitely data corruption
+ LOG.warning("Corrupted Road Rash stream");
+ _sectorStream.reset(); // do another loop
+ }
+ }
+
+ } catch (NeedsMoreData ex) {
+ // backup and try again when there's more data
+ _sectorStream.reset();
+ return finishedPackets;
+ } catch (EOFException ex) {
+ // stream was closed and we hit the end
+ return finishedPackets;
+ } catch (IOException ex) {
+ throw new RuntimeException("Should not happen");
+ }
+
+ }
+ }
+
+ public void sectorRead(@Nonnull SectorClaimSystem.ClaimableSector cs,
+ @Nonnull IOIterator peekIt,
+ @Nonnull ILocalizedLogger log)
+ throws SectorClaimSystem.ClaimerFailure
+ {
+ CdSector cdSector = cs.getSector();
+ if (cs.getClaimer() != null || cdSector.isCdAudioSector()) {
+ // close any existing stream
+ endVideo(log);
+ return;
+ }
+
+ int iStartEnd = 0;
+
+ if (_sectorStream == null) {
+ // No current movie
+
+ long lngMagic = cdSector.readUInt32BE(0);
+ if (lngMagic == RoadRashPacket.MAGIC_VLC0) {
+ // Probably a movie
+
+ DemuxPushInputStream stream = new DemuxPushInputStream(new CdSectorDemuxPiece(cdSector));
+ RoadRashPacket firstPacket;
+ try {
+ firstPacket = RoadRashPacket.readPacket(stream);
+ } catch (IOException ex) {
+ throw new RuntimeException("Should not happen");
+ }
+
+ if (firstPacket instanceof RoadRashPacket.VLC0) {
+ // Definitely a movie
+ // send first packet to listener
+ _sectorStream = stream;
+ iStartEnd = SectorRoadRash.START;
+ if (_listener != null) {
+ try {
+ _listener.feedPacket(new RoadRashPacketSectors(firstPacket,
+ cdSector.getSectorIndexFromStart(), cdSector.getSectorIndexFromStart()), log);
+ } catch (LoggedFailure ex) {
+ throw new SectorClaimSystem.ClaimerFailure(ex);
+ }
+ }
+ }
+ }
+
+ } else {
+ // add to existing stream
+ _sectorStream.addPiece(new CdSectorDemuxPiece(cdSector));
+ }
+
+ if (_sectorStream != null) {
+
+ List finishedPackets = readAsManyPacketsAsPossible();
+
+ List rrps = new ArrayList(finishedPackets.size());
+ for (RoadRashPacketSectors finishedPacket : finishedPackets) {
+ if (finishedPacket.packet instanceof RoadRashPacket.VLC0) {
+ throw new RuntimeException("Should not happen unless data is corrupted");
+ }
+
+ if (_listener != null) {
+ // Only send packets that are fully in the active sector range
+ // (in practice there should never be a packet crossing the border)
+ if (sectorIsInRange(finishedPacket.iStartSector) &&
+ sectorIsInRange(finishedPacket.iEndSector))
+ {
+ try {
+ _listener.feedPacket(finishedPacket, log);
+ } catch (LoggedFailure ex) {
+ throw new SectorClaimSystem.ClaimerFailure(ex);
+ }
+ }
+ }
+
+ rrps.add(finishedPacket.packet);
+ }
+
+ if (_blnVidEnd)
+ iStartEnd |= SectorRoadRash.END;
+ cs.claim(new SectorRoadRash(cdSector, rrps, iStartEnd));
+ if (_blnVidEnd)
+ endVideo(log);
+ }
+ }
+
+ private void endVideo(@Nonnull ILocalizedLogger log) {
+ if (_sectorStream != null) {
+ _blnVidEnd = false;
+ _sectorStream = null;
+ if (_listener != null)
+ _listener.endVideo(log);
+ }
+ }
+
+ public void endOfSectors(@Nonnull ILocalizedLogger log) {
+ endVideo(log);
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/modules/roadrash/SectorRoadRash.java b/jpsxdec/src/jpsxdec/modules/roadrash/SectorRoadRash.java
new file mode 100644
index 0000000..01b1460
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/roadrash/SectorRoadRash.java
@@ -0,0 +1,84 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.roadrash;
+
+import java.util.List;
+import javax.annotation.Nonnull;
+import jpsxdec.cdreaders.CdSector;
+import jpsxdec.modules.IdentifiedSector;
+
+/** Just a simple sector wrapper for Road Rash to claim sectors. */
+public class SectorRoadRash extends IdentifiedSector {
+
+ /** If the sector is at the start, end, or middle (0) of the stream (bit flags). */
+ public static final int START = 1, END = 2;
+
+ private final int _iStartEnd;
+ @Nonnull
+ private final List _packetsEndingInThisSector;
+
+ public SectorRoadRash(@Nonnull CdSector cdSector, @Nonnull List packetsEndingInThisSector, int iStartEnd) {
+ super(cdSector);
+ _packetsEndingInThisSector = packetsEndingInThisSector;
+ _iStartEnd = iStartEnd;
+ setProbability(100);
+ }
+
+ public String getTypeName() {
+ return "RoadRash";
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getTypeName()).append(' ')
+ .append(super.toString()).append(' ')
+ .append(_packetsEndingInThisSector.size()).append(" finished packets [");
+ for (int i = 0; i < _packetsEndingInThisSector.size(); i++) {
+ if (i > 0)
+ sb.append(", ");
+ sb.append(_packetsEndingInThisSector.get(i));
+ }
+ sb.append(']');
+ if ((_iStartEnd & START) != 0)
+ sb.append(" START");
+ if ((_iStartEnd & END) != 0)
+ sb.append(" END");
+ return sb.toString();
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/modules/sharedaudio/AudioSaverBuilder.java b/jpsxdec/src/jpsxdec/modules/sharedaudio/AudioSaverBuilder.java
index 28c188b..b609e99 100644
--- a/jpsxdec/src/jpsxdec/modules/sharedaudio/AudioSaverBuilder.java
+++ b/jpsxdec/src/jpsxdec/modules/sharedaudio/AudioSaverBuilder.java
@@ -176,7 +176,7 @@ public void commandLineOptions(@Nonnull ArgParser ap, @Nonnull FeedbackStream fb
throw new NumberFormatException();
setVolume(iVol / 100.0);
} catch (NumberFormatException ex) {
- fbs.printlnWarn(I.CMD_IGNORING_INVALID_VOLUME(vol.value));
+ fbs.printlnWarn(I.CMD_IGNORING_INVALID_VALUE_FOR_CMD(vol.value, "-vol"));
}
}
@@ -185,14 +185,14 @@ public void commandLineOptions(@Nonnull ArgParser ap, @Nonnull FeedbackStream fb
if (fmt != null) {
setContainerForamt(fmt);
} else {
- fbs.printlnWarn(I.CMD_IGNORING_INVALID_FORMAT(audfmt.value));
+ fbs.printlnWarn(I.CMD_IGNORING_INVALID_VALUE_FOR_CMD(audfmt.value, "-af,-audfmt"));
}
}
}
- public void printSelectedOptions(@Nonnull FeedbackStream fbs) {
- fbs.println(I.CMD_AUDIO_FORMAT(_containerFormat.getCmdId()));
- fbs.println(I.CMD_VOLUME_PERCENT(getVolume()));
- fbs.println(I.CMD_FILENAME(getFileRelativePath()));
+ public void printSelectedOptions(@Nonnull ILocalizedLogger log) {
+ log.log(Level.INFO, I.CMD_AUDIO_FORMAT(_containerFormat.getCmdId()));
+ log.log(Level.INFO, I.CMD_VOLUME_PERCENT(getVolume()));
+ log.log(Level.INFO, I.CMD_FILENAME(getFileRelativePath()));
}
public @Nonnull ILocalizedMessage getOutputSummary() {
@@ -208,9 +208,9 @@ public void startSave(final @Nonnull ProgressLogger pl, @CheckForNull File outpu
throws LoggedFailure, TaskCanceledException
{
clearGeneratedFiles();
+ printSelectedOptions(pl);
+
final File outputFile = new File(outputDir, getFileRelativePath().getPath());
- ISectorAudioDecoder decoder = _audItem.makeDecoder(getVolume());
- AudioFormat audioFmt = decoder.getOutputFormat();
try {
IO.makeDirsForFile(outputFile);
@@ -218,6 +218,10 @@ public void startSave(final @Nonnull ProgressLogger pl, @CheckForNull File outpu
throw new LoggedFailure(pl, Level.SEVERE, ex.getSourceMessage(), ex);
}
+ // SectorClaimSystem -> ISectorAudioDecoder -> DecodedAudioPacket -> AudioOutputFileWriter
+
+ ISectorAudioDecoder decoder = _audItem.makeDecoder(getVolume());
+ AudioFormat audioFmt = decoder.getOutputFormat();
final AudioOutputFileWriter audioWriter;
try {
audioWriter = new AudioOutputFileWriter(outputFile,
diff --git a/jpsxdec/src/jpsxdec/modules/sharedaudio/DecodedAudioPacket.java b/jpsxdec/src/jpsxdec/modules/sharedaudio/DecodedAudioPacket.java
index 455d1b3..0882122 100644
--- a/jpsxdec/src/jpsxdec/modules/sharedaudio/DecodedAudioPacket.java
+++ b/jpsxdec/src/jpsxdec/modules/sharedaudio/DecodedAudioPacket.java
@@ -39,6 +39,7 @@
import javax.annotation.Nonnull;
import javax.sound.sampled.AudioFormat;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.util.Fraction;
@@ -47,7 +48,8 @@ public class DecodedAudioPacket {
public interface Listener {
void audioPacketComplete(@Nonnull DecodedAudioPacket packet,
- @Nonnull ILocalizedLogger log);
+ @Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
}
/** Channel that this audio packet belongs to.
diff --git a/jpsxdec/src/jpsxdec/modules/sharedaudio/DiscItemAudioStream.java b/jpsxdec/src/jpsxdec/modules/sharedaudio/DiscItemAudioStream.java
index 7db388c..2c8fd59 100644
--- a/jpsxdec/src/jpsxdec/modules/sharedaudio/DiscItemAudioStream.java
+++ b/jpsxdec/src/jpsxdec/modules/sharedaudio/DiscItemAudioStream.java
@@ -119,7 +119,7 @@ public ILocalizedMessage getDetails() {
}
public @Nonnull PlayController makePlayController() {
- return new PlayController(new MediaPlayer(this));
+ return new MediaPlayer(this).getPlayController();
}
@Override
diff --git a/jpsxdec/src/jpsxdec/modules/sharedaudio/ISectorAudioDecoder.java b/jpsxdec/src/jpsxdec/modules/sharedaudio/ISectorAudioDecoder.java
index 2305b08..ed39367 100644
--- a/jpsxdec/src/jpsxdec/modules/sharedaudio/ISectorAudioDecoder.java
+++ b/jpsxdec/src/jpsxdec/modules/sharedaudio/ISectorAudioDecoder.java
@@ -59,9 +59,9 @@ public interface ISectorAudioDecoder {
/** Sector where the audio begins to play. */
int getAbsolutePresentationStartSector();
- @Deprecated
+ /** Physical start sector, not presentation start sector. */
int getStartSector();
- @Deprecated
+ /** Physical end sector, not presentation end sector. */
int getEndSector();
int getSampleFramesPerSecond();
diff --git a/jpsxdec/src/jpsxdec/modules/spu/DiscIndexerSpu.java b/jpsxdec/src/jpsxdec/modules/spu/DiscIndexerSpu.java
index a97d4cb..ade640c 100644
--- a/jpsxdec/src/jpsxdec/modules/spu/DiscIndexerSpu.java
+++ b/jpsxdec/src/jpsxdec/modules/spu/DiscIndexerSpu.java
@@ -147,7 +147,7 @@ public void addQuad(int iQuadIndex, int iQuad, int iSector, int iOffset) {
_blnOnlyZeroes = (iQuad & 0xffff) == 0;
}
} else if (_blnInRun) {
- _blnOnlyZeroes &= iQuad == 0;
+ _blnOnlyZeroes = _blnOnlyZeroes && iQuad == 0;
if (iQuadIndex == 3) {
_iEndSector = iSector;
_iEndOffset = iOffset + 3;
diff --git a/jpsxdec/src/jpsxdec/modules/spu/DiscItemSpu.java b/jpsxdec/src/jpsxdec/modules/spu/DiscItemSpu.java
index bbaf809..bdc3b74 100644
--- a/jpsxdec/src/jpsxdec/modules/spu/DiscItemSpu.java
+++ b/jpsxdec/src/jpsxdec/modules/spu/DiscItemSpu.java
@@ -54,6 +54,7 @@
import jpsxdec.i18n.UnlocalizedMessage;
import jpsxdec.i18n.exception.LocalizedDeserializationFail;
import jpsxdec.util.ExposedBAOS;
+import jpsxdec.util.Misc;
/** Represents a PlayStation Sound Processing Unit (SPU) audio clip.
* There's no way to know the sample rate of SPU clips, so the user
@@ -147,7 +148,7 @@ public void setSampleRate(int iSampleRate) {
public @Nonnull ILocalizedMessage getInterestingDescription() {
int iPcmSampleCount = _iSoundUnitCount * SoundUnitDecoder.SAMPLES_PER_SOUND_UNIT;
double dblApproxDuration = iPcmSampleCount / (double)_iSampleRate;
- Date secs = new Date(0, 0, 0, 0, 0, Math.max((int)dblApproxDuration, 1));
+ Date secs = Misc.dateFromSeconds(Math.max((int)dblApproxDuration, 1));
return new UnlocalizedMessage(MessageFormat.format("{0} samples at {1} Hz = {2,time,m:ss}", iPcmSampleCount, _iSampleRate, secs)); // I18N
}
diff --git a/jpsxdec/src/jpsxdec/modules/spu/SpuSaverBuilder.java b/jpsxdec/src/jpsxdec/modules/spu/SpuSaverBuilder.java
index 7072b73..02f97e4 100644
--- a/jpsxdec/src/jpsxdec/modules/spu/SpuSaverBuilder.java
+++ b/jpsxdec/src/jpsxdec/modules/spu/SpuSaverBuilder.java
@@ -125,6 +125,7 @@ private SpuSaverFormat(@Nonnull JavaAudioFormat jFmt) {
return _sExtension;
}
+ @Override
public String toString() {
if (_jFmt != null)
return _jFmt.toString();
@@ -318,14 +319,14 @@ public void commandLineOptions(@Nonnull ArgParser ap, @Nonnull FeedbackStream fb
// TODO
}
}
- public void printSelectedOptions(@Nonnull FeedbackStream fbs) {
+ public void printSelectedOptions(@Nonnull ILocalizedLogger log) {
SpuSaverFormat fmt = getContainerFormat();
JavaAudioFormat jFmt = fmt.getJavaType();
if (jFmt != null) {
- fbs.println(I.CMD_VOLUME_PERCENT(_dblVolume));
- fbs.println(I.CMD_AUDIO_FORMAT(jFmt.getCmdId()));
+ log.log(Level.INFO, I.CMD_VOLUME_PERCENT(_dblVolume));
+ log.log(Level.INFO, I.CMD_AUDIO_FORMAT(jFmt.getCmdId()));
}
- fbs.println(I.CMD_FILENAME(getFileRelativePath()));
+ log.log(Level.INFO, I.CMD_FILENAME(getFileRelativePath()));
}
public @Nonnull ILocalizedMessage getOutputSummary() {
@@ -341,6 +342,7 @@ public void startSave(@Nonnull ProgressLogger pl, @CheckForNull File directory)
throws LoggedFailure, TaskCanceledException
{
clearGeneratedFiles();
+ printSelectedOptions(pl);
pl.progressStart(1);
File outputFile = new File(directory, getFileRelativePath().getPath());
diff --git a/jpsxdec/src/jpsxdec/modules/square/DiscIndexerSquare.java b/jpsxdec/src/jpsxdec/modules/square/DiscIndexerSquareAudio.java
similarity index 98%
rename from jpsxdec/src/jpsxdec/modules/square/DiscIndexerSquare.java
rename to jpsxdec/src/jpsxdec/modules/square/DiscIndexerSquareAudio.java
index 41a7626..48e2fef 100644
--- a/jpsxdec/src/jpsxdec/modules/square/DiscIndexerSquare.java
+++ b/jpsxdec/src/jpsxdec/modules/square/DiscIndexerSquareAudio.java
@@ -52,7 +52,7 @@
/** Watches for Square's unique audio format streams.
* All known games that use Square audio run their streaming media at 2x
* disc speed. */
-public class DiscIndexerSquare extends DiscIndexer
+public class DiscIndexerSquareAudio extends DiscIndexer
implements SquareAudioSectorToSquareAudioSectorPair.Listener
{
@@ -110,7 +110,7 @@ public boolean pairDone(@Nonnull SquareAudioSectorPair pair) {
@CheckForNull
private AudioBuilder _audBldr;
- public DiscIndexerSquare(@Nonnull ILocalizedLogger errLog) {
+ public DiscIndexerSquareAudio(@Nonnull ILocalizedLogger errLog) {
_errLog = errLog;
}
diff --git a/jpsxdec/src/jpsxdec/modules/square/DiscItemSquareAudioStream.java b/jpsxdec/src/jpsxdec/modules/square/DiscItemSquareAudioStream.java
index 00d5873..48dd8df 100644
--- a/jpsxdec/src/jpsxdec/modules/square/DiscItemSquareAudioStream.java
+++ b/jpsxdec/src/jpsxdec/modules/square/DiscItemSquareAudioStream.java
@@ -67,6 +67,7 @@
import jpsxdec.modules.sharedaudio.ISectorAudioDecoder;
import jpsxdec.util.IO;
import jpsxdec.util.IncompatibleException;
+import jpsxdec.util.Misc;
import jpsxdec.util.TaskCanceledException;
/** Represents a series of Square SPU ADPCM sectors that combine to make an audio stream.
@@ -155,7 +156,7 @@ public int getSampleFramesPerSecond() {
@Override
public @Nonnull ILocalizedMessage getInterestingDescription() {
// unable to find ANY sources of info about how to localize durations
- Date secs = new Date(0, 0, 0, 0, 0, (int)Math.max(getSampleFrameCount() / _iSampleFramesPerSecond, 1));
+ Date secs = Misc.dateFromSeconds((int)Math.max(getSampleFrameCount() / _iSampleFramesPerSecond, 1));
return I.GUI_AUDIO_DESCRIPTION(secs, _iSampleFramesPerSecond, 2);
}
diff --git a/jpsxdec/src/jpsxdec/modules/square/SectorChronoXVideo.java b/jpsxdec/src/jpsxdec/modules/square/SectorChronoXVideo.java
index 63a3115..3b0e6b0 100644
--- a/jpsxdec/src/jpsxdec/modules/square/SectorChronoXVideo.java
+++ b/jpsxdec/src/jpsxdec/modules/square/SectorChronoXVideo.java
@@ -82,10 +82,10 @@ public SectorChronoXVideo(@Nonnull CdSector cdSector) {
_header.lngMagic != CHRONO_CROSS_VIDEO_CHUNK_MAGIC2)
return;
- if (!_header.isChunkNumberStandard()) return;
- if (!_header.isChunksInFrameStandard()) return;
- if (!_header.isFrameNumberStandard()) return;
- if (!_header.isUsedDemuxSizeStandard()) return;
+ if (!_header.hasStandardChunkNumber()) return;
+ if (!_header.hasStandardChunksInFrame()) return;
+ if (!_header.hasStandardFrameNumber()) return;
+ if (!_header.hasStandardUsedDemuxSize()) return;
_iWidth = cdSector.readSInt16LE(16);
if (_iWidth < 1) return;
_iHeight = cdSector.readSInt16LE(18);
diff --git a/jpsxdec/src/jpsxdec/modules/square/SectorClaimToSquareAudioSector.java b/jpsxdec/src/jpsxdec/modules/square/SectorClaimToSquareAudioSector.java
index c856140..3c2e4b1 100644
--- a/jpsxdec/src/jpsxdec/modules/square/SectorClaimToSquareAudioSector.java
+++ b/jpsxdec/src/jpsxdec/modules/square/SectorClaimToSquareAudioSector.java
@@ -41,6 +41,7 @@
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import jpsxdec.cdreaders.CdSector;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.SectorClaimSystem;
import jpsxdec.util.IOIterator;
@@ -49,8 +50,9 @@
public class SectorClaimToSquareAudioSector extends SectorClaimSystem.SectorClaimer {
public interface Listener {
- void sectorRead(@Nonnull ISquareAudioSector squareAudioSector, @Nonnull ILocalizedLogger log);
- void endOfSectors(@Nonnull ILocalizedLogger log);
+ void sectorRead(@Nonnull ISquareAudioSector squareAudioSector, @Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
+ void endOfSectors(@Nonnull ILocalizedLogger log) throws LoggedFailure;
}
public static @CheckForNull ISquareAudioSector id(@Nonnull CdSector sector) {
@@ -76,7 +78,7 @@ public void setListener(@CheckForNull Listener listener) {
public void sectorRead(@Nonnull SectorClaimSystem.ClaimableSector cs,
@Nonnull IOIterator peekIt,
@Nonnull ILocalizedLogger log)
- throws IOException
+ throws IOException, SectorClaimSystem.ClaimerFailure
{
if (cs.isClaimed())
return;
@@ -84,13 +86,25 @@ public void sectorRead(@Nonnull SectorClaimSystem.ClaimableSector cs,
if (audSector == null)
return;
cs.claim(audSector);
- if (_listener != null && sectorIsInRange(cs.getSector().getSectorIndexFromStart()))
- _listener.sectorRead(audSector, log);
+ if (_listener != null && sectorIsInRange(cs.getSector().getSectorIndexFromStart())) {
+ try {
+ _listener.sectorRead(audSector, log);
+ } catch (LoggedFailure ex) {
+ throw new SectorClaimSystem.ClaimerFailure(ex);
+ }
+ }
}
- public void endOfSectors(@Nonnull ILocalizedLogger log) {
- if (_listener != null)
- _listener.endOfSectors(log);
+ public void endOfSectors(@Nonnull ILocalizedLogger log)
+ throws SectorClaimSystem.ClaimerFailure
+ {
+ if (_listener != null) {
+ try {
+ _listener.endOfSectors(log);
+ } catch (LoggedFailure ex) {
+ throw new SectorClaimSystem.ClaimerFailure(ex);
+ }
+ }
}
}
diff --git a/jpsxdec/src/jpsxdec/modules/square/SectorFF9.java b/jpsxdec/src/jpsxdec/modules/square/SectorFF9.java
index 9cabc5d..1cfc776 100644
--- a/jpsxdec/src/jpsxdec/modules/square/SectorFF9.java
+++ b/jpsxdec/src/jpsxdec/modules/square/SectorFF9.java
@@ -51,6 +51,7 @@
import jpsxdec.modules.video.sectorbased.ISelfDemuxingVideoSector;
import jpsxdec.modules.video.sectorbased.SectorBasedFrameReplace;
import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_STRv2;
+import jpsxdec.psxvideo.mdec.Calc;
import jpsxdec.util.ByteArrayFPIS;
import jpsxdec.util.IO;
@@ -176,6 +177,7 @@ public SectorFF9Video(@Nonnull CdSector cdSector) {
// .. Public functions .................................................
+ @Override
public String toString() {
return String.format(
"%s %s frame:%d chunk:%d/%d %dx%d ver:%d " +
@@ -245,8 +247,8 @@ public void replaceVideoSectorHeader(@Nonnull byte[] abNewDemuxData, int iNewUse
IO.writeInt32LE(abCurrentVidSectorHeader, 12, iDemuxSizeForHeader / 4);
IO.writeInt16LE(abCurrentVidSectorHeader, 20,
- BitStreamUncompressor_STRv2.calculateHalfCeiling32(iNewMdecCodeCount));
- IO.writeInt16LE(abCurrentVidSectorHeader, 24, (short)(header.getQscale()));
+ Calc.calculateHalfCeiling32(iNewMdecCodeCount));
+ IO.writeInt16LE(abCurrentVidSectorHeader, 24, (short)(header.getQuantizationScale()));
}
}
diff --git a/jpsxdec/src/jpsxdec/modules/square/SquareAKAOstruct.java b/jpsxdec/src/jpsxdec/modules/square/SquareAKAOstruct.java
index e52c396..5a80781 100644
--- a/jpsxdec/src/jpsxdec/modules/square/SquareAKAOstruct.java
+++ b/jpsxdec/src/jpsxdec/modules/square/SquareAKAOstruct.java
@@ -64,6 +64,7 @@ public SquareAKAOstruct(@Nonnull CdSector cdSector, int iReadPos) {
BytesOfData = cdSector.readUInt32LE(iReadPos+32);
}
+ @Override
public String toString() {
return String.format(
"AKAO:%s frame-1:%d ?:%04x Size:%d",
diff --git a/jpsxdec/src/jpsxdec/modules/square/SquareAudioSectorPairToAudioPacket.java b/jpsxdec/src/jpsxdec/modules/square/SquareAudioSectorPairToAudioPacket.java
index 37f802d..7a78c60 100644
--- a/jpsxdec/src/jpsxdec/modules/square/SquareAudioSectorPairToAudioPacket.java
+++ b/jpsxdec/src/jpsxdec/modules/square/SquareAudioSectorPairToAudioPacket.java
@@ -45,6 +45,7 @@
import javax.sound.sampled.AudioFormat;
import jpsxdec.adpcm.SpuAdpcmDecoder;
import jpsxdec.i18n.I;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.sharedaudio.DecodedAudioPacket;
import jpsxdec.util.Fraction;
@@ -65,7 +66,9 @@ public void setListener(@CheckForNull DecodedAudioPacket.Listener listener) {
_listener = listener;
}
- public void pairDone(@Nonnull SquareAudioSectorPair pair, @Nonnull ILocalizedLogger log) {
+ public void pairDone(@Nonnull SquareAudioSectorPair pair, @Nonnull ILocalizedLogger log)
+ throws LoggedFailure
+ {
_buffer.reset();
try {
long lngSamplesWritten = _decoder.getSampleFramesWritten();
diff --git a/jpsxdec/src/jpsxdec/modules/square/SquareAudioSectorToSquareAudioSectorPair.java b/jpsxdec/src/jpsxdec/modules/square/SquareAudioSectorToSquareAudioSectorPair.java
index 0dd490f..c47abfa 100644
--- a/jpsxdec/src/jpsxdec/modules/square/SquareAudioSectorToSquareAudioSectorPair.java
+++ b/jpsxdec/src/jpsxdec/modules/square/SquareAudioSectorToSquareAudioSectorPair.java
@@ -39,12 +39,14 @@
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
public class SquareAudioSectorToSquareAudioSectorPair implements SectorClaimToSquareAudioSector.Listener {
public interface Listener {
- void pairDone(@Nonnull SquareAudioSectorPair pair, @Nonnull ILocalizedLogger log);
+ void pairDone(@Nonnull SquareAudioSectorPair pair, @Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
void endOfSectors(@Nonnull ILocalizedLogger log);
}
@@ -62,7 +64,9 @@ public void setListener(@CheckForNull Listener listener) {
_listener = listener;
}
- public void sectorRead(@Nonnull ISquareAudioSector audSector, @Nonnull ILocalizedLogger log) {
+ public void sectorRead(@Nonnull ISquareAudioSector audSector, @Nonnull ILocalizedLogger log)
+ throws LoggedFailure
+ {
if (_leftAudioSector != null) {
if (isPair(_leftAudioSector, audSector)) {
@@ -98,7 +102,7 @@ public void sectorRead(@Nonnull ISquareAudioSector audSector, @Nonnull ILocalize
}
}
- private void leftOnlyDone(@Nonnull ILocalizedLogger log) {
+ private void leftOnlyDone(@Nonnull ILocalizedLogger log) throws LoggedFailure {
_listener.pairDone(new SquareAudioSectorPair(
_leftAudioSector, null,
_leftAudioSector.getHeaderFrameNumber(),
@@ -119,7 +123,7 @@ private static boolean isPair(@Nonnull ISquareAudioSector left, @Nonnull ISquare
left.getSectorNumber() + 1 == right.getSectorNumber();
}
- public void endOfSectors(@Nonnull ILocalizedLogger log) {
+ public void endOfSectors(@Nonnull ILocalizedLogger log) throws LoggedFailure {
if (_listener != null) {
if (_leftAudioSector != null)
leftOnlyDone(log);
diff --git a/jpsxdec/src/jpsxdec/modules/strvideo/DiscIndexerStrVideo.java b/jpsxdec/src/jpsxdec/modules/strvideo/DiscIndexerStrVideo.java
index fd5ece9..2c6a2df 100644
--- a/jpsxdec/src/jpsxdec/modules/strvideo/DiscIndexerStrVideo.java
+++ b/jpsxdec/src/jpsxdec/modules/strvideo/DiscIndexerStrVideo.java
@@ -73,6 +73,8 @@ private static class VidBuilder {
@Nonnull
private final SectorBasedVideoInfoBuilder _vidInfoBuilder;
private int _iLastFrameNumber;
+ private final boolean _blnHasSpecialBs;
+
public VidBuilder(@Nonnull DemuxedFrameWithNumberAndDims firstFrame) {
_iLastFrameNumber = firstFrame.getHeaderFrameNumber();
@@ -81,6 +83,7 @@ public VidBuilder(@Nonnull DemuxedFrameWithNumberAndDims firstFrame) {
firstFrame.getStartSector(), firstFrame.getEndSector());
_indexSectorFrameNumberBuilder = new IndexSectorFrameNumber.Format.Builder(firstFrame.getStartSector());
_headerFrameNumberBuilder = new HeaderFrameNumber.Format.Builder(firstFrame.getHeaderFrameNumber());
+ _blnHasSpecialBs = firstFrame.getCustomFrameMdecStream() != null;
}
/** @return if the frame was accepted as part of this video, otherwise start a new video. */
@@ -96,6 +99,8 @@ public boolean addFrame(@Nonnull DemuxedFrameWithNumberAndDims frame) {
// a huge gap in frame numbers
return false;
}
+ if (_blnHasSpecialBs && frame.getCustomFrameMdecStream() == null)
+ return false;
_iLastFrameNumber = frame.getHeaderFrameNumber();
_vidInfoBuilder.next(frame.getStartSector(), frame.getEndSector());
_indexSectorFrameNumberBuilder.addFrameStartSector(frame.getStartSector());
@@ -109,7 +114,8 @@ public boolean addFrame(@Nonnull DemuxedFrameWithNumberAndDims frame) {
_vidInfoBuilder.makeDims(),
_indexSectorFrameNumberBuilder.makeFormat(),
_vidInfoBuilder.makeStrVidInfo(),
- _headerFrameNumberBuilder.makeFormat());
+ _headerFrameNumberBuilder.makeFormat(),
+ !_blnHasSpecialBs);
}
}
diff --git a/jpsxdec/src/jpsxdec/modules/strvideo/DiscItemStrVideoStream.java b/jpsxdec/src/jpsxdec/modules/strvideo/DiscItemStrVideoStream.java
index 9abe1e0..20a347a 100644
--- a/jpsxdec/src/jpsxdec/modules/strvideo/DiscItemStrVideoStream.java
+++ b/jpsxdec/src/jpsxdec/modules/strvideo/DiscItemStrVideoStream.java
@@ -46,6 +46,7 @@
import jpsxdec.discitems.DiscItem;
import jpsxdec.discitems.SerializedDiscItem;
import jpsxdec.i18n.exception.LocalizedDeserializationFail;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.DebugLogger;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.IIdentifiedSector;
@@ -78,15 +79,19 @@ public class DiscItemStrVideoStream extends DiscItemSectorBasedVideoStream {
@Nonnull
private final HeaderFrameNumber.Format _headerFrameNumberFormat;
+ private static final String INDEPENDENT_BITSTREAM = "Independent bitstream";
+ private final boolean _blnHasIndependentBitstream;
public DiscItemStrVideoStream(@Nonnull CdFileSectorReader cd, int iStartSector,
int iEndSector, @Nonnull Dimensions dim,
@Nonnull IndexSectorFrameNumber.Format indexSectorFrameNumberFormat,
@Nonnull SectorBasedVideoInfo strVidInfo,
- @Nonnull HeaderFrameNumber.Format headerFrameNumberFormat)
+ @Nonnull HeaderFrameNumber.Format headerFrameNumberFormat,
+ boolean blnHasIndependentBitstream)
{
super(cd, iStartSector, iEndSector, dim, indexSectorFrameNumberFormat, strVidInfo);
_headerFrameNumberFormat = headerFrameNumberFormat;
+ _blnHasIndependentBitstream = blnHasIndependentBitstream;
}
public DiscItemStrVideoStream(@Nonnull CdFileSectorReader cd, @Nonnull SerializedDiscItem fields)
@@ -94,12 +99,18 @@ public DiscItemStrVideoStream(@Nonnull CdFileSectorReader cd, @Nonnull Serialize
{
super(cd, fields);
_headerFrameNumberFormat = new HeaderFrameNumber.Format(fields);
+ if (fields.hasField(INDEPENDENT_BITSTREAM))
+ _blnHasIndependentBitstream = fields.getYesNo(INDEPENDENT_BITSTREAM);
+ else
+ _blnHasIndependentBitstream = true;
}
@Override
public @Nonnull SerializedDiscItem serialize() {
SerializedDiscItem serial = super.serialize();
_headerFrameNumberFormat.serialize(serial);
+ if (!_blnHasIndependentBitstream)
+ serial.addYesNo(INDEPENDENT_BITSTREAM, _blnHasIndependentBitstream);
return serial;
}
@@ -108,6 +119,11 @@ public DiscItemStrVideoStream(@Nonnull CdFileSectorReader cd, @Nonnull Serialize
return TYPE_ID;
}
+ @Override
+ public boolean hasIndependentBitstream() {
+ return _blnHasIndependentBitstream;
+ }
+
@Override
public int getParentRating(@Nonnull DiscItem child) {
if (!(child instanceof DiscItemAudioStream))
@@ -204,7 +220,9 @@ public void attachToSectorClaimer(@Nonnull SectorClaimSystem scs) {
s2sv.setListener(new StrVideoSectorToDemuxedStrFrame(this));
}
- public void frameComplete(@Nonnull DemuxedFrameWithNumberAndDims frame, @Nonnull ILocalizedLogger log) {
+ public void frameComplete(@Nonnull DemuxedFrameWithNumberAndDims frame, @Nonnull ILocalizedLogger log)
+ throws LoggedFailure
+ {
FrameNumber fn = _frameNumberFormatter.next(frame.getStartSector(),
frame.getHeaderFrameNumber(), log);
frame.setFrame(fn);
diff --git a/jpsxdec/src/jpsxdec/modules/strvideo/SectorAliceNullVideo.java b/jpsxdec/src/jpsxdec/modules/strvideo/SectorAliceNullVideo.java
index 43de65c..fe6d028 100644
--- a/jpsxdec/src/jpsxdec/modules/strvideo/SectorAliceNullVideo.java
+++ b/jpsxdec/src/jpsxdec/modules/strvideo/SectorAliceNullVideo.java
@@ -74,14 +74,14 @@ public SectorAliceNullVideo(@Nonnull CdSector cdSector) {
if (_header.lngMagic != ALICE_VIDEO_SECTOR_MAGIC)
return;
- if (!_header.isChunkNumberStandard())
+ if (!_header.hasStandardChunkNumber())
return;
if (_header.iChunksInThisFrame < 3)
return;
// null frames between movies have a frame number of 0xFFFF
// the high bit signifies the end of a video
- if (!_header.isFrameNumberStandard())
+ if (!_header.hasStandardFrameNumber())
return;
// make sure all 16 bytes are zero
diff --git a/jpsxdec/src/jpsxdec/modules/strvideo/SectorClaimToStrVideoSector.java b/jpsxdec/src/jpsxdec/modules/strvideo/SectorClaimToStrVideoSector.java
index e12e4e2..fa09971 100644
--- a/jpsxdec/src/jpsxdec/modules/strvideo/SectorClaimToStrVideoSector.java
+++ b/jpsxdec/src/jpsxdec/modules/strvideo/SectorClaimToStrVideoSector.java
@@ -40,6 +40,7 @@
import java.io.IOException;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.SectorClaimSystem;
import jpsxdec.modules.video.sectorbased.ISelfDemuxingVideoSector;
@@ -51,8 +52,10 @@ public class SectorClaimToStrVideoSector extends SectorClaimSystem.SectorClaimer
public interface Listener {
void feedSector(@Nonnull ISelfDemuxingVideoSector vidSector,
- @Nonnull ILocalizedLogger log);
- void endOfSectors(@Nonnull ILocalizedLogger log);
+ @Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
+ void endOfSectors(@Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
}
@CheckForNull
@@ -70,7 +73,7 @@ public void setListener(@CheckForNull Listener listener) {
public void sectorRead(@Nonnull SectorClaimSystem.ClaimableSector cs,
@Nonnull IOIterator peekIt,
@Nonnull ILocalizedLogger log)
- throws IOException
+ throws IOException, SectorClaimSystem.ClaimerFailure
{
if (cs.isClaimed())
return;
@@ -79,12 +82,23 @@ public void sectorRead(@Nonnull SectorClaimSystem.ClaimableSector cs,
if (vidSector != null && _listener != null &&
sectorIsInRange(cs.getSector().getSectorIndexFromStart()))
{
- _listener.feedSector(vidSector, log);
+ try {
+ _listener.feedSector(vidSector, log);
+ } catch (LoggedFailure ex) {
+ throw new SectorClaimSystem.ClaimerFailure(ex);
+ }
}
}
- public void endOfSectors(@Nonnull ILocalizedLogger log) {
- if (_listener != null)
- _listener.endOfSectors(log);
+ public void endOfSectors(@Nonnull ILocalizedLogger log)
+ throws SectorClaimSystem.ClaimerFailure
+ {
+ if (_listener != null) {
+ try {
+ _listener.endOfSectors(log);
+ } catch (LoggedFailure ex) {
+ throw new SectorClaimSystem.ClaimerFailure(ex);
+ }
+ }
}
}
diff --git a/jpsxdec/src/jpsxdec/modules/strvideo/SectorFF7Video.java b/jpsxdec/src/jpsxdec/modules/strvideo/SectorFF7Video.java
index b70462d..0dab7a4 100644
--- a/jpsxdec/src/jpsxdec/modules/strvideo/SectorFF7Video.java
+++ b/jpsxdec/src/jpsxdec/modules/strvideo/SectorFF7Video.java
@@ -77,9 +77,9 @@ public SectorFF7Video(@Nonnull CdSector cdSector) {
return;
if (_header.lngMagic != SectorStrVideo.VIDEO_SECTOR_MAGIC) return;
- if (!_header.isChunkNumberStandard()) return;
+ if (!_header.hasStandardChunkNumber()) return;
if (_header.iChunksInThisFrame < 6 || _header.iChunksInThisFrame > 10) return;
- if (!_header.isFrameNumberStandard()) return;
+ if (!_header.hasStandardFrameNumber()) return;
// this block is unfortunately necessary to prevent false-positives with Lain sectors
if (_header.iUsedDemuxedSize < 2500 || _header.iUsedDemuxedSize > 21000) return;
_iWidth = cdSector.readSInt16LE(16);
diff --git a/jpsxdec/src/jpsxdec/modules/strvideo/SectorIkiVideo.java b/jpsxdec/src/jpsxdec/modules/strvideo/SectorIkiVideo.java
index d3f29fd..d9b02ab 100644
--- a/jpsxdec/src/jpsxdec/modules/strvideo/SectorIkiVideo.java
+++ b/jpsxdec/src/jpsxdec/modules/strvideo/SectorIkiVideo.java
@@ -45,7 +45,7 @@
import jpsxdec.modules.video.sectorbased.SectorAbstractVideo;
import jpsxdec.modules.video.sectorbased.VideoSectorCommon16byteHeader;
import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_Iki;
-import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_STRv2;
+import jpsxdec.psxvideo.mdec.Calc;
import jpsxdec.util.IO;
@@ -78,10 +78,10 @@ public SectorIkiVideo(@Nonnull CdSector cdSector) {
return;
if (_header.lngMagic != SectorStrVideo.VIDEO_SECTOR_MAGIC) return;
- if (!_header.isChunkNumberStandard()) return;
- if (!_header.isChunksInFrameStandard()) return;
- if (!_header.isFrameNumberStandard()) return;
- if (!_header.isUsedDemuxSizeStandard()) return;
+ if (!_header.hasStandardChunkNumber()) return;
+ if (!_header.hasStandardChunksInFrame()) return;
+ if (!_header.hasStandardFrameNumber()) return;
+ if (!_header.hasStandardUsedDemuxSize()) return;
_iWidth = cdSector.readSInt16LE(16);
if (_iWidth < 1) return;
_iHeight = cdSector.readSInt16LE(18);
@@ -160,7 +160,7 @@ public void replaceVideoSectorHeader(@Nonnull byte[] abNewDemuxData, int iNewUse
IO.writeInt32LE(abCurrentVidSectorHeader, 12, iDemuxSizeForHeader);
IO.writeInt16LE(abCurrentVidSectorHeader, 20,
- BitStreamUncompressor_STRv2.calculateHalfCeiling32(iNewMdecCodeCount));
+ Calc.calculateHalfCeiling32(iNewMdecCodeCount));
}
}
diff --git a/jpsxdec/src/jpsxdec/modules/strvideo/SectorLainVideo.java b/jpsxdec/src/jpsxdec/modules/strvideo/SectorLainVideo.java
index 3a23594..72cd617 100644
--- a/jpsxdec/src/jpsxdec/modules/strvideo/SectorLainVideo.java
+++ b/jpsxdec/src/jpsxdec/modules/strvideo/SectorLainVideo.java
@@ -78,7 +78,7 @@ public SectorLainVideo(@Nonnull CdSector cdSector) {
if (_header.lngMagic != SectorStrVideo.VIDEO_SECTOR_MAGIC) return;
- if (!_header.isChunkNumberStandard()) return;
+ if (!_header.hasStandardChunkNumber()) return;
// this detail helps to avoid matching FF7 video sectors
if (_header.iChunksInThisFrame != 9 && _header.iChunksInThisFrame != 10) return;
if (_header.iFrameNumber < 1) return;
diff --git a/jpsxdec/src/jpsxdec/modules/strvideo/SectorReBoot.java b/jpsxdec/src/jpsxdec/modules/strvideo/SectorReBoot.java
new file mode 100644
index 0000000..02703ac
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/strvideo/SectorReBoot.java
@@ -0,0 +1,154 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2007-2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.strvideo;
+
+import javax.annotation.Nonnull;
+import jpsxdec.cdreaders.CdSector;
+import jpsxdec.cdreaders.CdSectorXaSubHeader;
+import jpsxdec.cdreaders.CdSectorXaSubHeader.SubMode;
+import jpsxdec.modules.video.sectorbased.SectorAbstractVideo;
+import jpsxdec.modules.video.sectorbased.VideoSectorCommon16byteHeader;
+import jpsxdec.util.IO;
+
+
+/** ReBoot video sector variant.
+ * Thanks to XBrav for doing the research to make this possible. */
+public class SectorReBoot extends SectorAbstractVideo {
+
+ @Nonnull
+ private final VideoSectorCommon16byteHeader _header;
+ private int _iWidth; // 16 [2 bytes]
+ private int _iHeight; // 18 [2 bytes]
+ // zeroes, in place of // 20 [2 bytes]
+ // RunLengthCodeCount
+ /** A number a little larger than the number of frames in the video. */
+ private int _iMoreThanFrameCount; // 22 [2 bytes]
+ // zeroes, in place of // 24 [4 bytes]
+ // QuantizationScale
+ // Version
+ // zeroes // 28 [4 bytes]
+ // 32 TOTAL
+
+ @Override
+ public int getVideoSectorHeaderSize() { return 32; }
+
+ public SectorReBoot(@Nonnull CdSector cdSector) {
+ super(cdSector);
+ _header = new VideoSectorCommon16byteHeader(cdSector);
+ if (isSuperInvalidElseReset()) return;
+
+ CdSectorXaSubHeader sh = cdSector.getSubHeader();
+ if (sh != null) {
+ // only if it has a sector header should we check if it reports REALTIME | VIDEO
+ if (sh.getSubMode().toByte() != (SubMode.MASK_REAL_TIME | SubMode.MASK_VIDEO))
+ return;
+ }
+
+ if (_header.lngMagic != SectorStrVideo.VIDEO_SECTOR_MAGIC) return;
+ if (!_header.hasStandardChunkNumber()) return;
+ if (!_header.hasStandardChunksInFrame()) return;
+ if (!_header.hasStandardFrameNumber()) return;
+ if (!_header.hasStandardUsedDemuxSize()) return;
+ // some non-video sectors look a little like video sectors but with 1x1 dimensions
+ _iWidth = cdSector.readSInt16LE(16);
+ if (_iWidth < 2) return;
+ _iHeight = cdSector.readSInt16LE(18);
+ if (_iHeight < 2) return;
+ int iZeroes = cdSector.readUInt16LE(20);
+ if (iZeroes != 0) return;
+ _iMoreThanFrameCount = cdSector.readUInt16LE(22);
+ if (_iMoreThanFrameCount < 1) return;
+ for (int i = 0; i < 8; i++) {
+ if (cdSector.readUserDataByte(24 + i) != 0) return;
+ }
+ setProbability(100);
+ }
+
+ // .. Public methods ...................................................
+
+ public @Nonnull String getTypeName() {
+ return "ReBoot video";
+ }
+
+ public String toString() {
+ return String.format("%s %s frame:%d chunk:%d/%d %dx%d " +
+ "{demux frame size=%d %d>frame count}",
+ getTypeName(),
+ super.cdToString(),
+ _header.iFrameNumber,
+ _header.iChunkNumber,
+ _header.iChunksInThisFrame,
+ _iWidth,
+ _iHeight,
+ _header.iUsedDemuxedSize,
+ _iMoreThanFrameCount
+ );
+ }
+
+ public int getChunkNumber() {
+ return _header.iChunkNumber;
+ }
+
+ public int getChunksInFrame() {
+ return _header.iChunksInThisFrame;
+ }
+
+ public int getHeaderFrameNumber() {
+ return _header.iFrameNumber;
+ }
+
+ public int getHeight() {
+ return _iHeight;
+ }
+
+ public int getWidth() {
+ return _iWidth;
+ }
+
+ public void replaceVideoSectorHeader(@Nonnull byte[] abNewDemuxData, int iNewUsedSize,
+ int iNewMdecCodeCount, @Nonnull byte[] abCurrentVidSectorHeader)
+ {
+ // Most values are 0 in the header
+
+ // Qscale is not required, so I guess no reason to restrict the frame type
+
+ int iDemuxSizeForHeader = (iNewUsedSize + 3) & ~3;
+ IO.writeInt32LE(abCurrentVidSectorHeader, 12, iDemuxSizeForHeader);
+ }
+}
+
diff --git a/jpsxdec/src/jpsxdec/modules/strvideo/SectorStrVideo.java b/jpsxdec/src/jpsxdec/modules/strvideo/SectorStrVideo.java
index 9eff804..d572ec8 100644
--- a/jpsxdec/src/jpsxdec/modules/strvideo/SectorStrVideo.java
+++ b/jpsxdec/src/jpsxdec/modules/strvideo/SectorStrVideo.java
@@ -47,6 +47,7 @@
import jpsxdec.modules.video.sectorbased.VideoSectorCommon16byteHeader;
import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_STRv2;
import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_STRv3;
+import jpsxdec.psxvideo.mdec.Calc;
import jpsxdec.util.IO;
@@ -90,12 +91,12 @@ public SectorStrVideo(@Nonnull CdSector cdSector) {
}
if (_header.lngMagic != VIDEO_SECTOR_MAGIC) return;
- if (!_header.isChunkNumberStandard()) return;
- if (!_header.isChunksInFrameStandard()) return;
+ if (!_header.hasStandardChunkNumber()) return;
+ if (!_header.hasStandardChunksInFrame()) return;
// normal STR sectors have frame number starting at 1
// but this STR sector also covers similar sectors that may not follow that
- if (!_header.isFrameNumberStandard()) return;
- if (!_header.isUsedDemuxSizeStandard()) return;
+ if (!_header.hasStandardFrameNumber()) return;
+ if (!_header.hasStandardUsedDemuxSize()) return;
_iWidth = cdSector.readSInt16LE(16);
if (_iWidth < 1) return;
_iHeight = cdSector.readSInt16LE(18);
@@ -180,11 +181,11 @@ public static void replaceStrVideoSectorHeader(@Nonnull byte[] abNewDemuxData, i
BitStreamUncompressor_STRv2.StrV2Header v2Header = new BitStreamUncompressor_STRv2.StrV2Header(abNewDemuxData, iNewUsedSize);
if (v2Header.isValid()) {
- iQscale = v2Header.getQscale();
+ iQscale = v2Header.getQuantizationScale();
} else {
BitStreamUncompressor_STRv3.StrV3Header v3Header = new BitStreamUncompressor_STRv3.StrV3Header(abNewDemuxData, iNewUsedSize);
if (v3Header.isValid()) {
- iQscale = v3Header.getQscale();
+ iQscale = v3Header.getQuantizationScale();
} else {
throw new LocalizedIncompatibleException(I.REPLACE_FRAME_TYPE_NOT_V2_V3());
}
@@ -194,7 +195,7 @@ public static void replaceStrVideoSectorHeader(@Nonnull byte[] abNewDemuxData, i
IO.writeInt32LE(abCurrentVidSectorHeader, 12, iDemuxSizeForHeader);
IO.writeInt16LE(abCurrentVidSectorHeader, 20,
- BitStreamUncompressor_STRv2.calculateHalfCeiling32(iNewMdecCodeCount));
+ Calc.calculateHalfCeiling32(iNewMdecCodeCount));
IO.writeInt16LE(abCurrentVidSectorHeader, 24, (short)(iQscale));
}
diff --git a/jpsxdec/src/jpsxdec/modules/strvideo/StrVideoSectorToDemuxedStrFrame.java b/jpsxdec/src/jpsxdec/modules/strvideo/StrVideoSectorToDemuxedStrFrame.java
index 1000210..86b6b05 100644
--- a/jpsxdec/src/jpsxdec/modules/strvideo/StrVideoSectorToDemuxedStrFrame.java
+++ b/jpsxdec/src/jpsxdec/modules/strvideo/StrVideoSectorToDemuxedStrFrame.java
@@ -39,6 +39,7 @@
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.video.sectorbased.DemuxedFrameWithNumberAndDims;
import jpsxdec.modules.video.sectorbased.ISelfDemuxingVideoSector;
@@ -66,6 +67,7 @@ public void setListener(@CheckForNull DemuxedFrameWithNumberAndDims.Listener lis
public void feedSector(@Nonnull ISelfDemuxingVideoSector vidSector,
@Nonnull ILocalizedLogger log)
+ throws LoggedFailure
{
if (_currentFrame != null && !_currentFrame.addSectorIfPartOfFrame(vidSector))
endFrame(log);
@@ -85,15 +87,18 @@ public void feedSector(@Nonnull ISelfDemuxingVideoSector vidSector,
// _listener.endVideo();
}
- private void endFrame(@Nonnull ILocalizedLogger log) {
+ private void endFrame(@Nonnull ILocalizedLogger log) throws LoggedFailure {
if (_currentFrame == null)
return;
- if (_listener != null)
- _listener.frameComplete(_currentFrame.finishFrame(log), log);
+ if (_listener != null) {
+ DemuxedFrameWithNumberAndDims frame = _currentFrame.finishFrame(log);
+ if (frame != null)
+ _listener.frameComplete(frame, log);
+ }
_currentFrame = null;
}
- public void endOfSectors(@Nonnull ILocalizedLogger log) {
+ public void endOfSectors(@Nonnull ILocalizedLogger log) throws LoggedFailure {
endFrame(log);
if (_listener != null)
_listener.endOfSectors(log);
diff --git a/jpsxdec/src/jpsxdec/modules/tim/TimSaverBuilder.java b/jpsxdec/src/jpsxdec/modules/tim/TimSaverBuilder.java
index 0ff2a73..df08271 100644
--- a/jpsxdec/src/jpsxdec/modules/tim/TimSaverBuilder.java
+++ b/jpsxdec/src/jpsxdec/modules/tim/TimSaverBuilder.java
@@ -65,6 +65,7 @@
import jpsxdec.i18n.UnlocalizedMessage;
import jpsxdec.i18n.exception.LocalizedFileNotFoundException;
import jpsxdec.i18n.exception.LoggedFailure;
+import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.i18n.log.ProgressLogger;
import jpsxdec.tim.Tim;
import jpsxdec.util.ArgParser;
@@ -105,6 +106,7 @@ private TimSaveFormat(@Nonnull JavaImageFormat eJavaFmt) {
return _javaFmt;
}
+ @Override
public String toString() {
if (_javaFmt == null)
return "tim";
@@ -133,10 +135,9 @@ public String getExtension() {
for (JavaImageFormat jif : availableFormats) {
if (jif.isAvailable()) {
if (jif.hasTrueColor()) {
+ TRUE_COLOR_FORMAT_LIST.add(new TimSaveFormat(jif));
if (jif.hasAlpha())
TRUE_COLOR_ALPHA_FORMAT_LIST.add(new TimSaveFormat(jif));
- else
- TRUE_COLOR_FORMAT_LIST.add(new TimSaveFormat(jif));
}
PALETTE_FORMAT_LIST.add(new TimSaveFormat(jif));
}
@@ -294,7 +295,7 @@ public void commandLineOptions(@Nonnull ArgParser ap, @Nonnull FeedbackStream fb
if (timpalettes.value != null) {
boolean[] ablnNewValues = parseNumberListRange(timpalettes.value, getPaletteCount());
if (ablnNewValues == null) {
- fbs.printlnWarn(I.CMD_TIM_PALETTE_LIST_INVALID(timpalettes.value));
+ fbs.printlnWarn(I.CMD_IGNORING_INVALID_VALUE_FOR_CMD(timpalettes.value, "-pal"));
} else {
System.arraycopy(ablnNewValues, 0, _ablnSavePalette, 0, getPaletteCount());
}
@@ -303,7 +304,7 @@ public void commandLineOptions(@Nonnull ArgParser ap, @Nonnull FeedbackStream fb
if (format.value != null) {
TimSaveFormat fmt = fromCmdLine(format.value);
if (fmt == null) {
- fbs.printlnWarn(I.CMD_TIM_SAVE_FORMAT_INVALID(format.value));
+ fbs.printlnWarn(I.CMD_IGNORING_INVALID_VALUE_FOR_CMD(format.value, "-if,-imgfmt"));
} else {
setImageFormat(fmt);
}
@@ -351,9 +352,10 @@ public void printHelp(@Nonnull FeedbackStream fbs) {
tfb.write(fbs.getUnderlyingStream());
}
- public void printSelectedOptions(@Nonnull FeedbackStream fbs) {
- fbs.println(I.CMD_TIM_SAVE_FORMAT(getImageFormat().getExtension()));
- fbs.println(getOutputFilesSummary());
+ public void printSelectedOptions(@Nonnull
+ ILocalizedLogger log) {
+ log.log(Level.INFO, I.CMD_TIM_SAVE_FORMAT(getImageFormat().getExtension()));
+ log.log(Level.INFO, getOutputFilesSummary());
}
private @Nonnull String makeTimFileName() {
@@ -375,6 +377,7 @@ public void startSave(@Nonnull ProgressLogger pl, @CheckForNull File directory)
throws LoggedFailure, TaskCanceledException
{
clearGeneratedFiles();
+ printSelectedOptions(pl);
if (getImageFormat() == TIM) {
startSaveTim(pl, directory, makeTimFileName());
} else {
diff --git a/jpsxdec/src/jpsxdec/modules/video/DiscItemVideoStream.java b/jpsxdec/src/jpsxdec/modules/video/DiscItemVideoStream.java
index db3f385..4ef00f9 100644
--- a/jpsxdec/src/jpsxdec/modules/video/DiscItemVideoStream.java
+++ b/jpsxdec/src/jpsxdec/modules/video/DiscItemVideoStream.java
@@ -57,6 +57,7 @@
import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor;
import jpsxdec.psxvideo.encode.ParsedMdecImage;
import jpsxdec.psxvideo.mdec.Calc;
+import jpsxdec.psxvideo.mdec.MdecInputStream;
import jpsxdec.util.BinaryDataNotRecognized;
import jpsxdec.util.Fraction;
import jpsxdec.util.TaskCanceledException;
@@ -133,6 +134,17 @@ final public int getFrameCount() {
/** Returns the sector on the disc where the video should start playing. */
abstract public int getAbsolutePresentationStartSector();
+ /** Returns if the raw video frame data (the bitstream) can be identified
+ * and decoded independent of any extra information.
+ * Nearly all videos do have bitstreams that can be identified and decoded
+ * all on their own (except for the frame dimensions usually).
+ * A few games however use very different bitstream formats that, on their
+ * own, would be impossible to decode. They need some additional
+ * contextual information to do so.
+ * The video saver uses this information to determine if the bitstream
+ * format (.bs) can be used as an output format. */
+ abstract public boolean hasIndependentBitstream();
+
/** Returns the approximate duration of the video in seconds.
* Intended for use with video playback progress bar. */
abstract public double getApproxDuration();
@@ -151,12 +163,16 @@ public void frameComplete(IDemuxedFrame frame) {
ps.println(" Available demux size: " + frame.getDemuxSize());
frame.printSectors(ps); // ideally would be indented by 4
- byte[] abBitStream = frame.copyDemuxData();
try {
- BitStreamUncompressor uncompressor = BitStreamUncompressor.identifyUncompressor(abBitStream, frame.getDemuxSize());
- ParsedMdecImage parsed = new ParsedMdecImage(uncompressor, getWidth(), getHeight());
- uncompressor.skipPaddingBits();
- ps.println(" Bitstream info: " + uncompressor);
+ MdecInputStream mis = frame.getCustomFrameMdecStream();
+ if (mis == null) {
+ byte[] abBitStream = frame.copyDemuxData();
+ BitStreamUncompressor uncompressor = BitStreamUncompressor.identifyUncompressor(abBitStream, frame.getDemuxSize());
+ uncompressor.skipPaddingBits();
+ mis = uncompressor;
+ }
+ ParsedMdecImage parsed = new ParsedMdecImage(mis, getWidth(), getHeight());
+ ps.println(" Frame data info: " + mis);
if (blnMore) {
int iMbWidth = Calc.macroblockDim(getWidth()),
iMbHeight = Calc.macroblockDim(getHeight());
diff --git a/jpsxdec/src/jpsxdec/modules/video/IDemuxedFrame.java b/jpsxdec/src/jpsxdec/modules/video/IDemuxedFrame.java
index dce130d..a15f6f0 100644
--- a/jpsxdec/src/jpsxdec/modules/video/IDemuxedFrame.java
+++ b/jpsxdec/src/jpsxdec/modules/video/IDemuxedFrame.java
@@ -38,18 +38,20 @@
package jpsxdec.modules.video;
import java.io.PrintStream;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import jpsxdec.cdreaders.CdFileSectorReader;
import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.video.framenumber.FrameNumber;
+import jpsxdec.psxvideo.mdec.MdecInputStream;
import jpsxdec.util.Fraction;
/** Universal demuxed video frame. */
public interface IDemuxedFrame {
public interface Listener {
- void frameComplete(@Nonnull IDemuxedFrame frame);
+ void frameComplete(@Nonnull IDemuxedFrame frame) throws LoggedFailure;
}
int getWidth();
@@ -71,12 +73,13 @@ public interface Listener {
/** Size of the demuxed frame. */
int getDemuxSize();
- /** Returns the contiguous demux copied into a buffer. If the supplied
- * buffer is not null and is big enough to fit the demuxed data, it is used,
- * otherwise a new buffer is created and returned.
- * @return the byte[] */
+ /** Returns the contiguous demux copied into a buffer. */
@Nonnull byte[] copyDemuxData();
+ /** The demux data my not be able to be converted to an mdec stream on its
+ * own. This can provide a direct mdec stream instead. */
+ @CheckForNull MdecInputStream getCustomFrameMdecStream();
+
void printSectors(@Nonnull PrintStream ps);
void writeToSectors(@Nonnull byte[] abNewDemux,
diff --git a/jpsxdec/src/jpsxdec/modules/video/framenumber/FrameNumberNumber.java b/jpsxdec/src/jpsxdec/modules/video/framenumber/FrameNumberNumber.java
index 5fb7d82..d5a2517 100644
--- a/jpsxdec/src/jpsxdec/modules/video/framenumber/FrameNumberNumber.java
+++ b/jpsxdec/src/jpsxdec/modules/video/framenumber/FrameNumberNumber.java
@@ -189,6 +189,14 @@ public void addNumber(int iFrameValue) {
}
}
+ public int getStartFrameValue() {
+ return _iStartFrameValue;
+ }
+
+ public int getLastFrameValue() {
+ return _iEndFrameValue;
+ }
+
public @Nonnull Format makeFormat() {
return new Format(_iStartFrameValue, _iEndFrameValue,
_iDuplicate, _iDuplicateMax);
diff --git a/jpsxdec/src/jpsxdec/modules/video/framenumber/HeaderFrameNumber.java b/jpsxdec/src/jpsxdec/modules/video/framenumber/HeaderFrameNumber.java
index 0cf27cd..04bafaa 100644
--- a/jpsxdec/src/jpsxdec/modules/video/framenumber/HeaderFrameNumber.java
+++ b/jpsxdec/src/jpsxdec/modules/video/framenumber/HeaderFrameNumber.java
@@ -76,13 +76,21 @@ public void addHeaderFrameNumber(int iHeaderFrameNumber) {
_headerNumberBuilder.addNumber(iHeaderFrameNumber);
}
+ public int getStartFrameNumber() {
+ return _headerNumberBuilder.getStartFrameValue();
+ }
+
+ public int getLastFrameNumber() {
+ return _headerNumberBuilder.getLastFrameValue();
+ }
+
public @Nonnull Format makeFormat() {
return new Format(_headerNumberBuilder.makeFormat());
}
}
- private static final String HEADER_FORMAT_KEY = "Header Frames";
+ public static final String HEADER_FORMAT_KEY = "Header Frames";
@Nonnull
private final FrameNumberNumber.Format _headerNumberFormat;
diff --git a/jpsxdec/src/jpsxdec/modules/video/framenumber/IndexSectorFrameNumber.java b/jpsxdec/src/jpsxdec/modules/video/framenumber/IndexSectorFrameNumber.java
index c5f842c..c754fde 100644
--- a/jpsxdec/src/jpsxdec/modules/video/framenumber/IndexSectorFrameNumber.java
+++ b/jpsxdec/src/jpsxdec/modules/video/framenumber/IndexSectorFrameNumber.java
@@ -182,4 +182,18 @@ private static void warnSectorFrameNumberIssues(@Nonnull FrameNumberNumber secto
return fn;
}
}
+
+ public static @Nonnull IFrameNumberFormatter makeSimpleFormatter(
+ int iFrameCount,
+ int iSectorMinValue, int iSectorMaxValue, int iSectorDuplicateMax)
+ {
+ // set the end duplicate = max duplicate for simplicity
+ FrameNumberNumber.Format snf = new FrameNumberNumber.Format(
+ iSectorMinValue, iSectorMaxValue, iSectorDuplicateMax, iSectorDuplicateMax);
+ FrameNumberNumber.Formatter sf = new FrameNumberNumber.Formatter(snf);
+
+ IndexSectorFrameNumber.Formatter sect = new IndexSectorFrameNumber.Formatter(iFrameCount, sf);
+ return sect;
+ }
+
}
diff --git a/jpsxdec/src/jpsxdec/modules/video/packetbased/DiscItemPacketBasedVideoStream.java b/jpsxdec/src/jpsxdec/modules/video/packetbased/DiscItemPacketBasedVideoStream.java
new file mode 100644
index 0000000..ebddcb3
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/video/packetbased/DiscItemPacketBasedVideoStream.java
@@ -0,0 +1,138 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2012-2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.video.packetbased;
+
+import java.util.Date;
+import javax.annotation.Nonnull;
+import jpsxdec.cdreaders.CdFileSectorReader;
+import jpsxdec.discitems.DiscItemSaverBuilder;
+import jpsxdec.discitems.SerializedDiscItem;
+import jpsxdec.i18n.I;
+import jpsxdec.i18n.ILocalizedMessage;
+import jpsxdec.i18n.exception.LocalizedDeserializationFail;
+import jpsxdec.modules.player.MediaPlayer;
+import jpsxdec.modules.video.Dimensions;
+import jpsxdec.modules.video.DiscItemVideoStream;
+import jpsxdec.modules.video.ISectorClaimToDemuxedFrame;
+import jpsxdec.modules.video.framenumber.IndexSectorFrameNumber;
+import jpsxdec.util.Misc;
+import jpsxdec.util.player.PlayController;
+
+
+public abstract class DiscItemPacketBasedVideoStream extends DiscItemVideoStream {
+
+ private static final String SOUND_UNIT_COUNT_KEY = "Sound unit count";
+ private final int _iSoundUnitCount;
+
+ public DiscItemPacketBasedVideoStream(@Nonnull CdFileSectorReader cd,
+ int iStartSector, int iEndSector,
+ @Nonnull Dimensions dim,
+ @Nonnull IndexSectorFrameNumber.Format sectorIndexFrameNumberFormat,
+ int iSoundUnitCount)
+ {
+ super(cd, iStartSector, iEndSector, dim, sectorIndexFrameNumberFormat);
+ _iSoundUnitCount = iSoundUnitCount;
+ }
+
+ public DiscItemPacketBasedVideoStream(@Nonnull CdFileSectorReader cd, @Nonnull SerializedDiscItem fields)
+ throws LocalizedDeserializationFail
+ {
+ super(cd, fields);
+ _iSoundUnitCount = fields.getInt(SOUND_UNIT_COUNT_KEY);
+ }
+
+ @Override
+ public @Nonnull SerializedDiscItem serialize() {
+ SerializedDiscItem serial = super.serialize();
+ serial.addNumber(SOUND_UNIT_COUNT_KEY, _iSoundUnitCount);
+ return serial;
+ }
+
+ final public boolean hasAudio() {
+ return _iSoundUnitCount > 0;
+ }
+
+ @Override
+ final public int getDiscSpeed() {
+ return 2; // this doesn't really matter
+ }
+
+ @Override
+ final public @Nonnull ILocalizedMessage getInterestingDescription() {
+ int iFrames = getFrameCount();
+ double dblFps = getPacketBasedFpsInterestingDescription();
+ Date secs = Misc.dateFromSeconds(Math.max(iFrames / (int)Math.round(dblFps), 1));
+ if (hasAudio())
+ return I.GUI_PACKET_BASED_VID_DETAILS_WITH_AUDIO(getWidth() ,getHeight(), iFrames, dblFps, secs, getAudioSampleFramesPerSecond());
+ else
+ return I.GUI_PACKET_BASED_VID_DETAILS(getWidth() ,getHeight(), iFrames, dblFps, secs);
+ }
+
+ abstract protected double getPacketBasedFpsInterestingDescription();
+
+ @Override
+ final public int getAbsolutePresentationStartSector() {
+ return getStartSector();
+ }
+
+ abstract public @Nonnull SectorClaimToAudioAndFrame makeAudioVideoDemuxer(double dblVolume);
+ abstract public int getAudioSampleFramesPerSecond();
+
+ @Override
+ final public ISectorClaimToDemuxedFrame makeDemuxer() {
+ return makeAudioVideoDemuxer(1.0);
+ }
+
+ @Override
+ final public DiscItemSaverBuilder makeSaverBuilder() {
+ return new PacketBasedVideoSaverBuilder(this);
+ }
+
+ @Override
+ final public @Nonnull PlayController makePlayController() {
+ SectorClaimToAudioAndFrame demuxer = makeAudioVideoDemuxer(1.0);
+ MediaPlayer mp;
+ if (hasAudio())
+ mp = new MediaPlayer(this, demuxer, demuxer, getStartSector(), getEndSector());
+ else
+ mp = new MediaPlayer(this, demuxer, getStartSector(), getEndSector());
+ return mp.getPlayController();
+ }
+
+
+}
diff --git a/jpsxdec/src/jpsxdec/modules/crusader/VideoSaverBuilderCrusader.java b/jpsxdec/src/jpsxdec/modules/video/packetbased/PacketBasedVideoSaverBuilder.java
similarity index 79%
rename from jpsxdec/src/jpsxdec/modules/crusader/VideoSaverBuilderCrusader.java
rename to jpsxdec/src/jpsxdec/modules/video/packetbased/PacketBasedVideoSaverBuilder.java
index 2525cd9..b5b6831 100644
--- a/jpsxdec/src/jpsxdec/modules/crusader/VideoSaverBuilderCrusader.java
+++ b/jpsxdec/src/jpsxdec/modules/video/packetbased/PacketBasedVideoSaverBuilder.java
@@ -35,10 +35,11 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package jpsxdec.modules.crusader;
+package jpsxdec.modules.video.packetbased;
import argparser.BooleanHolder;
import java.io.File;
+import java.util.logging.Level;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import jpsxdec.discitems.DiscItemSaverBuilder;
@@ -47,19 +48,20 @@
import jpsxdec.i18n.I;
import jpsxdec.i18n.TabularFeedback;
import jpsxdec.i18n.exception.LoggedFailure;
+import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.i18n.log.ProgressLogger;
+import jpsxdec.modules.sharedaudio.ISectorAudioDecoder;
import jpsxdec.modules.video.save.VideoSaver;
import jpsxdec.modules.video.save.VideoSaverBuilder;
import jpsxdec.util.ArgParser;
import jpsxdec.util.TaskCanceledException;
-/** Extends {@link VideoSaverBuilder} with Crusader specific settings. */
-public class VideoSaverBuilderCrusader extends VideoSaverBuilder {
+public class PacketBasedVideoSaverBuilder extends VideoSaverBuilder {
@Nonnull
- private final DiscItemCrusader _sourceVidItem;
+ private final DiscItemPacketBasedVideoStream _sourceVidItem;
- public VideoSaverBuilderCrusader(@Nonnull DiscItemCrusader vidItem) {
+ public PacketBasedVideoSaverBuilder(@Nonnull DiscItemPacketBasedVideoStream vidItem) {
super(vidItem);
_sourceVidItem = vidItem;
}
@@ -67,8 +69,8 @@ public VideoSaverBuilderCrusader(@Nonnull DiscItemCrusader vidItem) {
@Override
public boolean copySettingsTo(@Nonnull DiscItemSaverBuilder otherBuilder) {
if (super.copySettingsTo(otherBuilder)) {
- if (otherBuilder instanceof VideoSaverBuilderCrusader){
- VideoSaverBuilderCrusader other = (VideoSaverBuilderCrusader) otherBuilder;
+ if (otherBuilder instanceof PacketBasedVideoSaverBuilder){
+ PacketBasedVideoSaverBuilder other = (PacketBasedVideoSaverBuilder) otherBuilder;
other.setSavingAudio(getSavingAudio());
}
return true;
@@ -78,7 +80,7 @@ public boolean copySettingsTo(@Nonnull DiscItemSaverBuilder otherBuilder) {
}
public @Nonnull DiscItemSaverBuilderGui getOptionPane() {
- return new VideoSaverBuilderCrusaderGui(this);
+ return new PacketBasedVideoSaverBuilderGui(this);
}
// .........................................................................
@@ -91,11 +93,11 @@ public boolean getAudioVolume_enabled() {
// .........................................................................
public boolean getSavingAudio_enabled() {
- return getVideoFormat().isAvi() && getSaveStartFrame() == null;
+ return hasAudio() && getVideoFormat().isAvi() && getSaveStartFrame() == null;
}
public boolean hasAudio() {
- return true;
+ return _sourceVidItem.hasAudio();
}
private boolean _blnSavingAudio = true;
@@ -140,28 +142,26 @@ protected void makeHelpTable(@Nonnull TabularFeedback tfb) {
}
@Override
- protected void printSelectedAudioOptions(@Nonnull FeedbackStream fbs) {
- fbs.println(I.EMBEDDED_CRUSADER_AUDIO_HZ(CrusaderPacketToFrameAndAudio.CRUSADER_SAMPLES_PER_SECOND));
+ protected void printSelectedAudioOptions(@Nonnull ILocalizedLogger log) {
+ log.log(Level.INFO, I.CMD_EMBEDDED_PACKET_BASED_AUDIO_HZ(_sourceVidItem.getAudioSampleFramesPerSecond()));
}
public void startSave(@Nonnull ProgressLogger pl, @CheckForNull File directory)
throws LoggedFailure, TaskCanceledException
{
clearGeneratedFiles();
+ printSelectedOptions(pl);
- DiscItemCrusader.Demuxer av = _sourceVidItem.makeDemuxer(getAudioVolume());
- DiscItemCrusader.Demuxer ad;
+ SectorClaimToAudioAndFrame vid = _sourceVidItem.makeAudioVideoDemuxer(getAudioVolume());
+ ISectorAudioDecoder aud;
if (getSavingAudio()) {
- // TODO the saver will call attach twice,
- // which works since the 2nd time will simply overwrite the first time
- // it's just kinda messy
- ad = av;
+ aud = vid;
} else {
- ad = null;
+ aud = null;
}
- VideoSaver vs = new VideoSaver(_sourceVidItem, this, thisGeneratedFileListener, directory);
- vs.save(pl, av, ad);
+ VideoSaver vs = new VideoSaver(_sourceVidItem, this, thisGeneratedFileListener, directory, pl, vid, aud);
+ vs.save(pl);
}
}
diff --git a/jpsxdec/src/jpsxdec/modules/crusader/VideoSaverBuilderCrusaderGui.java b/jpsxdec/src/jpsxdec/modules/video/packetbased/PacketBasedVideoSaverBuilderGui.java
similarity index 81%
rename from jpsxdec/src/jpsxdec/modules/crusader/VideoSaverBuilderCrusaderGui.java
rename to jpsxdec/src/jpsxdec/modules/video/packetbased/PacketBasedVideoSaverBuilderGui.java
index 354f3fe..cf7e0bf 100644
--- a/jpsxdec/src/jpsxdec/modules/crusader/VideoSaverBuilderCrusaderGui.java
+++ b/jpsxdec/src/jpsxdec/modules/video/packetbased/PacketBasedVideoSaverBuilderGui.java
@@ -35,7 +35,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package jpsxdec.modules.crusader;
+package jpsxdec.modules.video.packetbased;
import java.awt.BorderLayout;
import javax.annotation.Nonnull;
@@ -46,14 +46,14 @@
import jpsxdec.modules.video.save.VideoSaverPanel;
-public class VideoSaverBuilderCrusaderGui extends DiscItemSaverBuilderGui {
+public class PacketBasedVideoSaverBuilderGui extends DiscItemSaverBuilderGui {
@Nonnull
- private final CombinedBuilderListener _bl;
+ private final CombinedBuilderListener _bl;
- public VideoSaverBuilderCrusaderGui(@Nonnull VideoSaverBuilderCrusader saverBuilder) {
+ public PacketBasedVideoSaverBuilderGui(@Nonnull PacketBasedVideoSaverBuilder saverBuilder) {
super(new BorderLayout());
- _bl = new CombinedBuilderListener(saverBuilder);
+ _bl = new CombinedBuilderListener(saverBuilder);
add(new PPanel(_bl), BorderLayout.NORTH);
}
@@ -62,9 +62,9 @@ public boolean useSaverBuilder(@Nonnull DiscItemSaverBuilder saverBuilder) {
return _bl.changeSourceBuilder(saverBuilder);
}
- private static class PPanel extends VideoSaverPanel {
+ private static class PPanel extends VideoSaverPanel {
- public PPanel(@Nonnull CombinedBuilderListener bl) {
+ public PPanel(@Nonnull CombinedBuilderListener bl) {
super(bl);
bl.addListeners(new SaveAudio());
}
@@ -80,6 +80,10 @@ public void setSelected(boolean b) {
public boolean isEnabled() {
return _bl.getBuilder().getSavingAudio_enabled();
}
+ @Override
+ public boolean isVisibile() {
+ return _bl.getBuilder().hasAudio();
+ }
}
}
diff --git a/jpsxdec/src/jpsxdec/modules/video/packetbased/SectorClaimToAudioAndFrame.java b/jpsxdec/src/jpsxdec/modules/video/packetbased/SectorClaimToAudioAndFrame.java
new file mode 100644
index 0000000..6b0d988
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/video/packetbased/SectorClaimToAudioAndFrame.java
@@ -0,0 +1,47 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.video.packetbased;
+
+import jpsxdec.modules.sharedaudio.ISectorAudioDecoder;
+import jpsxdec.modules.video.ISectorClaimToDemuxedFrame;
+
+
+public abstract class SectorClaimToAudioAndFrame
+ implements ISectorClaimToDemuxedFrame, ISectorAudioDecoder
+{
+}
diff --git a/jpsxdec/src/jpsxdec/modules/video/replace/ReplaceFrameFull.java b/jpsxdec/src/jpsxdec/modules/video/replace/ReplaceFrameFull.java
index 160d24c..d7122f3 100644
--- a/jpsxdec/src/jpsxdec/modules/video/replace/ReplaceFrameFull.java
+++ b/jpsxdec/src/jpsxdec/modules/video/replace/ReplaceFrameFull.java
@@ -189,25 +189,27 @@ else if (abNewFrame.length > frame.getDemuxSize()) // for bs or mdec formats
getFrameLookup().toString(), abNewFrame.length, frame.getDemuxSize()));
// find out how many bytes and mdec codes are used by the new frame
- BitStreamUncompressor verifyBsu;
+ BitStreamUncompressor verifiedBsu;
try {
+ verifiedBsu = BitStreamUncompressor.identifyUncompressor(abNewFrame);
// also verify it is the same bitstream type (for bs format)
- verifyBsu = bsu.getType().makeNew(abNewFrame);
+ if (!verifiedBsu.getClass().equals(bsu.getClass()))
+ throw new BinaryDataNotRecognized();
} catch (BinaryDataNotRecognized ex) {
throw new LoggedFailure(log, Level.SEVERE, I.REPLACE_BITSTREAM_MISMATCH(_imageFile), ex);
}
try {
- verifyBsu.skipMacroBlocks(frame.getWidth(), frame.getHeight());
- verifyBsu.skipPaddingBits();
+ verifiedBsu.skipMacroBlocks(frame.getWidth(), frame.getHeight());
+ verifiedBsu.skipPaddingBits();
} catch (MdecException.EndOfStream ex) {
throw new RuntimeException("Can't decode a frame we just encoded?", ex);
} catch (MdecException.ReadCorruption ex) {
throw new RuntimeException("Can't decode a frame we just encoded?", ex);
}
- int iUsedSize = ((verifyBsu.getBitPosition() + 15) / 16) * 2; // rounded up to nearest word
- frame.writeToSectors(abNewFrame, iUsedSize, verifyBsu.getReadMdecCodeCount(), cd, log);
+ int iUsedSize = ((verifiedBsu.getBitPosition() + 15) / 16) * 2; // rounded up to nearest word
+ frame.writeToSectors(abNewFrame, iUsedSize, verifiedBsu.getReadMdecCodeCount(), cd, log);
}
private static byte[] readBitstreamFile(@Nonnull File imageFile, @Nonnull ILocalizedLogger log)
diff --git a/jpsxdec/src/jpsxdec/modules/video/replace/ReplaceFramePartial.java b/jpsxdec/src/jpsxdec/modules/video/replace/ReplaceFramePartial.java
index edf6364..c578943 100644
--- a/jpsxdec/src/jpsxdec/modules/video/replace/ReplaceFramePartial.java
+++ b/jpsxdec/src/jpsxdec/modules/video/replace/ReplaceFramePartial.java
@@ -63,7 +63,7 @@
import jpsxdec.psxvideo.encode.MdecEncoder;
import jpsxdec.psxvideo.encode.ParsedMdecImage;
import jpsxdec.psxvideo.encode.PsxYCbCrImage;
-import jpsxdec.psxvideo.mdec.Ac0Cleaner;
+import jpsxdec.psxvideo.mdec.Ac0Checker;
import jpsxdec.psxvideo.mdec.Calc;
import jpsxdec.psxvideo.mdec.MdecDecoder_double;
import jpsxdec.psxvideo.mdec.MdecException;
@@ -177,7 +177,8 @@ public void replace(@Nonnull IDemuxedFrame frame, @Nonnull CdFileSectorReader cd
final int WIDTH = frame.getWidth();
final int HEIGHT = frame.getHeight();
if (newImg.getWidth() < WIDTH || newImg.getHeight() < HEIGHT)
- throw new LoggedFailure(log, Level.SEVERE, I.REPLACE_FRAME_DIMENSIONS_TOO_SMALL());
+ throw new LoggedFailure(log, Level.SEVERE, I.REPLACE_FRAME_DIMENSIONS_TOO_SMALL(
+ newImg.getWidth(), newImg.getHeight(), frame.getWidth(), frame.getHeight()));
// 1. Parse original image
byte[] abExistingFrame = frame.copyDemuxData();
@@ -191,7 +192,7 @@ public void replace(@Nonnull IDemuxedFrame frame, @Nonnull CdFileSectorReader cd
MdecDecoder_double decoder = new MdecDecoder_double(new StephensIDCT(),
WIDTH, HEIGHT);
try {
- ParsedMdecImage parsedOrig = new ParsedMdecImage(new Ac0Cleaner(bsu), WIDTH, HEIGHT);
+ ParsedMdecImage parsedOrig = new ParsedMdecImage(Ac0Checker.wrapWithChecker(bsu, true), WIDTH, HEIGHT);
// 2. convert both to RGB
// TODO: use best quality to decode, but same as encode
@@ -206,7 +207,7 @@ public void replace(@Nonnull IDemuxedFrame frame, @Nonnull CdFileSectorReader cd
// the bounding box and mask
ArrayList diffMacblks = findDiffMacroblocks(origImg, newImg, log);
if (diffMacblks.isEmpty()) {
- log.log(Level.INFO, I.CMD_NO_DIFFERENCE_SKIPPING());
+ log.log(Level.INFO, I.CMD_NO_DIFFERENCE_SKIPPING(getFrameLookup().toString()));
return;
} else if (diffMacblks.size() == Calc.macroblocks(WIDTH, HEIGHT)) {
log.log(Level.WARNING, I.CMD_ENTIRE_FRAME_DIFFERENT());
diff --git a/jpsxdec/src/jpsxdec/modules/video/replace/ReplaceFrames.java b/jpsxdec/src/jpsxdec/modules/video/replace/ReplaceFrames.java
index 3471be7..1794ee1 100644
--- a/jpsxdec/src/jpsxdec/modules/video/replace/ReplaceFrames.java
+++ b/jpsxdec/src/jpsxdec/modules/video/replace/ReplaceFrames.java
@@ -69,7 +69,6 @@
import jpsxdec.modules.video.framenumber.FrameCompareIs;
import jpsxdec.modules.video.framenumber.FrameNumber;
import jpsxdec.util.IO;
-import jpsxdec.util.IOException6;
import jpsxdec.util.TaskCanceledException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -99,7 +98,7 @@ public XmlFileNotFoundException(FileNotFoundException cause) {
}
- public static class XmlReadException extends IOException6 {
+ public static class XmlReadException extends IOException {
public XmlReadException(IOException cause) {
super(cause);
@@ -196,9 +195,9 @@ public void save(@Nonnull String sFile) throws IOException {
StreamResult result = new StreamResult(new File(sFile));
transformer.transform(source, result);
} catch (ParserConfigurationException ex) {
- throw new IOException6(ex);
+ throw new IOException(ex);
} catch (TransformerException ex) {
- throw new IOException6(ex);
+ throw new IOException(ex);
}
}
diff --git a/jpsxdec/src/jpsxdec/modules/video/save/AutowireVDP.java b/jpsxdec/src/jpsxdec/modules/video/save/AutowireVDP.java
new file mode 100644
index 0000000..63f0921
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/video/save/AutowireVDP.java
@@ -0,0 +1,302 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.video.save;
+
+import java.util.Arrays;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import jpsxdec.modules.SectorClaimSystem;
+import jpsxdec.modules.sharedaudio.DecodedAudioPacket;
+import jpsxdec.modules.sharedaudio.ISectorAudioDecoder;
+import jpsxdec.modules.video.IDemuxedFrame;
+import jpsxdec.modules.video.ISectorClaimToDemuxedFrame;
+
+/** Automatically connects all video pipeline and other components. */
+public class AutowireVDP {
+
+ // Expose these publicly for the saver to send data into
+ @CheckForNull
+ private VDP.IBitstreamListener _bitstreamListener;
+ public @CheckForNull VDP.IBitstreamListener getBitstreamListener() {
+ return _bitstreamListener;
+ }
+ @CheckForNull
+ private VDP.IMdecListener _mdecListener;
+ public @CheckForNull VDP.IMdecListener getMdecListener() {
+ return _mdecListener;
+ }
+
+ // Expose this publicly to open/close the AVI
+ @CheckForNull
+ private VDP.ToAvi _toAvi;
+ public @CheckForNull VDP.ToAvi getAvi() {
+ return _toAvi;
+ }
+
+
+ // =========================================================================
+
+ public void autowire() throws IllegalStateException {
+ _bitstreamListener = chooseOnlyOne(_bitstream2File, _bitstream2Mdec);
+ _mdecListener = chooseOnlyOne(_mdec2Decoded, _mdec2File, _mdec2Jpeg, _mdec2MjpegAvi);
+
+ if (_frame2Bitstream != null) {
+ _frame2Bitstream.setListener(_bitstreamListener);
+ _frame2Bitstream.setListener(_mdecListener);
+ }
+
+ wireDecodedIntoMdec();
+ wireMdecIntoBitstream();
+ _toAvi = chooseOnlyOne(_decoded2JYuvAvi, _decoded2RgbAvi, _decoded2YuvAvi, _mdec2MjpegAvi);
+ wireGenFileListener();
+ wireSectorClaim();
+ wireAudioAndFrame();
+ }
+
+ private void wireGenFileListener() {
+ if (_generatedFileListener == null)
+ return;
+ if (_bitstream2File != null)
+ _bitstream2File.setGenFileListener(_generatedFileListener);
+ if (_decoded2JavaImage != null)
+ _decoded2JavaImage.setGenFileListener(_generatedFileListener);
+ if (_decoded2JYuvAvi != null)
+ _decoded2JYuvAvi.setGenFileListener(_generatedFileListener);
+ if (_decoded2RgbAvi != null)
+ _decoded2RgbAvi.setGenFileListener(_generatedFileListener);
+ if (_decoded2YuvAvi != null)
+ _decoded2YuvAvi.setGenFileListener(_generatedFileListener);
+ if (_mdec2File != null)
+ _mdec2File.setGenFileListener(_generatedFileListener);
+ if (_mdec2Jpeg != null)
+ _mdec2Jpeg.setGenFileListener(_generatedFileListener);
+ if (_mdec2MjpegAvi != null)
+ _mdec2MjpegAvi.setGenFileListener(_generatedFileListener);
+ }
+
+ private void wireMdecIntoBitstream() {
+ VDP.IMdecListener mdecListener = chooseOnlyOne(_mdec2Decoded, _mdec2File, _mdec2Jpeg, _mdec2MjpegAvi);
+ if (_bitstream2Mdec == null)
+ return;
+ if (mdecListener != null)
+ _bitstream2Mdec.setMdecListener(mdecListener);
+ }
+
+ private void wireDecodedIntoMdec() {
+ if (_decodedListener == null)
+ _decodedListener = chooseOnlyOne(_decoded2JYuvAvi, _decoded2JavaImage, _decoded2RgbAvi, _decoded2YuvAvi);
+ if (_decodedListener == null)
+ return;
+ if (_mdec2Decoded != null)
+ _mdec2Decoded.setDecoded(_decodedListener);
+ }
+
+ private static @CheckForNull T chooseOnlyOne(T... elements) {
+ T nonNull = null;
+ for (T element : elements) {
+ if (element != null) {
+ if (nonNull != null)
+ throw new IllegalStateException("More than one set: " + Arrays.toString(elements));
+ nonNull = element;
+ }
+ }
+ return nonNull;
+ }
+
+ // =========================================================================
+ // Sector claim, audio, video
+
+ @CheckForNull
+ private SectorClaimSystem _sectorClaimSystem;
+ public void attachToSectorClaimer(@Nonnull SectorClaimSystem sectorClaimSystem) {
+ assertNull(_sectorClaimSystem);
+ _sectorClaimSystem = sectorClaimSystem;
+ }
+
+ private void wireSectorClaim() {
+ if (_sectorClaimSystem == null)
+ return;
+ if (_sectorAudioDecoder != null)
+ _sectorAudioDecoder.attachToSectorClaimer(_sectorClaimSystem);
+ if (_sectorClaimToDemuxedFrame != null)
+ _sectorClaimToDemuxedFrame.attachToSectorClaimer(_sectorClaimSystem);
+ }
+
+ @CheckForNull
+ private ISectorAudioDecoder _sectorAudioDecoder;
+ public void setAudioDecoder(@Nonnull ISectorAudioDecoder sectorAudioDecoder) {
+ assertNull(_sectorAudioDecoder);
+ _sectorAudioDecoder = sectorAudioDecoder;
+ }
+ @CheckForNull
+ private ISectorClaimToDemuxedFrame _sectorClaimToDemuxedFrame;
+ public void setMap(@Nonnull ISectorClaimToDemuxedFrame sectorClaimToDemuxedFrame) {
+ assertNull(_sectorClaimToDemuxedFrame);
+ _sectorClaimToDemuxedFrame = sectorClaimToDemuxedFrame;
+ }
+
+ @CheckForNull
+ private IDemuxedFrame.Listener _frameListener;
+ public void setFrameListener(@Nonnull IDemuxedFrame.Listener frameListener) {
+ assertNull(_frameListener);
+ _frameListener = frameListener;
+ }
+ @CheckForNull
+ private Frame2Bitstream _frame2Bitstream;
+ public void setMap(@Nonnull Frame2Bitstream frame2Bitstream) {
+ setFrameListener(frame2Bitstream);
+ _frame2Bitstream = frame2Bitstream;
+ }
+
+ @CheckForNull
+ private DecodedAudioPacket.Listener _audioListener;
+ public void setAudioPacketListener(@Nonnull DecodedAudioPacket.Listener audioListener) {
+ assertNull(_audioListener);
+ _audioListener = audioListener;
+ }
+
+ private void wireAudioAndFrame() {
+ if (_sectorAudioDecoder != null && _audioListener != null)
+ _sectorAudioDecoder.setAudioListener(_audioListener);
+ if (_sectorClaimToDemuxedFrame != null && _frameListener != null)
+ _sectorClaimToDemuxedFrame.setFrameListener(_frameListener);
+ }
+
+ // =========================================================================
+
+ @CheckForNull
+ private VDP.GeneratedFileListener _generatedFileListener;
+ public void setFileListener(@Nonnull VDP.GeneratedFileListener generatedFileListener) {
+ assertNull(_generatedFileListener);
+ _generatedFileListener = generatedFileListener;
+ }
+
+ // =========================================================================
+ // Bitstream
+
+
+ @CheckForNull
+ private VDP.Bitstream2File _bitstream2File;
+ public void setMap(@Nonnull VDP.Bitstream2File bitstream2File) {
+ assertNull(_bitstream2File);
+ _bitstream2File = bitstream2File;
+ }
+
+ @CheckForNull
+ private VDP.Bitstream2Mdec _bitstream2Mdec;
+ public void setMap(@Nonnull VDP.Bitstream2Mdec bitstream2Mdec) {
+ assertNull(_bitstream2Mdec);
+ _bitstream2Mdec = bitstream2Mdec;
+ }
+
+ // =========================================================================
+ // decoded
+
+ @CheckForNull
+ private VDP.Decoded2JavaImage _decoded2JavaImage;
+ public void setMap(@Nonnull VDP.Decoded2JavaImage decoded2JavaImage) {
+ assertNull(_decoded2JavaImage);
+ _decoded2JavaImage = decoded2JavaImage;
+ }
+
+ // =========================================================================
+ // MDEC
+
+ @CheckForNull
+ private VDP.Mdec2Decoded _mdec2Decoded;
+ public void setMap(@Nonnull VDP.Mdec2Decoded mdec2Decoded) {
+ assertNull(_mdec2Decoded);
+ _mdec2Decoded = mdec2Decoded;
+ }
+
+ @CheckForNull
+ private VDP.Mdec2File _mdec2File;
+ public void setMap(@Nonnull VDP.Mdec2File mdec2File) {
+ assertNull(_mdec2File);
+ _mdec2File = mdec2File;
+ }
+
+ @CheckForNull
+ private VDP.Mdec2Jpeg _mdec2Jpeg;
+ public void setMap(@Nonnull VDP.Mdec2Jpeg mdec2Jpeg) {
+ assertNull(_mdec2Jpeg);
+ _mdec2Jpeg = mdec2Jpeg;
+ }
+
+ // =========================================================================
+ // AVI
+
+ @CheckForNull
+ private VDP.IDecodedListener _decodedListener;
+ public void setDecodedListener(@Nonnull VDP.IDecodedListener decodedListener) {
+ assertNull(_decodedListener);
+ _decodedListener = decodedListener;
+ }
+ @CheckForNull
+ private VDP.Decoded2JYuvAvi _decoded2JYuvAvi;
+ public void setToAvi(@Nonnull VDP.Decoded2JYuvAvi decoded2JYuvAvi) {
+ assertNull(_decoded2JYuvAvi);
+ _decoded2JYuvAvi = decoded2JYuvAvi;
+ }
+ @CheckForNull
+ private VDP.Decoded2RgbAvi _decoded2RgbAvi;
+ public void setToAvi(@Nonnull VDP.Decoded2RgbAvi decoded2RgbAvi) {
+ assertNull(_decoded2RgbAvi);
+ _decoded2RgbAvi = decoded2RgbAvi;
+ }
+ @CheckForNull
+ private VDP.Decoded2YuvAvi _decoded2YuvAvi;
+ public void setToAvi(@Nonnull VDP.Decoded2YuvAvi decoded2YuvAvi) {
+ assertNull(_decoded2YuvAvi);
+ _decoded2YuvAvi = decoded2YuvAvi;
+ }
+ @CheckForNull
+ private VDP.Mdec2MjpegAvi _mdec2MjpegAvi;
+ public void setToAvi(@Nonnull VDP.Mdec2MjpegAvi mdec2MjpegAvi) {
+ assertNull(_mdec2MjpegAvi);
+ _mdec2MjpegAvi = mdec2MjpegAvi;
+ }
+
+ // =========================================================================
+
+ private static void assertNull(Object o) {
+ if (o != null)
+ throw new IllegalStateException(o.getClass() + " was already set");
+ }
+
+}
diff --git a/jpsxdec/src/jpsxdec/modules/video/save/Frame2Bitstream.java b/jpsxdec/src/jpsxdec/modules/video/save/Frame2Bitstream.java
new file mode 100644
index 0000000..1957ff2
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/modules/video/save/Frame2Bitstream.java
@@ -0,0 +1,91 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.modules.video.save;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import jpsxdec.i18n.exception.LoggedFailure;
+import jpsxdec.modules.video.IDemuxedFrame;
+import jpsxdec.modules.video.framenumber.FormattedFrameNumber;
+import jpsxdec.modules.video.framenumber.FrameNumber;
+import jpsxdec.psxvideo.mdec.MdecInputStream;
+
+public class Frame2Bitstream implements IDemuxedFrame.Listener {
+
+ @Nonnull
+ private final FrameNumber.Type _frameNumberType;
+
+ @CheckForNull
+ private VDP.IBitstreamListener _bitstreamListener;
+
+ @CheckForNull
+ private VDP.IMdecListener _mdecListener;
+
+ public Frame2Bitstream(@Nonnull FrameNumber.Type frameNumberType) {
+ _frameNumberType = frameNumberType;
+ }
+
+ final public void setListener(@CheckForNull VDP.IBitstreamListener bitstreamListener) {
+ _bitstreamListener = bitstreamListener;
+ }
+
+ final public void setListener(@CheckForNull VDP.IMdecListener mdecListener) {
+ _mdecListener = mdecListener;
+ }
+
+ final public @Nonnull FrameNumber.Type getFrameNumberType() {
+ return _frameNumberType;
+ }
+
+ @Override
+ public void frameComplete(@Nonnull IDemuxedFrame frame) throws LoggedFailure {
+ FormattedFrameNumber ffn = frame.getFrame().getNumber(_frameNumberType);
+ MdecInputStream customStream = frame.getCustomFrameMdecStream();
+
+ if (customStream != null) {
+ if (_mdecListener == null)
+ throw new IllegalStateException("No mdec to write to");
+ _mdecListener.mdec(customStream, ffn, frame.getPresentationSector());
+ } else {
+ if (_bitstreamListener == null)
+ throw new IllegalStateException("No bitstream to write to");
+ byte[] abBitstream = frame.copyDemuxData();
+ _bitstreamListener.bitstream(abBitstream, frame.getDemuxSize(), ffn, frame.getPresentationSector());
+ }
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/modules/video/save/MdecDecodeQuality.java b/jpsxdec/src/jpsxdec/modules/video/save/MdecDecodeQuality.java
index 1831751..08b5ef4 100644
--- a/jpsxdec/src/jpsxdec/modules/video/save/MdecDecodeQuality.java
+++ b/jpsxdec/src/jpsxdec/modules/video/save/MdecDecodeQuality.java
@@ -42,7 +42,7 @@
import jpsxdec.i18n.I;
import jpsxdec.i18n.ILocalizedMessage;
import jpsxdec.psxvideo.mdec.MdecDecoder;
-import jpsxdec.psxvideo.mdec.MdecDecoder_double_interpolate;
+import jpsxdec.psxvideo.mdec.MdecDecoder_double;
import jpsxdec.psxvideo.mdec.MdecDecoder_int;
import jpsxdec.psxvideo.mdec.idct.PsxMdecIDCT_double;
import jpsxdec.psxvideo.mdec.idct.PsxMdecIDCT_int;
@@ -55,9 +55,9 @@ public MdecDecoder makeDecoder(int iWidth, int iHeight) {
return new MdecDecoder_int(new SimpleIDCT(), iWidth, iHeight);
}
},
- HIGH_PLUS(I.QUALITY_HIGH_DESCRIPTION(), I.QUALITY_HIGH_COMMAND()) {
+ HIGH(I.QUALITY_HIGH_DESCRIPTION(), I.QUALITY_HIGH_COMMAND()) {
public MdecDecoder makeDecoder(int iWidth, int iHeight) {
- return new MdecDecoder_double_interpolate(new PsxMdecIDCT_double(), iWidth, iHeight);
+ return new MdecDecoder_double(new PsxMdecIDCT_double(), iWidth, iHeight);
}
public boolean canUpsample() { return true; }
},
diff --git a/jpsxdec/src/jpsxdec/modules/video/save/VDP.java b/jpsxdec/src/jpsxdec/modules/video/save/VDP.java
index 0cbc5f1..068071e 100644
--- a/jpsxdec/src/jpsxdec/modules/video/save/VDP.java
+++ b/jpsxdec/src/jpsxdec/modules/video/save/VDP.java
@@ -159,16 +159,19 @@ public void setGenFileListener(@CheckForNull GeneratedFileListener listener) {
public static class Bitstream2Mdec implements IBitstreamListener {
- @Nonnull
- private final ILocalizedLogger _log;
- @Nonnull
- private final IMdecListener _listener;
@CheckForNull
- private BitStreamUncompressor.Type _uncompressorType;
+ private IMdecListener _listener;
+ @CheckForNull
+ private Class extends BitStreamUncompressor> _uncompressorType;
+ public Bitstream2Mdec() {
+ }
public Bitstream2Mdec(@Nonnull IMdecListener mdecListener) {
_listener = mdecListener;
- _log = _listener.getLog();
+ }
+
+ public void setMdecListener(@CheckForNull IMdecListener listener) {
+ _listener = listener;
}
public void bitstream(@Nonnull byte[] abBitstream, int iBitstreamSize,
@@ -180,22 +183,25 @@ public void bitstream(@Nonnull byte[] abBitstream, int iBitstreamSize,
BitStreamUncompressor uncompressor = BitStreamUncompressor.identifyUncompressor(
abBitstream, iBitstreamSize);
if (_uncompressorType != null) {
- BitStreamUncompressor.Type newType = uncompressor.getType();
- if (_uncompressorType != newType) {
+ Class extends BitStreamUncompressor> newType = uncompressor.getClass();
+ if (!_uncompressorType.equals(newType)) {
LOG.log(Level.WARNING, "Bitstream format changed from {0} to {1}",
- new Object[]{_uncompressorType, newType});
+ new Object[]{_uncompressorType.getSimpleName(), newType.getSimpleName()});
_uncompressorType = newType;
}
} else {
- _uncompressorType = uncompressor.getType();
- LOG.log(Level.INFO, "Bitstream format identified {0}",
- _uncompressorType);
+ _uncompressorType = uncompressor.getClass();
+ LOG.log(Level.INFO, "Bitstream format identified {0}",
+ _uncompressorType.getSimpleName());
}
- _listener.mdec(uncompressor, frameNumber, presentationSector);
+ if (_listener != null)
+ _listener.mdec(uncompressor, frameNumber, presentationSector);
} catch (BinaryDataNotRecognized ex) {
ILocalizedMessage msg = FrameMessage.UNABLE_TO_DETERMINE_FRAME_TYPE_FRM(frameNumber);
- _log.log(Level.SEVERE, msg, ex);
- _listener.error(msg, frameNumber, presentationSector);
+ if (_listener != null) {
+ _listener.getLog().log(Level.SEVERE, msg, ex);
+ _listener.error(msg, frameNumber, presentationSector);
+ }
}
}
@@ -484,7 +490,7 @@ public void setGenFileListener(@CheckForNull GeneratedFileListener listener) {
/** Most Avi will take Decoded as input, but MJPG will need Mdec as input,
* so save the interface implementation for subclasses. */
- public static abstract class ToAvi implements Closeable {
+ public static abstract class ToAvi implements Closeable, DecodedAudioPacket.Listener {
@Nonnull
protected final File _outputFile;
protected final int _iWidth, _iHeight;
@@ -525,6 +531,10 @@ public ToAvi(@Nonnull File outputFile, int iWidth, int iHeight,
return _outputFile;
}
+ final public @CheckForNull AviWriter getAviWriter() {
+ return _writer;
+ }
+
abstract public void open()
throws LocalizedFileNotFoundException, FileNotFoundException, IOException;
@@ -565,9 +575,11 @@ final protected void prepForFrame(@CheckForNull FormattedFrameNumber frameNumber
} else {
while (iDupCount > 0) { // could happen with first frame
if (_writer.getVideoFramesWritten() < 1) { // TODO: fix design so this isn't needed
+ _log.log(Level.INFO, I.WRITING_BLANK_FRAMES_TO_ALIGN_AV(1));
LOG.log(Level.INFO, "Writing blank frame for frame {0}", frameNumber);
_writer.writeBlankFrame();
} else {
+ _log.log(Level.INFO, I.WRITING_DUP_FRAMES_TO_ALIGN_AV(1));
LOG.log(Level.INFO, "Writing dup frame for frame {0}", frameNumber);
_writer.repeatPreviousFrame();
}
@@ -576,7 +588,9 @@ final protected void prepForFrame(@CheckForNull FormattedFrameNumber frameNumber
}
}
- final public void writeAudio(@Nonnull DecodedAudioPacket packet) throws LoggedFailure
+ final public void audioPacketComplete(@Nonnull DecodedAudioPacket packet,
+ @Nonnull ILocalizedLogger log)
+ throws LoggedFailure
{
if (_writer == null)
throw new IllegalStateException("Avi writer is not open");
@@ -680,20 +694,27 @@ public void error(@Nonnull ILocalizedMessage errMsg, @CheckForNull FormattedFram
}
+ /** Only supports videos with even dimensions. */
public static class Decoded2YuvAvi extends ToAvi implements IDecodedListener {
@CheckForNull
protected YCbCrImage _yuvImgBuff;
@CheckForNull
protected AviWriterYV12 _writerYuv;
+ /** @throws IllegalArgumentException if dimensions are not even */
public Decoded2YuvAvi(@Nonnull File outputFile, int iWidth, int iHeight, @Nonnull VideoSync vidSync, @Nonnull ILocalizedLogger log) {
super(outputFile, iWidth, iHeight, vidSync, log);
+ if (((iWidth | iHeight) & 1) != 0)
+ throw new IllegalArgumentException("YUV AVI only supports even dimensions");
}
+ /** @throws IllegalArgumentException if dimensions are not even */
public Decoded2YuvAvi(@Nonnull File outputFile, int iWidth, int iHeight,
@Nonnull AudioVideoSync avSync, @Nonnull AudioFormat af, @Nonnull ILocalizedLogger log)
{
super(outputFile, iWidth, iHeight, avSync, af, log);
+ if (((iWidth | iHeight) & 1) != 0)
+ throw new IllegalArgumentException("YUV AVI only supports even dimensions");
}
public void assertAcceptsDecoded(@Nonnull MdecDecoder decoder) throws IllegalArgumentException {
diff --git a/jpsxdec/src/jpsxdec/modules/video/save/VideoFormat.java b/jpsxdec/src/jpsxdec/modules/video/save/VideoFormat.java
index 8a89db0..afea025 100644
--- a/jpsxdec/src/jpsxdec/modules/video/save/VideoFormat.java
+++ b/jpsxdec/src/jpsxdec/modules/video/save/VideoFormat.java
@@ -61,13 +61,15 @@ public enum VideoFormat {
public String getExtension() { return ".avi"; }
public boolean isAvi() { return true; }
public int getDecodeQualityCount() { return 1; }
- public MdecDecodeQuality getMdecDecodeQuality(int i) { return MdecDecodeQuality.HIGH_PLUS; }
+ public MdecDecodeQuality getMdecDecodeQuality(int i) { return MdecDecodeQuality.HIGH; }
+ public boolean mustHaveEvenDims() { return true; };
},
AVI_JYUV(I.VID_AVI_JYUV_DESCRIPTION(), I.VID_AVI_JYUV_COMMAND()) {
public String getExtension() { return ".avi"; }
public boolean isAvi() { return true; }
public int getDecodeQualityCount() { return 1; }
- public MdecDecodeQuality getMdecDecodeQuality(int i) { return MdecDecodeQuality.HIGH_PLUS; }
+ public MdecDecodeQuality getMdecDecodeQuality(int i) { return MdecDecodeQuality.HIGH; }
+ public boolean mustHaveEvenDims() { return true; };
},
IMGSEQ_PNG(I.VID_IMG_SEQ_PNG_DESCRIPTION(), I.VID_IMG_SEQ_PNG_COMMAND(),
JavaImageFormat.PNG)
@@ -131,6 +133,7 @@ public boolean isAvailable() {
}
public boolean isCroppable() { return true; }
+ public boolean mustHaveEvenDims() { return false; };
public int getDecodeQualityCount() { return MdecDecodeQuality.values().length; }
public @Nonnull MdecDecodeQuality getMdecDecodeQuality(int i) { return MdecDecodeQuality.values()[i]; }
diff --git a/jpsxdec/src/jpsxdec/modules/video/save/VideoSaver.java b/jpsxdec/src/jpsxdec/modules/video/save/VideoSaver.java
index 90b9c60..94136c0 100644
--- a/jpsxdec/src/jpsxdec/modules/video/save/VideoSaver.java
+++ b/jpsxdec/src/jpsxdec/modules/video/save/VideoSaver.java
@@ -54,7 +54,6 @@
import jpsxdec.i18n.log.ProgressLogger;
import jpsxdec.modules.IIdentifiedSector;
import jpsxdec.modules.SectorClaimSystem;
-import jpsxdec.modules.sharedaudio.DecodedAudioPacket;
import jpsxdec.modules.sharedaudio.ISectorAudioDecoder;
import jpsxdec.modules.video.DiscItemVideoStream;
import jpsxdec.modules.video.IDemuxedFrame;
@@ -63,14 +62,15 @@
import jpsxdec.modules.video.framenumber.FrameCompareIs;
import jpsxdec.modules.video.framenumber.FrameLookup;
import jpsxdec.modules.video.framenumber.FrameNumber;
+import jpsxdec.psxvideo.mdec.ChromaUpsample;
import jpsxdec.psxvideo.mdec.MdecDecoder;
-import jpsxdec.psxvideo.mdec.MdecDecoder_double_interpolate;
+import jpsxdec.psxvideo.mdec.MdecDecoder_double;
import jpsxdec.util.IO;
import jpsxdec.util.TaskCanceledException;
/** Constructs a {@link VDP Video decoder pipeline} from a
* {@link VideoSaverBuilder} and performs the actual saving of video. */
-public class VideoSaver implements DecodedAudioPacket.Listener {
+public class VideoSaver {
private static final Logger LOG = Logger.getLogger(VideoSaver.class.getName());
@@ -80,81 +80,188 @@ public class VideoSaver implements DecodedAudioPacket.Listener {
private final VideoSaverBuilder _vsb;
@Nonnull
private final VideoFormat _videoFormat;
- @Nonnull
- private final VDP.GeneratedFileListener _genFileListener;
@CheckForNull
private final File _directory;
+ private final AutowireVDP _pipeline = new AutowireVDP();
+
+ private final int _iStartSector;
+ private final int _iEndSector;
+ @Nonnull
+ private final FrameToBitstreamFilter _frame2bitstream;
@CheckForNull
- private VDP.ToAvi _toAvi;
+ private final ISectorAudioDecoder _audioDecoder;
public VideoSaver(@Nonnull DiscItemVideoStream vidItem,
@Nonnull VideoSaverBuilder vsb,
@Nonnull VDP.GeneratedFileListener genFileListener,
- @CheckForNull File directory)
+ @CheckForNull File directory,
+ @Nonnull ILocalizedLogger log,
+ @Nonnull ISectorClaimToDemuxedFrame demuxer,
+ @CheckForNull ISectorAudioDecoder audioDecoder)
{
_vidItem = vidItem;
_vsb = vsb;
_videoFormat = vsb.getVideoFormat();
- _genFileListener = genFileListener;
_directory = directory;
+ _audioDecoder = audioDecoder;
+
+ _pipeline.setMap(demuxer);
+ _pipeline.setFileListener(genFileListener);
+
+ VDP.ToAvi toAvi = null;
+ switch (_videoFormat) {
+
+ case IMGSEQ_BITSTREAM: {
+ VDP.Bitstream2File bs2f = new VDP.Bitstream2File(makeFormatter(), log);
+ _pipeline.setMap(bs2f);
+ }
+ break;
+
+ case IMGSEQ_MDEC: {
+ addBitstream2Mdec();
+ VDP.Mdec2File m2f = new VDP.Mdec2File(makeFormatter(), _vsb.getWidth(), _vsb.getHeight(), log);
+ _pipeline.setMap(m2f);
+ } break;
+
+ case IMGSEQ_BMP:
+ case IMGSEQ_PNG: {
+ addBitstream2Mdec();
+ addMdec2Decoded(log);
+ JavaImageFormat javaImgFmt = _videoFormat.getImgFmt();
+ VDP.Decoded2JavaImage d2j = new VDP.Decoded2JavaImage(
+ makeFormatter(), javaImgFmt, _vsb.getWidth(), _vsb.getHeight(), log);
+ _pipeline.setMap(d2j);
+ } break;
+
+ case IMGSEQ_JPG: {
+ addBitstream2Mdec();
+ VDP.Mdec2Jpeg m2jpg = new VDP.Mdec2Jpeg(makeFormatter(), _vsb.getWidth(), _vsb.getHeight(), log);
+ _pipeline.setMap(m2jpg);
+ } break;
+
+ case AVI_MJPG: {
+ addBitstream2Mdec();
+ VDP.Mdec2MjpegAvi m2mjpg;
+ if (_audioDecoder == null)
+ m2mjpg = new VDP.Mdec2MjpegAvi(getAviFile(), _vsb.getWidth(), _vsb.getHeight(), makeVSync(), log);
+ else
+ m2mjpg = new VDP.Mdec2MjpegAvi(getAviFile(), _vsb.getWidth(), _vsb.getHeight(), makeAvSync(_audioDecoder), _audioDecoder.getOutputFormat(), log);
+ _pipeline.setToAvi(m2mjpg);
+ toAvi = m2mjpg;
+ } break;
+
+ case AVI_JYUV: {
+ addBitstream2Mdec();
+ addMdec2Decoded(log);
+ VDP.Decoded2JYuvAvi d2jyuv;
+ if (_audioDecoder == null)
+ d2jyuv = new VDP.Decoded2JYuvAvi(getAviFile(), _vsb.getWidth(), _vsb.getHeight(), makeVSync(), log);
+ else
+ d2jyuv = new VDP.Decoded2JYuvAvi(getAviFile(), _vsb.getWidth(), _vsb.getHeight(), makeAvSync(_audioDecoder), _audioDecoder.getOutputFormat(), log);
+ _pipeline.setToAvi(d2jyuv);
+ toAvi = d2jyuv;
+ } break;
+
+ case AVI_YUV: {
+ addBitstream2Mdec();
+ addMdec2Decoded(log);
+ VDP.Decoded2YuvAvi d2yuv;
+ if (_audioDecoder == null)
+ d2yuv = new VDP.Decoded2YuvAvi(getAviFile(), _vsb.getWidth(), _vsb.getHeight(), makeVSync(), log);
+ else
+ d2yuv = new VDP.Decoded2YuvAvi(getAviFile(), _vsb.getWidth(), _vsb.getHeight(), makeAvSync(_audioDecoder), _audioDecoder.getOutputFormat(), log);
+ _pipeline.setToAvi(d2yuv);
+ toAvi = d2yuv;
+ } break;
+
+ case AVI_RGB: {
+ addBitstream2Mdec();
+ addMdec2Decoded(log);
+ VDP.Decoded2RgbAvi d2rgb;
+ if (_audioDecoder == null)
+ d2rgb = new VDP.Decoded2RgbAvi(getAviFile(), _vsb.getWidth(), _vsb.getHeight(), makeVSync(), log);
+ else
+ d2rgb = new VDP.Decoded2RgbAvi(getAviFile(), _vsb.getWidth(), _vsb.getHeight(), makeAvSync(_audioDecoder), _audioDecoder.getOutputFormat(), log);
+ _pipeline.setToAvi(d2rgb);
+ toAvi = d2rgb;
+ } break;
+
+ default:
+ throw new RuntimeException();
+ }
+
+ if (_audioDecoder == null) {
+ _iStartSector = _vidItem.getStartSector();
+ _iEndSector = _vidItem.getEndSector();
+ _frame2bitstream = new FrameToBitstreamFilter(_vsb.getFileNumberType(), _vsb.getSaveStartFrame(), _vsb.getSaveEndFrame(), log);
+ } else {
+ _pipeline.setAudioDecoder(_audioDecoder);
+ if (toAvi != null)
+ _pipeline.setAudioPacketListener(toAvi);
+
+ _iStartSector = Math.min(_vidItem.getStartSector(),
+ _audioDecoder.getStartSector());
+ _iEndSector = Math.max(_vidItem.getEndSector(),
+ _audioDecoder.getEndSector());
+ // when saving with audio, you can't choose start/end frames
+ _frame2bitstream = new FrameToBitstreamFilter(_vsb.getFileNumberType(), null, null, log);
+ }
+ _pipeline.setMap(_frame2bitstream);
+ }
+
+ private void addBitstream2Mdec() {
+ VDP.Bitstream2Mdec bs2m = new VDP.Bitstream2Mdec();
+ _pipeline.setMap(bs2m);
+ }
+
+ private void addMdec2Decoded(@Nonnull ILocalizedLogger log) {
+ MdecDecodeQuality quality = _vsb.getDecodeQuality();
+ MdecDecoder vidDecoder = quality.makeDecoder(_vidItem.getWidth(), _vidItem.getHeight());
+ if (vidDecoder instanceof MdecDecoder_double) {
+ ChromaUpsample chroma = _vsb.getChromaInterpolation();
+ ((MdecDecoder_double)vidDecoder).setUpsampler(chroma);
+ }
+
+ VDP.Mdec2Decoded mdec2decode = new VDP.Mdec2Decoded(vidDecoder, log);
+ _pipeline.setMap(mdec2decode);
}
private void startup(@Nonnull ILocalizedLogger log) throws LoggedFailure {
- if (_toAvi != null) {
+ VDP.ToAvi avi = _pipeline.getAvi();
+ if (avi != null) {
try {
- _toAvi.open();
+ avi.open();
} catch (LocalizedFileNotFoundException ex) {
throw new LoggedFailure(log, Level.SEVERE, ex.getSourceMessage(), ex);
} catch (FileNotFoundException ex) {
- throw new LoggedFailure(log, Level.SEVERE, I.IO_OPENING_FILE_ERROR_NAME(_toAvi.getOutputFile().toString()), ex);
+ throw new LoggedFailure(log, Level.SEVERE, I.IO_OPENING_FILE_ERROR_NAME(avi.getOutputFile().toString()), ex);
} catch (IOException ex) {
- throw new LoggedFailure(log, Level.SEVERE, I.IO_WRITING_TO_FILE_ERROR_NAME(_toAvi.getOutputFile().toString()), ex);
+ throw new LoggedFailure(log, Level.SEVERE, I.IO_WRITING_TO_FILE_ERROR_NAME(avi.getOutputFile().toString()), ex);
}
}
}
private void shutdown() {
- if (_toAvi != null)
- IO.closeSilently(_toAvi, LOG);
+ VDP.ToAvi avi = _pipeline.getAvi();
+ if (avi != null)
+ IO.closeSilently(avi, LOG);
}
- public void save(@Nonnull ProgressLogger pl,
- @Nonnull ISectorClaimToDemuxedFrame demuxer,
- @CheckForNull ISectorAudioDecoder audioDecoder)
- throws LoggedFailure, TaskCanceledException
- {
- VDP.IBitstreamListener bsListener = setupDecode(pl, audioDecoder);
-
- final int iStartSector, iEndSector;
- FrameToBitstream f2bs;
- if (audioDecoder == null) {
- iStartSector = _vidItem.getStartSector();
- iEndSector = _vidItem.getEndSector();
- f2bs = new FrameToBitstream(bsListener, _vsb.getFileNumberType(), _vsb.getSaveStartFrame(), _vsb.getSaveEndFrame(), pl);
- } else {
- iStartSector = Math.min(_vidItem.getStartSector(),
- audioDecoder.getStartSector());
- iEndSector = Math.max(_vidItem.getEndSector(),
- audioDecoder.getEndSector());
- // when saving with audio, you can't choose start/end frames
- f2bs = new FrameToBitstream(bsListener, _vsb.getFileNumberType(), null, null, pl);
- }
+ public void save(@Nonnull ProgressLogger pl) throws LoggedFailure, TaskCanceledException {
+ SectorClaimSystem it = SectorClaimSystem.create(_vidItem.getSourceCd(), _iStartSector, _iEndSector);
+ _pipeline.attachToSectorClaimer(it);
- demuxer.setFrameListener(f2bs);
+ // finish setting up the pipeline
+ _pipeline.autowire();
+ pl.progressStart(_iEndSector - _iStartSector + 1);
startup(pl);
-
try {
- pl.progressStart(iEndSector - iStartSector + 1);
- SectorClaimSystem it = SectorClaimSystem.create(_vidItem.getSourceCd(), iStartSector, iEndSector);
- demuxer.attachToSectorClaimer(it);
- if (audioDecoder != null)
- audioDecoder.attachToSectorClaimer(it);
for (int iSector = 0; it.hasNext(); iSector++) {
IIdentifiedSector identifiedSector; // keep it out here so I can see what it was while debugging
try {
@@ -164,16 +271,16 @@ public void save(@Nonnull ProgressLogger pl,
I.IO_READING_FROM_FILE_ERROR_NAME(ex.getFile().toString()), ex);
}
- sendEvent(pl, f2bs);
+ sendLogEvent(pl, _frame2bitstream);
pl.progressUpdate(iSector);
// if we've already handled the frames we want to save, break early
- if (f2bs.isDone())
+ if (_frame2bitstream.isDone())
break;
}
it.close(pl);
- sendEvent(pl, f2bs);
+ sendLogEvent(pl, _frame2bitstream);
pl.progressEnd();
} finally {
shutdown();
@@ -181,8 +288,8 @@ public void save(@Nonnull ProgressLogger pl,
}
- private @Nonnull void sendEvent(@Nonnull ProgressLogger pl,
- @Nonnull FrameToBitstream f2bs)
+ private @Nonnull void sendLogEvent(@Nonnull ProgressLogger pl,
+ @Nonnull FrameToBitstreamFilter f2bs)
{
if (!pl.isSeekingEvent())
return;
@@ -205,126 +312,6 @@ public void save(@Nonnull ProgressLogger pl,
}
- private @Nonnull VDP.IBitstreamListener setupDecode(@Nonnull ILocalizedLogger log, @CheckForNull ISectorAudioDecoder audio) {
- final VDP.IBitstreamListener bsListener;
- if (_videoFormat == VideoFormat.IMGSEQ_BITSTREAM) {
- VDP.Bitstream2File bs2f = new VDP.Bitstream2File(makeFormatter(), log);
- bs2f.setGenFileListener(_genFileListener);
- bsListener = bs2f;
- } else {
- bsListener = mdec(log, audio);
- }
-
- return bsListener;
- }
-
- private @Nonnull VDP.IBitstreamListener mdec(@Nonnull ILocalizedLogger log, @CheckForNull ISectorAudioDecoder audio) {
- final VDP.IMdecListener mdecListener;
- switch (_videoFormat) {
- case IMGSEQ_MDEC: {
- VideoFileNameFormatter outFileFormat = makeFormatter();
- VDP.Mdec2File m2f = new VDP.Mdec2File(outFileFormat, _vsb.getWidth(), _vsb.getHeight(), log);
- m2f.setGenFileListener(_genFileListener);
- mdecListener = m2f;
- } break;
- case IMGSEQ_JPG: {
- VDP.Mdec2Jpeg m2jpg = new VDP.Mdec2Jpeg(makeFormatter(), _vsb.getWidth(), _vsb.getHeight(), log);
- m2jpg.setGenFileListener(_genFileListener);
- mdecListener = m2jpg;
- } break;
- case AVI_MJPG: {
- if (audio == null) {
- VDP.Mdec2MjpegAvi x = new VDP.Mdec2MjpegAvi(getAviFile(), _vsb.getWidth(), _vsb.getHeight(), makeVSync(), log);
- _toAvi = x;
- mdecListener = x;
- } else {
- VDP.Mdec2MjpegAvi x = new VDP.Mdec2MjpegAvi(getAviFile(), _vsb.getWidth(), _vsb.getHeight(), makeAvSync(audio), audio.getOutputFormat(), log);
- _toAvi = x;
- mdecListener = x;
- audio.setAudioListener(this);
- }
- _toAvi.setGenFileListener(_genFileListener);
- } break;
- default:
- mdecListener = toDecoded(log, audio);
- }
- return new VDP.Bitstream2Mdec(mdecListener);
- }
-
-
-
- private @Nonnull VDP.IMdecListener toDecoded(@Nonnull ILocalizedLogger log, @CheckForNull ISectorAudioDecoder audio) {
- final VDP.IDecodedListener decodedListener;
- if (_videoFormat == VideoFormat.IMGSEQ_BMP || _videoFormat == VideoFormat.IMGSEQ_PNG) {
- JavaImageFormat javaImgFmt = _videoFormat.getImgFmt();
- VDP.Decoded2JavaImage d2j = new VDP.Decoded2JavaImage(
- makeFormatter(), javaImgFmt, _vsb.getWidth(), _vsb.getHeight(), log);
- d2j.setGenFileListener(_genFileListener);
- decodedListener = d2j;
- } else {
- decodedListener = toAvi(log, audio);
- }
-
- MdecDecodeQuality quality = _vsb.getDecodeQuality();
- MdecDecoder vidDecoder = quality.makeDecoder(_vidItem.getWidth(), _vidItem.getHeight());
- if (vidDecoder instanceof MdecDecoder_double_interpolate) {
- MdecDecoder_double_interpolate.Upsampler chroma = _vsb.getChromaInterpolation();
- ((MdecDecoder_double_interpolate)vidDecoder).setResampler(chroma);
- }
-
- VDP.Mdec2Decoded mdec2decode = new VDP.Mdec2Decoded(vidDecoder, log);
- mdec2decode.setDecoded(decodedListener);
- return mdec2decode;
- }
-
- private VDP.IDecodedListener toAvi(@Nonnull ILocalizedLogger log, @CheckForNull ISectorAudioDecoder audio) {
- final VDP.IDecodedListener toDec;
- if (audio == null) {
- switch (_videoFormat) {
- case AVI_JYUV: {
- VDP.Decoded2JYuvAvi d2 = new VDP.Decoded2JYuvAvi(getAviFile(), _vsb.getWidth(), _vsb.getHeight(), makeVSync(), log);
- _toAvi = d2;
- toDec = d2;
- } break;
- case AVI_YUV: {
- VDP.Decoded2YuvAvi d2 = new VDP.Decoded2YuvAvi(getAviFile(), _vsb.getWidth(), _vsb.getHeight(), makeVSync(), log);
- _toAvi = d2;
- toDec = d2;
- } break;
- case AVI_RGB: {
- VDP.Decoded2RgbAvi d2 = new VDP.Decoded2RgbAvi(getAviFile(), _vsb.getWidth(), _vsb.getHeight(), makeVSync(), log);
- _toAvi = d2;
- toDec = d2;
- } break;
- default:
- throw new RuntimeException();
- }
- } else {
- switch (_videoFormat) {
- case AVI_JYUV: {
- VDP.Decoded2JYuvAvi d2 = new VDP.Decoded2JYuvAvi(getAviFile(), _vsb.getWidth(), _vsb.getHeight(), makeAvSync(audio), audio.getOutputFormat(), log);
- _toAvi = d2;
- toDec = d2;
- } break;
- case AVI_YUV: {
- VDP.Decoded2YuvAvi d2 = new VDP.Decoded2YuvAvi(getAviFile(), _vsb.getWidth(), _vsb.getHeight(), makeAvSync(audio), audio.getOutputFormat(), log);
- _toAvi = d2;
- toDec = d2;
- } break;
- case AVI_RGB: {
- VDP.Decoded2RgbAvi d2 = new VDP.Decoded2RgbAvi(getAviFile(), _vsb.getWidth(), _vsb.getHeight(), makeAvSync(audio), audio.getOutputFormat(), log);
- _toAvi = d2;
- toDec = d2;
- } break;
- default:
- throw new RuntimeException();
- }
- audio.setAudioListener(this);
- }
- _toAvi.setGenFileListener(_genFileListener);
- return toDec;
- }
-
private @Nonnull VideoSync makeVSync() {
VideoSync vidSync = new VideoSync(_vidItem.getAbsolutePresentationStartSector(),
getSectorsPerSecond(),
@@ -358,25 +345,7 @@ private int getSectorsPerSecond() {
// ==============
- /** Captures any output {@link LoggedFailure} and unwinds the stack so the
- * {@link LoggedFailure} can be thrown outside the pipeline. */
- private static class UnwindException extends RuntimeException {
- @Nonnull
- private final LoggedFailure _fail;
- public UnwindException(@Nonnull LoggedFailure fail) {
- _fail = fail;
- }
- public LoggedFailure getFailure() {
- return _fail;
- }
- }
-
- private static class FrameToBitstream implements IDemuxedFrame.Listener {
- @Nonnull
- private final VDP.IBitstreamListener _bsListener;
-
- @Nonnull
- private final FrameNumber.Type _frameNumberType;
+ private static class FrameToBitstreamFilter extends Frame2Bitstream {
@CheckForNull
private final FrameLookup _startFrame;
@@ -390,19 +359,19 @@ private static class FrameToBitstream implements IDemuxedFrame.Listener {
private FrameNumber _currentFrame = null;
private boolean _blnIsDone = false;
- public FrameToBitstream(@Nonnull VDP.IBitstreamListener bsListener,
- @Nonnull FrameNumber.Type frameNumberType,
- @CheckForNull FrameLookup startFrame,
- @CheckForNull FrameLookup endFrame,
- @Nonnull ILocalizedLogger log)
+ public FrameToBitstreamFilter(@Nonnull FrameNumber.Type frameNumberType,
+ @CheckForNull FrameLookup startFrame,
+ @CheckForNull FrameLookup endFrame,
+ @Nonnull ILocalizedLogger log)
{
- _bsListener = bsListener;
- _frameNumberType = frameNumberType;
+ super(frameNumberType);
_startFrame = startFrame;
_endFrame = endFrame;
_log = log;
}
- public void frameComplete(@Nonnull IDemuxedFrame frame) {
+
+ @Override
+ public void frameComplete(@Nonnull IDemuxedFrame frame) throws LoggedFailure {
_currentFrame = frame.getFrame();
if ((_startFrame != null && _startFrame.compareTo(_currentFrame) == FrameCompareIs.GREATERTHAN))
return; // haven't received a starting frame yet
@@ -410,26 +379,22 @@ public void frameComplete(@Nonnull IDemuxedFrame frame) {
_blnIsDone = true;
return; // have past the end frame
}
- byte[] abBitstream = frame.copyDemuxData();
- try {
- FormattedFrameNumber ffn = frame.getFrame().getNumber(_frameNumberType);
- if (ffn == null) {
- // if this video saver was created correctly, the frame number
- // type (i.e. header) should be available in every frame number
- // if not, something weird happened
-
- // this could get ugly down the pipeline if
- // individual frame files are expected.
- // without a frame number, it will keep
- // generating the same file name over and over
- _log.log(Level.SEVERE, I.FRAME_MISSING_FRAME_NUMBER_HEADER(frame.getFrame().getIndexNumber().getFrameValue()));
- // maybe it would be better to just throw here?
- }
- _bsListener.bitstream(abBitstream, frame.getDemuxSize(), ffn, frame.getPresentationSector());
- } catch (LoggedFailure ex) {
- // fire the exception outside of the pipeline
- throw new UnwindException(ex);
+
+ FormattedFrameNumber ffn = frame.getFrame().getNumber(getFrameNumberType());
+ if (ffn == null) {
+ // if this video saver was created correctly, the frame number
+ // type (i.e. header) should be available in every frame number
+ // if not, something weird happened
+
+ // this could get ugly down the pipeline if
+ // individual frame files are expected.
+ // without a frame number, it will keep
+ // generating the same file name over and over
+ _log.log(Level.SEVERE, I.FRAME_MISSING_FRAME_NUMBER_HEADER(frame.getFrame().getIndexNumber().getFrameValue()));
+ // maybe it would be better to just throw here?
}
+
+ super.frameComplete(frame);
}
public @CheckForNull FrameNumber getCurrentFrame() {
return _currentFrame;
@@ -439,14 +404,4 @@ public boolean isDone() {
}
}
- public void audioPacketComplete(DecodedAudioPacket packet,
- ILocalizedLogger log)
- {
- try {
- _toAvi.writeAudio(packet);
- } catch (LoggedFailure ex) {
- // intercept the exception, then unwind outside of the pipeline
- throw new UnwindException(ex);
- }
- }
}
diff --git a/jpsxdec/src/jpsxdec/modules/video/save/VideoSaverBuilder.java b/jpsxdec/src/jpsxdec/modules/video/save/VideoSaverBuilder.java
index 131a56e..be2b5a7 100644
--- a/jpsxdec/src/jpsxdec/modules/video/save/VideoSaverBuilder.java
+++ b/jpsxdec/src/jpsxdec/modules/video/save/VideoSaverBuilder.java
@@ -40,7 +40,9 @@
import argparser.BooleanHolder;
import argparser.StringHolder;
import java.io.File;
+import java.util.ArrayList;
import java.util.List;
+import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -53,13 +55,14 @@
import jpsxdec.i18n.UnlocalizedMessage;
import jpsxdec.i18n.exception.LocalizedDeserializationFail;
import jpsxdec.i18n.exception.LoggedFailure;
+import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.i18n.log.ProgressLogger;
import jpsxdec.modules.video.DiscItemVideoStream;
import jpsxdec.modules.video.framenumber.FormattedFrameNumber;
import jpsxdec.modules.video.framenumber.FrameLookup;
import jpsxdec.modules.video.framenumber.FrameNumber;
import jpsxdec.psxvideo.mdec.Calc;
-import jpsxdec.psxvideo.mdec.MdecDecoder_double_interpolate.Upsampler;
+import jpsxdec.psxvideo.mdec.ChromaUpsample;
import jpsxdec.util.ArgParser;
import jpsxdec.util.Fraction;
import jpsxdec.util.TaskCanceledException;
@@ -72,9 +75,15 @@ public abstract class VideoSaverBuilder extends DiscItemSaverBuilder {
@Nonnull
private final DiscItemVideoStream _sourceVidItem;
+ private final List _imgFmtList = VideoFormat.getAvailable();
+ private final List _imgFmtListNoBs;
+
+
protected VideoSaverBuilder(@Nonnull DiscItemVideoStream vidItem) {
_sourceVidItem = vidItem;
_types = vidItem.getFrameNumberTypes();
+ _imgFmtListNoBs = new ArrayList(_imgFmtList);
+ _imgFmtListNoBs.remove(VideoFormat.IMGSEQ_BITSTREAM);
}
public boolean copySettingsTo(@Nonnull DiscItemSaverBuilder otherBuilder) {
@@ -170,12 +179,17 @@ public boolean getSingleSpeed_enabled() {
// .........................................................................
- private final List _imgFmtList = VideoFormat.getAvailable();
public @Nonnull VideoFormat getVideoFormat_listItem(int i) {
- return _imgFmtList.get(i);
+ if (_sourceVidItem.hasIndependentBitstream())
+ return _imgFmtList.get(i);
+ else
+ return _imgFmtListNoBs.get(i);
}
public int getVideoFormat_listSize() {
- return _imgFmtList.size();
+ if (_sourceVidItem.hasIndependentBitstream())
+ return _imgFmtList.size();
+ else
+ return _imgFmtListNoBs.size();
}
@Nonnull
@@ -184,6 +198,13 @@ public int getVideoFormat_listSize() {
return _videoFormat;
}
public void setVideoFormat(@Nonnull VideoFormat val) {
+ if (_sourceVidItem.hasIndependentBitstream()) {
+ if (!_imgFmtList.contains(val))
+ throw new IllegalArgumentException();
+ } else {
+ if (!_imgFmtListNoBs.contains(val))
+ throw new IllegalArgumentException();
+ }
_videoFormat = val;
firePossibleChange();
}
@@ -206,17 +227,32 @@ public boolean getCrop_enabled() {
}
public int getWidth() {
- if (getCrop())
- return _sourceVidItem.getWidth();
- else
+ if (getCrop()) {
+ if (getVideoFormat().mustHaveEvenDims() && _sourceVidItem.getWidth() % 2 == 1) {
+ return _sourceVidItem.getWidth() + 1;
+ } else {
+ return _sourceVidItem.getWidth();
+ }
+ } else {
return Calc.fullDimension(_sourceVidItem.getWidth());
+ }
}
public int getHeight() {
- if (getCrop())
- return _sourceVidItem.getHeight();
- else
+ if (getCrop()) {
+ if (getVideoFormat().mustHaveEvenDims() && _sourceVidItem.getHeight() % 2 == 1) {
+ return _sourceVidItem.getHeight() + 1;
+ } else {
+ return _sourceVidItem.getHeight();
+ }
+ } else {
return Calc.fullDimension(_sourceVidItem.getHeight());
+ }
+ }
+
+ public boolean makingDimensionsEven() {
+ return getCrop() && getVideoFormat().mustHaveEvenDims() &&
+ ((_sourceVidItem.getWidth() | _sourceVidItem.getHeight() & 1) != 0);
}
// .........................................................................
@@ -229,7 +265,7 @@ public int getDecodeQuality_listSize() {
}
@CheckForNull
- private MdecDecodeQuality _decodeQuality = MdecDecodeQuality.HIGH_PLUS;
+ private MdecDecodeQuality _decodeQuality = MdecDecodeQuality.HIGH;
public @CheckForNull MdecDecodeQuality getDecodeQuality() {
if (getVideoFormat().getDecodeQualityCount() == 1)
return getVideoFormat().getMdecDecodeQuality(0);
@@ -247,29 +283,29 @@ public boolean getDecodeQuality_enabled() {
// .........................................................................
@Nonnull
- private Upsampler _mdecUpsampler = Upsampler.Bicubic;
+ private ChromaUpsample _mdecUpsampler = ChromaUpsample.Bicubic;
public boolean getChromaInterpolation_enabled() {
MdecDecodeQuality q = getDecodeQuality();
return getDecodeQuality_enabled() && q != null && q.canUpsample();
}
- public @Nonnull Upsampler getChromaInterpolation_listItem(int i) {
- return Upsampler.values()[i];
+ public @Nonnull ChromaUpsample getChromaInterpolation_listItem(int i) {
+ return ChromaUpsample.values()[i];
}
public int getChromaInterpolation_listSize() {
- return Upsampler.values().length;
+ return ChromaUpsample.values().length;
}
- public @Nonnull Upsampler getChromaInterpolation() {
+ public @Nonnull ChromaUpsample getChromaInterpolation() {
if (getChromaInterpolation_enabled())
return _mdecUpsampler;
else
- return Upsampler.NearestNeighbor;
+ return ChromaUpsample.NearestNeighbor;
}
- public void setChromaInterpolation(@Nonnull Upsampler val) {
+ public void setChromaInterpolation(@Nonnull ChromaUpsample val) {
_mdecUpsampler = val;
firePossibleChange();
}
@@ -351,7 +387,7 @@ protected void makeHelpTable(@Nonnull TabularFeedback tfb) {
tfb.newRow();
tfb.addCell(I.CMD_VIDEO_QUALITY());
- c = new Cell(I.CMD_VIDEO_QUALITY_HELP(MdecDecodeQuality.HIGH_PLUS.getCmdLine()));
+ c = new Cell(I.CMD_VIDEO_QUALITY_HELP(MdecDecodeQuality.HIGH.getCmdLine()));
for (MdecDecodeQuality quality : MdecDecodeQuality.values()) {
c.addLine(quality.getCmdLine(), 2);
}
@@ -360,8 +396,8 @@ protected void makeHelpTable(@Nonnull TabularFeedback tfb) {
tfb.newRow();
tfb.addCell(I.CMD_VIDEO_UP());
- c = new Cell(I.CMD_VIDEO_UP_HELP(Upsampler.Bicubic.getDescription()));
- for (Upsampler up : Upsampler.values()) {
+ c = new Cell(I.CMD_VIDEO_UP_HELP(ChromaUpsample.Bicubic.getDescription()));
+ for (ChromaUpsample up : ChromaUpsample.values()) {
c.addLine(up.getCmdLineHelp(), 2);
}
tfb.addCell(c);
@@ -455,7 +491,7 @@ public void commandLineOptions(@Nonnull ArgParser ap, @Nonnull FeedbackStream fb
throw new RuntimeException("Only header type should ever be unsupported here");
}
} else {
- fbs.printlnWarn(I.CMD_FRAME_NUMBER_TYPE_INVALID(num.value));
+ fbs.printlnWarn(I.CMD_IGNORING_INVALID_VALUE_FOR_CMD(num.value, "-num"));
}
}
@@ -468,7 +504,7 @@ public void commandLineOptions(@Nonnull ArgParser ap, @Nonnull FeedbackStream fb
if (vf != null)
setVideoFormat(vf);
else
- fbs.printlnWarn(I.CMD_VIDEO_FORMAT_INVALID(vidfmt.value));
+ fbs.printlnWarn(I.CMD_IGNORING_INVALID_VALUE_FOR_CMD(vidfmt.value, "-vf,-vidfmt"));
}
if (quality.value != null) {
@@ -476,15 +512,15 @@ public void commandLineOptions(@Nonnull ArgParser ap, @Nonnull FeedbackStream fb
if (dq != null)
setDecodeQuality(dq);
else
- fbs.printlnWarn(I.CMD_DECODE_QUALITY_INVALID(quality.value));
+ fbs.printlnWarn(I.CMD_IGNORING_INVALID_VALUE_FOR_CMD(quality.value, "-q,-quality"));
}
if (up.value != null) {
- Upsampler upsampler = Upsampler.fromCmdLine(up.value);
+ ChromaUpsample upsampler = ChromaUpsample.fromCmdLine(up.value);
if (upsampler != null)
setChromaInterpolation(upsampler);
else
- fbs.printlnWarn(I.CMD_UPSAMPLE_QUALITY_INVALID(up.value));
+ fbs.printlnWarn(I.CMD_IGNORING_INVALID_VALUE_FOR_CMD(up.value, "-up"));
}
setCrop(!nocrop.value);
@@ -495,60 +531,64 @@ public void commandLineOptions(@Nonnull ArgParser ap, @Nonnull FeedbackStream fb
} else if ("2".equals(discSpeed.value)) {
setSingleSpeed(false);
} else {
- fbs.printWarn(I.CMD_IGNORING_INVALID_DISC_SPEED(discSpeed.value));
+ fbs.printWarn(I.CMD_IGNORING_INVALID_VALUE_FOR_CMD(discSpeed.value, "-ds"));
}
}
}
@Override
- public void printSelectedOptions(@Nonnull FeedbackStream fbs) {
+ public void printSelectedOptions(@Nonnull ILocalizedLogger log) {
VideoFormat vidFmt = getVideoFormat();
+ log.log(Level.INFO, I.CMD_VIDEO_FORMAT(getVideoFormat().toString()));
+
if (vidFmt.getDecodeQualityCount() > 0) {
MdecDecodeQuality quality = getDecodeQuality();
- fbs.println(I.CMD_DECODE_QUALITY(quality.toString()));
+ log.log(Level.INFO, I.CMD_DECODE_QUALITY(quality.toString()));
if (quality.canUpsample()) {
- Upsampler chroma = getChromaInterpolation();
- fbs.println(I.CMD_UPSAMPLE_QUALITY(chroma.toString()));
+ ChromaUpsample chroma = getChromaInterpolation();
+ log.log(Level.INFO, I.CMD_UPSAMPLE_QUALITY(chroma.getDescription().getLocalizedMessage()));
}
}
if (getCrop_enabled())
- fbs.println(I.CMD_CROPPING(getCrop() ? 1 : 0));
+ log.log(Level.INFO, I.CMD_CROPPING(getCrop() ? 1 : 0));
- fbs.println(I.CMD_VIDEO_FORMAT(getVideoFormat().toString()));
+ if (makingDimensionsEven())
+ log.log(Level.INFO, I.CMD_VIDEO_MUST_HAVE_EVEN_DIMS(getVideoFormat().toString()));
+ log.log(Level.INFO, I.CMD_DIMENSIONS(getWidth(), getHeight()));
if (vidFmt.isSequence()) {
File[] _aoOutRng = getOutputFileRange();
if (_aoOutRng.length == 1) {
- fbs.println(I.CMD_OUTPUT_FILE(_aoOutRng[0]));
+ log.log(Level.INFO, I.CMD_OUTPUT_FILE(_aoOutRng[0]));
} else {
- fbs.println(I.CMD_OUTPUT_FILES(_aoOutRng[0], _aoOutRng[1]));
+ log.log(Level.INFO, I.CMD_OUTPUT_FILES(_aoOutRng[0], _aoOutRng[1]));
}
} else {
File outFile = VideoFileNameFormatter.singleFile(null, _sourceVidItem, vidFmt);
- fbs.println(I.CMD_DISC_SPEED(getSingleSpeed() ? 1 : 2, getFps().asDouble()));
+ log.log(Level.INFO, I.CMD_DISC_SPEED(getSingleSpeed() ? 1 : 2, getFps().asDouble()));
if (getSavingAudio()) {
- fbs.println(I.CMD_SAVING_WITH_AUDIO_ITEMS());
- printSelectedAudioOptions(fbs);
- fbs.println(I.CMD_EMULATE_PSX_AV_SYNC_NY(getEmulatePsxAvSync() ? 1 : 0));
+ log.log(Level.INFO, I.CMD_SAVING_WITH_AUDIO_ITEMS());
+ printSelectedAudioOptions(log);
+ log.log(Level.INFO, I.CMD_EMULATE_PSX_AV_SYNC_NY(getEmulatePsxAvSync() ? 1 : 0));
} else {
- fbs.println(I.CMD_NO_AUDIO());
+ log.log(Level.INFO, I.CMD_NO_AUDIO());
}
- fbs.println(I.CMD_SAVING_AS(outFile));
+ log.log(Level.INFO, I.CMD_SAVING_AS(outFile));
}
FrameLookup startFrame = getSaveStartFrame();
FrameLookup endFrame = getSaveEndFrame();
if (startFrame != null)
- fbs.println(I.CMD_FRAME_RANGE_BEFORE(startFrame.toString()));
+ log.log(Level.INFO, I.CMD_FRAME_RANGE_BEFORE(startFrame.toString()));
if (endFrame != null)
- fbs.println(I.CMD_FRAME_RANGE_AFTER(endFrame.toString()));
+ log.log(Level.INFO, I.CMD_FRAME_RANGE_AFTER(endFrame.toString()));
}
- abstract protected void printSelectedAudioOptions(@Nonnull FeedbackStream fbs);
+ abstract protected void printSelectedAudioOptions(@Nonnull ILocalizedLogger log);
@Override
diff --git a/jpsxdec/src/jpsxdec/modules/video/save/VideoSaverPanel.java b/jpsxdec/src/jpsxdec/modules/video/save/VideoSaverPanel.java
index 14a1a7e..4501bc3 100644
--- a/jpsxdec/src/jpsxdec/modules/video/save/VideoSaverPanel.java
+++ b/jpsxdec/src/jpsxdec/modules/video/save/VideoSaverPanel.java
@@ -54,7 +54,7 @@
import jpsxdec.discitems.CombinedBuilderListener;
import jpsxdec.discitems.ParagraphPanel;
import jpsxdec.i18n.I;
-import jpsxdec.psxvideo.mdec.MdecDecoder_double_interpolate.Upsampler;
+import jpsxdec.psxvideo.mdec.ChromaUpsample;
import jpsxdec.util.Fraction;
/** Abstract {@link ParagraphPanel} shared among video
@@ -123,7 +123,7 @@ public Object getElementAt(int index) {
return _bl.getBuilder().getChromaInterpolation_listItem(index);
}
public void setSelectedItem(Object anItem) {
- _bl.getBuilder().setChromaInterpolation((Upsampler) anItem);
+ _bl.getBuilder().setChromaInterpolation((ChromaUpsample) anItem);
}
public Object getSelectedItem() {
return _bl.getBuilder().getChromaInterpolation();
diff --git a/jpsxdec/src/jpsxdec/modules/video/sectorbased/DemuxedFrameWithNumberAndDims.java b/jpsxdec/src/jpsxdec/modules/video/sectorbased/DemuxedFrameWithNumberAndDims.java
index 9d07c60..2450092 100644
--- a/jpsxdec/src/jpsxdec/modules/video/sectorbased/DemuxedFrameWithNumberAndDims.java
+++ b/jpsxdec/src/jpsxdec/modules/video/sectorbased/DemuxedFrameWithNumberAndDims.java
@@ -46,6 +46,7 @@
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.video.IDemuxedFrame;
import jpsxdec.modules.video.framenumber.FrameNumber;
+import jpsxdec.psxvideo.mdec.MdecInputStream;
import jpsxdec.util.DemuxedData;
import jpsxdec.util.Fraction;
@@ -53,7 +54,8 @@
public class DemuxedFrameWithNumberAndDims implements IDemuxedFrame {
public interface Listener {
- void frameComplete(@Nonnull DemuxedFrameWithNumberAndDims frame, @Nonnull ILocalizedLogger log);
+ void frameComplete(@Nonnull DemuxedFrameWithNumberAndDims frame, @Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
void endOfSectors(@Nonnull ILocalizedLogger log);
}
@@ -83,6 +85,10 @@ public void setFrame(@Nonnull FrameNumber frameNumber) {
return _frameNumber;
}
+ public @CheckForNull MdecInputStream getCustomFrameMdecStream() {
+ return null;
+ }
+
public int getWidth() { return _iWidth; }
public int getHeight() { return _iHeight; }
public int getStartSector() { return _demux.getStartSector(); }
@@ -113,7 +119,7 @@ public void writeToSectors(@Nonnull byte[] abNewDemux,
@Override
public String toString() {
- return String.format("Frame %d sectors %d-%d %dx%d %d chunks %d bytes",
+ return String.format("Frame %d sectors %d-%d %dx%d chunks:%d bytes:%d",
getHeaderFrameNumber(),
getStartSector(), getEndSector(),
getWidth(), getHeight(), _demux.getPieceCount(),
diff --git a/jpsxdec/src/jpsxdec/modules/video/sectorbased/DiscItemSectorBasedVideoStream.java b/jpsxdec/src/jpsxdec/modules/video/sectorbased/DiscItemSectorBasedVideoStream.java
index 3c46fab..0ac3a45 100644
--- a/jpsxdec/src/jpsxdec/modules/video/sectorbased/DiscItemSectorBasedVideoStream.java
+++ b/jpsxdec/src/jpsxdec/modules/video/sectorbased/DiscItemSectorBasedVideoStream.java
@@ -65,6 +65,7 @@
import jpsxdec.modules.video.framenumber.IndexSectorFrameNumber;
import jpsxdec.modules.xa.DiscItemXaAudioStream;
import jpsxdec.util.Fraction;
+import jpsxdec.util.Misc;
import jpsxdec.util.player.PlayController;
/** Represents generic sector-based PlayStation video streams
@@ -169,20 +170,20 @@ final public double getApproxDuration() {
}
@Override
- public @Nonnull ILocalizedMessage getInterestingDescription() {
+ final public @Nonnull ILocalizedMessage getInterestingDescription() {
int iDiscSpeed = getDiscSpeed();
int iFrameCount = getFrameCount();
if (iDiscSpeed > 0) {
int iSectorsPerSecond = iDiscSpeed * 75;
- Date secs = new Date(0, 0, 0, 0, 0, Math.max(getSectorLength() / iSectorsPerSecond, 1));
+ Date secs = Misc.dateFromSeconds(Math.max(getSectorLength() / iSectorsPerSecond, 1));
return I.GUI_STR_VIDEO_DETAILS(
getWidth(), getHeight(),
iFrameCount,
Fraction.divide(iSectorsPerSecond, getSectorsPerFrame()).asDouble(),
secs);
} else {
- Date secs150 = new Date(0, 0, 0, 0, 0, Math.max(getSectorLength() / 150, 1));
- Date secs75 = new Date(0, 0, 0, 0, 0, Math.max(getSectorLength() / 75, 1));
+ Date secs150 = Misc.dateFromSeconds(Math.max(getSectorLength() / 150, 1));
+ Date secs75 = Misc.dateFromSeconds(Math.max(getSectorLength() / 75, 1));
return I.GUI_STR_VIDEO_DETAILS_UNKNOWN_FPS(
getWidth(), getHeight(),
iFrameCount,
@@ -229,6 +230,7 @@ public void frameComplete(IDemuxedFrame frame) {
@Override
public @Nonnull PlayController makePlayController() {
+ MediaPlayer mp;
if (hasAudio()) {
List audios = _parallelAudio.getLongestNonIntersectingAudioStreams();
@@ -243,10 +245,11 @@ public void frameComplete(IDemuxedFrame frame) {
int iStartSector = Math.min(decoder.getStartSector(), getStartSector());
int iEndSector = Math.max(decoder.getEndSector(), getEndSector());
- return new PlayController(new MediaPlayer(this, makeDemuxer(), decoder, iStartSector, iEndSector));
+ mp = new MediaPlayer(this, makeDemuxer(), decoder, iStartSector, iEndSector);
} else {
- return new PlayController(new MediaPlayer(this, makeDemuxer()));
+ mp = new MediaPlayer(this, makeDemuxer());
}
+ return mp.getPlayController();
}
}
diff --git a/jpsxdec/src/jpsxdec/modules/video/sectorbased/ISelfDemuxingVideoSector.java b/jpsxdec/src/jpsxdec/modules/video/sectorbased/ISelfDemuxingVideoSector.java
index 71ad179..8017191 100644
--- a/jpsxdec/src/jpsxdec/modules/video/sectorbased/ISelfDemuxingVideoSector.java
+++ b/jpsxdec/src/jpsxdec/modules/video/sectorbased/ISelfDemuxingVideoSector.java
@@ -37,6 +37,7 @@
package jpsxdec.modules.video.sectorbased;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.IIdentifiedSector;
@@ -48,6 +49,6 @@ public interface ISelfDemuxingVideoSector extends IIdentifiedSector {
public interface IDemuxer {
boolean addSectorIfPartOfFrame(@Nonnull ISelfDemuxingVideoSector sector);
boolean isFrameComplete();
- @Nonnull DemuxedFrameWithNumberAndDims finishFrame(@Nonnull ILocalizedLogger log);
+ @CheckForNull DemuxedFrameWithNumberAndDims finishFrame(@Nonnull ILocalizedLogger log);
}
}
diff --git a/jpsxdec/src/jpsxdec/modules/video/sectorbased/SectorBasedFrameBuilder.java b/jpsxdec/src/jpsxdec/modules/video/sectorbased/SectorBasedFrameBuilder.java
index 4ccb886..4842889 100644
--- a/jpsxdec/src/jpsxdec/modules/video/sectorbased/SectorBasedFrameBuilder.java
+++ b/jpsxdec/src/jpsxdec/modules/video/sectorbased/SectorBasedFrameBuilder.java
@@ -56,6 +56,7 @@ public class SectorBasedFrameBuilder {
private final int _iHeaderFrameNumber;
/** Start building the frame with the first sector. */
+ @SuppressWarnings("unchecked")
public SectorBasedFrameBuilder(@Nonnull T firstChunk,
int iChunkNumber, int iExpectedChunks,
int iSector, int iHeaderFrameNumber,
@@ -67,7 +68,7 @@ public SectorBasedFrameBuilder(@Nonnull T firstChunk,
// if this happens, the incoming data is pretty messed up
// this logic will effictively immediately end the frame
log.log(Level.WARNING,
- I.DEMUX_CHUNK_NUM_GTE_CHUNKS_IN_FRAME(iSector, iChunkNumber, iExpectedChunks));
+ I.FRAME_NUM_CORRUPTED(String.valueOf(iHeaderFrameNumber)));
_aoChunks = (T[]) new Object[iChunkNumber + 1];
}
_aoChunks[iChunkNumber] = firstChunk;
diff --git a/jpsxdec/src/jpsxdec/modules/video/sectorbased/SectorBasedVideoSaverBuilder.java b/jpsxdec/src/jpsxdec/modules/video/sectorbased/SectorBasedVideoSaverBuilder.java
index 6d9725c..628f00d 100644
--- a/jpsxdec/src/jpsxdec/modules/video/sectorbased/SectorBasedVideoSaverBuilder.java
+++ b/jpsxdec/src/jpsxdec/modules/video/sectorbased/SectorBasedVideoSaverBuilder.java
@@ -41,6 +41,7 @@
import java.io.File;
import java.util.ArrayList;
import java.util.List;
+import java.util.logging.Level;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import jpsxdec.discitems.DiscItemSaverBuilder;
@@ -49,6 +50,7 @@
import jpsxdec.i18n.I;
import jpsxdec.i18n.TabularFeedback;
import jpsxdec.i18n.exception.LoggedFailure;
+import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.i18n.log.ProgressLogger;
import jpsxdec.modules.sharedaudio.DiscItemAudioStream;
import jpsxdec.modules.sharedaudio.ISectorAudioDecoder;
@@ -240,9 +242,9 @@ protected void makeHelpTable(@Nonnull TabularFeedback tfb) {
}
@Override
- protected void printSelectedAudioOptions(FeedbackStream fbs) {
+ protected void printSelectedAudioOptions(@Nonnull ILocalizedLogger log) {
for (DiscItemAudioStream discItemAudioStream : collectSelectedAudio()) {
- fbs.println(discItemAudioStream.getDetails());
+ log.log(Level.INFO, discItemAudioStream.getDetails());
}
}
@@ -261,6 +263,7 @@ public void startSave(@Nonnull ProgressLogger pl, @CheckForNull File directory)
throws LoggedFailure, TaskCanceledException
{
clearGeneratedFiles();
+ printSelectedOptions(pl);
final ISectorAudioDecoder audDecoder;
final ISectorClaimToDemuxedFrame demuxer = _sourceVidItem.makeDemuxer();
@@ -272,8 +275,8 @@ else if (parallelAudio.size() == 1)
else
audDecoder = new AudioStreamsCombiner(parallelAudio, getAudioVolume());
- VideoSaver vs = new VideoSaver(_sourceVidItem, this, thisGeneratedFileListener, directory);
- vs.save(pl, demuxer, audDecoder);
+ VideoSaver vs = new VideoSaver(_sourceVidItem, this, thisGeneratedFileListener, directory, pl, demuxer, audDecoder);
+ vs.save(pl);
}
}
diff --git a/jpsxdec/src/jpsxdec/modules/video/sectorbased/VideoSectorCommon16byteHeader.java b/jpsxdec/src/jpsxdec/modules/video/sectorbased/VideoSectorCommon16byteHeader.java
index 58e135a..aa45080 100644
--- a/jpsxdec/src/jpsxdec/modules/video/sectorbased/VideoSectorCommon16byteHeader.java
+++ b/jpsxdec/src/jpsxdec/modules/video/sectorbased/VideoSectorCommon16byteHeader.java
@@ -58,20 +58,20 @@ public VideoSectorCommon16byteHeader(@Nonnull CdSector cdSector) {
iUsedDemuxedSize = cdSector.readSInt32LE(12);
}
- /** @return If the chunk number is invalid according to common convention. */
- public boolean isChunkNumberStandard() {
+ /** @return If the chunk number is valid according to common convention. */
+ public boolean hasStandardChunkNumber() {
return iChunkNumber >= 0;
}
- /** @return If the chunk count is invalid according to common convention. */
- public boolean isChunksInFrameStandard() {
+ /** @return If the chunk count is valid according to common convention. */
+ public boolean hasStandardChunksInFrame() {
return iChunksInThisFrame >= 1;
}
- /** @return If the frame number is invalid according to common convention. */
- public boolean isFrameNumberStandard() {
+ /** @return If the frame number is valid according to common convention. */
+ public boolean hasStandardFrameNumber() {
return iFrameNumber >= 0;
}
- /** @return If the used demux size is invalid according to common convention. */
- public boolean isUsedDemuxSizeStandard() {
+ /** @return If the used demux size is valid according to common convention. */
+ public boolean hasStandardUsedDemuxSize() {
return iUsedDemuxedSize >= 1;
}
}
diff --git a/jpsxdec/src/jpsxdec/modules/video/sectorbased/VideoSectorIdentifier.java b/jpsxdec/src/jpsxdec/modules/video/sectorbased/VideoSectorIdentifier.java
index c96c51b..9ccc9be 100644
--- a/jpsxdec/src/jpsxdec/modules/video/sectorbased/VideoSectorIdentifier.java
+++ b/jpsxdec/src/jpsxdec/modules/video/sectorbased/VideoSectorIdentifier.java
@@ -42,6 +42,7 @@
import jpsxdec.cdreaders.CdSector;
import jpsxdec.modules.IIdentifiedSector;
import jpsxdec.modules.SectorClaimSystem;
+import jpsxdec.modules.aconcagua.SectorAconcaguaVideo;
import jpsxdec.modules.granturismo.SectorGTVideo;
import jpsxdec.modules.square.SectorChronoXVideo;
import jpsxdec.modules.square.SectorChronoXVideoNull;
@@ -52,6 +53,7 @@
import jpsxdec.modules.strvideo.SectorFF7Video;
import jpsxdec.modules.strvideo.SectorIkiVideo;
import jpsxdec.modules.strvideo.SectorLainVideo;
+import jpsxdec.modules.strvideo.SectorReBoot;
import jpsxdec.modules.strvideo.SectorStrVideo;
/** Shared place for all modules to register order sensitive
@@ -74,6 +76,7 @@ public class VideoSectorIdentifier {
if ((vid = isVideo(new SectorIkiVideo(cdSector), cs)) != null) return vid;
if ((vid = isVideo(new SectorGTVideo(cdSector), cs)) != null) return vid;
if ((vid = isVideo(new SectorChronoXVideo(cdSector), cs)) != null) return vid;
+ if ((vid = isVideo(new SectorAconcaguaVideo(cdSector), cs)) != null) return vid;
if (isMatch(new SectorChronoXVideoNull(cdSector), cs)) return null;
if ((vid = isVideo(new SectorLainVideo(cdSector), cs)) != null) return vid;
@@ -85,6 +88,8 @@ public class VideoSectorIdentifier {
return null;
}
+ if ((vid = isVideo(new SectorReBoot(cdSector), cs)) != null) return vid;
+
// FF7 has such a vague header, it can easily be falsely identified
// when it should be one of the headers above
if ((vid = isVideo(new SectorFF7Video(cdSector), cs)) != null) return vid;
diff --git a/jpsxdec/src/jpsxdec/modules/video/sectorbased/VideoSectorWithFrameNumberDemuxer.java b/jpsxdec/src/jpsxdec/modules/video/sectorbased/VideoSectorWithFrameNumberDemuxer.java
index 599c54c..879c9eb 100644
--- a/jpsxdec/src/jpsxdec/modules/video/sectorbased/VideoSectorWithFrameNumberDemuxer.java
+++ b/jpsxdec/src/jpsxdec/modules/video/sectorbased/VideoSectorWithFrameNumberDemuxer.java
@@ -54,7 +54,7 @@ public class VideoSectorWithFrameNumberDemuxer implements ISelfDemuxingVideoSect
private final int _iWidth, _iHeight;
public VideoSectorWithFrameNumberDemuxer(@Nonnull IVideoSectorWithFrameNumber firstChunk,
- @Nonnull ILocalizedLogger log)
+ @Nonnull ILocalizedLogger log)
{
_bldr = new SectorBasedFrameBuilder(firstChunk,
firstChunk.getChunkNumber(), firstChunk.getChunksInFrame(),
@@ -64,6 +64,18 @@ public VideoSectorWithFrameNumberDemuxer(@Nonnull IVideoSectorWithFrameNumber fi
_iHeight = firstChunk.getHeight();
}
+ public int getWidth() {
+ return _iWidth;
+ }
+
+ public int getHeight() {
+ return _iHeight;
+ }
+
+ public int getHeaderFrameNumber() {
+ return _bldr.getHeaderFrameNumber();
+ }
+
public boolean addSectorIfPartOfFrame(@Nonnull ISelfDemuxingVideoSector sector) {
if (!(sector instanceof IVideoSectorWithFrameNumber))
return false;
@@ -81,12 +93,16 @@ public boolean isFrameComplete() {
return _bldr.isFrameComplete();
}
+ final protected @Nonnull List getNonNullChunks(@Nonnull ILocalizedLogger log) {
+ return _bldr.getNonNullChunks(log);
+ }
+
public @Nonnull DemuxedFrameWithNumberAndDims finishFrame(@Nonnull ILocalizedLogger log) {
- List sectors = _bldr.getNonNullChunks(log);
+ List sectors = getNonNullChunks(log);
// need to wrap the sectors in something compatible with IReplaceableVideoSector
List wrappedSectors =
- new ArrayList();
+ new ArrayList(sectors.size());
for (IVideoSectorWithFrameNumber vidSector : sectors) {
wrappedSectors.add(new VideoSectorReplaceableDemuxPiece(vidSector));
diff --git a/jpsxdec/src/jpsxdec/modules/video/sectorbased/fps/WholeNumberSectorsPerFrame.java b/jpsxdec/src/jpsxdec/modules/video/sectorbased/fps/WholeNumberSectorsPerFrame.java
index 692df61..115235c 100644
--- a/jpsxdec/src/jpsxdec/modules/video/sectorbased/fps/WholeNumberSectorsPerFrame.java
+++ b/jpsxdec/src/jpsxdec/modules/video/sectorbased/fps/WholeNumberSectorsPerFrame.java
@@ -178,6 +178,7 @@ else if (_startingPoints.isEmpty())
* The original Collection is not modified. */
private static @Nonnull TreeSet removeFactors(@Nonnull TreeSet sourceValues)
{
+ @SuppressWarnings("unchecked")
TreeSet copy = (TreeSet)sourceValues.clone();
for (Iterator it = copy.iterator(); it.hasNext();) {
diff --git a/jpsxdec/src/jpsxdec/modules/xa/DiscItemXaAudioStream.java b/jpsxdec/src/jpsxdec/modules/xa/DiscItemXaAudioStream.java
index e58739b..a1686f4 100644
--- a/jpsxdec/src/jpsxdec/modules/xa/DiscItemXaAudioStream.java
+++ b/jpsxdec/src/jpsxdec/modules/xa/DiscItemXaAudioStream.java
@@ -67,6 +67,7 @@
import jpsxdec.modules.sharedaudio.ISectorAudioDecoder;
import jpsxdec.util.IO;
import jpsxdec.util.IncompatibleException;
+import jpsxdec.util.Misc;
import jpsxdec.util.TaskCanceledException;
/** Represents a series of XA ADPCM sectors that combine to make an audio stream. */
@@ -226,7 +227,7 @@ public int getDiscSpeed() {
@Override
public @Nonnull ILocalizedMessage getInterestingDescription() {
- Date secs = new Date(0, 0, 0, 0, 0, Math.max((int)getApproxDuration(), 1));
+ Date secs = Misc.dateFromSeconds(Math.max((int)getApproxDuration(), 1));
return I.GUI_AUDIO_DESCRIPTION(secs, _iSampleFramesPerSecond, _blnIsStereo ? 2 : 1);
}
diff --git a/jpsxdec/src/jpsxdec/modules/xa/SectorClaimToSectorXaAudio.java b/jpsxdec/src/jpsxdec/modules/xa/SectorClaimToSectorXaAudio.java
index 2facec4..183f762 100644
--- a/jpsxdec/src/jpsxdec/modules/xa/SectorClaimToSectorXaAudio.java
+++ b/jpsxdec/src/jpsxdec/modules/xa/SectorClaimToSectorXaAudio.java
@@ -43,6 +43,7 @@
import javax.annotation.Nonnull;
import jpsxdec.cdreaders.CdSector;
import jpsxdec.cdreaders.CdSectorXaSubHeader;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.SectorClaimSystem;
import jpsxdec.util.IOIterator;
@@ -52,13 +53,13 @@ public class SectorClaimToSectorXaAudio extends SectorClaimSystem.SectorClaimer
public interface Listener {
void feedXaSector(@Nonnull CdSector cdSector,
@CheckForNull SectorXaAudio xaSector,
- @Nonnull ILocalizedLogger log);
+ @Nonnull ILocalizedLogger log)
+ throws LoggedFailure;
void xaEof(int iChannel);
public void endOfSectors(@Nonnull ILocalizedLogger log);
}
- @CheckForNull
private final ArrayList _listeners = new ArrayList();
public SectorClaimToSectorXaAudio() {
@@ -70,7 +71,7 @@ public void addListener(@CheckForNull Listener listener) {
public void sectorRead(@Nonnull SectorClaimSystem.ClaimableSector cs,
@Nonnull IOIterator peekIt,
@Nonnull ILocalizedLogger log)
- throws IOException
+ throws IOException, SectorClaimSystem.ClaimerFailure
{
if (cs.isClaimed())
return;
@@ -90,7 +91,11 @@ public void sectorRead(@Nonnull SectorClaimSystem.ClaimableSector cs,
if (sectorIsInRange(cs.getSector().getSectorIndexFromStart())) {
for (Listener listener : _listeners) {
- listener.feedXaSector(cdSector, xaSect, log);
+ try {
+ listener.feedXaSector(cdSector, xaSect, log);
+ } catch (LoggedFailure ex) {
+ throw new SectorClaimSystem.ClaimerFailure(ex);
+ }
}
CdSectorXaSubHeader sh = cdSector.getSubHeader();
diff --git a/jpsxdec/src/jpsxdec/modules/xa/SectorXaAudioToAudioPacket.java b/jpsxdec/src/jpsxdec/modules/xa/SectorXaAudioToAudioPacket.java
index 9d86b95..d497393 100644
--- a/jpsxdec/src/jpsxdec/modules/xa/SectorXaAudioToAudioPacket.java
+++ b/jpsxdec/src/jpsxdec/modules/xa/SectorXaAudioToAudioPacket.java
@@ -46,6 +46,7 @@
import jpsxdec.adpcm.XaAdpcmDecoder;
import jpsxdec.cdreaders.CdSector;
import jpsxdec.i18n.I;
+import jpsxdec.i18n.exception.LoggedFailure;
import jpsxdec.i18n.log.ILocalizedLogger;
import jpsxdec.modules.sharedaudio.DecodedAudioPacket;
import jpsxdec.util.ByteArrayFPIS;
@@ -83,6 +84,7 @@ public void setListener(@CheckForNull DecodedAudioPacket.Listener listener) {
public void feedXaSector(@Nonnull CdSector cdSector,
@CheckForNull SectorXaAudio xaSector,
@Nonnull ILocalizedLogger log)
+ throws LoggedFailure
{
if (cdSector.getSectorIndexFromStart() < _iStartSector ||
cdSector.getSectorIndexFromStart() > _iEndSectorInclusive)
diff --git a/jpsxdec/src/jpsxdec/psxvideo/PsxYCbCr.java b/jpsxdec/src/jpsxdec/psxvideo/PsxYCbCr.java
index 57309c3..c8e6685 100644
--- a/jpsxdec/src/jpsxdec/psxvideo/PsxYCbCr.java
+++ b/jpsxdec/src/jpsxdec/psxvideo/PsxYCbCr.java
@@ -37,6 +37,7 @@
package jpsxdec.psxvideo;
+import javax.annotation.Nonnull;
import jpsxdec.formats.RGB;
import jpsxdec.formats.Rec601YCbCr;
@@ -93,7 +94,7 @@ public class PsxYCbCr {
public PsxYCbCr() {
}
- public void fromRgb(RGB rgb1, RGB rgb2, RGB rgb3, RGB rgb4) {
+ public void fromRgb(@Nonnull RGB rgb1, @Nonnull RGB rgb2, @Nonnull RGB rgb3, @Nonnull RGB rgb4) {
cb = cr = 0;
y1 = oneRgb(rgb1);
y2 = oneRgb(rgb2);
@@ -102,7 +103,7 @@ public void fromRgb(RGB rgb1, RGB rgb2, RGB rgb3, RGB rgb4) {
cb /= 4.0;
cr /= 4.0;
}
- private double oneRgb(RGB rgb) {
+ private double oneRgb(@Nonnull RGB rgb) {
int r_128 = rgb.getR() - 128;
int g_128 = rgb.getG() - 128;
int b_128 = rgb.getB() - 128;
@@ -122,7 +123,7 @@ private double oneRgb(RGB rgb) {
}
}
- public static void toRgb(double y, double cb, double cr, RGB rgb) {
+ public static void toRgb(double y, double cb, double cr, @Nonnull RGB rgb) {
double dblChromRed, dblChromGreen, dblChromBlue;
// MUST store chroma first like in instance method or result is slightly different
if (INCORRECTLY_SWAP_CB_CR_LIKE_PSXMC) {
@@ -142,7 +143,7 @@ public static void toRgb(double y, double cb, double cr, RGB rgb) {
rgb.setB(dblYshift + dblChromBlue );
}
- final public void toRgb(RGB rgb1, RGB rgb2, RGB rgb3, RGB rgb4) {
+ final public void toRgb(@Nonnull RGB rgb1, @Nonnull RGB rgb2, @Nonnull RGB rgb3, @Nonnull RGB rgb4) {
double dblChromRed, dblChromGreen, dblChromBlue;
if (INCORRECTLY_SWAP_CB_CR_LIKE_PSXMC) {
// this math is wrong, wrong, WRONG
@@ -203,7 +204,7 @@ final public void toRgb(RGB rgb1, RGB rgb2, RGB rgb3, RGB rgb4) {
* Unfortunately this conversion doesn't take into account chroma
* upsampling interpolation.
*/
- public void toRec_601_YCbCr(Rec601YCbCr ycc) {
+ public void toRec_601_YCbCr(@Nonnull Rec601YCbCr ycc) {
double dblYChroma = cb * (-488509./2660418030.) + cr * (-82738./1330209015.) + 16;
ycc.y1 = (y1+128)*(250./291.) + dblYChroma;
@@ -215,7 +216,7 @@ public void toRec_601_YCbCr(Rec601YCbCr ycc) {
ycc.cr = cb * (3673./27426990.) + cr * (8031459./9142330.) + 128;
}
- public void toRec_JFIF_YCbCr(Rec601YCbCr ycc) {
+ public void toRec_JFIF_YCbCr(@Nonnull Rec601YCbCr ycc) {
double dblYChroma = cb * -3415973./13224846875. + cr * 1242172./13224846875.;
ycc.y1 = y1+128 + dblYChroma;
@@ -227,6 +228,7 @@ public void toRec_JFIF_YCbCr(Rec601YCbCr ycc) {
ycc.cr = cb * 19492./105798775. + cr * 105791687./105798775. + 128;
}
+ @Override
public String toString() {
return String.format("([%f, %f, %f, %f] %f, %f)", y1, y2, y3, y4, cb, cr);
}
diff --git a/jpsxdec/src/jpsxdec/psxvideo/PsxYCbCr_int.java b/jpsxdec/src/jpsxdec/psxvideo/PsxYCbCr_int.java
index 383bd89..bd6f306 100644
--- a/jpsxdec/src/jpsxdec/psxvideo/PsxYCbCr_int.java
+++ b/jpsxdec/src/jpsxdec/psxvideo/PsxYCbCr_int.java
@@ -37,6 +37,7 @@
package jpsxdec.psxvideo;
+import javax.annotation.Nonnull;
import jpsxdec.formats.RGB;
import jpsxdec.util.Maths;
@@ -62,7 +63,7 @@ public PsxYCbCr_int() {
public static final long _0_7143 = 46812; // Math.round(0.7143 * FIXED_MULT);
public static final long _1_772 = 116224; // Math.round(1.772 * FIXED_MULT)+94;
- public static void toRgb(int y, int cb, int cr, RGB rgb) {
+ public static void toRgb(int y, int cb, int cr, @Nonnull RGB rgb) {
int Yshift = y + 128;
long c_r = _1_402 * cr,
c_g = -_0_3437 * cb - _0_7143 * cr,
@@ -72,7 +73,7 @@ public static void toRgb(int y, int cb, int cr, RGB rgb) {
rgb.setB(Yshift + (int)Maths.shrRound(c_b, FIXED_BITS));
}
- final public void toRgb(RGB rgb1, RGB rgb2, RGB rgb3, RGB rgb4) {
+ final public void toRgb(@Nonnull RGB rgb1, @Nonnull RGB rgb2, @Nonnull RGB rgb3, @Nonnull RGB rgb4) {
int iChromRed = (int)Maths.shrRound( _1_402 * cr , FIXED_BITS);
int iChromGreen = (int)Maths.shrRound( -(_0_3437 * cb) - (_0_7143 * cr), FIXED_BITS);
int iChromBlue = (int)Maths.shrRound( _1_772 * cb , FIXED_BITS);
@@ -99,6 +100,7 @@ final public void toRgb(RGB rgb1, RGB rgb2, RGB rgb3, RGB rgb4) {
rgb4.setB(iYshift + iChromBlue);
}
+ @Override
public String toString() {
return String.format( "([%d, %d, %d, %d] %d, %d)" , y1, y2, y3, y4, cb, cr);
}
diff --git a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamCode.java b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamCode.java
new file mode 100644
index 0000000..0a9ad33
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamCode.java
@@ -0,0 +1,218 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.psxvideo.bitstreams;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Specifically designed to decode the 111 MPEG1 AC coefficient
+ * variable-length (Huffman) bit codes, also used by the PlayStation.
+ *
+ * The codes defined in the MPEG1 spec lists the 111 codes with a 'sign' bit at
+ * the end. Here we split the code with the sign bit into two codes. The order
+ * follows the list found in the MPG1 specification with the positive sign bit
+ * (0) first, followed by the negative sign bit (1). Consumers of this table are
+ * dependent on the order of these codes.
+ */
+public enum BitStreamCode {
+
+ _110______________, _111______________, // 11s
+ _0110_____________, _0111_____________, // 011s
+ _01000____________, _01001____________, // 0100s
+ _01010____________, _01011____________, // 0101s
+ _001010___________, _001011___________, // 00101s
+ _001100___________, _001101___________, // 00110s
+ _001110___________, _001111___________, // 00111s
+ _0001000__________, _0001001__________, // 000100s
+ _0001010__________, _0001011__________, // 000101s
+ _0001100__________, _0001101__________, // 000110s
+ _0001110__________, _0001111__________, // 000111s
+ _00001000_________, _00001001_________, // 0000100s
+ _00001010_________, _00001011_________, // 0000101s
+ _00001100_________, _00001101_________, // 0000110s
+ _00001110_________, _00001111_________, // 0000111s
+ _001000000________, _001000001________, // 00100000s
+ _001000010________, _001000011________, // 00100001s
+ _001000100________, _001000101________, // 00100010s
+ _001000110________, _001000111________, // 00100011s
+ _001001000________, _001001001________, // 00100100s
+ _001001010________, _001001011________, // 00100101s
+ _001001100________, _001001101________, // 00100110s
+ _001001110________, _001001111________, // 00100111s
+ _00000010000______, _00000010001______, // 0000001000s
+ _00000010010______, _00000010011______, // 0000001001s
+ _00000010100______, _00000010101______, // 0000001010s
+ _00000010110______, _00000010111______, // 0000001011s
+ _00000011000______, _00000011001______, // 0000001100s
+ _00000011010______, _00000011011______, // 0000001101s
+ _00000011100______, _00000011101______, // 0000001110s
+ _00000011110______, _00000011111______, // 0000001111s
+ _0000000100000____, _0000000100001____, // 000000010000s
+ _0000000100010____, _0000000100011____, // 000000010001s
+ _0000000100100____, _0000000100101____, // 000000010010s
+ _0000000100110____, _0000000100111____, // 000000010011s
+ _0000000101000____, _0000000101001____, // 000000010100s
+ _0000000101010____, _0000000101011____, // 000000010101s
+ _0000000101100____, _0000000101101____, // 000000010110s
+ _0000000101110____, _0000000101111____, // 000000010111s
+ _0000000110000____, _0000000110001____, // 000000011000s
+ _0000000110010____, _0000000110011____, // 000000011001s
+ _0000000110100____, _0000000110101____, // 000000011010s
+ _0000000110110____, _0000000110111____, // 000000011011s
+ _0000000111000____, _0000000111001____, // 000000011100s
+ _0000000111010____, _0000000111011____, // 000000011101s
+ _0000000111100____, _0000000111101____, // 000000011110s
+ _0000000111110____, _0000000111111____, // 000000011111s
+ _00000000100000___, _00000000100001___, // 0000000010000s
+ _00000000100010___, _00000000100011___, // 0000000010001s
+ _00000000100100___, _00000000100101___, // 0000000010010s
+ _00000000100110___, _00000000100111___, // 0000000010011s
+ _00000000101000___, _00000000101001___, // 0000000010100s
+ _00000000101010___, _00000000101011___, // 0000000010101s
+ _00000000101100___, _00000000101101___, // 0000000010110s
+ _00000000101110___, _00000000101111___, // 0000000010111s
+ _00000000110000___, _00000000110001___, // 0000000011000s
+ _00000000110010___, _00000000110011___, // 0000000011001s
+ _00000000110100___, _00000000110101___, // 0000000011010s
+ _00000000110110___, _00000000110111___, // 0000000011011s
+ _00000000111000___, _00000000111001___, // 0000000011100s
+ _00000000111010___, _00000000111011___, // 0000000011101s
+ _00000000111100___, _00000000111101___, // 0000000011110s
+ _00000000111110___, _00000000111111___, // 0000000011111s
+ _000000000100000__, _000000000100001__, // 00000000010000s
+ _000000000100010__, _000000000100011__, // 00000000010001s
+ _000000000100100__, _000000000100101__, // 00000000010010s
+ _000000000100110__, _000000000100111__, // 00000000010011s
+ _000000000101000__, _000000000101001__, // 00000000010100s
+ _000000000101010__, _000000000101011__, // 00000000010101s
+ _000000000101100__, _000000000101101__, // 00000000010110s
+ _000000000101110__, _000000000101111__, // 00000000010111s
+ _000000000110000__, _000000000110001__, // 00000000011000s
+ _000000000110010__, _000000000110011__, // 00000000011001s
+ _000000000110100__, _000000000110101__, // 00000000011010s
+ _000000000110110__, _000000000110111__, // 00000000011011s
+ _000000000111000__, _000000000111001__, // 00000000011100s
+ _000000000111010__, _000000000111011__, // 00000000011101s
+ _000000000111100__, _000000000111101__, // 00000000011110s
+ _000000000111110__, _000000000111111__, // 00000000011111s
+ _0000000000100000_, _0000000000100001_, // 000000000010000s
+ _0000000000100010_, _0000000000100011_, // 000000000010001s
+ _0000000000100100_, _0000000000100101_, // 000000000010010s
+ _0000000000100110_, _0000000000100111_, // 000000000010011s
+ _0000000000101000_, _0000000000101001_, // 000000000010100s
+ _0000000000101010_, _0000000000101011_, // 000000000010101s
+ _0000000000101100_, _0000000000101101_, // 000000000010110s
+ _0000000000101110_, _0000000000101111_, // 000000000010111s
+ _0000000000110000_, _0000000000110001_, // 000000000011000s
+ _0000000000110010_, _0000000000110011_, // 000000000011001s
+ _0000000000110100_, _0000000000110101_, // 000000000011010s
+ _0000000000110110_, _0000000000110111_, // 000000000011011s
+ _0000000000111000_, _0000000000111001_, // 000000000011100s
+ _0000000000111010_, _0000000000111011_, // 000000000011101s
+ _0000000000111100_, _0000000000111101_, // 000000000011110s
+ _0000000000111110_, _0000000000111111_, // 000000000011111s
+ _00000000000100000, _00000000000100001, // 0000000000010000s
+ _00000000000100010, _00000000000100011, // 0000000000010001s
+ _00000000000100100, _00000000000100101, // 0000000000010010s
+ _00000000000100110, _00000000000100111, // 0000000000010011s
+ _00000000000101000, _00000000000101001, // 0000000000010100s
+ _00000000000101010, _00000000000101011, // 0000000000010101s
+ _00000000000101100, _00000000000101101, // 0000000000010110s
+ _00000000000101110, _00000000000101111, // 0000000000010111s
+ _00000000000110000, _00000000000110001, // 0000000000011000s
+ _00000000000110010, _00000000000110011, // 0000000000011001s
+ _00000000000110100, _00000000000110101, // 0000000000011010s
+ _00000000000110110, _00000000000110111, // 0000000000011011s
+ _00000000000111000, _00000000000111001, // 0000000000011100s
+ _00000000000111010, _00000000000111011, // 0000000000011101s
+ _00000000000111100, _00000000000111101, // 0000000000011110s
+ _00000000000111110, _00000000000111111, // 0000000000011111s
+
+ /** Usually "end of block" (EOB). */
+ _10_______________,
+ /** Usually escape code. */
+ _000001___________;
+
+ // #########################################################################
+
+ private final String _sBitString;
+
+ /** Bit length of this code (could use _sBitString.length() , but
+ * this appears to be faster). */
+ private final int _iBitLength;
+
+ private BitStreamCode() {
+ _sBitString = this.name().replaceAll("_", "");
+ _iBitLength = _sBitString.length();
+ }
+
+ /** Returns the bits as a string. */
+ public @Nonnull String getString() {
+ return _sBitString;
+ }
+
+ public int getLength() {
+ return _iBitLength;
+ }
+
+ // #########################################################################
+
+ /** Longest AC variable-length (Huffman) bit code, in bits. */
+ public static final int LONGEST_BITSTREAM_CODE_17BITS = 17;
+
+ /** Pre-load all the values into an array to avoid creating a
+ * new array for every call. */
+ private static final BitStreamCode[] VALUES = values();
+
+ static {
+ assert VALUES.length == 111 * 2 + 2;
+ }
+
+ public static @Nonnull BitStreamCode get(int i) {
+ return VALUES[i];
+ }
+
+ public static int getNormalCount() {
+ return VALUES.length - 2;
+ }
+
+ public static int getTotalCount() {
+ return VALUES.length;
+ }
+
+}
diff --git a/jpsxdec/src/jpsxdec/util/player/ObjectPool.java b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamDebugging.java
similarity index 64%
rename from jpsxdec/src/jpsxdec/util/player/ObjectPool.java
rename to jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamDebugging.java
index d6e25a2..f3dfd14 100644
--- a/jpsxdec/src/jpsxdec/util/player/ObjectPool.java
+++ b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamDebugging.java
@@ -35,45 +35,46 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package jpsxdec.util.player;
+package jpsxdec.psxvideo.bitstreams;
-import java.util.Collection;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
import javax.annotation.Nonnull;
+import jpsxdec.psxvideo.mdec.MdecCode;
+import jpsxdec.psxvideo.mdec.MdecContext;
-public abstract class ObjectPool {
+/** Class to gather debugging info for display on each read. */
+public class BitStreamDebugging {
- private int _iBalance = 0;
+ /** Enable to print the detailed decoding process. */
+ public static boolean DEBUG = false;
- @Nonnull
- private final Queue _objects;
-
- public ObjectPool() {
- _objects = new ConcurrentLinkedQueue();
+ public static boolean println(@Nonnull String s) {
+ System.out.println(s);
+ return true;
}
- public ObjectPool(@Nonnull Collection extends T> objects) {
- _objects = new ConcurrentLinkedQueue(objects);
+ public static long Position;
+ private static final StringBuilder Bits = new StringBuilder();
+
+ public static boolean appendBits(@Nonnull String s) {
+ Bits.append(s);
+ return true;
}
- @Nonnull
- protected abstract T createNewObject();
+ public static boolean printBitsResult(int iVectorPosition, @Nonnull MdecCode code) {
+ System.out.format("@%d %s -> [%d] %s", Position, Bits, iVectorPosition, code).println();
+ Bits.setLength(0);
+ return true;
+ }
- public @Nonnull T borrow() {
- T t;
- if ((t = _objects.poll()) == null) {
- t = createNewObject();
- }
- _iBalance++;
- return t;
+ public static boolean setPosition(int iPosition) {
+ Position = iPosition;
+ return true;
}
- public void giveBack(@Nonnull T object) {
- boolean blnIgnored = _objects.offer(object); // no point to wait for free space, just return
- _iBalance--;
- if (_iBalance == 0) {
- //System.err.println("Object pool balanced.");
- }
+ public static boolean printStartOfBlock(MdecContext context) {
+ System.out.println("==== Block start " + context + " =====");
+ return true;
}
}
+
+
diff --git a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor.java b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor.java
index 081aa39..2b45490 100644
--- a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor.java
+++ b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor.java
@@ -37,23 +37,17 @@
package jpsxdec.psxvideo.bitstreams;
-import java.io.PrintStream;
-import java.util.Arrays;
-import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import jpsxdec.psxvideo.mdec.Calc;
+import jpsxdec.psxvideo.mdec.MdecCode;
+import jpsxdec.psxvideo.mdec.MdecContext;
import jpsxdec.psxvideo.mdec.MdecException;
import jpsxdec.psxvideo.mdec.MdecInputStream;
-import jpsxdec.psxvideo.mdec.MdecInputStream.MdecCode;
import jpsxdec.util.BinaryDataNotRecognized;
-import jpsxdec.util.Misc;
/** Converts a (demuxed) video frame bitstream into an {@link MdecInputStream},
* that can then be fed into an MDEC decoder to produce an image. */
-public abstract class BitStreamUncompressor extends MdecInputStream {
-
- /** Enable to print the detailed decoding process. */
- public static boolean DEBUG = false;
+public abstract class BitStreamUncompressor implements MdecInputStream {
final static public @Nonnull BitStreamUncompressor identifyUncompressor(
@Nonnull byte[] abBitstream)
@@ -84,753 +78,141 @@ public abstract class BitStreamUncompressor extends MdecInputStream {
throw new BinaryDataNotRecognized();
}
- public enum Type {
- STRv1 {
- public @Nonnull BitStreamUncompressor_STRv1 makeNew(@Nonnull byte[] abBitstream, int iBitstreamSize)
- throws BinaryDataNotRecognized
- {
- return BitStreamUncompressor_STRv1.makeV1(abBitstream, iBitstreamSize);
- }
- },
- STRv2 {
- public @Nonnull BitStreamUncompressor_STRv2 makeNew(@Nonnull byte[] abBitstream, int iBitstreamSize)
- throws BinaryDataNotRecognized
- {
- return BitStreamUncompressor_STRv2.makeV2(abBitstream, iBitstreamSize);
- }
- },
- STRv3 {
- public @Nonnull BitStreamUncompressor_STRv3 makeNew(@Nonnull byte[] abBitstream, int iBitstreamSize)
- throws BinaryDataNotRecognized
- {
- return BitStreamUncompressor_STRv3.makeV3(abBitstream, iBitstreamSize);
- }
- },
- Iki {
- public @Nonnull BitStreamUncompressor_Iki makeNew(@Nonnull byte[] abBitstream, int iBitstreamSize)
- throws BinaryDataNotRecognized
- {
- return BitStreamUncompressor_Iki.makeIki(abBitstream, iBitstreamSize);
- }
- },
- Lain {
- public @Nonnull BitStreamUncompressor_Lain makeNew(@Nonnull byte[] abBitstream, int iBitstreamSize)
- throws BinaryDataNotRecognized
- {
- return BitStreamUncompressor_Lain.makeLain(abBitstream, iBitstreamSize);
- }
- };
-
- public @Nonnull BitStreamUncompressor makeNew(@Nonnull byte[] abBitstream) throws BinaryDataNotRecognized {
- return makeNew(abBitstream, abBitstream.length);
- }
+ // #########################################################################
- abstract public @Nonnull BitStreamUncompressor makeNew(@Nonnull byte[] abBitstream, int iBitstreamSize)
- throws BinaryDataNotRecognized;
+ public interface IAcEscapeCode {
+ /** Read an AC Coefficient escaped (zero-run, AC level) value. */
+ void readAcEscapeCode(@Nonnull ArrayBitReader bitReader, @Nonnull MdecCode code)
+ throws MdecException.EndOfStream;
}
- /** Longest AC variable-length (Huffman) bit code, in bits. */
- public final static int AC_LONGEST_VARIABLE_LENGTH_CODE = 17;
-
- /** Holds the mapping of bit string to Zero-Run Length + AC Coefficient. */
- protected static class AcBitCode {
- /** Readable string of bits of this code. */
- @Nonnull
- final public String BitString;
- /** Number of AC coefficient zero values,
- * or Integer.MIN_VALUE if N/A. */
- final public int ZeroRun;
- /** Non-zero AC coefficient value (may be an absolute value),
- * or Integer.MIN_VALUE if N/A. */
- final public int AcCoefficient;
- /** Bit length of this code (could use Bits.length() , but
- * this appears to be faster). */
- final public int BitLength;
-
- /** Create a bit code with valid {@link #Run} and {@link Ac} values. */
- private AcBitCode(@Nonnull String sBitString, int iZeroRun, int iAcCoefficient) {
- BitString = sBitString;
- ZeroRun = iZeroRun;
- AcCoefficient = iAcCoefficient;
- BitLength = sBitString.length();
- }
-
- @Override
- public String toString() {
- return BitString + "=(" + ZeroRun + ", " + AcCoefficient + ")";
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null || getClass() != obj.getClass())
- return false;
- final AcBitCode other = (AcBitCode) obj;
- return this.ZeroRun == other.ZeroRun && this.AcCoefficient == other.AcCoefficient;
- }
-
- @Override
- public int hashCode() {
- int hash = 7;
- hash = 79 * hash + this.ZeroRun;
- hash = 79 * hash + this.AcCoefficient;
- return hash;
- }
+ public interface IQuantizationDc {
+ /** Read the quantization scale and DC coefficient from the bitstream. */
+ void readQuantizationScaleAndDc(@Nonnull ArrayBitReader bitReader,
+ @Nonnull MdecContext context,
+ @Nonnull MdecCode out)
+ throws MdecException.ReadCorruption, MdecException.EndOfStream;
}
- /** A bit code that doesn't have meaningful
- * {@link #ZeroRun} and {@link #AcCoefficient} values.
- * Superclass fields are effectively ignored. */
- private static class SpecialAcBitCode extends AcBitCode {
-
- @Nonnull
- private final String _sId;
-
- private SpecialAcBitCode(@Nonnull String sBitString, @Nonnull String sId) {
- super(sBitString, Integer.MIN_VALUE, Integer.MIN_VALUE);
- _sId = sId;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null || getClass() != obj.getClass())
- return false;
- final SpecialAcBitCode other = (SpecialAcBitCode) obj;
- // no need to check superclass fields since the id is the only important value
- return Misc.objectEquals(_sId, other._sId);
- }
-
- @Override
- public int hashCode() {
- int hash = 5;
- hash = 89 * hash + (_sId != null ? _sId.hashCode() : 0);
- return hash;
- }
-
- @Override
- public String toString() {
- return BitString + "=" + _sId;
- }
+ public interface IFrameEndPaddingBits {
+ void skipPaddingBits(@Nonnull ArrayBitReader bitReader) throws MdecException.EndOfStream;
}
-
- /** Blazing fast bitstream parser.
- * Specifically designed to decode the 111 PSX (and MPEG1) AC coefficient
- * variable-length (Huffman) bit codes, including the {@link #END_OF_BLOCK}
- * code and {@link #ESCAPE_CODE}. Every method beginning with
- * underscore ('_') should be called before the class is used for parsing.
- */
- protected static final class AcLookup {
-
- /** Sequence of bits indicating the end of a block. */
- public final static AcBitCode END_OF_BLOCK = new SpecialAcBitCode("10", "EOB");
- /** Sequence of bits indicating an escape code. */
- public final static AcBitCode ESCAPE_CODE = new SpecialAcBitCode("000001", "ESCAPE_CODE");
-
- /** Bit codes for '11s'. Can be used as an alternative to the
- * {@link #Table_1xx} table. */
- private AcBitCode _110, _111;
-
- /** Table to look up END_OF_BLOCK ('10') and 11s codes using all but the first (1) bit. */
- private final AcBitCode[] Table_1xx = new AcBitCode[4];
- /** Table to look up codes '011s' to '00100111s' using all but the first (0) bit.
- * Given a bit code in that range, strip the leading zero bit, then pad
- * any extra trailing bits to make an 8 bit value. Use that value as the
- * index in this table to get the corresponding code. */
- private final AcBitCode[] Table_0xxxxxxx = new AcBitCode[256];
- /** Table to look up codes '0000001000s' to '0000000011111s' using all but
- * the first 6 zero bits.
- * Given a bit code in that range, strip the leading 6 zero bits, then pad
- * any extra trailing bits to make an 8 bit value. Use that value as the
- * index in this table to get the corresponding code. */
- private final AcBitCode[] Table_000000xxxxxxxx = new AcBitCode[256];
- /** Table to look up codes '00000000010000s' to '0000000000011111s' using
- * all but the first 9 zero bits.
- * Given a bit code in that range, strip the leading 9 zero bits, then pad
- * any extra trailing bits to make an 8 bit value. Use that value as the
- * index in this table to get the corresponding code. */
- private final AcBitCode[] Table_000000000xxxxxxxx = new AcBitCode[256];
-
- /** Holds all the codes for references and compression. */
- private final AcBitCode[] _aoAcBitCodes = new AcBitCode[111];
-
- public AcLookup() {
- // initialize the two codes we know about
- setBits(END_OF_BLOCK);
- setBits(ESCAPE_CODE);
- }
-
- //
- public AcLookup _11s(int r, int aac) {
- set(0, "11s", r, aac);
- _110 = new AcBitCode("110", r, aac);
- _111 = new AcBitCode("111", r, -aac);
- return this;
- }
- //
- public AcLookup _011s (int r, int aac) { return set( 1, "011s", r, aac); }
- public AcLookup _0100s (int r, int aac) { return set( 2, "0100s", r, aac); }
- public AcLookup _0101s (int r, int aac) { return set( 3, "0101s", r, aac); }
- public AcLookup _00101s (int r, int aac) { return set( 4, "00101s", r, aac); }
- public AcLookup _00110s (int r, int aac) { return set( 5, "00110s", r, aac); }
- public AcLookup _00111s (int r, int aac) { return set( 6, "00111s", r, aac); }
- public AcLookup _000100s (int r, int aac) { return set( 7, "000100s", r, aac); }
- public AcLookup _000101s (int r, int aac) { return set( 8, "000101s", r, aac); }
- public AcLookup _000110s (int r, int aac) { return set( 9, "000110s", r, aac); }
- public AcLookup _000111s (int r, int aac) { return set( 10, "000111s", r, aac); }
- public AcLookup _0000100s (int r, int aac) { return set( 11, "0000100s", r, aac); }
- public AcLookup _0000101s (int r, int aac) { return set( 12, "0000101s", r, aac); }
- public AcLookup _0000110s (int r, int aac) { return set( 13, "0000110s", r, aac); }
- public AcLookup _0000111s (int r, int aac) { return set( 14, "0000111s", r, aac); }
- public AcLookup _00100000s(int r, int aac) { return set( 15, "00100000s", r, aac); }
- public AcLookup _00100001s(int r, int aac) { return set( 16, "00100001s", r, aac); }
- public AcLookup _00100010s(int r, int aac) { return set( 17, "00100010s", r, aac); }
- public AcLookup _00100011s(int r, int aac) { return set( 18, "00100011s", r, aac); }
- public AcLookup _00100100s(int r, int aac) { return set( 19, "00100100s", r, aac); }
- public AcLookup _00100101s(int r, int aac) { return set( 20, "00100101s", r, aac); }
- public AcLookup _00100110s(int r, int aac) { return set( 21, "00100110s", r, aac); }
- public AcLookup _00100111s(int r, int aac) { return set( 22, "00100111s", r, aac); }
- //
- // ------------------------------------------------------------------------------
- //
- public AcLookup _0000001000s(int r, int aac) { return set( 23, "0000001000s", r, aac); }
- public AcLookup _0000001001s(int r, int aac) { return set( 24, "0000001001s", r, aac); }
- public AcLookup _0000001010s(int r, int aac) { return set( 25, "0000001010s", r, aac); }
- public AcLookup _0000001011s(int r, int aac) { return set( 26, "0000001011s", r, aac); }
- public AcLookup _0000001100s(int r, int aac) { return set( 27, "0000001100s", r, aac); }
- public AcLookup _0000001101s(int r, int aac) { return set( 28, "0000001101s", r, aac); }
- public AcLookup _0000001110s(int r, int aac) { return set( 29, "0000001110s", r, aac); }
- public AcLookup _0000001111s(int r, int aac) { return set( 30, "0000001111s", r, aac); }
- public AcLookup _000000010000s(int r, int aac) { return set( 31, "000000010000s", r, aac); }
- public AcLookup _000000010001s(int r, int aac) { return set( 32, "000000010001s", r, aac); }
- public AcLookup _000000010010s(int r, int aac) { return set( 33, "000000010010s", r, aac); }
- public AcLookup _000000010011s(int r, int aac) { return set( 34, "000000010011s", r, aac); }
- public AcLookup _000000010100s(int r, int aac) { return set( 35, "000000010100s", r, aac); }
- public AcLookup _000000010101s(int r, int aac) { return set( 36, "000000010101s", r, aac); }
- public AcLookup _000000010110s(int r, int aac) { return set( 37, "000000010110s", r, aac); }
- public AcLookup _000000010111s(int r, int aac) { return set( 38, "000000010111s", r, aac); }
- public AcLookup _000000011000s(int r, int aac) { return set( 39, "000000011000s", r, aac); }
- public AcLookup _000000011001s(int r, int aac) { return set( 40, "000000011001s", r, aac); }
- public AcLookup _000000011010s(int r, int aac) { return set( 41, "000000011010s", r, aac); }
- public AcLookup _000000011011s(int r, int aac) { return set( 42, "000000011011s", r, aac); }
- public AcLookup _000000011100s(int r, int aac) { return set( 43, "000000011100s", r, aac); }
- public AcLookup _000000011101s(int r, int aac) { return set( 44, "000000011101s", r, aac); }
- public AcLookup _000000011110s(int r, int aac) { return set( 45, "000000011110s", r, aac); }
- public AcLookup _000000011111s(int r, int aac) { return set( 46, "000000011111s", r, aac); }
- public AcLookup _0000000010000s(int r, int aac) { return set( 47, "0000000010000s", r, aac); }
- public AcLookup _0000000010001s(int r, int aac) { return set( 48, "0000000010001s", r, aac); }
- public AcLookup _0000000010010s(int r, int aac) { return set( 49, "0000000010010s", r, aac); }
- public AcLookup _0000000010011s(int r, int aac) { return set( 50, "0000000010011s", r, aac); }
- public AcLookup _0000000010100s(int r, int aac) { return set( 51, "0000000010100s", r, aac); }
- public AcLookup _0000000010101s(int r, int aac) { return set( 52, "0000000010101s", r, aac); }
- public AcLookup _0000000010110s(int r, int aac) { return set( 53, "0000000010110s", r, aac); }
- public AcLookup _0000000010111s(int r, int aac) { return set( 54, "0000000010111s", r, aac); }
- public AcLookup _0000000011000s(int r, int aac) { return set( 55, "0000000011000s", r, aac); }
- public AcLookup _0000000011001s(int r, int aac) { return set( 56, "0000000011001s", r, aac); }
- public AcLookup _0000000011010s(int r, int aac) { return set( 57, "0000000011010s", r, aac); }
- public AcLookup _0000000011011s(int r, int aac) { return set( 58, "0000000011011s", r, aac); }
- public AcLookup _0000000011100s(int r, int aac) { return set( 59, "0000000011100s", r, aac); }
- public AcLookup _0000000011101s(int r, int aac) { return set( 60, "0000000011101s", r, aac); }
- public AcLookup _0000000011110s(int r, int aac) { return set( 61, "0000000011110s", r, aac); }
- public AcLookup _0000000011111s(int r, int aac) { return set( 62, "0000000011111s", r, aac); }
- //
- // ---------------------------------------------------------------------------------------
- //
- public AcLookup _00000000010000s(int r, int aac) { return set( 63, "00000000010000s", r, aac); }
- public AcLookup _00000000010001s(int r, int aac) { return set( 64, "00000000010001s", r, aac); }
- public AcLookup _00000000010010s(int r, int aac) { return set( 65, "00000000010010s", r, aac); }
- public AcLookup _00000000010011s(int r, int aac) { return set( 66, "00000000010011s", r, aac); }
- public AcLookup _00000000010100s(int r, int aac) { return set( 67, "00000000010100s", r, aac); }
- public AcLookup _00000000010101s(int r, int aac) { return set( 68, "00000000010101s", r, aac); }
- public AcLookup _00000000010110s(int r, int aac) { return set( 69, "00000000010110s", r, aac); }
- public AcLookup _00000000010111s(int r, int aac) { return set( 70, "00000000010111s", r, aac); }
- public AcLookup _00000000011000s(int r, int aac) { return set( 71, "00000000011000s", r, aac); }
- public AcLookup _00000000011001s(int r, int aac) { return set( 72, "00000000011001s", r, aac); }
- public AcLookup _00000000011010s(int r, int aac) { return set( 73, "00000000011010s", r, aac); }
- public AcLookup _00000000011011s(int r, int aac) { return set( 74, "00000000011011s", r, aac); }
- public AcLookup _00000000011100s(int r, int aac) { return set( 75, "00000000011100s", r, aac); }
- public AcLookup _00000000011101s(int r, int aac) { return set( 76, "00000000011101s", r, aac); }
- public AcLookup _00000000011110s(int r, int aac) { return set( 77, "00000000011110s", r, aac); }
- public AcLookup _00000000011111s(int r, int aac) { return set( 78, "00000000011111s", r, aac); }
- public AcLookup _000000000010000s(int r, int aac) { return set( 79, "000000000010000s", r, aac); }
- public AcLookup _000000000010001s(int r, int aac) { return set( 80, "000000000010001s", r, aac); }
- public AcLookup _000000000010010s(int r, int aac) { return set( 81, "000000000010010s", r, aac); }
- public AcLookup _000000000010011s(int r, int aac) { return set( 82, "000000000010011s", r, aac); }
- public AcLookup _000000000010100s(int r, int aac) { return set( 83, "000000000010100s", r, aac); }
- public AcLookup _000000000010101s(int r, int aac) { return set( 84, "000000000010101s", r, aac); }
- public AcLookup _000000000010110s(int r, int aac) { return set( 85, "000000000010110s", r, aac); }
- public AcLookup _000000000010111s(int r, int aac) { return set( 86, "000000000010111s", r, aac); }
- public AcLookup _000000000011000s(int r, int aac) { return set( 87, "000000000011000s", r, aac); }
- public AcLookup _000000000011001s(int r, int aac) { return set( 88, "000000000011001s", r, aac); }
- public AcLookup _000000000011010s(int r, int aac) { return set( 89, "000000000011010s", r, aac); }
- public AcLookup _000000000011011s(int r, int aac) { return set( 90, "000000000011011s", r, aac); }
- public AcLookup _000000000011100s(int r, int aac) { return set( 91, "000000000011100s", r, aac); }
- public AcLookup _000000000011101s(int r, int aac) { return set( 92, "000000000011101s", r, aac); }
- public AcLookup _000000000011110s(int r, int aac) { return set( 93, "000000000011110s", r, aac); }
- public AcLookup _000000000011111s(int r, int aac) { return set( 94, "000000000011111s", r, aac); }
- public AcLookup _0000000000010000s(int r, int aac) { return set( 95, "0000000000010000s", r, aac); }
- public AcLookup _0000000000010001s(int r, int aac) { return set( 96, "0000000000010001s", r, aac); }
- public AcLookup _0000000000010010s(int r, int aac) { return set( 97, "0000000000010010s", r, aac); }
- public AcLookup _0000000000010011s(int r, int aac) { return set( 98, "0000000000010011s", r, aac); }
- public AcLookup _0000000000010100s(int r, int aac) { return set( 99, "0000000000010100s", r, aac); }
- public AcLookup _0000000000010101s(int r, int aac) { return set(100, "0000000000010101s", r, aac); }
- public AcLookup _0000000000010110s(int r, int aac) { return set(101, "0000000000010110s", r, aac); }
- public AcLookup _0000000000010111s(int r, int aac) { return set(102, "0000000000010111s", r, aac); }
- public AcLookup _0000000000011000s(int r, int aac) { return set(103, "0000000000011000s", r, aac); }
- public AcLookup _0000000000011001s(int r, int aac) { return set(104, "0000000000011001s", r, aac); }
- public AcLookup _0000000000011010s(int r, int aac) { return set(105, "0000000000011010s", r, aac); }
- public AcLookup _0000000000011011s(int r, int aac) { return set(106, "0000000000011011s", r, aac); }
- public AcLookup _0000000000011100s(int r, int aac) { return set(107, "0000000000011100s", r, aac); }
- public AcLookup _0000000000011101s(int r, int aac) { return set(108, "0000000000011101s", r, aac); }
- public AcLookup _0000000000011110s(int r, int aac) { return set(109, "0000000000011110s", r, aac); }
- public AcLookup _0000000000011111s(int r, int aac) { return set(110, "0000000000011111s", r, aac); }
- //
- //
-
- /** Given the AC coefficient absolute value, creates both positive and negative
- * versions and assigns them to appropriate lookup tables. Also adds
- * the absolute value version to the reference list of codes. */
- private AcLookup set(int iCodeNum, String sBits, int iRun, int iAbsoluteAc) {
- _aoAcBitCodes[iCodeNum] = new AcBitCode(sBits, iRun, iAbsoluteAc);
- setBits(new AcBitCode(sBits.replace('s', '0'), iRun, iAbsoluteAc));
- setBits(new AcBitCode(sBits.replace('s', '1'), iRun, -iAbsoluteAc));
- return this;
- }
-
- /** Identifies the lookup table in which to place the bit code. */
- private void setBits(AcBitCode lu) {
- final int iBitsRemain;
- final AcBitCode[] aoTable;
- final int iTableStart;
-
- if (lu.BitString.startsWith("000000000")) {
- aoTable = Table_000000000xxxxxxxx;
- iBitsRemain = 8 - (lu.BitString.length() - 9);
- iTableStart = Integer.parseInt(lu.BitString, 2) << iBitsRemain;
- } else if (lu.BitString.startsWith("000000" )) {
- aoTable = Table_000000xxxxxxxx;
- iBitsRemain = 8 - (lu.BitString.length() - 6);
- iTableStart = Integer.parseInt(lu.BitString, 2) << iBitsRemain;
- } else if (lu.BitString.startsWith("0" )) {
- aoTable = Table_0xxxxxxx;
- iBitsRemain = 8 - (lu.BitString.length() - 1);
- iTableStart = Integer.parseInt(lu.BitString, 2) << iBitsRemain;
- } else { // startsWith("1")
- aoTable = Table_1xx;
- iBitsRemain = 2 - (lu.BitString.length() - 1);
- iTableStart = Integer.parseInt(lu.BitString.substring(1), 2) << iBitsRemain;
- }
-
- final int iTableEntriesToAssociate = (1 << iBitsRemain);
- for (int i = 0; i < iTableEntriesToAssociate; i++) {
- if (aoTable[iTableStart + i] != null)
- throw new RuntimeException("Resetting an existing bitstream lookup probably means some code is wrong.");
- aoTable[iTableStart + i] = lu;
- }
- }
-
- public @Nonnull Iterable getCodeList() {
- return Arrays.asList(_aoAcBitCodes);
- }
-
- /** Useful bitmasks. */
- private static final int
- b11000000000000000 = 0x18000,
- b10000000000000000 = 0x10000,
- b01000000000000000 = 0x08000,
- b00100000000000000 = 0x04000,
- b01111100000000000 = 0x0F800,
- b00000011100000000 = 0x00700,
- b00000000011100000 = 0x000E0;
-
- /** Converts bits to the equivalent {@link BitstreamToMdecLookup}.
- * 17 bits need to be supplied to decode (the longest bit code).
- * Bits should start at the least-significant bit.
- * Bits beyond the 17 least-significant bits are ignored.
- * If a full 17 bits are unavailable, fill the remaining with zeros
- * to ensure failure if bit code is invalid.
- *
- * @param i17bits Integer containing 17 bits to decode.
- */
- private @Nonnull AcBitCode lookup(final int i17bits) throws MdecException.ReadCorruption {
- if ((i17bits & b10000000000000000) != 0) {
- assert !DEBUG || debugPrintln("Table 0 offset " + ((i17bits >> 14) & 3));
- return Table_1xx[(i17bits >> 14) & 3];
- } else if ((i17bits & b01111100000000000) != 0) {
- assert !DEBUG || debugPrintln("Table 1 offset " + ((i17bits >> 8) & 0xff));
- return Table_0xxxxxxx[(i17bits >> 8) & 0xff];
- } else if ((i17bits & b00000011100000000) != 0) {
- assert !DEBUG || debugPrintln("Table 2 offset " + ((i17bits >> 3) & 0xff));
- return Table_000000xxxxxxxx[(i17bits >> 3) & 0xff];
- } else if ((i17bits & b00000000011100000) != 0) {
- assert !DEBUG || debugPrintln("Table 3 offset " + (i17bits & 0xff));
- return Table_000000000xxxxxxxx[i17bits & 0xff];
- } else {
- throw new MdecException.ReadCorruption(UNMATCHED_AC_VLC(i17bits));
- }
- }
- private static String UNMATCHED_AC_VLC(int i17bits) {
- return "Unmatched AC variable length code: " +
- Misc.bitsToString(i17bits, AC_LONGEST_VARIABLE_LENGTH_CODE);
- }
-
- // ..................................................
-
- //
- /** Alternative lookup method that is slower that {@link #lookup(int)}. */
- private AcBitCode lookup_slow1(final int i17bits) throws MdecException.ReadCorruption {
- if ((i17bits & b11000000000000000) == b10000000000000000) {
- return END_OF_BLOCK;
- } else if ((i17bits & b11000000000000000) == b11000000000000000) {
- // special handling for first AC code
- if ((i17bits & b00100000000000000) == 0) // check sign bit
- return _110;
- else
- return _111;
- } else {
- // escape code is already set in the lookup table
- final AcBitCode[] array;
- final int c;
- if ((i17bits & b01111100000000000) != 0) {
- array = Table_0xxxxxxx;
- c = (i17bits >> 8) & 0xff;
- } else if ((i17bits & b00000011100000000) != 0) {
- array = Table_000000xxxxxxxx;
- c = (i17bits >> 3) & 0xff;
- } else if ((i17bits & b00000000011100000) != 0) {
- array = Table_000000000xxxxxxxx;
- c = i17bits & 0xff;
- } else {
- throw new MdecException.ReadCorruption(UNMATCHED_AC_VLC(i17bits));
- }
- return array[c];
- }
- }
- /** Alternative lookup method that is slower that {@link #lookup(int)}. */
- private AcBitCode lookup_slow2(final int i17bits) throws MdecException.ReadCorruption {
- if ((i17bits & b11000000000000000) == b10000000000000000) {
- return END_OF_BLOCK;
- } else if ((i17bits & b11000000000000000) == b11000000000000000) {
- // special handling for first AC code
- if ((i17bits & b00100000000000000) == 0) // check sign bit
- return _110;
- else
- return _111;
- } else {
- // escape code is already part of the lookup table
- if ((i17bits & b01111100000000000) != 0) {
- return Table_0xxxxxxx[(i17bits >> 8) & 0xff];
- } else if ((i17bits & b00000011100000000) != 0) {
- return Table_000000xxxxxxxx[(i17bits >> 3) & 0xff];
- } else if ((i17bits & b00000000011100000) != 0) {
- return Table_000000000xxxxxxxx[i17bits & 0xff];
- } else {
- throw new MdecException.ReadCorruption(UNMATCHED_AC_VLC(i17bits));
- }
- }
- }
- /** Alternative lookup method that is slower that {@link #lookup(int)}. */
- private AcBitCode lookup_slow3(final int i17bits) throws MdecException.ReadCorruption {
- if ((i17bits & b10000000000000000) != 0) { // 1st bit is 1?
- if ((i17bits & b01000000000000000) == 0) { // initial bits == '10'?
- return END_OF_BLOCK;
- } else { // initial bits == '11'
- // special handling for first AC code
- // check sign bit
- if ((i17bits & b00100000000000000) == 0) // initial bits == '110'?
- return _110;
- else // initial bits == '111'
- return _111;
- }
- } else { // 1st bit is 0
- // escape code is already set in the lookup table
- final AcBitCode[] array;
- final int c;
- if ((i17bits & b01111100000000000) != 0) {
- array = Table_0xxxxxxx;
- c = (i17bits >> 8) & 0xff;
- } else if ((i17bits & b00000011100000000) != 0) {
- array = Table_000000xxxxxxxx;
- c = (i17bits >> 3) & 0xff;
- } else if ((i17bits & b00000000011100000) != 0) {
- array = Table_000000000xxxxxxxx;
- c = i17bits & 0xff;
- } else {
- throw new MdecException.ReadCorruption(UNMATCHED_AC_VLC(i17bits));
- }
- return array[c];
- }
- }
-
- /** Bit masks for
- * {@link #lookup_old(int, jpsxdec.psxvideo.mdec.MdecInputStream.MdecCode)} */
- private static final int
- b1000000000000000_ = 0x8000 << 1,
- b0100000000000000_ = 0x4000 << 1,
- b0010000000000000_ = 0x2000 << 1,
- b0001100000000000_ = 0x1800 << 1,
- b0001000000000000_ = 0x1000 << 1,
- b0000100000000000_ = 0x0800 << 1,
- b0000010000000000_ = 0x0400 << 1,
- b0000001000000000_ = 0x0200 << 1,
- b0000000100000000_ = 0x0100 << 1,
- b0000000010000000_ = 0x0080 << 1,
- b0000000001000000_ = 0x0040 << 1,
- b0000000000100000_ = 0x0020 << 1,
- b0000000000010000_ = 0x0010 << 1;
- /** This lookup approach used in 0.96.0 and earlier needs a slightly
- * different API to work. The calling code will need some adjustment. */
- private AcBitCode lookup_old(final int i17bits, MdecCode code) throws MdecException.ReadCorruption {
-
- final AcBitCode vlc;
-
- // Walk through the bits, one-by-one
- // Fun fact: The Lain Playstation game uses this same decoding approach
- if ( (i17bits & b1000000000000000_) != 0) { // "1"
- if ((i17bits & b0100000000000000_) != 0) { // "11"
- vlc = _aoAcBitCodes[0];
- } else { // "10"
- // End of block
- code.setToEndOfData();
- return END_OF_BLOCK;
- }
- } else if ((i17bits & b0100000000000000_) != 0) { // "01"
- if ((i17bits & b0010000000000000_) != 0) { // "011"
- vlc = _aoAcBitCodes[1];
- } else { // "010x"
- vlc = _aoAcBitCodes[2 + (int)((i17bits >>> 13) & 1)];
- }
- } else if ((i17bits & b0010000000000000_) != 0) { // "001"
- if ((i17bits & b0001100000000000_) != 0) { // "001xx"
- vlc = _aoAcBitCodes[3 + (int)((i17bits >>> 12) & 3)];
- } else { // "00100xxx"
- vlc = _aoAcBitCodes[15 + (int)((i17bits >>> 9) & 7)];
- }
- } else if ((i17bits & b0001000000000000_) != 0) { // "0001xx"
- vlc = _aoAcBitCodes[7 + (int)((i17bits >>> 11) & 3)];
- } else if ((i17bits & b0000100000000000_) != 0) { // "00001xx"
- vlc = _aoAcBitCodes[11 + (int)((i17bits >>> 10) & 3)];
- } else if ((i17bits & b0000010000000000_) != 0) { // "000001"
- // escape code
- return ESCAPE_CODE;
- } else if ((i17bits & b0000001000000000_) != 0) { // "0000001xxx"
- vlc = _aoAcBitCodes[23 + (int)((i17bits >>> 7) & 7)];
- } else if ((i17bits & b0000000100000000_) != 0) { // "00000001xxxx"
- vlc = _aoAcBitCodes[31 + (int)((i17bits >>> 5) & 15)];
- } else if ((i17bits & b0000000010000000_) != 0) { // "000000001xxxx"
- vlc = _aoAcBitCodes[47 + (int)((i17bits >>> 4) & 15)];
- } else if ((i17bits & b0000000001000000_) != 0) { // "0000000001xxxx"
- vlc = _aoAcBitCodes[63 + (int)((i17bits >>> 3) & 15)];
- } else if ((i17bits & b0000000000100000_) != 0) { // "00000000001xxxx"
- vlc = _aoAcBitCodes[79 + (int)((i17bits >>> 2) & 15)];
- } else if ((i17bits & b0000000000010000_) != 0) { // "000000000001xxxx"
- vlc = _aoAcBitCodes[95 + (int)((i17bits >>> 1) & 15)];
- } else {
- throw new MdecException.ReadCorruption(UNMATCHED_AC_VLC(i17bits));
- }
-
- code.setTop6Bits(vlc.ZeroRun);
-
- // Take either the positive or negitive AC coefficient,
- // depending on the sign bit
- if ((i17bits & (1 << (16 - vlc.BitLength))) == 0) {
- // positive
- code.setBottom10Bits(vlc.AcCoefficient);
- } else {
- // negative
- code.setBottom10Bits(-vlc.AcCoefficient);
- }
-
- return vlc;
- }
- //
-
- public void print(@Nonnull PrintStream ps) {
- for (int i = 0; i < Table_1xx.length; i++) {
- ps.println("Table_1xx["+i+"] = "+Table_1xx[i]);
- }
- for (int i = 0; i < Table_0xxxxxxx.length; i++) {
- ps.println("Table_0xxxxxxx["+i+"] = "+Table_0xxxxxxx[i]);
- }
- for (int i = 0; i < Table_000000xxxxxxxx.length; i++) {
- ps.println("Table_000000xxxxxxxx["+i+"] = "+Table_000000xxxxxxxx[i]);
- }
- for (int i = 0; i < Table_000000000xxxxxxxx.length; i++) {
- ps.println("Table_000000000xxxxxxxx["+i+"] = "+Table_000000000xxxxxxxx[i]);
- }
+ private static class FrameEndPaddingBits_None implements IFrameEndPaddingBits {
+ public void skipPaddingBits(@Nonnull ArrayBitReader bitReader) {
}
}
- private static boolean debugPrintln(@Nonnull String s) {
- System.out.println(s);
- return true;
- }
+ public static final IFrameEndPaddingBits FRAME_END_PADDING_BITS_NONE = new FrameEndPaddingBits_None();
- /** Class to gather debugging info for display on each read. */
- public static class MdecDebugger {
- public long Position;
- private final StringBuilder Bits = new StringBuilder();
- public boolean append(@Nonnull String s) {
- Bits.append(s);
- return true;
- }
- public boolean print(int iVectorPosition, @Nonnull MdecCode code) {
- System.out.format("@%d %s -> [%d] %s", Position, Bits, iVectorPosition, code).println();
- Bits.setLength(0);
- return true;
- }
-
- public boolean setPosition(int iPosition) {
- Position = iPosition;
- return true;
- }
+ // #########################################################################
- private boolean printBlock(int iCurrentMacroBlock, int iCurrentMacroBlockSubBlock) {
- System.out.format("==== MB %d Block %d ====", iCurrentMacroBlock, iCurrentMacroBlockSubBlock).println();
- return true;
- }
- }
+ /** Binary input stream being read. */
+ @Nonnull
+ private final ArrayBitReader _bitReader;
- /** A strange value needed for video bitstreams and video sector headers.
- * It's the number of MDEC codes, divided by two, then rounded up to the
- * next closest multiple of 32 (if not already a multiple of 32).
- * In other words, its the number of 32-byte blocks it would take to hold
- * the MDEC codes. */
- public static short calculateHalfCeiling32(int iMdecCodeCount) {
- return (short) ((((iMdecCodeCount + 1) / 2) + 31) & ~31);
- }
+ /** Table for looking up AC Coefficient bit codes. */
+ @Nonnull
+ private final ZeroRunLengthAcLookup _lookupTable;
- // #########################################################################
- // #########################################################################
+ @Nonnull
+ private final IQuantizationDc _qscaleDcReader;
- /** Table for looking up AC Coefficient bit codes. */
@Nonnull
- private final AcLookup _lookupTable;
- /** Binary input stream being read. */
+ private final IAcEscapeCode _escapeCodeReader;
+
@Nonnull
- protected final ArrayBitReader _bitReader;
-
- /** Holds the debugger when debugging is enabled. */
- @CheckForNull
- protected final MdecDebugger _debug;
-
- /** Indicates if the next read will be the Quantization Scale and DC Coefficient. */
- private boolean _blnBlockStart;
- /** Indicates if the next read will be the Quantization Scale and DC Coefficient. */
- protected boolean atStartOfBlock() { return _blnBlockStart; }
- /** Number of the current Macro Block being read. */
- private int _iCurrentMacroBlock;
- /** Number of the current Macro Block being read. */
- protected int getFullMacroBlocksRead() { return _iCurrentMacroBlock; }
- /** 0 to 5 to indicate the current Macro Block's sub-block being read. */
- private int _iCurrentMacroBlockSubBlock;
- /** Returns 0 to 5 to indicate the current Macro Block's sub-block being read. */
- protected int getCurrentMacroBlockSubBlock() { return _iCurrentMacroBlockSubBlock; }
+ private final IFrameEndPaddingBits _endPaddingBits;
+
+ protected final MdecContext _context = new MdecContext();
+
/** Track the current Block's vector position to detect errors. */
- private int _iCurrentBlockVectorPos;
+ private int _iCurrentBlockVectorPos = 0;
/** Number of MDEC codes that have been read thus far. */
- private int _iReadMdecCodeCount;
- /** Number of MDEC codes that have been read thus far. */
- public int getReadMdecCodeCount() { return _iReadMdecCodeCount; }
+ public int getReadMdecCodeCount() { return _context.getTotalMdecCodesRead(); }
- protected BitStreamUncompressor(@Nonnull AcLookup lookupTable,
- @Nonnull ArrayBitReader bitReader)
+ public BitStreamUncompressor(@Nonnull ArrayBitReader bitReader,
+ @Nonnull ZeroRunLengthAcLookup lookupTable,
+ @Nonnull IQuantizationDc qscaleDcReader,
+ @Nonnull IAcEscapeCode escapeCodeReader,
+ @Nonnull IFrameEndPaddingBits endPaddingBits)
{
+ _bitReader = bitReader;
_lookupTable = lookupTable;
- if (DEBUG)
- _debug = new MdecDebugger();
- else
- _debug = null;
+ _qscaleDcReader = qscaleDcReader;
+ _escapeCodeReader = escapeCodeReader;
+ _endPaddingBits = endPaddingBits;
+ }
- _bitReader = bitReader;
-
- _blnBlockStart = true;
- _iReadMdecCodeCount = 0;
- _iCurrentBlockVectorPos = 0;
- _iCurrentMacroBlock = 0;
- _iCurrentMacroBlockSubBlock = 0;
+ final public int getBitPosition() {
+ return _bitReader.getBitsRead();
}
- /** @throws NullPointerException if {@code reset()} has not been called. */
final public boolean readMdecCode(@Nonnull MdecCode code) throws MdecException.EndOfStream, MdecException.ReadCorruption {
- assert !DEBUG || _debug.setPosition(_bitReader.getWordPosition());
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.setPosition(_bitReader.getWordPosition());
- if (_blnBlockStart) {
- assert !DEBUG || _debug.printBlock(_iCurrentMacroBlock, _iCurrentMacroBlockSubBlock);
+ if (_context.atStartOfBlock()) {
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.printStartOfBlock(_context);
- readQscaleAndDC(code);
- _blnBlockStart = false;
+ _qscaleDcReader.readQuantizationScaleAndDc(_bitReader, _context, code);
+ _context.nextCode();
} else {
- int i17bits = _bitReader.peekUnsignedBits(AC_LONGEST_VARIABLE_LENGTH_CODE);
- AcBitCode bitCode = _lookupTable.lookup(i17bits);
- _bitReader.skipBits(bitCode.BitLength);
+ int i17bits = _bitReader.peekUnsignedBits(BitStreamCode.LONGEST_BITSTREAM_CODE_17BITS);
+ ZeroRunLengthAc bitCode = _lookupTable.lookup(i17bits);
+ _bitReader.skipBits(bitCode.getBitLength());
+
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.appendBits(bitCode.getBitString());
- if (bitCode == AcLookup.END_OF_BLOCK) {
+ if (bitCode.isIsEndOfBlock()) {
// end of block
code.setToEndOfData();
- _blnBlockStart = true;
_iCurrentBlockVectorPos = 0;
- _iCurrentMacroBlockSubBlock++;
- if (_iCurrentMacroBlockSubBlock >= 6) {
- _iCurrentMacroBlockSubBlock = 0;
- _iCurrentMacroBlock++;
- }
- assert !DEBUG || _debug.append(AcLookup.END_OF_BLOCK.BitString);
+ _context.nextCodeEndBlock();
} else {
// block continues
- assert !DEBUG || _debug.append(bitCode.BitString);
- if (bitCode == AcLookup.ESCAPE_CODE) {
- readEscapeAcCode(code);
+ if (bitCode.isIsEscapeCode()) {
+ _escapeCodeReader.readAcEscapeCode(_bitReader, code);
} else {
- code.setBits(bitCode.ZeroRun, bitCode.AcCoefficient);
+ bitCode.getMdecCode(code);
}
_iCurrentBlockVectorPos += code.getTop6Bits() + 1;
if (_iCurrentBlockVectorPos >= 64) {
- throw new MdecException.ReadCorruption(MdecException.RLC_OOB_IN_MB_BLOCK(_iCurrentBlockVectorPos, _iCurrentMacroBlock, _iCurrentMacroBlockSubBlock));
+ throw new MdecException.ReadCorruption(MdecException.RLC_OOB_IN_MB_BLOCK(_iCurrentBlockVectorPos, _context.getTotalMacroBlocksRead(), _context.getCurrentBlock().ordinal()));
}
- }
+ _context.nextCode();
+ }
}
-
- assert !DEBUG || _debug.print(_iCurrentBlockVectorPos, code);
- // _blnBlockStart will be set to true if an EOB code was read
- _iReadMdecCodeCount++;
- return _blnBlockStart;
- }
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.printBitsResult(_iCurrentBlockVectorPos, code);
- final public int getBitPosition() {
- return _bitReader.getBitsRead();
+ return _context.atStartOfBlock();
}
/** Skips macroblocks that would fit within the given dimensions. */
- public void skipMacroBlocks(int iPixelWidth, int iPixelHeight) throws MdecException.EndOfStream, MdecException.ReadCorruption {
- int iBlockCount = Calc.blocks(iPixelWidth, iPixelHeight);
+ final public void skipMacroBlocks(int iPixelWidth, int iPixelHeight) throws MdecException.EndOfStream, MdecException.ReadCorruption {
+ int iBlocksToSkip = Calc.blocks(iPixelWidth, iPixelHeight);
MdecCode code = new MdecCode();
- for (int i = 0; i < iBlockCount; i++) {
+ for (int i = 0; i < iBlocksToSkip; i++) {
while (!readMdecCode(code)) {
}
}
}
- abstract public void skipPaddingBits() throws MdecException.EndOfStream;
-
- /** Read the quantization scale and DC coefficient from the bitstream. */
- abstract protected void readQscaleAndDC(@Nonnull MdecCode code)
- throws MdecException.ReadCorruption, MdecException.EndOfStream;
-
- /** Read an AC Coefficient escaped (zero-run, AC level) value. */
- abstract protected void readEscapeAcCode(@Nonnull MdecCode code)
- throws MdecException.EndOfStream;
-
- /** Create an equivalent bitstream compressor. */
- abstract public @Nonnull BitStreamCompressor makeCompressor();
+ final public void skipPaddingBits() throws MdecException.EndOfStream {
+ _endPaddingBits.skipPaddingBits(_bitReader);
+ }
- abstract public @Nonnull Type getType();
+ /** Create an equivalent bitstream compressor.
+ * @throws UnsupportedOperationException if the bitstream cannot be created for this format. */
+ abstract public @Nonnull BitStreamCompressor makeCompressor() throws UnsupportedOperationException;
@Override
- abstract public String toString();
+ public String toString() {
+ return getClass().getSimpleName() + " " + _context.toString() + " offset=" + _bitReader.getWordPosition();
+ }
}
diff --git a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_Iki.java b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_Iki.java
index 16730f2..8b89ab9 100644
--- a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_Iki.java
+++ b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_Iki.java
@@ -51,9 +51,11 @@
import jpsxdec.psxvideo.encode.MacroBlockEncoder;
import jpsxdec.psxvideo.encode.MdecEncoder;
import jpsxdec.psxvideo.mdec.Calc;
+import jpsxdec.psxvideo.mdec.MdecBlock;
+import jpsxdec.psxvideo.mdec.MdecCode;
+import jpsxdec.psxvideo.mdec.MdecContext;
import jpsxdec.psxvideo.mdec.MdecException;
import jpsxdec.psxvideo.mdec.MdecInputStream;
-import jpsxdec.psxvideo.mdec.MdecInputStream.MdecCode;
import jpsxdec.util.BinaryDataNotRecognized;
import jpsxdec.util.IO;
import jpsxdec.util.IncompatibleException;
@@ -153,7 +155,7 @@ public int getFrameBlockCount() {
return _iBlockCount;
}
- public int getBlockQscale(int iBlock) {
+ public int getBlockQscaleDc(int iBlock) {
if (!_blnIsValid) throw new IllegalStateException();
int b1 = _abQscaleDcLookupTable[iBlock] & 0xff;
int b2 = _abQscaleDcLookupTable[iBlock+_iBlockCount] & 0xff;
@@ -190,37 +192,34 @@ public int getBlockQscale(int iBlock) {
@Nonnull
private final IkiHeader _header;
- private int _iCurrentBlock = 0;
-
private BitStreamUncompressor_Iki(@Nonnull IkiHeader header,
@Nonnull ArrayBitReader bitReader)
{
- super(BitStreamUncompressor_STRv2.AC_VARIABLE_LENGTH_CODES_MPEG1, bitReader);
+ super(bitReader, ZeroRunLengthAcLookup_STR.AC_VARIABLE_LENGTH_CODES_MPEG1,
+ new QuantizationDcReader_Iki(header), BitStreamUncompressor_STRv2.AC_ESCAPE_CODE_STR,
+ FRAME_END_PADDING_BITS_NONE);
_header = header;
}
- /** Read the quantization scale and DC coefficient from the iki lzss
- * compressed header. */
- @Override
- protected void readQscaleAndDC(@Nonnull MdecCode code) throws MdecException.EndOfStream {
- if (_iCurrentBlock >= _header.getFrameBlockCount())
- throw new MdecException.EndOfStream(MdecException.inBlockOfBlocks(_iCurrentBlock, _header.getFrameBlockCount()));
- readBlockQscaleAndDC(code, _iCurrentBlock);
- _iCurrentBlock++;
- }
+ private static class QuantizationDcReader_Iki implements IQuantizationDc {
- /** Looks up the given block's quantization scale and DC coefficient. */
- private void readBlockQscaleAndDC(@Nonnull MdecCode code, int iBlock) {
- code.set(_header.getBlockQscale(iBlock));
- }
+ @Nonnull
+ private final BitStreamUncompressor_Iki.IkiHeader _header;
- @Override
- protected void readEscapeAcCode(MdecCode code) throws MdecException.EndOfStream {
- BitStreamUncompressor_STRv2.readStrEscapeAcCode(_bitReader, code, _debug, LOG);
- }
+ public QuantizationDcReader_Iki(@Nonnull BitStreamUncompressor_Iki.IkiHeader header) {
+ _header = header;
+ }
- @Override
- public void skipPaddingBits() {
+ /** Read the quantization scale and DC coefficient from the iki lzss
+ * compressed header. */
+ /** Looks up the given block's quantization scale and DC coefficient. */
+ public void readQuantizationScaleAndDc(@Nonnull ArrayBitReader bitReader, @Nonnull MdecContext context, @Nonnull MdecCode mdecCode)
+ throws MdecException.ReadCorruption, MdecException.EndOfStream
+ {
+ if (context.getTotalBlocksRead() >= _header.getFrameBlockCount())
+ throw new MdecException.EndOfStream(MdecException.inBlockOfBlocks(context.getTotalBlocksRead(), _header.getFrameBlockCount()));
+ mdecCode.set(_header.getBlockQscaleDc(context.getTotalBlocksRead()));
+ }
}
/** .iki videos utilize yet another LZSS compression format that is
@@ -242,19 +241,19 @@ private static void ikiLzssUncompress(@Nonnull byte[] abSrc, int iSrcPosition,
int iFlags = abSrc[iSrcPosition++] & 0xff;
- if (DEBUG)
+ if (BitStreamDebugging.DEBUG)
System.err.println("Flags " + Misc.bitsToString(iFlags, 8));
for (int iBit = 0; iBit < 8; iBit++, iFlags >>= 1) {
- if (DEBUG)
+ if (BitStreamDebugging.DEBUG)
System.err.format("[InPos: %d OutPos: %d] bit %02x: ",
iSrcPosition, iDestPosition, 1 << iBit );
if ((iFlags & 1) == 0) {
byte b = abSrc[iSrcPosition++];
- if (DEBUG)
+ if (BitStreamDebugging.DEBUG)
System.err.println(String.format("{Byte %02x}", b));
abDest[iDestPosition++] = b;
@@ -267,7 +266,7 @@ private static void ikiLzssUncompress(@Nonnull byte[] abSrc, int iSrcPosition,
}
iCopyOffset++;
- if (DEBUG)
+ if (BitStreamDebugging.DEBUG)
System.err.println(
"Copy " + iCopySize + " bytes from " + (iDestPosition - (iCopyOffset + 1)) + "(-"+iCopyOffset+")");
@@ -281,7 +280,7 @@ private static void ikiLzssUncompress(@Nonnull byte[] abSrc, int iSrcPosition,
break;
}
}
- if (DEBUG)
+ if (BitStreamDebugging.DEBUG)
System.err.println("Src pos at end: " + iSrcPosition);
}
@@ -299,7 +298,7 @@ public void compress(@Nonnull byte[] abSrcData, @Nonnull ByteArrayOutputStream o
for (int iSrcPos = 0; iSrcPos < abSrcData.length;) {
- if (DEBUG)
+ if (BitStreamDebugging.DEBUG)
_logger.format("[InPos: %d OutPos: %d]: bit %02x: ",
out.size()+1+_buffer.size(), iSrcPos, 1 << _iFlagBit );
@@ -328,7 +327,7 @@ public void compress(@Nonnull byte[] abSrcData, @Nonnull ByteArrayOutputStream o
addRun(iSrcPos - iLongestRunPos, iLongestRunLen, iSrcPos);
iSrcPos += iLongestRunLen;
} else {
- if (DEBUG) _logger.format("{Byte %02x}", abSrcData[iSrcPos]&0xff).println();
+ if (BitStreamDebugging.DEBUG) _logger.format("{Byte %02x}", abSrcData[iSrcPos]&0xff).println();
addCopy(abSrcData[iSrcPos]);
iSrcPos++;
}
@@ -336,7 +335,7 @@ public void compress(@Nonnull byte[] abSrcData, @Nonnull ByteArrayOutputStream o
}
if (_iFlagBit > 0) {
- if (DEBUG) _logger.println("Flags " + Misc.bitsToString(_iFlags, 8));
+ if (BitStreamDebugging.DEBUG) _logger.println("Flags " + Misc.bitsToString(_iFlags, 8));
out.write(_iFlags);
byte[] ab = _buffer.toByteArray();
out.write(ab, 0, ab.length);
@@ -346,7 +345,7 @@ public void compress(@Nonnull byte[] abSrcData, @Nonnull ByteArrayOutputStream o
private void addRun(int iPosition, int iLength, int iSrcPos) {
assert iPosition > 0;
- if (DEBUG) _logger.format("Copy %d bytes from %d(%d)", iLength, iSrcPos-iPosition, -iPosition).println();
+ if (BitStreamDebugging.DEBUG) _logger.format("Copy %d bytes from %d(%d)", iLength, iSrcPos-iPosition, -iPosition).println();
_iFlags |= (1 << _iFlagBit);
_buffer.write(iLength - 3);
iPosition--;
@@ -365,7 +364,7 @@ private void addCopy(byte b) {
private void incFlag(@Nonnull ByteArrayOutputStream out) {
_iFlagBit++;
if (_iFlagBit >= 8) {
- if (DEBUG) {
+ if (BitStreamDebugging.DEBUG) {
System.err.println("Flags " + Misc.bitsToString(_iFlags, 8));
_logger.flush();
System.err.print(_baosLogger.toString());
@@ -399,32 +398,20 @@ private static int matchLength(@Nonnull byte[] abData, int iMatchStart, int iEnd
@Override
- public @Nonnull Type getType() {
- return Type.Iki;
- }
-
public String toString() {
- if (_header.isValid()) {
- // find the minimum and maximum quantization scales used
- int iMinQscale = 64, iMaxQscale = 0;
- MdecCode code = new MdecCode();
- for (int i = 0; i < _header.getFrameBlockCount(); i++) {
- readBlockQscaleAndDC(code, i);
- int iQscale = code.getTop6Bits();
- if (iQscale < iMinQscale)
- iMinQscale = iQscale;
- if(iQscale > iMaxQscale)
- iMaxQscale = iQscale;
- }
- return String.format("%s Qscale=%d-%d Offset=%d MB=%d.%d Mdec count=%d %dx%d",
- getType(), iMinQscale, iMaxQscale,
- _bitReader.getWordPosition(),
- getFullMacroBlocksRead(), getCurrentMacroBlockSubBlock(),
- getReadMdecCodeCount(),
- _header.getWidth(), _header.getHeight());
- } else {
- return "Invalid IKI";
+ // find the minimum and maximum quantization scales used
+ int iMinQscale = 64, iMaxQscale = 0;
+ MdecCode code = new MdecCode();
+ for (int i = 0; i < _header.getFrameBlockCount(); i++) {
+ code.set(_header.getBlockQscaleDc(i));
+ int iQscale = code.getTop6Bits();
+ if (iQscale < iMinQscale)
+ iMinQscale = iQscale;
+ if(iQscale > iMaxQscale)
+ iMaxQscale = iQscale;
}
+ return super.toString() + String.format(" Qscale=%d-%d %dx%d",
+ iMinQscale, iMaxQscale, _header.getWidth(), _header.getHeight());
}
@Override
@@ -548,7 +535,7 @@ public int compare(MacroBlockEncoder o1, MacroBlockEncoder o2) {
if (iNewDemuxSize <= iOriginalLength) {
log.log(Level.INFO, I.NEW_FRAME_FITS(sFrameDescription, iNewDemuxSize, iOriginalLength));
} else {
- log.log(Level.INFO, I.IKI_NEW_FRAME_GT_SRC_STOPPING(sFrameDescription, iNewDemuxSize, iOriginalLength));
+ log.log(Level.INFO, I.NEW_FRAME_DOES_NOT_FIT(sFrameDescription, iNewDemuxSize, iOriginalLength));
break;
}
abLastGoodDemux = abNewDemux;
@@ -590,13 +577,13 @@ public int compare(MacroBlockEncoder o1, MacroBlockEncoder o2) {
}
@Override
- protected void setBlockQscale(int iBlock, int iQscale) {
+ protected void setBlockQscale(@Nonnull MdecBlock block, int iQscale) {
_currentBlockQscaleDc.setTop6Bits(iQscale);
}
@Override
- protected @Nonnull String encodeDC(int iDC, int iBlock) {
+ protected @Nonnull String encodeDC(int iDC, @Nonnull MdecBlock block) {
_currentBlockQscaleDc.setBottom10Bits(iDC);
int iMdec = _currentBlockQscaleDc.toMdecWord();
_top8.write(iMdec >> 8);
@@ -619,7 +606,7 @@ protected void setBlockQscale(int iBlock, int iQscale) {
ab = _bottom8.toByteArray();
byte[] abHdr = new byte[10];
- IO.writeInt16LE(abHdr, 0, (short)calculateHalfCeiling32(iMdecCodeCount));
+ IO.writeInt16LE(abHdr, 0, (short)Calc.calculateHalfCeiling32(iMdecCodeCount));
IO.writeInt16LE(abHdr, 2, (short)0x3800);
IO.writeInt16LE(abHdr, 4, (short)_iWidth);
IO.writeInt16LE(abHdr, 6, (short)_iHeight);
diff --git a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_Lain.java b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_Lain.java
index 1f7ba6e..cfe1c71 100644
--- a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_Lain.java
+++ b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_Lain.java
@@ -46,6 +46,9 @@
import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_STRv2.BitStreamCompressor_STRv2;
import jpsxdec.psxvideo.encode.MacroBlockEncoder;
import jpsxdec.psxvideo.encode.MdecEncoder;
+import jpsxdec.psxvideo.mdec.MdecBlock;
+import jpsxdec.psxvideo.mdec.MdecCode;
+import jpsxdec.psxvideo.mdec.MdecContext;
import jpsxdec.psxvideo.mdec.MdecException;
import jpsxdec.psxvideo.mdec.MdecInputStream;
import jpsxdec.util.BinaryDataNotRecognized;
@@ -149,11 +152,13 @@ public int getVlcCount() {
return new BitStreamUncompressor_Lain(header, bitReader);
}
-
+ public static final ZeroRunLengthAc ESCAPE_CODE = new ZeroRunLengthAc(BitStreamCode._000001___________, true, false);
+ public static final ZeroRunLengthAc END_OF_BLOCK = new ZeroRunLengthAc(BitStreamCode._10_______________,
+ MdecCode.MDEC_END_OF_DATA_TOP6, MdecCode.MDEC_END_OF_DATA_BOTTOM10, false, true);
/** The custom Serial Experiments Lain PlayStation game
* AC coefficient variable-length (Huffman) code table. */
- private final static AcLookup AC_VARIABLE_LENGTH_CODES_LAIN = new AcLookup()
+ private final static ZeroRunLengthAcLookup AC_VARIABLE_LENGTH_CODES_LAIN = new ZeroRunLengthAcLookup.Builder()
// Code "Run" "Level"
._11s ( 0 , 1 )
._011s ( 0 , 2 )
@@ -265,7 +270,10 @@ public int getVlcCount() {
._0000000000011100s ( 0 , 60 )
._0000000000011101s ( 9 , 2 )
._0000000000011110s ( 24 , 1 )
- ._0000000000011111s ( 18 , 1 );
+ ._0000000000011111s ( 18 , 1 )
+ .add(ESCAPE_CODE)
+ .add(END_OF_BLOCK)
+ .build();
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
@@ -275,117 +283,124 @@ public int getVlcCount() {
private final LainHeader _header;
public BitStreamUncompressor_Lain(@Nonnull LainHeader header, @Nonnull ArrayBitReader bitReader) {
- super(AC_VARIABLE_LENGTH_CODES_LAIN, bitReader);
+ super(bitReader, AC_VARIABLE_LENGTH_CODES_LAIN,
+ new QuantizationDcReader_Lain(header.getLumaQscale(), header.getChromaQscale()),
+ AC_ESCAPE_CODE_LAIN, FRAME_END_PADDING_BITS_NONE);
_header = header;
}
- @Override
- protected void readQscaleAndDC(@Nonnull MdecCode code) throws MdecException.EndOfStream {
- code.setBottom10Bits( _bitReader.readSignedBits(10) );
- assert !DEBUG || _debug.append(Misc.bitsToString(code.getBottom10Bits(), 10));
- if (getCurrentMacroBlockSubBlock() < 2)
- code.setTop6Bits(_header.getChromaQscale());
- else
- code.setTop6Bits(_header.getLumaQscale());
- }
+ private static class QuantizationDcReader_Lain implements IQuantizationDc {
+ private final int _iFrameLumaQuantizationScale;
+ private final int _iFrameChromaQuantizationScale;
-
- protected void readEscapeAcCode(@Nonnull MdecCode code) throws MdecException.EndOfStream
- {
+ public QuantizationDcReader_Lain(int iFrameLumaQuantizationScale,
+ int iFrameChromaQuantizationScale)
+ {
+ _iFrameLumaQuantizationScale = iFrameLumaQuantizationScale;
+ _iFrameChromaQuantizationScale = iFrameChromaQuantizationScale;
+ }
- int iBits = _bitReader.readUnsignedBits(6+8);
+ public void readQuantizationScaleAndDc(@Nonnull ArrayBitReader bitReader,
+ @Nonnull MdecContext context,
+ @Nonnull MdecCode code)
+ throws MdecException.EndOfStream
+ {
+ code.setBottom10Bits(bitReader.readSignedBits(10) );
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.appendBits(Misc.bitsToString(code.getBottom10Bits(), 10));
+ if (context.getCurrentBlock().isChroma())
+ code.setTop6Bits(_iFrameChromaQuantizationScale);
+ else
+ code.setTop6Bits(_iFrameLumaQuantizationScale);
+ }
+ }
- // Get the (6 bit) run of zeros from the bits already read
- // 17 bits: eeeeeezzzzzz_____ : e = escape code, z = run of zeros
- code.setTop6Bits( (iBits >>> 8) & 63 );
- assert !DEBUG || _debug.append(Misc.bitsToString(code.getTop6Bits(), 6));
+ private static class AcEscapeCode_Lain implements IAcEscapeCode {
- // Lain
-
- /* Lain playstation uses mpeg1 specification escape code
- Fixed Length Code Level
- forbidden -256
- 1000 0000 0000 0001 -255
- 1000 0000 0000 0010 -254
- ...
- 1000 0000 0111 1111 -129
- 1000 0000 1000 0000 -128
- 1000 0001 -127
- 1000 0010 -126
- ...
- 1111 1110 -2
- 1111 1111 -1
- forbidden 0
- 0000 0001 1
- 0000 0010 2
- ...
- 0111 1110 126
- 0111 1111 127
- 0000 0000 1000 0000 128
- 0000 0000 1000 0001 129
- ...
- 0000 0000 1111 1110 254
- 0000 0000 1111 1111 255
- */
- // Chop down to the first 8 bits
- iBits = iBits & 0xff;
- int iACCoefficient;
- if (iBits == 0x00) {
- // If it's the special 00000000
- // Positive
- assert !DEBUG || _debug.append("00000000");
-
- iACCoefficient = _bitReader.readUnsignedBits(8);
-
- assert !DEBUG || _debug.append(Misc.bitsToString(iACCoefficient, 8));
-
- code.setBottom10Bits(iACCoefficient);
- } else if (iBits == 0x80) {
- // If it's the special 10000000
- // Negative
- assert !DEBUG || _debug.append("10000000");
-
- iACCoefficient = -256 + _bitReader.readUnsignedBits(8);
-
- assert !DEBUG || _debug.append(Misc.bitsToString(iACCoefficient, 8));
-
- code.setBottom10Bits(iACCoefficient);
- } else {
- // Otherwise we already have the value
- assert !DEBUG || _debug.append(Misc.bitsToString(iBits, 8));
-
- // changed to signed
- iACCoefficient = (byte)iBits;
-
- code.setBottom10Bits(iACCoefficient);
- }
+ public void readAcEscapeCode(@Nonnull ArrayBitReader bitReader, @Nonnull MdecCode code) throws MdecException.EndOfStream
+ {
- }
+ int iBits = bitReader.readUnsignedBits(6+8);
+
+ // Get the (6 bit) run of zeros from the bits already read
+ // 17 bits: eeeeeezzzzzz_____ : e = escape code, z = run of zeros
+ code.setTop6Bits( (iBits >>> 8) & 63 );
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.appendBits(Misc.bitsToString(code.getTop6Bits(), 6));
+
+ // Lain
+
+ /* Lain playstation uses mpeg1 specification escape code
+ Fixed Length Code Level
+ forbidden -256
+ 1000 0000 0000 0001 -255
+ 1000 0000 0000 0010 -254
+ ...
+ 1000 0000 0111 1111 -129
+ 1000 0000 1000 0000 -128
+ 1000 0001 -127
+ 1000 0010 -126
+ ...
+ 1111 1110 -2
+ 1111 1111 -1
+ forbidden 0
+ 0000 0001 1
+ 0000 0010 2
+ ...
+ 0111 1110 126
+ 0111 1111 127
+ 0000 0000 1000 0000 128
+ 0000 0000 1000 0001 129
+ ...
+ 0000 0000 1111 1110 254
+ 0000 0000 1111 1111 255
+ */
+ // Chop down to the first 8 bits
+ iBits = iBits & 0xff;
+ int iACCoefficient;
+ if (iBits == 0x00) {
+ // If it's the special 00000000
+ // Positive
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.appendBits("00000000");
+
+ iACCoefficient = bitReader.readUnsignedBits(8);
+
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.appendBits(Misc.bitsToString(iACCoefficient, 8));
+
+ code.setBottom10Bits(iACCoefficient);
+ } else if (iBits == 0x80) {
+ // If it's the special 10000000
+ // Negative
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.appendBits("10000000");
+
+ iACCoefficient = -256 + bitReader.readUnsignedBits(8);
+
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.appendBits(Misc.bitsToString(iACCoefficient, 8));
+
+ code.setBottom10Bits(iACCoefficient);
+ } else {
+ // Otherwise we already have the value
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.appendBits(Misc.bitsToString(iBits, 8));
- @Override
- public void skipPaddingBits() {
- // Lain doesn't have ending padding bits
- }
+ // changed to signed
+ iACCoefficient = (byte)iBits;
- @Override
- public @Nonnull Type getType() {
- return Type.Lain;
+ code.setBottom10Bits(iACCoefficient);
+ }
+
+ }
}
+ private static final AcEscapeCode_Lain AC_ESCAPE_CODE_LAIN = new AcEscapeCode_Lain();
+ @Override
public String toString() {
- return String.format("%s Qscale L=%d C=%d 3800=%x Offset=%d MB=%d.%d Mdec count=%d",
- getType(), _header.getLumaQscale(), _header.getChromaQscale(),
- _header.getMagic3800orFrame(),
- _bitReader.getWordPosition(),
- getFullMacroBlocksRead(), getCurrentMacroBlockSubBlock(),
- getReadMdecCodeCount());
+ return super.toString() + " Qscale L=" + _header.getLumaQscale()
+ +" C=" + _header.getChromaQscale();
}
@Override
public @Nonnull BitStreamCompressor_Lain makeCompressor() {
- return new BitStreamCompressor_Lain(getFullMacroBlocksRead(), _header.getMagic3800orFrame());
+ return new BitStreamCompressor_Lain(_context.getTotalMacroBlocksRead(), _header.getMagic3800orFrame());
}
// =========================================================================
@@ -458,7 +473,7 @@ public BitStreamCompressor_Lain(int iMacroBlockCount, int iMagic3800orFrame) {
{
LainHeader header = new LainHeader(abOriginal, abOriginal.length);
if (!header.isValid())
- throw new LocalizedIncompatibleException(I.FRAME_NOT_LAIN());
+ throw new LocalizedIncompatibleException(I.FRAME_IS_NOT_BITSTREAM_FORMAT("Lain"));
final int iFrameLQscale = header.getLumaQscale();
final int iFrameCQscale = header.getChromaQscale();
@@ -515,8 +530,8 @@ public BitStreamCompressor_Lain(int iMacroBlockCount, int iMagic3800orFrame) {
}
@Override
- protected void setBlockQscale(int iBlock, int iQscale) throws IncompatibleException {
- if (iBlock < 2) {
+ protected void setBlockQscale(@Nonnull MdecBlock block, int iQscale) throws IncompatibleException {
+ if (block.isChroma()) {
if (_iChromaQscale < 0)
_iChromaQscale = iQscale;
else if (_iChromaQscale != iQscale) {
@@ -560,7 +575,7 @@ protected int getHeaderVersion() {
}
@Override
- protected @Nonnull AcLookup getAcVaribleLengthCodeList() {
+ protected @Nonnull ZeroRunLengthAcLookup getAcVaribleLengthCodeList() {
return AC_VARIABLE_LENGTH_CODES_LAIN;
}
@@ -580,12 +595,12 @@ protected int getHeaderVersion() {
"Unable to escape %s, AC code too large for Lain", code));
if (code.getBottom10Bits() >= -127 && code.getBottom10Bits() <= 127) {
- return AcLookup.ESCAPE_CODE.BitString + sTopBits + Misc.bitsToString(code.getBottom10Bits(), 8);
+ return ESCAPE_CODE.getBitString() + sTopBits + Misc.bitsToString(code.getBottom10Bits(), 8);
} else {
if (code.getBottom10Bits() > 0) {
- return AcLookup.ESCAPE_CODE.BitString + sTopBits + "00000000" + Misc.bitsToString(code.getBottom10Bits(), 8);
+ return ESCAPE_CODE.getBitString() + sTopBits + "00000000" + Misc.bitsToString(code.getBottom10Bits(), 8);
} else {
- return AcLookup.ESCAPE_CODE.BitString + sTopBits + "10000000" + Misc.bitsToString(code.getBottom10Bits()+256, 8);
+ return ESCAPE_CODE.getBitString() + sTopBits + "10000000" + Misc.bitsToString(code.getBottom10Bits()+256, 8);
}
}
}
diff --git a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_STRv1.java b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_STRv1.java
index 2babfbf..f444b63 100644
--- a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_STRv1.java
+++ b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_STRv1.java
@@ -51,18 +51,24 @@
* This case obviously works with PlayStation hardware, so is already
* accepted by the STRv2 uncompressor to make things simpler, faster, and
* more robust (because AC=0 may occur in games besides FF7). See
- * {@link BitStreamUncompressor_STRv2#readEscapeAcCode(jpsxdec.psxvideo.mdec.MdecInputStream.MdecCode)}.
+ * {@link BitStreamUncompressor_STRv2#readEscapeAcCode(jpsxdec.psxvideo.mdec.MdecCode)}.
*
* I suspect the reason for this FF7 AC=0 waste is because they compressed the
* frames further to fit camera data. This led to AC values being reduced,
* some falling to 0, but they didn't merge those codes to save space.
*/
-public class BitStreamUncompressor_STRv1 extends BitStreamUncompressor_STRv2 {
+public class BitStreamUncompressor_STRv1 extends BitStreamUncompressor {
public static class StrV1Header extends StrHeader {
public StrV1Header(byte[] abFrameData, int iDataSize) {
super(abFrameData, iDataSize, 1);
}
+
+ public @Nonnull BitStreamUncompressor_STRv1 makeNew(@Nonnull byte[] abBitstream, int iBitstreamSize)
+ throws BinaryDataNotRecognized
+ {
+ return BitStreamUncompressor_STRv1.makeV1(abBitstream, iBitstreamSize);
+ }
}
public static @Nonnull BitStreamUncompressor_STRv1 makeV1(@Nonnull byte[] abFrameData)
@@ -84,28 +90,30 @@ public StrV1Header(byte[] abFrameData, int iDataSize) {
StrV1Header header = new StrV1Header(abFrameData, iDataSize);
if (!header.isValid())
return null;
- ArrayBitReader bitReader = makeStrBitReader(abFrameData, iDataSize);
+ ArrayBitReader bitReader = BitStreamUncompressor_STRv2.makeStrBitReader(abFrameData, iDataSize);
return new BitStreamUncompressor_STRv1(header, bitReader);
}
- public BitStreamUncompressor_STRv1(@Nonnull StrHeader header,
+ @Nonnull
+ private final StrV1Header _header;
+
+ public BitStreamUncompressor_STRv1(@Nonnull StrV1Header header,
@Nonnull ArrayBitReader bitReader)
{
- super(header, bitReader);
+ super(bitReader, ZeroRunLengthAcLookup_STR.AC_VARIABLE_LENGTH_CODES_MPEG1,
+ new BitStreamUncompressor_STRv2.QuantizationDc_STRv12(header.getQuantizationScale()),
+ BitStreamUncompressor_STRv2.AC_ESCAPE_CODE_STR,
+ BitStreamUncompressor_STRv2.FRAME_END_PADDING_BITS_STRV2);
+ _header = header;
}
- @Override
- public @Nonnull Type getType() {
- return Type.STRv1;
- }
-
@Override
public @Nonnull BitStreamCompressor_STRv1 makeCompressor() {
- return new BitStreamCompressor_STRv1(getFullMacroBlocksRead());
+ return new BitStreamCompressor_STRv1(_context.getTotalMacroBlocksRead());
}
- public static class BitStreamCompressor_STRv1 extends BitStreamCompressor_STRv2 {
+ public static class BitStreamCompressor_STRv1 extends BitStreamUncompressor_STRv2.BitStreamCompressor_STRv2 {
private BitStreamCompressor_STRv1(int iMacroBlockCount) {
super(iMacroBlockCount);
@@ -118,8 +126,8 @@ private BitStreamCompressor_STRv1(int iMacroBlockCount) {
protected int getFrameQscale(@Nonnull byte[] abFrameData) throws LocalizedIncompatibleException {
StrV1Header header = new StrV1Header(abFrameData, abFrameData.length);
if (!header.isValid())
- throw new LocalizedIncompatibleException(I.FRAME_NOT_STRV1());
- return header.getQscale();
+ throw new LocalizedIncompatibleException(I.FRAME_IS_NOT_BITSTREAM_FORMAT("STRv1"));
+ return header.getQuantizationScale();
}
}
diff --git a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_STRv2.java b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_STRv2.java
index 56ab56d..5af6c0c 100644
--- a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_STRv2.java
+++ b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_STRv2.java
@@ -44,14 +44,14 @@
import jpsxdec.i18n.I;
import jpsxdec.i18n.exception.LocalizedIncompatibleException;
import jpsxdec.i18n.log.ILocalizedLogger;
-import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor.AcBitCode;
-import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor.AcLookup;
-import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor.MdecDebugger;
import jpsxdec.psxvideo.encode.MacroBlockEncoder;
import jpsxdec.psxvideo.encode.MdecEncoder;
+import jpsxdec.psxvideo.mdec.Calc;
+import jpsxdec.psxvideo.mdec.MdecBlock;
+import jpsxdec.psxvideo.mdec.MdecCode;
+import jpsxdec.psxvideo.mdec.MdecContext;
import jpsxdec.psxvideo.mdec.MdecException;
import jpsxdec.psxvideo.mdec.MdecInputStream;
-import jpsxdec.psxvideo.mdec.MdecInputStream.MdecCode;
import jpsxdec.util.BinaryDataNotRecognized;
import jpsxdec.util.IO;
import jpsxdec.util.IncompatibleException;
@@ -68,6 +68,12 @@ public static class StrV2Header extends StrHeader {
public StrV2Header(byte[] abFrameData, int iDataSize) {
super(abFrameData, iDataSize, 2);
}
+
+ public @Nonnull BitStreamUncompressor_STRv2 makeNew(@Nonnull byte[] abBitstream, int iBitstreamSize)
+ throws BinaryDataNotRecognized
+ {
+ return BitStreamUncompressor_STRv2.makeV2(abBitstream, iBitstreamSize);
+ }
}
public static @Nonnull BitStreamUncompressor_STRv2 makeV2(@Nonnull byte[] abBitstream)
@@ -94,125 +100,6 @@ public StrV2Header(byte[] abFrameData, int iDataSize) {
return new BitStreamUncompressor_STRv2(header, bitReader);
}
- /** STR v2, v3, FF7, and .iki AC coefficient variable-length (Huffman) codes.
- * Conveniently identical to MPEG1. */
- static final AcLookup AC_VARIABLE_LENGTH_CODES_MPEG1 = new AcLookup()
- // Code "Run" "Level"
- // Table 1
- ._11s (0 , 1)
- ._011s (1 , 1)
- ._0100s (0 , 2)
- ._0101s (2 , 1)
- ._00101s (0 , 3)
- ._00110s (4 , 1)
- ._00111s (3 , 1)
- ._000100s (7 , 1)
- ._000101s (6 , 1)
- ._000110s (1 , 2)
- ._000111s (5 , 1)
- ._0000100s (2 , 2)
- ._0000101s (9 , 1)
- ._0000110s (0 , 4)
- ._0000111s (8 , 1)
- ._00100000s (13, 1)
- ._00100001s (0 , 6)
- ._00100010s (12, 1)
- ._00100011s (11, 1)
- ._00100100s (3 , 2)
- ._00100101s (1 , 3)
- ._00100110s (0 , 5)
- ._00100111s (10, 1)
- // Table 2
- ._0000001000s (16, 1)
- ._0000001001s (5 , 2)
- ._0000001010s (0 , 7)
- ._0000001011s (2 , 3)
- ._0000001100s (1 , 4)
- ._0000001101s (15, 1)
- ._0000001110s (14, 1)
- ._0000001111s (4 , 2)
- ._000000010000s (0 , 11)
- ._000000010001s (8 , 2)
- ._000000010010s (4 , 3)
- ._000000010011s (0 , 10)
- ._000000010100s (2 , 4)
- ._000000010101s (7 , 2)
- ._000000010110s (21, 1)
- ._000000010111s (20, 1)
- ._000000011000s (0 , 9)
- ._000000011001s (19, 1)
- ._000000011010s (18, 1)
- ._000000011011s (1 , 5)
- ._000000011100s (3 , 3)
- ._000000011101s (0 , 8)
- ._000000011110s (6 , 2)
- ._000000011111s (17, 1)
- ._0000000010000s (10, 2)
- ._0000000010001s (9 , 2)
- ._0000000010010s (5 , 3)
- ._0000000010011s (3 , 4)
- ._0000000010100s (2 , 5)
- ._0000000010101s (1 , 7)
- ._0000000010110s (1 , 6)
- ._0000000010111s (0 , 15)
- ._0000000011000s (0 , 14)
- ._0000000011001s (0 , 13)
- ._0000000011010s (0 , 12)
- ._0000000011011s (26, 1)
- ._0000000011100s (25, 1)
- ._0000000011101s (24, 1)
- ._0000000011110s (23, 1)
- ._0000000011111s (22, 1)
- // Table 3
- ._00000000010000s (0 , 31)
- ._00000000010001s (0 , 30)
- ._00000000010010s (0 , 29)
- ._00000000010011s (0 , 28)
- ._00000000010100s (0 , 27)
- ._00000000010101s (0 , 26)
- ._00000000010110s (0 , 25)
- ._00000000010111s (0 , 24)
- ._00000000011000s (0 , 23)
- ._00000000011001s (0 , 22)
- ._00000000011010s (0 , 21)
- ._00000000011011s (0 , 20)
- ._00000000011100s (0 , 19)
- ._00000000011101s (0 , 18)
- ._00000000011110s (0 , 17)
- ._00000000011111s (0 , 16)
- ._000000000010000s (0 , 40)
- ._000000000010001s (0 , 39)
- ._000000000010010s (0 , 38)
- ._000000000010011s (0 , 37)
- ._000000000010100s (0 , 36)
- ._000000000010101s (0 , 35)
- ._000000000010110s (0 , 34)
- ._000000000010111s (0 , 33)
- ._000000000011000s (0 , 32)
- ._000000000011001s (1 , 14)
- ._000000000011010s (1 , 13)
- ._000000000011011s (1 , 12)
- ._000000000011100s (1 , 11)
- ._000000000011101s (1 , 10)
- ._000000000011110s (1 , 9)
- ._000000000011111s (1 , 8)
- ._0000000000010000s(1 , 18)
- ._0000000000010001s(1 , 17)
- ._0000000000010010s(1 , 16)
- ._0000000000010011s(1 , 15)
- ._0000000000010100s(6 , 3)
- ._0000000000010101s(16, 2)
- ._0000000000010110s(15, 2)
- ._0000000000010111s(14, 2)
- ._0000000000011000s(13, 2)
- ._0000000000011001s(12, 2)
- ._0000000000011010s(11, 2)
- ._0000000000011011s(31, 1)
- ._0000000000011100s(30, 1)
- ._0000000000011101s(29, 1)
- ._0000000000011110s(28, 1)
- ._0000000000011111s(27, 1);
-
/** 11 bits found at the end of STR v2 movies.
* 011 111 111 10 */
private final static String END_OF_FRAME_EXTRA_BITS = "01111111110";
@@ -221,125 +108,72 @@ public StrV2Header(byte[] abFrameData, int iDataSize) {
* 011 111 111 10 */
private static final int b01111111110 = 0x3FE;
- // -------------------------------------------------------------------------
- // -------------------------------------------------------------------------
- // -------------------------------------------------------------------------
-
- protected abstract static class StrHeader {
- /** Frame's quantization scale. */
- private int _iQscale = -1;
- private int _iHalfVlcCountCeil32 = -1;
-
- private final boolean _blnIsValid;
- protected StrHeader(@Nonnull byte[] abFrameData, int iDataSize,
- int iExpectedVersion)
- {
- if (iDataSize < 8) {
- _blnIsValid = false;
- } else {
- int iHalfVlcCountCeil32 = IO.readSInt16LE(abFrameData, 0);
- int iMagic3800 = IO.readUInt16LE(abFrameData, 2);
- int iQscale = IO.readSInt16LE(abFrameData, 4);
- int iVersion = IO.readSInt16LE(abFrameData, 6);
-
- _blnIsValid = iMagic3800 == 0x3800 &&
- iQscale >= 1 &&
- iVersion == iExpectedVersion &&
- iHalfVlcCountCeil32 >= 0;
- if (_blnIsValid) {
- _iQscale = iQscale;
- _iHalfVlcCountCeil32 = iHalfVlcCountCeil32;
- }
- }
- }
-
- public int getQscale() {
- if (!_blnIsValid) throw new IllegalStateException();
- return _iQscale;
- }
-
- public int getHalfVlcCountCeil32() {
- if (!_blnIsValid) throw new IllegalStateException();
- return _iHalfVlcCountCeil32;
- }
-
- public boolean isValid() {
- return _blnIsValid;
- }
-
- }
- protected static @Nonnull ArrayBitReader makeStrBitReader(@Nonnull byte[] abBitstream, int iDataSize) {
+ public static @Nonnull ArrayBitReader makeStrBitReader(@Nonnull byte[] abBitstream, int iDataSize) {
return new ArrayBitReader(abBitstream, iDataSize, true, 8);
}
- protected final StrHeader _header;
+ @Nonnull
+ private final StrV2Header _header;
- protected BitStreamUncompressor_STRv2(@Nonnull StrHeader header,
- @Nonnull ArrayBitReader bitReader)
+ private BitStreamUncompressor_STRv2(@Nonnull StrV2Header header,
+ @Nonnull ArrayBitReader bitReader)
{
- super(AC_VARIABLE_LENGTH_CODES_MPEG1, bitReader);
+ super(bitReader, ZeroRunLengthAcLookup_STR.AC_VARIABLE_LENGTH_CODES_MPEG1,
+ new QuantizationDc_STRv12(header.getQuantizationScale()), new AcEscapeCode_STR(),
+ new FrameEndPaddingBits_STRv2());
_header = header;
}
- protected void readQscaleAndDC(@Nonnull MdecCode code)
- throws MdecException.ReadCorruption, MdecException.EndOfStream
- {
- code.setTop6Bits(_header.getQscale());
- code.setBottom10Bits(_bitReader.readSignedBits(10));
- assert !DEBUG || _debug.append(Misc.bitsToString(code.getBottom10Bits(), 10));
- assert !code.isEOD(); // a Qscale of 63 and DC of -512 would look like EOD
- }
+ public static class QuantizationDc_STRv12 implements IQuantizationDc {
- protected void readEscapeAcCode(@Nonnull MdecCode code)
- throws MdecException.EndOfStream
- {
- readStrEscapeAcCode(_bitReader, code, _debug, LOG);
- }
+ private final int _iFrameQuantizationScale;
- static void readStrEscapeAcCode(@Nonnull ArrayBitReader bitReader,
- @Nonnull MdecCode code,
- @CheckForNull MdecDebugger debug,
- @Nonnull Logger log)
- throws MdecException.EndOfStream
- {
- // Normal playstation encoding stores the escape code in 16 bits:
- // 6 for run of zeros, 10 for AC Coefficient
- int iRunAndAc = bitReader.readUnsignedBits(6 + 10);
- code.set(iRunAndAc);
- assert !DEBUG || debug.append(Misc.bitsToString(iRunAndAc, 16));
-
- // Ignore AC == 0 coefficients.
- // (I consider this an error, but FF7 and other games have these codes,
- // so clearly the MDEC can handle it.)
- if (code.getBottom10Bits() == 0) {
- log.info("Escape code has 0 AC coefficient.");
+ public QuantizationDc_STRv12(int iFrameQuantizationScale) {
+ _iFrameQuantizationScale = iFrameQuantizationScale;
}
- }
- @Override
- public void skipPaddingBits() throws MdecException.EndOfStream {
- int iPaddingBits = _bitReader.readUnsignedBits(11);
- if (iPaddingBits != b01111111110)
- LOG.log(Level.WARNING, "Incorrect padding bits {0}", Misc.bitsToString(iPaddingBits, 11));
+ public void readQuantizationScaleAndDc(@Nonnull ArrayBitReader bitReader, @Nonnull MdecContext context, @Nonnull MdecCode code)
+ throws MdecException.ReadCorruption, MdecException.EndOfStream
+ {
+ code.setTop6Bits(_iFrameQuantizationScale);
+ code.setBottom10Bits(bitReader.readSignedBits(10));
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.appendBits(Misc.bitsToString(code.getBottom10Bits(), 10));
+ assert !code.isEOD(); // a Qscale of 63 and DC of -512 would look like EOD
+ }
}
- @Override
- public @Nonnull BitStreamCompressor_STRv2 makeCompressor() {
- return new BitStreamCompressor_STRv2(getFullMacroBlocksRead());
+ private static class AcEscapeCode_STR implements IAcEscapeCode {
+ public void readAcEscapeCode(@Nonnull ArrayBitReader bitReader, @Nonnull MdecCode code)
+ throws MdecException.EndOfStream
+ {
+ // Normal playstation encoding stores the escape code in 16 bits:
+ // 6 for run of zeros, 10 for AC Coefficient
+ int iRunAndAc = bitReader.readUnsignedBits(6 + 10);
+ code.set(iRunAndAc);
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.appendBits(Misc.bitsToString(iRunAndAc, 16));
+ }
+ }
+ public static final IAcEscapeCode AC_ESCAPE_CODE_STR = new AcEscapeCode_STR();
+
+ private static class FrameEndPaddingBits_STRv2 implements IFrameEndPaddingBits {
+ @Override
+ public void skipPaddingBits(@Nonnull ArrayBitReader bitReader) throws MdecException.EndOfStream {
+ int iPaddingBits = bitReader.readUnsignedBits(11);
+ if (iPaddingBits != b01111111110)
+ LOG.log(Level.WARNING, "Incorrect padding bits {0}", Misc.bitsToString(iPaddingBits, 11));
+ }
}
+ public static final IFrameEndPaddingBits FRAME_END_PADDING_BITS_STRV2 = new FrameEndPaddingBits_STRv2();
@Override
- public @Nonnull Type getType() {
- return Type.STRv2;
+ public String toString() {
+ return super.toString() + " Qscale=" + _header.getQuantizationScale();
}
- public String toString() {
- return String.format("%s Qscale=%d, Current Offset=%d, Current MB.Blk=%d.%d, MDEC count=%d",
- getType(), _header.getQscale(),
- _bitReader.getWordPosition(),
- getFullMacroBlocksRead(), getCurrentMacroBlockSubBlock(),
- getReadMdecCodeCount());
+ @Override
+ public @Nonnull BitStreamCompressor_STRv2 makeCompressor() {
+ return new BitStreamCompressor_STRv2(_context.getTotalMacroBlocksRead());
}
/*########################################################################*/
@@ -354,7 +188,7 @@ public static class BitStreamCompressor_STRv2 implements BitStreamCompressor {
private int _iQscale;
private int _iMdecCodeCount;
- protected BitStreamCompressor_STRv2(int iMacroBlockCount) {
+ public BitStreamCompressor_STRv2(int iMacroBlockCount) {
_iMacroBlockCount = iMacroBlockCount;
}
@@ -441,47 +275,41 @@ protected BitStreamCompressor_STRv2(int iMacroBlockCount) {
bitStream.setLittleEndian(isBitstreamLittleEndian());
final MdecCode code = new MdecCode();
- int iMdecCodeCount = 0;
+ MdecContext context = new MdecContext();
- boolean blnNewBlk = true;
- int iBlock = 0;
- for (int iMacroBlock = 0; iMacroBlock < _iMacroBlockCount;) {
+ while (context.getTotalMacroBlocksRead() < _iMacroBlockCount) {
String sBitsToWrite;
boolean blnEod = inStream.readMdecCode(code);
if (!code.isValid())
throw new MdecException.ReadCorruption("Invalid MDEC code " + code);
if (blnEod) {
- sBitsToWrite = AcLookup.END_OF_BLOCK.BitString;
- blnNewBlk = true;
- iBlock = (iBlock + 1) % 6;
- if (iBlock == 0)
- iMacroBlock++;
+ sBitsToWrite = ZeroRunLengthAcLookup_STR.END_OF_BLOCK.getBitString();
+ context.nextCodeEndBlock();
} else {
- if (blnNewBlk) {
- setBlockQscale(iBlock, code.getTop6Bits());
- sBitsToWrite = encodeDC(code.getBottom10Bits(), iBlock);
- blnNewBlk = false;
+ if (context.atStartOfBlock()) {
+ setBlockQscale(context.getCurrentBlock(), code.getTop6Bits());
+ sBitsToWrite = encodeDC(code.getBottom10Bits(), context.getCurrentBlock());
} else {
sBitsToWrite = encodeAC(code);
}
+ context.nextCode();
}
- iMdecCodeCount++;
- if (DEBUG)
+ if (BitStreamDebugging.DEBUG)
System.out.println("Converting " + code.toString() + " to " + sBitsToWrite + " at " + bitStream.getCurrentWordPosition());
bitStream.write(sBitsToWrite);
}
- if (iBlock != 0)
+ if (!context.atStartOfBlock())
throw new IllegalStateException("Ended compressing in the middle of a macroblock.");
addTrailingBits(bitStream);
byte[] abBitstream = bitStream.toByteArray();
- byte[] abHeader = createHeader(iMdecCodeCount);
+ byte[] abHeader = createHeader(context.getTotalMdecCodesRead());
byte[] abReturn = new byte[abHeader.length + abBitstream.length];
System.arraycopy(abHeader, 0, abReturn, 0, abHeader.length);
System.arraycopy(abBitstream, 0, abReturn, abHeader.length, abBitstream.length);
- _iMdecCodeCount = iMdecCodeCount;
+ _iMdecCodeCount = context.getTotalMdecCodesRead();
return abReturn;
}
@@ -501,7 +329,7 @@ protected void addTrailingBits(@Nonnull BitStreamWriter bitStream) {
* Performs any necessary preparations for encoding the block.
* Ensures the quantization scale is compatible with the bitstream.
* Caller will ensure parameters are valid. */
- protected void setBlockQscale(int iBlock, int iQscale) throws IncompatibleException {
+ protected void setBlockQscale(@Nonnull MdecBlock block, int iQscale) throws IncompatibleException {
if (_iQscale < 0)
_iQscale = iQscale;
else if (_iQscale != iQscale)
@@ -510,11 +338,9 @@ else if (_iQscale != iQscale)
_iQscale, iQscale));
}
- protected @Nonnull String encodeDC(int iDC, int iBlock) throws MdecException.TooMuchEnergy {
+ protected @Nonnull String encodeDC(int iDC, @Nonnull MdecBlock block) throws MdecException.TooMuchEnergy {
if (iDC < -512 || iDC > 511)
throw new IllegalArgumentException("Invalid DC code " + iDC);
- if (iBlock < 0 || iBlock > 5)
- throw new IllegalArgumentException("Invalid block " + iBlock);
return Misc.bitsToString(iDC, 10);
}
@@ -525,17 +351,16 @@ private String encodeAC(@Nonnull MdecCode code)
if (!code.isValid())
throw new IllegalArgumentException("Invalid MDEC code " + code);
- for (AcBitCode vlc : getAcVaribleLengthCodeList().getCodeList()) {
- if (code.getTop6Bits() == vlc.ZeroRun && Math.abs(code.getBottom10Bits()) == vlc.AcCoefficient) {
- return vlc.BitString.replace('s', (code.getBottom10Bits() < 0) ? '1' : '0');
- }
+ for (ZeroRunLengthAc vlc : getAcVaribleLengthCodeList()) {
+ if (vlc.equalsMdec(code))
+ return vlc.getBitString();
}
// not a pre-defined code
return encodeAcEscape(code);
}
- protected @Nonnull AcLookup getAcVaribleLengthCodeList() {
- return AC_VARIABLE_LENGTH_CODES_MPEG1;
+ protected @Nonnull ZeroRunLengthAcLookup getAcVaribleLengthCodeList() {
+ return ZeroRunLengthAcLookup_STR.AC_VARIABLE_LENGTH_CODES_MPEG1;
}
protected @Nonnull String encodeAcEscape(@Nonnull MdecCode code)
@@ -544,7 +369,7 @@ private String encodeAC(@Nonnull MdecCode code)
if (!code.isValid())
throw new IllegalArgumentException("Invalid MDEC code " + code);
- return AcLookup.ESCAPE_CODE.BitString +
+ return ZeroRunLengthAcLookup_STR.ESCAPE_CODE.getBitString() +
Misc.bitsToString(code.getTop6Bits(), 6) +
Misc.bitsToString(code.getBottom10Bits(), 10);
}
@@ -552,7 +377,7 @@ private String encodeAC(@Nonnull MdecCode code)
protected @Nonnull byte[] createHeader(int iMdecCodeCount) {
byte[] ab = new byte[8];
- IO.writeInt16LE(ab, 0, calculateHalfCeiling32(iMdecCodeCount));
+ IO.writeInt16LE(ab, 0, Calc.calculateHalfCeiling32(iMdecCodeCount));
IO.writeInt16LE(ab, 2, (short)0x3800);
IO.writeInt16LE(ab, 4, (short)_iQscale);
IO.writeInt16LE(ab, 6, (short)getHeaderVersion());
@@ -565,14 +390,9 @@ private String encodeAC(@Nonnull MdecCode code)
protected int getFrameQscale(@Nonnull byte[] abFrameData) throws LocalizedIncompatibleException {
StrV2Header header = new StrV2Header(abFrameData, abFrameData.length);
if (!header.isValid())
- throw new LocalizedIncompatibleException(I.FRAME_NOT_STRV2());
- return header.getQscale();
+ throw new LocalizedIncompatibleException(I.FRAME_IS_NOT_BITSTREAM_FORMAT("STRv2"));
+ return header.getQuantizationScale();
}
}
-
- /** Debug */
- public static void main(String[] args) {
- AC_VARIABLE_LENGTH_CODES_MPEG1.print(System.out);
- }
}
diff --git a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_STRv3.java b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_STRv3.java
index 9094787..e640b46 100644
--- a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_STRv3.java
+++ b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/BitStreamUncompressor_STRv3.java
@@ -43,23 +43,31 @@
import javax.annotation.Nonnull;
import jpsxdec.i18n.I;
import jpsxdec.i18n.exception.LocalizedIncompatibleException;
+import jpsxdec.psxvideo.mdec.MdecBlock;
+import jpsxdec.psxvideo.mdec.MdecCode;
+import jpsxdec.psxvideo.mdec.MdecContext;
import jpsxdec.psxvideo.mdec.MdecException;
import jpsxdec.psxvideo.mdec.MdecInputStream;
-import jpsxdec.psxvideo.mdec.MdecInputStream.MdecCode;
import jpsxdec.util.BinaryDataNotRecognized;
import jpsxdec.util.IncompatibleException;
import jpsxdec.util.Misc;
/** Uncompressor for demuxed STR v3 video bitstream data.
* Makes use of most of STR v2 code. Adds v3 handling for DC values. */
-public class BitStreamUncompressor_STRv3 extends BitStreamUncompressor_STRv2 {
+public class BitStreamUncompressor_STRv3 extends BitStreamUncompressor {
private static final Logger LOG = Logger.getLogger(BitStreamUncompressor_STRv3.class.getName());
public static class StrV3Header extends StrHeader {
- public StrV3Header(byte[] abFrameData, int iDataSize) {
+ public StrV3Header(@Nonnull byte[] abFrameData, int iDataSize) {
super(abFrameData, iDataSize, 3);
}
+
+ public @Nonnull BitStreamUncompressor_STRv3 makeNew(@Nonnull byte[] abBitstream, int iBitstreamSize)
+ throws BinaryDataNotRecognized
+ {
+ return BitStreamUncompressor_STRv3.makeV3(abBitstream, iBitstreamSize);
+ }
}
public static @Nonnull BitStreamUncompressor_STRv3 makeV3(@Nonnull byte[] abFrameData)
@@ -81,7 +89,7 @@ public StrV3Header(byte[] abFrameData, int iDataSize) {
StrV3Header header = new StrV3Header(abFrameData, iDataSize);
if (!header.isValid())
return null;
- ArrayBitReader bitReader = makeStrBitReader(abFrameData, iDataSize);
+ ArrayBitReader bitReader = BitStreamUncompressor_STRv2.makeStrBitReader(abFrameData, iDataSize);
return new BitStreamUncompressor_STRv3(header, bitReader);
}
@@ -116,8 +124,7 @@ public void fillLookupArray(@Nonnull DcVariableLengthCode[] aoLookup, int iLonge
}
}
- abstract public int readDc(@Nonnull ArrayBitReader bitReader,
- @CheckForNull MdecDebugger debug)
+ abstract public int readDc(@Nonnull ArrayBitReader bitReader)
throws MdecException.EndOfStream;
/** Attempts to encode a DC value that has already been diff'ed from
* the previous value and divided by 4.
@@ -137,7 +144,7 @@ public DcVlc0(@Nonnull String sCode, int iDifferentialBitLen, int iDifferential)
}
@Override
- public int readDc(@Nonnull ArrayBitReader bitReader, @CheckForNull MdecDebugger debug) {
+ public int readDc(@Nonnull ArrayBitReader bitReader) {
return _iDifferential;
}
@@ -173,11 +180,11 @@ public DcVlc_(@Nonnull String sCode, int iDifferentialBitLen,
}
@Override
- public int readDc(@Nonnull ArrayBitReader bitReader, @CheckForNull MdecDebugger debug)
+ public int readDc(@Nonnull ArrayBitReader bitReader)
throws MdecException.EndOfStream
{
int iDC_Differential = bitReader.readUnsignedBits(_iDifferentialBitLen);
- assert !DEBUG || debug.append(Misc.bitsToString(iDC_Differential, _iDifferentialBitLen));
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.appendBits(Misc.bitsToString(iDC_Differential, _iDifferentialBitLen));
// top bit == 0 means it's negative
if ((iDC_Differential & _iTopBitMask) == 0) {
iDC_Differential += _iNegativeDifferentialMin;
@@ -280,116 +287,131 @@ public int readDc(@Nonnull ArrayBitReader bitReader, @CheckForNull MdecDebugger
// ## Instance stuff ######################################################
// ########################################################################
- /** Holds the previous DC values during a version 3 frame decoding. */
- private int _iPreviousCr_DC = 0,
- _iPreviousCb_DC = 0,
- _iPreviousY_DC = 0;
+ @Nonnull
+ private final StrV3Header _header;
public BitStreamUncompressor_STRv3(@Nonnull StrV3Header header,
@Nonnull ArrayBitReader bitReader)
{
- super(header, bitReader);
+ super(bitReader, ZeroRunLengthAcLookup_STR.AC_VARIABLE_LENGTH_CODES_MPEG1,
+ new QuantizationDcReader_STRv3(header.getQuantizationScale()),
+ BitStreamUncompressor_STRv2.AC_ESCAPE_CODE_STR,
+ FRAME_END_PADDING_BITS_STRV3);
+ _header = header;
}
- @Override
- protected void readQscaleAndDC(@Nonnull MdecCode code)
- throws MdecException.ReadCorruption, MdecException.EndOfStream
- {
- code.setTop6Bits(_header.getQscale());
- switch (getCurrentMacroBlockSubBlock()) {
- case 0:
- code.setBottom10Bits(_iPreviousCr_DC = readV3DcChroma(_iPreviousCr_DC));
- return;
- case 1:
- code.setBottom10Bits(_iPreviousCb_DC = readV3DcChroma(_iPreviousCb_DC));
- return;
- default:
- readV3DcLuma();
- code.setBottom10Bits(_iPreviousY_DC);
+ private static class QuantizationDcReader_STRv3 implements IQuantizationDc {
+
+ private final int _iFrameQuantizationScale;
+
+ /** Holds the previous DC values during a version 3 frame decoding. */
+ private int _iPreviousCr_DC = 0,
+ _iPreviousCb_DC = 0,
+ _iPreviousY_DC = 0;
+
+ public QuantizationDcReader_STRv3(int iFrameQuantizationScale) {
+ _iFrameQuantizationScale = iFrameQuantizationScale;
}
- }
-
- private int readV3DcChroma(int iPreviousDC)
- throws MdecException.ReadCorruption, MdecException.EndOfStream
- {
- // Peek enough bits
- int iBits = _bitReader.peekUnsignedBits(DC_CHROMA_LONGEST_VARIABLE_LENGTH_CODE);
-
- DcVariableLengthCode dcVlc = CHROMA_LOOKUP[iBits];
-
- if (dcVlc == null) {
- throw new MdecException.ReadCorruption(MdecException.STRV3_BLOCK_UNCOMPRESS_ERR_UNKNOWN_CHROMA_DC_VLC(
- getFullMacroBlocksRead(), getCurrentMacroBlockSubBlock(),
- Misc.bitsToString(iBits, DC_CHROMA_LONGEST_VARIABLE_LENGTH_CODE)));
+ public void readQuantizationScaleAndDc(@Nonnull ArrayBitReader bitReader,
+ @Nonnull MdecContext context,
+ @Nonnull MdecCode code)
+ throws MdecException.ReadCorruption, MdecException.EndOfStream
+ {
+ code.setTop6Bits(_iFrameQuantizationScale);
+ switch (context.getCurrentBlock()) {
+ case Cr:
+ code.setBottom10Bits(_iPreviousCr_DC = readV3DcChroma(_iPreviousCr_DC, bitReader, context));
+ return;
+ case Cb:
+ code.setBottom10Bits(_iPreviousCb_DC = readV3DcChroma(_iPreviousCb_DC, bitReader, context));
+ return;
+ default:
+ readV3DcLuma(bitReader, context);
+ code.setBottom10Bits(_iPreviousY_DC);
+ }
}
- assert !DEBUG || _debug.append(dcVlc.VariableLengthCode);
- // skip the variable length code bits
- _bitReader.skipBits(dcVlc.VariableLengthCode.length());
+ private int readV3DcChroma(int iPreviousDC, @Nonnull ArrayBitReader bitReader, @Nonnull MdecContext context)
+ throws MdecException.ReadCorruption, MdecException.EndOfStream
+ {
+ // Peek enough bits
+ int iBits = bitReader.peekUnsignedBits(DC_CHROMA_LONGEST_VARIABLE_LENGTH_CODE);
- iPreviousDC += dcVlc.readDc(_bitReader, _debug);
+ DcVariableLengthCode dcVlc = CHROMA_LOOKUP[iBits];
- if (iPreviousDC < -512 || iPreviousDC > 511) {
- throw new MdecException.ReadCorruption(MdecException.STRV3_BLOCK_UNCOMPRESS_ERR_CHROMA_DC_OOB(
- getFullMacroBlocksRead(), getCurrentMacroBlockSubBlock(),
- iPreviousDC));
- }
+ if (dcVlc == null) {
+ throw new MdecException.ReadCorruption(MdecException.STRV3_BLOCK_UNCOMPRESS_ERR_UNKNOWN_CHROMA_DC_VLC(
+ context.getTotalMacroBlocksRead(), context.getCurrentBlock().ordinal(),
+ Misc.bitsToString(iBits, DC_CHROMA_LONGEST_VARIABLE_LENGTH_CODE)));
+ }
- return iPreviousDC;
- }
-
- private void readV3DcLuma() throws MdecException.ReadCorruption, MdecException.EndOfStream {
- // Peek enough bits
- int iBits = _bitReader.peekUnsignedBits(DC_LUMA_LONGEST_VARIABLE_LENGTH_CODE);
-
- DcVariableLengthCode dcVlc = LUMA_LOOKUP[iBits];
-
- if (dcVlc == null) {
- throw new MdecException.ReadCorruption(MdecException.STRV3_BLOCK_UNCOMPRESS_ERR_UNKNOWN_LUMA_DC_VLC(
- getFullMacroBlocksRead(), getCurrentMacroBlockSubBlock(),
- Misc.bitsToString(iBits, DC_LUMA_LONGEST_VARIABLE_LENGTH_CODE)));
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.appendBits(dcVlc.VariableLengthCode);
+
+ // skip the variable length code bits
+ bitReader.skipBits(dcVlc.VariableLengthCode.length());
+
+ iPreviousDC += dcVlc.readDc(bitReader);
+
+ if (iPreviousDC < -512 || iPreviousDC > 511) {
+ throw new MdecException.ReadCorruption(MdecException.STRV3_BLOCK_UNCOMPRESS_ERR_CHROMA_DC_OOB(
+ context.getTotalMacroBlocksRead(), context.getCurrentBlock().ordinal(),
+ iPreviousDC));
+ }
+
+ return iPreviousDC;
}
-
- assert !DEBUG || _debug.append(dcVlc.VariableLengthCode);
- // skip the variable length code bits
- _bitReader.skipBits(dcVlc.VariableLengthCode.length());
+ private void readV3DcLuma(@Nonnull ArrayBitReader bitReader, @Nonnull MdecContext context) throws MdecException.ReadCorruption, MdecException.EndOfStream {
+ // Peek enough bits
+ int iBits = bitReader.peekUnsignedBits(DC_LUMA_LONGEST_VARIABLE_LENGTH_CODE);
+
+ DcVariableLengthCode dcVlc = LUMA_LOOKUP[iBits];
+
+ if (dcVlc == null) {
+ throw new MdecException.ReadCorruption(MdecException.STRV3_BLOCK_UNCOMPRESS_ERR_UNKNOWN_LUMA_DC_VLC(
+ context.getTotalMacroBlocksRead(), context.getCurrentBlock().ordinal(),
+ Misc.bitsToString(iBits, DC_LUMA_LONGEST_VARIABLE_LENGTH_CODE)));
+ }
+
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.appendBits(dcVlc.VariableLengthCode);
+
+ // skip the variable length code bits
+ bitReader.skipBits(dcVlc.VariableLengthCode.length());
- _iPreviousY_DC += dcVlc.readDc(_bitReader, _debug);
+ _iPreviousY_DC += dcVlc.readDc(bitReader);
- if (_iPreviousY_DC < -512 || _iPreviousY_DC > 511) {
- throw new MdecException.ReadCorruption(MdecException.STRV3_BLOCK_UNCOMPRESS_ERR_LUMA_DC_OOB(
- getFullMacroBlocksRead(), getCurrentMacroBlockSubBlock(),
- _iPreviousY_DC));
+ if (_iPreviousY_DC < -512 || _iPreviousY_DC > 511) {
+ throw new MdecException.ReadCorruption(MdecException.STRV3_BLOCK_UNCOMPRESS_ERR_LUMA_DC_OOB(
+ context.getTotalMacroBlocksRead(), context.getCurrentBlock().ordinal(),
+ _iPreviousY_DC));
+ }
}
}
- @Override
- public void skipPaddingBits() throws MdecException.EndOfStream {
- int iPaddingBits = _bitReader.readUnsignedBits(11);
- if (iPaddingBits != b11111111110) {
- LOG.log(Level.WARNING, "Incorrect padding bits {0}", Misc.bitsToString(iPaddingBits, 11));
+ private static class FrameEndPaddingBits_STRv3 implements IFrameEndPaddingBits {
+ @Override
+ public void skipPaddingBits(@Nonnull ArrayBitReader bitReader) throws MdecException.EndOfStream {
+ int iPaddingBits = bitReader.readUnsignedBits(11);
+ if (iPaddingBits != b11111111110) {
+ LOG.log(Level.WARNING, "Incorrect padding bits {0}", Misc.bitsToString(iPaddingBits, 11));
+ }
}
}
+ private static final FrameEndPaddingBits_STRv3 FRAME_END_PADDING_BITS_STRV3 = new FrameEndPaddingBits_STRv3();
- @Override
- public @Nonnull Type getType() {
- return Type.STRv3;
- }
-
@Override
public @Nonnull BitStreamCompressor_STRv3 makeCompressor() {
- return new BitStreamCompressor_STRv3(getFullMacroBlocksRead());
+ return new BitStreamCompressor_STRv3(_context.getTotalMacroBlocksRead());
}
// =========================================================================
/** Note unlike all other compressors, STRv3 is LOSSY when encoding
* DC coefficients. */
- public static class BitStreamCompressor_STRv3 extends BitStreamCompressor_STRv2 {
+ public static class BitStreamCompressor_STRv3 extends BitStreamUncompressor_STRv2.BitStreamCompressor_STRv2 {
BitStreamCompressor_STRv3(int iMacroBlockCount) {
super(iMacroBlockCount);
@@ -402,8 +424,8 @@ public static class BitStreamCompressor_STRv3 extends BitStreamCompressor_STRv2
protected int getFrameQscale(@Nonnull byte[] abFrameData) throws LocalizedIncompatibleException {
StrV3Header header = new StrV3Header(abFrameData, abFrameData.length);
if (!header.isValid())
- throw new LocalizedIncompatibleException(I.FRAME_NOT_STRV3());
- return header.getQscale();
+ throw new LocalizedIncompatibleException(I.FRAME_IS_NOT_BITSTREAM_FORMAT("STRv3"));
+ return header.getQuantizationScale();
}
@@ -424,7 +446,7 @@ protected int getFrameQscale(@Nonnull byte[] abFrameData) throws LocalizedIncomp
_iPreviousY_DcRound4;
@Override
- protected @Nonnull String encodeDC(int iDC, int iBlock) throws MdecException.TooMuchEnergy {
+ protected @Nonnull String encodeDC(int iDC, @Nonnull MdecBlock block) throws MdecException.TooMuchEnergy {
// round to the nearest multiple of 4
// TODO: Maybe try to expose this quality loss somehow
int iDcRound4 = (int)Math.round(iDC / 4.0) * 4;
@@ -434,13 +456,13 @@ protected int getFrameQscale(@Nonnull byte[] abFrameData) throws LocalizedIncomp
// and save the rounded DC for the next iteration
DcVariableLengthCode[] lookupTable;
int iDcDiffRound4Div4;
- switch (iBlock) {
- case 0:
+ switch (block) {
+ case Cr:
iDcDiffRound4Div4 = (iDcRound4 - _iPreviousCr_DcRound4) / 4;
_iPreviousCr_DcRound4 = iDcRound4;
lookupTable = DC_Chroma_VarLenCodes;
break;
- case 1:
+ case Cb:
iDcDiffRound4Div4 = (iDcRound4 - _iPreviousCb_DcRound4) / 4;
_iPreviousCb_DcRound4 = iDcRound4;
lookupTable = DC_Chroma_VarLenCodes;
diff --git a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/StrHeader.java b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/StrHeader.java
new file mode 100644
index 0000000..1b1feb2
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/StrHeader.java
@@ -0,0 +1,104 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2007-2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.psxvideo.bitstreams;
+
+import javax.annotation.Nonnull;
+import jpsxdec.util.BinaryDataNotRecognized;
+import jpsxdec.util.IO;
+
+public abstract class StrHeader {
+
+ public static final int SIZEOF = 8;
+
+ /** Frame's quantization scale. */
+ private int _iQuantizationScale = -1;
+ private int _iHalfVlcCountCeil32 = -1;
+
+ private final boolean _blnIsValid;
+ protected StrHeader(@Nonnull byte[] abFrameData, int iDataSize,
+ int iExpectedVersion)
+ {
+ if (iDataSize < 8) {
+ _blnIsValid = false;
+ } else {
+ int iHalfVlcCountCeil32 = IO.readSInt16LE(abFrameData, 0);
+ int iMagic3800 = IO.readUInt16LE(abFrameData, 2);
+ int iQscale = IO.readSInt16LE(abFrameData, 4);
+ int iVersion = IO.readSInt16LE(abFrameData, 6);
+
+ _blnIsValid = iMagic3800 == 0x3800 &&
+ iQscale >= 1 &&
+ iVersion == iExpectedVersion &&
+ iHalfVlcCountCeil32 >= 0;
+ if (_blnIsValid) {
+ _iQuantizationScale = iQscale;
+ _iHalfVlcCountCeil32 = iHalfVlcCountCeil32;
+ }
+ }
+ }
+
+ public int getQuantizationScale() {
+ if (!_blnIsValid) throw new IllegalStateException();
+ return _iQuantizationScale;
+ }
+
+ public int getHalfVlcCountCeil32() {
+ if (!_blnIsValid) throw new IllegalStateException();
+ return _iHalfVlcCountCeil32;
+ }
+
+ public boolean isValid() {
+ return _blnIsValid;
+ }
+
+ public @Nonnull BitStreamUncompressor makeNew(@Nonnull byte[] abBitstream) throws BinaryDataNotRecognized {
+ return makeNew(abBitstream, abBitstream.length);
+ }
+
+ abstract public @Nonnull BitStreamUncompressor makeNew(@Nonnull byte[] abBitstream, int iBitstreamSize)
+ throws BinaryDataNotRecognized;
+
+ @Override
+ public String toString() {
+ if (_blnIsValid)
+ return "Qscale " + _iQuantizationScale + " count " + _iHalfVlcCountCeil32;
+ else
+ return "Invalid STR header";
+ }
+
+}
diff --git a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/ZeroRunLengthAc.java b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/ZeroRunLengthAc.java
new file mode 100644
index 0000000..06fed3e
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/ZeroRunLengthAc.java
@@ -0,0 +1,144 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.psxvideo.bitstreams;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import jpsxdec.psxvideo.mdec.MdecCode;
+
+/** Assigns value to a {@link BitStreamCode}. The value can have a
+ * zero-run-length and AC coefficient (i.e. {@link MdecCode})
+ * and/or the escape code or end-of-block code. */
+public class ZeroRunLengthAc {
+
+ @Nonnull
+ private final BitStreamCode _bitStreamCode;
+
+ @CheckForNull
+ private final MdecCode _mdecCode;
+
+ private final boolean _blnIsEscapeCode;
+ private final boolean _blnIsEndOfBlock;
+
+ /* If this is a normal AC code with MDEC code equivalent. */
+ public ZeroRunLengthAc(@Nonnull BitStreamCode bitStreamCode, int iZeroRunLength, int iAcCoefficient) {
+ _bitStreamCode = bitStreamCode;
+ _mdecCode = new MdecCode(iZeroRunLength, iAcCoefficient);
+ _blnIsEscapeCode = false;
+ _blnIsEndOfBlock = false;
+ }
+
+ /* If this is a special AC code without an MDEC equialent. */
+ public ZeroRunLengthAc(@Nonnull BitStreamCode bitStreamCode, boolean blnIsEscapeCode, boolean blnIsEndOfBlock) {
+ this(bitStreamCode, null, blnIsEscapeCode, blnIsEndOfBlock);
+ }
+
+ /* If this is a special AC code with an MDEC equialent. */
+ public ZeroRunLengthAc(@Nonnull BitStreamCode bitStreamCode,
+ int iZeroRunLength, int iAcCoefficient,
+ boolean blnIsEscapeCode, boolean blnIsEndOfBlock)
+ {
+ this(bitStreamCode, new MdecCode(iZeroRunLength, iAcCoefficient), blnIsEscapeCode, blnIsEndOfBlock);
+ }
+
+ /* If this is a special AC code with an MDEC equialent. */
+ private ZeroRunLengthAc(@Nonnull BitStreamCode bitStreamCode,
+ @CheckForNull MdecCode mdecCode,
+ boolean blnIsEscapeCode, boolean blnIsEndOfBlock)
+ {
+ if (blnIsEscapeCode && blnIsEndOfBlock)
+ throw new IllegalArgumentException("Only one of [escape code] or [end of block] can be true");
+ _bitStreamCode = bitStreamCode;
+ _mdecCode = mdecCode;
+ _blnIsEscapeCode = blnIsEscapeCode;
+ _blnIsEndOfBlock = blnIsEndOfBlock;
+ }
+
+ public void getMdecCode(@Nonnull MdecCode out) {
+ if (_mdecCode == null) {
+ throw new IllegalStateException("MDEC code requested from AC without code " + this);
+ } else {
+ out.setFrom(_mdecCode);
+ }
+ }
+
+ public @CheckForNull MdecCode getMdecCodeCopy() {
+ if (_mdecCode == null)
+ return null;
+ else
+ return _mdecCode.copy();
+ }
+
+ public @Nonnull BitStreamCode getBitStreamCode() {
+ return _bitStreamCode;
+ }
+
+ public @Nonnull String getBitString() {
+ return _bitStreamCode.getString();
+ }
+
+ public int getBitLength() {
+ return _bitStreamCode.getLength();
+ }
+
+ public boolean isIsEscapeCode() {
+ return _blnIsEscapeCode;
+ }
+
+ public boolean isIsEndOfBlock() {
+ return _blnIsEndOfBlock;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(_bitStreamCode);
+ if (_mdecCode != null)
+ sb.append(' ').append(_mdecCode);
+ if (_blnIsEscapeCode)
+ sb.append(" ESCAPE_CODE");
+ if (_blnIsEndOfBlock)
+ sb.append(" END_OF_BLOCK");
+ return sb.toString();
+ }
+
+ public boolean equalsMdec(@Nonnull MdecCode code) {
+ return _mdecCode != null && _mdecCode.equals(code);
+ }
+
+}
diff --git a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/ZeroRunLengthAcLookup.java b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/ZeroRunLengthAcLookup.java
new file mode 100644
index 0000000..93a1dbf
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/ZeroRunLengthAcLookup.java
@@ -0,0 +1,527 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2007-2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.psxvideo.bitstreams;
+
+import java.io.PrintStream;
+import java.util.Iterator;
+import java.util.TreeSet;
+import javax.annotation.Nonnull;
+import static jpsxdec.psxvideo.bitstreams.BitStreamCode.*;
+import jpsxdec.psxvideo.mdec.MdecCode;
+import jpsxdec.psxvideo.mdec.MdecException;
+import jpsxdec.util.Misc;
+
+/** Creates ultra fast bit-stream lookup tables. */
+public class ZeroRunLengthAcLookup implements Iterable {
+
+ public static class Builder {
+
+ private final ZeroRunLengthAc[] _aoList = new ZeroRunLengthAc[BitStreamCode.getTotalCount()];
+
+ private final TreeSet _duplicateCodeChecker = new TreeSet();
+
+ /** To set the zero run-length and AC coefficient for a single bit stream code. */
+ public @Nonnull Builder set(@Nonnull BitStreamCode bitStreamCode, int iZeroRunLength, int iAcCoefficient) {
+ return add(new ZeroRunLengthAc(bitStreamCode, iZeroRunLength, iAcCoefficient));
+ }
+
+ /** To set the zero run-length and AC coefficient for a single bit stream code. */
+ public @Nonnull Builder add(@Nonnull ZeroRunLengthAc zrlac) {
+ MdecCode mdecCode = zrlac.getMdecCodeCopy();
+ if (mdecCode != null) {
+ if (!_duplicateCodeChecker.add(mdecCode))
+ throw new RuntimeException("Already got MDEC code " + mdecCode);
+ }
+ int iIndex = zrlac.getBitStreamCode().ordinal();
+ if (_aoList[iIndex] != null)
+ throw new RuntimeException("Trying to replace " + _aoList[iIndex] + " with " + zrlac + " at " + iIndex);
+ _aoList[iIndex] = zrlac;
+ return this;
+ }
+
+ // To set the zero run-length and AC coefficient for the 2 codes covered with a sign bit.
+ //
+ public Builder _11s (int zr, int aac) { return set(_110______________, _111______________, zr, aac); }
+ // ------------------------------------------------------------------------------
+ public Builder _011s (int zr, int aac) { return set(_0110_____________, _0111_____________, zr, aac); }
+ public Builder _0100s (int zr, int aac) { return set(_01000____________, _01001____________, zr, aac); }
+ public Builder _0101s (int zr, int aac) { return set(_01010____________, _01011____________, zr, aac); }
+ public Builder _00101s (int zr, int aac) { return set(_001010___________, _001011___________, zr, aac); }
+ public Builder _00110s (int zr, int aac) { return set(_001100___________, _001101___________, zr, aac); }
+ public Builder _00111s (int zr, int aac) { return set(_001110___________, _001111___________, zr, aac); }
+ public Builder _000100s (int zr, int aac) { return set(_0001000__________, _0001001__________, zr, aac); }
+ public Builder _000101s (int zr, int aac) { return set(_0001010__________, _0001011__________, zr, aac); }
+ public Builder _000110s (int zr, int aac) { return set(_0001100__________, _0001101__________, zr, aac); }
+ public Builder _000111s (int zr, int aac) { return set(_0001110__________, _0001111__________, zr, aac); }
+ public Builder _0000100s (int zr, int aac) { return set(_00001000_________, _00001001_________, zr, aac); }
+ public Builder _0000101s (int zr, int aac) { return set(_00001010_________, _00001011_________, zr, aac); }
+ public Builder _0000110s (int zr, int aac) { return set(_00001100_________, _00001101_________, zr, aac); }
+ public Builder _0000111s (int zr, int aac) { return set(_00001110_________, _00001111_________, zr, aac); }
+ public Builder _00100000s(int zr, int aac) { return set(_001000000________, _001000001________, zr, aac); }
+ public Builder _00100001s(int zr, int aac) { return set(_001000010________, _001000011________, zr, aac); }
+ public Builder _00100010s(int zr, int aac) { return set(_001000100________, _001000101________, zr, aac); }
+ public Builder _00100011s(int zr, int aac) { return set(_001000110________, _001000111________, zr, aac); }
+ public Builder _00100100s(int zr, int aac) { return set(_001001000________, _001001001________, zr, aac); }
+ public Builder _00100101s(int zr, int aac) { return set(_001001010________, _001001011________, zr, aac); }
+ public Builder _00100110s(int zr, int aac) { return set(_001001100________, _001001101________, zr, aac); }
+ public Builder _00100111s(int zr, int aac) { return set(_001001110________, _001001111________, zr, aac); }
+ // ------------------------------------------------------------------------------
+ public Builder _0000001000s(int zr, int aac) { return set(_00000010000______, _00000010001______, zr, aac); }
+ public Builder _0000001001s(int zr, int aac) { return set(_00000010010______, _00000010011______, zr, aac); }
+ public Builder _0000001010s(int zr, int aac) { return set(_00000010100______, _00000010101______, zr, aac); }
+ public Builder _0000001011s(int zr, int aac) { return set(_00000010110______, _00000010111______, zr, aac); }
+ public Builder _0000001100s(int zr, int aac) { return set(_00000011000______, _00000011001______, zr, aac); }
+ public Builder _0000001101s(int zr, int aac) { return set(_00000011010______, _00000011011______, zr, aac); }
+ public Builder _0000001110s(int zr, int aac) { return set(_00000011100______, _00000011101______, zr, aac); }
+ public Builder _0000001111s(int zr, int aac) { return set(_00000011110______, _00000011111______, zr, aac); }
+ public Builder _000000010000s(int zr, int aac) { return set(_0000000100000____, _0000000100001____, zr, aac); }
+ public Builder _000000010001s(int zr, int aac) { return set(_0000000100010____, _0000000100011____, zr, aac); }
+ public Builder _000000010010s(int zr, int aac) { return set(_0000000100100____, _0000000100101____, zr, aac); }
+ public Builder _000000010011s(int zr, int aac) { return set(_0000000100110____, _0000000100111____, zr, aac); }
+ public Builder _000000010100s(int zr, int aac) { return set(_0000000101000____, _0000000101001____, zr, aac); }
+ public Builder _000000010101s(int zr, int aac) { return set(_0000000101010____, _0000000101011____, zr, aac); }
+ public Builder _000000010110s(int zr, int aac) { return set(_0000000101100____, _0000000101101____, zr, aac); }
+ public Builder _000000010111s(int zr, int aac) { return set(_0000000101110____, _0000000101111____, zr, aac); }
+ public Builder _000000011000s(int zr, int aac) { return set(_0000000110000____, _0000000110001____, zr, aac); }
+ public Builder _000000011001s(int zr, int aac) { return set(_0000000110010____, _0000000110011____, zr, aac); }
+ public Builder _000000011010s(int zr, int aac) { return set(_0000000110100____, _0000000110101____, zr, aac); }
+ public Builder _000000011011s(int zr, int aac) { return set(_0000000110110____, _0000000110111____, zr, aac); }
+ public Builder _000000011100s(int zr, int aac) { return set(_0000000111000____, _0000000111001____, zr, aac); }
+ public Builder _000000011101s(int zr, int aac) { return set(_0000000111010____, _0000000111011____, zr, aac); }
+ public Builder _000000011110s(int zr, int aac) { return set(_0000000111100____, _0000000111101____, zr, aac); }
+ public Builder _000000011111s(int zr, int aac) { return set(_0000000111110____, _0000000111111____, zr, aac); }
+ public Builder _0000000010000s(int zr, int aac) { return set(_00000000100000___, _00000000100001___, zr, aac); }
+ public Builder _0000000010001s(int zr, int aac) { return set(_00000000100010___, _00000000100011___, zr, aac); }
+ public Builder _0000000010010s(int zr, int aac) { return set(_00000000100100___, _00000000100101___, zr, aac); }
+ public Builder _0000000010011s(int zr, int aac) { return set(_00000000100110___, _00000000100111___, zr, aac); }
+ public Builder _0000000010100s(int zr, int aac) { return set(_00000000101000___, _00000000101001___, zr, aac); }
+ public Builder _0000000010101s(int zr, int aac) { return set(_00000000101010___, _00000000101011___, zr, aac); }
+ public Builder _0000000010110s(int zr, int aac) { return set(_00000000101100___, _00000000101101___, zr, aac); }
+ public Builder _0000000010111s(int zr, int aac) { return set(_00000000101110___, _00000000101111___, zr, aac); }
+ public Builder _0000000011000s(int zr, int aac) { return set(_00000000110000___, _00000000110001___, zr, aac); }
+ public Builder _0000000011001s(int zr, int aac) { return set(_00000000110010___, _00000000110011___, zr, aac); }
+ public Builder _0000000011010s(int zr, int aac) { return set(_00000000110100___, _00000000110101___, zr, aac); }
+ public Builder _0000000011011s(int zr, int aac) { return set(_00000000110110___, _00000000110111___, zr, aac); }
+ public Builder _0000000011100s(int zr, int aac) { return set(_00000000111000___, _00000000111001___, zr, aac); }
+ public Builder _0000000011101s(int zr, int aac) { return set(_00000000111010___, _00000000111011___, zr, aac); }
+ public Builder _0000000011110s(int zr, int aac) { return set(_00000000111100___, _00000000111101___, zr, aac); }
+ public Builder _0000000011111s(int zr, int aac) { return set(_00000000111110___, _00000000111111___, zr, aac); }
+ // ------------------------------------------------------------------------------
+ public Builder _00000000010000s(int zr, int aac) { return set(_000000000100000__, _000000000100001__, zr, aac); }
+ public Builder _00000000010001s(int zr, int aac) { return set(_000000000100010__, _000000000100011__, zr, aac); }
+ public Builder _00000000010010s(int zr, int aac) { return set(_000000000100100__, _000000000100101__, zr, aac); }
+ public Builder _00000000010011s(int zr, int aac) { return set(_000000000100110__, _000000000100111__, zr, aac); }
+ public Builder _00000000010100s(int zr, int aac) { return set(_000000000101000__, _000000000101001__, zr, aac); }
+ public Builder _00000000010101s(int zr, int aac) { return set(_000000000101010__, _000000000101011__, zr, aac); }
+ public Builder _00000000010110s(int zr, int aac) { return set(_000000000101100__, _000000000101101__, zr, aac); }
+ public Builder _00000000010111s(int zr, int aac) { return set(_000000000101110__, _000000000101111__, zr, aac); }
+ public Builder _00000000011000s(int zr, int aac) { return set(_000000000110000__, _000000000110001__, zr, aac); }
+ public Builder _00000000011001s(int zr, int aac) { return set(_000000000110010__, _000000000110011__, zr, aac); }
+ public Builder _00000000011010s(int zr, int aac) { return set(_000000000110100__, _000000000110101__, zr, aac); }
+ public Builder _00000000011011s(int zr, int aac) { return set(_000000000110110__, _000000000110111__, zr, aac); }
+ public Builder _00000000011100s(int zr, int aac) { return set(_000000000111000__, _000000000111001__, zr, aac); }
+ public Builder _00000000011101s(int zr, int aac) { return set(_000000000111010__, _000000000111011__, zr, aac); }
+ public Builder _00000000011110s(int zr, int aac) { return set(_000000000111100__, _000000000111101__, zr, aac); }
+ public Builder _00000000011111s(int zr, int aac) { return set(_000000000111110__, _000000000111111__, zr, aac); }
+ public Builder _000000000010000s(int zr, int aac) { return set(_0000000000100000_, _0000000000100001_, zr, aac); }
+ public Builder _000000000010001s(int zr, int aac) { return set(_0000000000100010_, _0000000000100011_, zr, aac); }
+ public Builder _000000000010010s(int zr, int aac) { return set(_0000000000100100_, _0000000000100101_, zr, aac); }
+ public Builder _000000000010011s(int zr, int aac) { return set(_0000000000100110_, _0000000000100111_, zr, aac); }
+ public Builder _000000000010100s(int zr, int aac) { return set(_0000000000101000_, _0000000000101001_, zr, aac); }
+ public Builder _000000000010101s(int zr, int aac) { return set(_0000000000101010_, _0000000000101011_, zr, aac); }
+ public Builder _000000000010110s(int zr, int aac) { return set(_0000000000101100_, _0000000000101101_, zr, aac); }
+ public Builder _000000000010111s(int zr, int aac) { return set(_0000000000101110_, _0000000000101111_, zr, aac); }
+ public Builder _000000000011000s(int zr, int aac) { return set(_0000000000110000_, _0000000000110001_, zr, aac); }
+ public Builder _000000000011001s(int zr, int aac) { return set(_0000000000110010_, _0000000000110011_, zr, aac); }
+ public Builder _000000000011010s(int zr, int aac) { return set(_0000000000110100_, _0000000000110101_, zr, aac); }
+ public Builder _000000000011011s(int zr, int aac) { return set(_0000000000110110_, _0000000000110111_, zr, aac); }
+ public Builder _000000000011100s(int zr, int aac) { return set(_0000000000111000_, _0000000000111001_, zr, aac); }
+ public Builder _000000000011101s(int zr, int aac) { return set(_0000000000111010_, _0000000000111011_, zr, aac); }
+ public Builder _000000000011110s(int zr, int aac) { return set(_0000000000111100_, _0000000000111101_, zr, aac); }
+ public Builder _000000000011111s(int zr, int aac) { return set(_0000000000111110_, _0000000000111111_, zr, aac); }
+ public Builder _0000000000010000s(int zr, int aac) { return set(_00000000000100000, _00000000000100001, zr, aac); }
+ public Builder _0000000000010001s(int zr, int aac) { return set(_00000000000100010, _00000000000100011, zr, aac); }
+ public Builder _0000000000010010s(int zr, int aac) { return set(_00000000000100100, _00000000000100101, zr, aac); }
+ public Builder _0000000000010011s(int zr, int aac) { return set(_00000000000100110, _00000000000100111, zr, aac); }
+ public Builder _0000000000010100s(int zr, int aac) { return set(_00000000000101000, _00000000000101001, zr, aac); }
+ public Builder _0000000000010101s(int zr, int aac) { return set(_00000000000101010, _00000000000101011, zr, aac); }
+ public Builder _0000000000010110s(int zr, int aac) { return set(_00000000000101100, _00000000000101101, zr, aac); }
+ public Builder _0000000000010111s(int zr, int aac) { return set(_00000000000101110, _00000000000101111, zr, aac); }
+ public Builder _0000000000011000s(int zr, int aac) { return set(_00000000000110000, _00000000000110001, zr, aac); }
+ public Builder _0000000000011001s(int zr, int aac) { return set(_00000000000110010, _00000000000110011, zr, aac); }
+ public Builder _0000000000011010s(int zr, int aac) { return set(_00000000000110100, _00000000000110101, zr, aac); }
+ public Builder _0000000000011011s(int zr, int aac) { return set(_00000000000110110, _00000000000110111, zr, aac); }
+ public Builder _0000000000011100s(int zr, int aac) { return set(_00000000000111000, _00000000000111001, zr, aac); }
+ public Builder _0000000000011101s(int zr, int aac) { return set(_00000000000111010, _00000000000111011, zr, aac); }
+ public Builder _0000000000011110s(int zr, int aac) { return set(_00000000000111100, _00000000000111101, zr, aac); }
+ public Builder _0000000000011111s(int zr, int aac) { return set(_00000000000111110, _00000000000111111, zr, aac); }
+
+ private @Nonnull Builder set(@Nonnull BitStreamCode positiveBitStreamCodeEndsWith0,
+ @Nonnull BitStreamCode negitiveBitStreamCodeEndsWith1,
+ int iZeroRunLength, int iAbsoluteAcCoefficient)
+ {
+ set(positiveBitStreamCodeEndsWith0, iZeroRunLength, iAbsoluteAcCoefficient);
+ set(negitiveBitStreamCodeEndsWith1, iZeroRunLength, -iAbsoluteAcCoefficient);
+ return this;
+ }
+
+ public @Nonnull ZeroRunLengthAcLookup build() {
+ return new ZeroRunLengthAcLookup(_aoList);
+ }
+
+ }
+
+ @Nonnull
+ private final ZeroRunLengthAc[] _aoList;
+
+ /** Table to look up '10' and '11s' codes using all but the first (1) bit. */
+ private final ZeroRunLengthAc[] _aoTable_1xx = new ZeroRunLengthAc[4];
+ /** Table to look up codes '011s' to '00100111s' using all but the first (0) bit.
+ * Given a bit code in that range, strip the leading zero bit, then pad
+ * any extra trailing bits to make an 8 bit value. Use that value as the
+ * index in this table to get the corresponding code. */
+ private final ZeroRunLengthAc[] _aoTable_0xxxxxxx = new ZeroRunLengthAc[256];
+ /** Table to look up codes '0000001000s' to '0000000011111s' using all but
+ * the first 6 zero bits.
+ * Given a bit code in that range, strip the leading 6 zero bits, then pad
+ * any extra trailing bits to make an 8 bit value. Use that value as the
+ * index in this table to get the corresponding code. */
+ private final ZeroRunLengthAc[] _aoTable_000000xxxxxxxx = new ZeroRunLengthAc[256];
+ /** Table to look up codes '00000000010000s' to '0000000000011111s' using
+ * all but the first 9 zero bits.
+ * Given a bit code in that range, strip the leading 9 zero bits, then pad
+ * any extra trailing bits to make an 8 bit value. Use that value as the
+ * index in this table to get the corresponding code. */
+ private final ZeroRunLengthAc[] _aoTable_000000000xxxxxxxx = new ZeroRunLengthAc[256];
+
+ private ZeroRunLengthAcLookup(@Nonnull ZeroRunLengthAc[] aoList) {
+ _aoList = aoList;
+ for (int i = 0; i < aoList.length; i++) {
+ ZeroRunLengthAc zrlac = aoList[i];
+ BitStreamCode bitStreamCode = BitStreamCode.get(i);
+ if (zrlac == null)
+ throw new IllegalStateException("Table incomplete: missing " + bitStreamCode);
+ setBits(bitStreamCode, zrlac);
+ }
+ }
+
+ /** Identifies the lookup table in which to place the bit code. */
+ private void setBits(@Nonnull BitStreamCode bsc, @Nonnull ZeroRunLengthAc zrlac) {
+ final int iBitsRemain;
+ final ZeroRunLengthAc[] aoTable;
+ final int iTableStart;
+
+ // This needs some explaination
+ if (bsc.getString().startsWith("000000000")) {
+ aoTable = _aoTable_000000000xxxxxxxx;
+ iBitsRemain = 8 - (bsc.getLength() - 9);
+ iTableStart = Integer.parseInt(bsc.getString(), 2) << iBitsRemain;
+ } else if (bsc.getString().startsWith("000000" )) {
+ aoTable = _aoTable_000000xxxxxxxx;
+ iBitsRemain = 8 - (bsc.getLength() - 6);
+ iTableStart = Integer.parseInt(bsc.getString(), 2) << iBitsRemain;
+ } else if (bsc.getString().startsWith("0" )) {
+ aoTable = _aoTable_0xxxxxxx;
+ iBitsRemain = 8 - (bsc.getLength() - 1);
+ iTableStart = Integer.parseInt(bsc.getString(), 2) << iBitsRemain;
+ } else { // startsWith("1")
+ aoTable = _aoTable_1xx;
+ iBitsRemain = 2 - (bsc.getLength() - 1);
+ iTableStart = Integer.parseInt(bsc.getString().substring(1), 2) << iBitsRemain;
+ }
+
+ final int iTableEntriesToAssociate = (1 << iBitsRemain);
+ for (int i = 0; i < iTableEntriesToAssociate; i++) {
+ if (aoTable[iTableStart + i] != null)
+ throw new RuntimeException("Trying to replace " + aoTable[iTableStart + i] +
+ " with " + zrlac);
+ aoTable[iTableStart + i] = zrlac;
+ }
+ }
+
+ // #########################################################################
+
+ public @Nonnull Iterator iterator() {
+ return new Iterator() {
+ private int _i = 0;
+ public boolean hasNext() {
+ return _i < _aoList.length;
+ }
+
+ public @Nonnull ZeroRunLengthAc next() {
+ return _aoList[_i++];
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("List is immutable");
+ }
+ };
+ }
+
+ /** Useful bitmasks. */
+ private static final int
+ b11000000000000000 = 0x18000,
+ b10000000000000000 = 0x10000,
+ b01000000000000000 = 0x08000,
+ b00100000000000000 = 0x04000,
+ b01111100000000000 = 0x0F800,
+ b00000011100000000 = 0x00700,
+ b00000000011100000 = 0x000E0;
+
+ /** Converts bits to the equivalent {@link BitstreamToMdecLookup}.
+ * 17 bits need to be supplied to decode (the longest bit code).
+ * Bits should start at the least-significant bit.
+ * Bits beyond the 17 least-significant bits are ignored.
+ * If a full 17 bits are unavailable, fill the remaining with zeros
+ * to ensure failure if bit code is invalid.
+ *
+ * @param i17bits Integer containing 17 bits to decode.
+ */
+ public @Nonnull ZeroRunLengthAc lookup(final int i17bits) throws MdecException.ReadCorruption {
+ if ((i17bits & b10000000000000000) != 0) {
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.println("Table 0 offset " + ((i17bits >> 14) & 3));
+ return _aoTable_1xx[(i17bits >> 14) & 3];
+ } else if ((i17bits & b01111100000000000) != 0) {
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.println("Table 1 offset " + ((i17bits >> 8) & 0xff));
+ return _aoTable_0xxxxxxx[(i17bits >> 8) & 0xff];
+ } else if ((i17bits & b00000011100000000) != 0) {
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.println("Table 2 offset " + ((i17bits >> 3) & 0xff));
+ return _aoTable_000000xxxxxxxx[(i17bits >> 3) & 0xff];
+ } else if ((i17bits & b00000000011100000) != 0) {
+ assert !BitStreamDebugging.DEBUG || BitStreamDebugging.println("Table 3 offset " + (i17bits & 0xff));
+ return _aoTable_000000000xxxxxxxx[i17bits & 0xff];
+ } else {
+ throw new MdecException.ReadCorruption(UNMATCHED_AC_VLC(i17bits));
+ }
+ }
+
+ private static @Nonnull String UNMATCHED_AC_VLC(int i17bits) {
+ return "Unmatched AC variable length code: " +
+ Misc.bitsToString(i17bits, LONGEST_BITSTREAM_CODE_17BITS);
+ }
+
+ // ..................................................
+
+ /** Alternative lookup method that is slower that {@link #lookup(int)}. */
+ public @Nonnull ZeroRunLengthAc lookup_slow1(final int i17bits) throws MdecException.ReadCorruption {
+ if ((i17bits & b11000000000000000) == b10000000000000000) {
+ return _aoList[_10_______________.ordinal()];
+ } else if ((i17bits & b11000000000000000) == b11000000000000000) {
+ // special handling for first AC code
+ if ((i17bits & b00100000000000000) == 0) // check sign bit
+ return _aoList[_110______________.ordinal()];
+ else
+ return _aoList[_111______________.ordinal()];
+ } else {
+ // escape code is already set in the lookup table
+ final ZeroRunLengthAc[] array;
+ final int c;
+ if ((i17bits & b01111100000000000) != 0) {
+ array = _aoTable_0xxxxxxx;
+ c = (i17bits >> 8) & 0xff;
+ } else if ((i17bits & b00000011100000000) != 0) {
+ array = _aoTable_000000xxxxxxxx;
+ c = (i17bits >> 3) & 0xff;
+ } else if ((i17bits & b00000000011100000) != 0) {
+ array = _aoTable_000000000xxxxxxxx;
+ c = i17bits & 0xff;
+ } else {
+ throw new MdecException.ReadCorruption(UNMATCHED_AC_VLC(i17bits));
+ }
+ return array[c];
+ }
+ }
+
+ /** Alternative lookup method that is slower that {@link #lookup(int)}. */
+ public @Nonnull ZeroRunLengthAc lookup_slow2(final int i17bits) throws MdecException.ReadCorruption {
+ if ((i17bits & b11000000000000000) == b10000000000000000) {
+ return _aoList[_10_______________.ordinal()];
+ } else if ((i17bits & b11000000000000000) == b11000000000000000) {
+ // special handling for first AC code
+ if ((i17bits & b00100000000000000) == 0) // check sign bit
+ return _aoList[_110______________.ordinal()];
+ else
+ return _aoList[_111______________.ordinal()];
+ } else {
+ // escape code is already part of the lookup table
+ if ((i17bits & b01111100000000000) != 0) {
+ return _aoTable_0xxxxxxx[(i17bits >> 8) & 0xff];
+ } else if ((i17bits & b00000011100000000) != 0) {
+ return _aoTable_000000xxxxxxxx[(i17bits >> 3) & 0xff];
+ } else if ((i17bits & b00000000011100000) != 0) {
+ return _aoTable_000000000xxxxxxxx[i17bits & 0xff];
+ } else {
+ throw new MdecException.ReadCorruption(UNMATCHED_AC_VLC(i17bits));
+ }
+ }
+ }
+
+ /** Alternative lookup method that is slower that {@link #lookup(int)}. */
+ public @Nonnull ZeroRunLengthAc lookup_slow3(final int i17bits) throws MdecException.ReadCorruption {
+ if ((i17bits & b10000000000000000) != 0) { // 1st bit is 1?
+ if ((i17bits & b01000000000000000) == 0) { // initial bits == '10'?
+ return _aoList[_10_______________.ordinal()];
+ } else { // initial bits == '11'
+ // special handling for first AC code
+ // check sign bit
+ if ((i17bits & b00100000000000000) == 0) // initial bits == '110'?
+ return _aoList[_110______________.ordinal()];
+ else // initial bits == '111'
+ return _aoList[_111______________.ordinal()];
+ }
+ } else { // 1st bit is 0
+ // escape code is already set in the lookup table
+ final ZeroRunLengthAc[] array;
+ final int c;
+ if ((i17bits & b01111100000000000) != 0) {
+ array = _aoTable_0xxxxxxx;
+ c = (i17bits >> 8) & 0xff;
+ } else if ((i17bits & b00000011100000000) != 0) {
+ array = _aoTable_000000xxxxxxxx;
+ c = (i17bits >> 3) & 0xff;
+ } else if ((i17bits & b00000000011100000) != 0) {
+ array = _aoTable_000000000xxxxxxxx;
+ c = i17bits & 0xff;
+ } else {
+ throw new MdecException.ReadCorruption(UNMATCHED_AC_VLC(i17bits));
+ }
+ return array[c];
+ }
+ }
+
+ /** Bit masks for
+ * {@link #lookup_old(int)} */
+ private static final int
+ b1000000000000000_ = 0x8000 << 1,
+ b0100000000000000_ = 0x4000 << 1,
+ b0010000000000000_ = 0x2000 << 1,
+ b0001100000000000_ = 0x1800 << 1,
+ b0001000000000000_ = 0x1000 << 1,
+ b0000100000000000_ = 0x0800 << 1,
+ b0000010000000000_ = 0x0400 << 1,
+ b0000001000000000_ = 0x0200 << 1,
+ b0000000100000000_ = 0x0100 << 1,
+ b0000000010000000_ = 0x0080 << 1,
+ b0000000001000000_ = 0x0040 << 1,
+ b0000000000100000_ = 0x0020 << 1,
+ b0000000000010000_ = 0x0010 << 1;
+
+ /** This lookup approach was used in 0.96.0 and earlier. */
+ public @Nonnull ZeroRunLengthAc lookup_old(final int i17bits) throws MdecException.ReadCorruption {
+ final BitStreamCode vlc;
+
+ // Walk through the bits, one-by-one
+ // Fun fact: The Lain Playstation game uses this same decoding approach
+ if ( (i17bits & b1000000000000000_) != 0) { // "1"
+ if ((i17bits & b0100000000000000_) != 0) { // "11"
+ vlc = BitStreamCode.get(0);
+ } else { // "10"
+ // End of block
+ return _aoList[_10_______________.ordinal()];
+ }
+ } else if ((i17bits & b0100000000000000_) != 0) { // "01"
+ if ((i17bits & b0010000000000000_) != 0) { // "011"
+ vlc = BitStreamCode.get(1);
+ } else { // "010x"
+ vlc = BitStreamCode.get(2 + (int)((i17bits >>> 13) & 1));
+ }
+ } else if ((i17bits & b0010000000000000_) != 0) { // "001"
+ if ((i17bits & b0001100000000000_) != 0) { // "001xx"
+ vlc = BitStreamCode.get(3 + (int)((i17bits >>> 12) & 3));
+ } else { // "00100xxx"
+ vlc = BitStreamCode.get(15 + (int)((i17bits >>> 9) & 7));
+ }
+ } else if ((i17bits & b0001000000000000_) != 0) { // "0001xx"
+ vlc = BitStreamCode.get(7 + (int)((i17bits >>> 11) & 3));
+ } else if ((i17bits & b0000100000000000_) != 0) { // "00001xx"
+ vlc = BitStreamCode.get(11 + (int)((i17bits >>> 10) & 3));
+ } else if ((i17bits & b0000010000000000_) != 0) { // "000001"
+ // escape code
+ return _aoList[_000001___________.ordinal()];
+ } else if ((i17bits & b0000001000000000_) != 0) { // "0000001xxx"
+ vlc = BitStreamCode.get(23 + (int)((i17bits >>> 7) & 7));
+ } else if ((i17bits & b0000000100000000_) != 0) { // "00000001xxxx"
+ vlc = BitStreamCode.get(31 + (int)((i17bits >>> 5) & 15));
+ } else if ((i17bits & b0000000010000000_) != 0) { // "000000001xxxx"
+ vlc = BitStreamCode.get(47 + (int)((i17bits >>> 4) & 15));
+ } else if ((i17bits & b0000000001000000_) != 0) { // "0000000001xxxx"
+ vlc = BitStreamCode.get(63 + (int)((i17bits >>> 3) & 15));
+ } else if ((i17bits & b0000000000100000_) != 0) { // "00000000001xxxx"
+ vlc = BitStreamCode.get(79 + (int)((i17bits >>> 2) & 15));
+ } else if ((i17bits & b0000000000010000_) != 0) { // "000000000001xxxx"
+ vlc = BitStreamCode.get(95 + (int)((i17bits >>> 1) & 15));
+ } else {
+ throw new MdecException.ReadCorruption(UNMATCHED_AC_VLC(i17bits));
+ }
+
+ // Take either the positive (0) or negitive (1) AC coefficient,
+ // depending on the sign bit
+ if ((i17bits & (1 << (16 - vlc.getLength()))) == 0) {
+ // positive
+ return _aoList[vlc.ordinal()];
+ } else {
+ // negative
+ return _aoList[vlc.ordinal() + 1];
+ }
+ }
+
+ public @Nonnull ZeroRunLengthAc lookup(@Nonnull String sBits) throws IllegalArgumentException {
+ int i = Integer.parseInt(sBits, 2);
+ i <<= LONGEST_BITSTREAM_CODE_17BITS - sBits.length();
+ try {
+ return lookup(i);
+ } catch (MdecException.ReadCorruption ex) {
+ throw new IllegalArgumentException(ex);
+ }
+ }
+
+ public void printAllLookupTables(@Nonnull PrintStream ps) {
+ for (int i = 0; i < _aoTable_1xx.length; i++) {
+ ps.println("Table_1xx["+i+"] = "+_aoTable_1xx[i]);
+ }
+ for (int i = 0; i < _aoTable_0xxxxxxx.length; i++) {
+ ps.println("Table_0xxxxxxx["+i+"] = "+_aoTable_0xxxxxxx[i]);
+ }
+ for (int i = 0; i < _aoTable_000000xxxxxxxx.length; i++) {
+ ps.println("Table_000000xxxxxxxx["+i+"] = "+_aoTable_000000xxxxxxxx[i]);
+ }
+ for (int i = 0; i < _aoTable_000000000xxxxxxxx.length; i++) {
+ ps.println("Table_000000000xxxxxxxx["+i+"] = "+_aoTable_000000000xxxxxxxx[i]);
+ }
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/ZeroRunLengthAcLookup_STR.java b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/ZeroRunLengthAcLookup_STR.java
new file mode 100644
index 0000000..1be77d6
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/ZeroRunLengthAcLookup_STR.java
@@ -0,0 +1,173 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2007-2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.psxvideo.bitstreams;
+
+import jpsxdec.psxvideo.mdec.MdecCode;
+
+
+public class ZeroRunLengthAcLookup_STR {
+
+ public static final ZeroRunLengthAc ESCAPE_CODE = new ZeroRunLengthAc(BitStreamCode._000001___________, true, false);
+ public static final ZeroRunLengthAc END_OF_BLOCK = new ZeroRunLengthAc(BitStreamCode._10_______________,
+ MdecCode.MDEC_END_OF_DATA_TOP6, MdecCode.MDEC_END_OF_DATA_BOTTOM10, false, true);
+
+ /** The standard bit-stream Huffman variable length codes used in almost
+ * all PlayStation games. Conveniently identical to MPEG1. */
+ public static final ZeroRunLengthAcLookup AC_VARIABLE_LENGTH_CODES_MPEG1 = new ZeroRunLengthAcLookup.Builder()
+ // Code "Run" "Level"
+ ._11s (0 , 1)
+ ._011s (1 , 1)
+ ._0100s (0 , 2)
+ ._0101s (2 , 1)
+ ._00101s (0 , 3)
+ ._00110s (4 , 1)
+ ._00111s (3 , 1)
+ ._000100s (7 , 1)
+ ._000101s (6 , 1)
+ ._000110s (1 , 2)
+ ._000111s (5 , 1)
+ ._0000100s (2 , 2)
+ ._0000101s (9 , 1)
+ ._0000110s (0 , 4)
+ ._0000111s (8 , 1)
+ ._00100000s (13, 1)
+ ._00100001s (0 , 6)
+ ._00100010s (12, 1)
+ ._00100011s (11, 1)
+ ._00100100s (3 , 2)
+ ._00100101s (1 , 3)
+ ._00100110s (0 , 5)
+ ._00100111s (10, 1)
+ ._0000001000s (16, 1)
+ ._0000001001s (5 , 2)
+ ._0000001010s (0 , 7)
+ ._0000001011s (2 , 3)
+ ._0000001100s (1 , 4)
+ ._0000001101s (15, 1)
+ ._0000001110s (14, 1)
+ ._0000001111s (4 , 2)
+ ._000000010000s (0 , 11)
+ ._000000010001s (8 , 2)
+ ._000000010010s (4 , 3)
+ ._000000010011s (0 , 10)
+ ._000000010100s (2 , 4)
+ ._000000010101s (7 , 2)
+ ._000000010110s (21, 1)
+ ._000000010111s (20, 1)
+ ._000000011000s (0 , 9)
+ ._000000011001s (19, 1)
+ ._000000011010s (18, 1)
+ ._000000011011s (1 , 5)
+ ._000000011100s (3 , 3)
+ ._000000011101s (0 , 8)
+ ._000000011110s (6 , 2)
+ ._000000011111s (17, 1)
+ ._0000000010000s (10, 2)
+ ._0000000010001s (9 , 2)
+ ._0000000010010s (5 , 3)
+ ._0000000010011s (3 , 4)
+ ._0000000010100s (2 , 5)
+ ._0000000010101s (1 , 7)
+ ._0000000010110s (1 , 6)
+ ._0000000010111s (0 , 15)
+ ._0000000011000s (0 , 14)
+ ._0000000011001s (0 , 13)
+ ._0000000011010s (0 , 12)
+ ._0000000011011s (26, 1)
+ ._0000000011100s (25, 1)
+ ._0000000011101s (24, 1)
+ ._0000000011110s (23, 1)
+ ._0000000011111s (22, 1)
+ ._00000000010000s (0 , 31)
+ ._00000000010001s (0 , 30)
+ ._00000000010010s (0 , 29)
+ ._00000000010011s (0 , 28)
+ ._00000000010100s (0 , 27)
+ ._00000000010101s (0 , 26)
+ ._00000000010110s (0 , 25)
+ ._00000000010111s (0 , 24)
+ ._00000000011000s (0 , 23)
+ ._00000000011001s (0 , 22)
+ ._00000000011010s (0 , 21)
+ ._00000000011011s (0 , 20)
+ ._00000000011100s (0 , 19)
+ ._00000000011101s (0 , 18)
+ ._00000000011110s (0 , 17)
+ ._00000000011111s (0 , 16)
+ ._000000000010000s (0 , 40)
+ ._000000000010001s (0 , 39)
+ ._000000000010010s (0 , 38)
+ ._000000000010011s (0 , 37)
+ ._000000000010100s (0 , 36)
+ ._000000000010101s (0 , 35)
+ ._000000000010110s (0 , 34)
+ ._000000000010111s (0 , 33)
+ ._000000000011000s (0 , 32)
+ ._000000000011001s (1 , 14)
+ ._000000000011010s (1 , 13)
+ ._000000000011011s (1 , 12)
+ ._000000000011100s (1 , 11)
+ ._000000000011101s (1 , 10)
+ ._000000000011110s (1 , 9)
+ ._000000000011111s (1 , 8)
+ ._0000000000010000s(1 , 18)
+ ._0000000000010001s(1 , 17)
+ ._0000000000010010s(1 , 16)
+ ._0000000000010011s(1 , 15)
+ ._0000000000010100s(6 , 3)
+ ._0000000000010101s(16, 2)
+ ._0000000000010110s(15, 2)
+ ._0000000000010111s(14, 2)
+ ._0000000000011000s(13, 2)
+ ._0000000000011001s(12, 2)
+ ._0000000000011010s(11, 2)
+ ._0000000000011011s(31, 1)
+ ._0000000000011100s(30, 1)
+ ._0000000000011101s(29, 1)
+ ._0000000000011110s(28, 1)
+ ._0000000000011111s(27, 1)
+ .add(ESCAPE_CODE)
+ .add(END_OF_BLOCK)
+ .build();
+
+ /** Debug */
+ public static void main(String[] args) {
+ AC_VARIABLE_LENGTH_CODES_MPEG1.printAllLookupTables(System.out);
+ }
+
+}
diff --git a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/package.html b/jpsxdec/src/jpsxdec/psxvideo/bitstreams/package.html
deleted file mode 100644
index cbcc9b4..0000000
--- a/jpsxdec/src/jpsxdec/psxvideo/bitstreams/package.html
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-jPSXdec
-
-Compressed PlayStation 1 bitstream video data compression and decompression.
-
- The PlayStation 1 uses a video format similar to MPEG1 I-frames.
- The final step in the encoding process compresses the data into
- a stream of bits (a form of 'entropy' encoding).
-
-
- There are 5 known bitstream formats:
-
-
- {@link jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_STRv2}:
- Sony developed version 2.
- Used in the majority of games.
- {@link jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_STRv1}
- is nearly identical to STRv2, but has a couple interesting
- variations worth identifying.
- {@link jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_STRv3}:
- Sony developed version 3.
- Not used very much, but provides better compression, probably
- at the cost of additional processing.
- {@link jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_Iki}:
- .iki videos used by a few games.
- {@link jpsxdec.psxvideo.bitstreams.BitStreamUncompressor_Lain}:
- Used only by the Serial Experiments Lain game
-
-
-
-
\ No newline at end of file
diff --git a/jpsxdec/src/jpsxdec/psxvideo/encode/MacroBlockEncoder.java b/jpsxdec/src/jpsxdec/psxvideo/encode/MacroBlockEncoder.java
index abfca05..dfcfaf5 100644
--- a/jpsxdec/src/jpsxdec/psxvideo/encode/MacroBlockEncoder.java
+++ b/jpsxdec/src/jpsxdec/psxvideo/encode/MacroBlockEncoder.java
@@ -39,26 +39,35 @@
import java.util.ArrayList;
import java.util.Iterator;
+import javax.annotation.Nonnull;
+import jpsxdec.psxvideo.mdec.MdecCode;
import jpsxdec.psxvideo.mdec.MdecInputStream;
-import jpsxdec.psxvideo.mdec.MdecInputStream.MdecCode;
import static jpsxdec.psxvideo.mdec.MdecInputStream.REVERSE_ZIG_ZAG_LOOKUP_LIST;
import jpsxdec.psxvideo.mdec.idct.StephensIDCT;
/** Encodes a single macroblock into MDEC codes. */
-public class MacroBlockEncoder implements Iterable {
+public class MacroBlockEncoder implements Iterable {
private static final boolean DEBUG = false;
private static final int[] PSX_DEFAULT_QUANTIZATION_MATRIX =
- MdecInputStream.getDefaultPsxQuantMatrixCopy();
+ new int[MdecInputStream.PSX_DEFAULT_QUANTIZATION_MATRIX.length];
+ static {
+ System.arraycopy(MdecInputStream.PSX_DEFAULT_QUANTIZATION_MATRIX, 0,
+ PSX_DEFAULT_QUANTIZATION_MATRIX, 0,
+ MdecInputStream.PSX_DEFAULT_QUANTIZATION_MATRIX.length);
+ }
// TODO: Change to use a Forward DCT more closely resembling the PSX
private final StephensIDCT _DCT = new StephensIDCT();
private final double[][] _aadblYBlockVectors = new double[4][];
+ @Nonnull
private final double[] _adblCbBlockVector;
+ @Nonnull
private final double[] _adblCrBlockVector;
+ @Nonnull
private int[] _aiQscales, _aiSquashQscales;
public final int X, Y;
@@ -67,7 +76,7 @@ public class MacroBlockEncoder implements Iterable {
* It is calculated using my best guess as an approach. */
private double _dblEnergy = 0;
- MacroBlockEncoder(PsxYCbCrImage ycbcr, int iMacroBlockX, int iMacroBlockY) {
+ MacroBlockEncoder(@Nonnull PsxYCbCrImage ycbcr, int iMacroBlockX, int iMacroBlockY) {
X = iMacroBlockX;
Y = iMacroBlockY;
@@ -96,7 +105,7 @@ public class MacroBlockEncoder implements Iterable {
}
- private double[] preEncodeBlock(double[] adblBlock, int iBlock) {
+ private @Nonnull double[] preEncodeBlock(@Nonnull double[] adblBlock, int iBlock) {
if (DEBUG) {
System.out.println("Pre DCT");
for (int y = 0; y < 8; y++) {
@@ -139,7 +148,7 @@ private double[] preEncodeBlock(double[] adblBlock, int iBlock) {
}
- private double[] preQuantizeZigZagBlock(double[] adblBlock, int iBlock) {
+ private @Nonnull double[] preQuantizeZigZagBlock(@Nonnull double[] adblBlock, int iBlock) {
double[] adblVector = new double[8*8];
// partially quantize it
adblVector[0] = (int)Math.round(adblBlock[0]
@@ -165,22 +174,22 @@ public double getEnergy() {
return _dblEnergy;
}
- public void setToFullEncode(int[] aiQscales) {
+ public void setToFullEncode(@Nonnull int[] aiQscales) {
if (aiQscales.length != 6)
throw new IllegalArgumentException();
_aiSquashQscales = _aiQscales = aiQscales.clone();
}
- public void setToPartialEncode(int[] aiQscales, int[] aiSquashQscales) {
+ public void setToPartialEncode(@Nonnull int[] aiQscales, @Nonnull int[] aiSquashQscales) {
if (aiQscales.length != 6)
throw new IllegalArgumentException();
_aiQscales = aiQscales.clone();
_aiSquashQscales = aiSquashQscales.clone();
}
- public Iterator iterator() {
+ public @Nonnull Iterator iterator() {
if (_aiQscales == null || _aiSquashQscales == null)
throw new IllegalStateException();
- ArrayList codes = new ArrayList();
+ ArrayList codes = new ArrayList();
encodeBlock(_adblCrBlockVector, codes, _aiQscales[0], _aiSquashQscales[0]);
encodeBlock(_adblCbBlockVector, codes, _aiQscales[1], _aiSquashQscales[1]);
encodeBlock(_aadblYBlockVectors[0], codes, _aiQscales[2], _aiSquashQscales[2]);
@@ -192,11 +201,11 @@ public Iterator iterator() {
// -------------------------------------------------------------------------
- private void encodeBlock(double[] adblVector,
- ArrayList out,
+ private void encodeBlock(@Nonnull double[] adblVector,
+ @Nonnull ArrayList out,
int iQscale, int iSquashQscale)
{
- final MdecInputStream.MdecCode code = new MdecInputStream.MdecCode();
+ final MdecCode code = new MdecCode();
code.setTop6Bits(iQscale);
code.setBottom10Bits((int)Math.round(adblVector[0]));
out.add(code.copy());
diff --git a/jpsxdec/src/jpsxdec/psxvideo/encode/MdecEncoder.java b/jpsxdec/src/jpsxdec/psxvideo/encode/MdecEncoder.java
index fde1c58..fd07a0f 100644
--- a/jpsxdec/src/jpsxdec/psxvideo/encode/MdecEncoder.java
+++ b/jpsxdec/src/jpsxdec/psxvideo/encode/MdecEncoder.java
@@ -43,9 +43,9 @@
import java.util.List;
import javax.annotation.Nonnull;
import jpsxdec.psxvideo.mdec.Calc;
+import jpsxdec.psxvideo.mdec.MdecCode;
import jpsxdec.psxvideo.mdec.MdecException;
import jpsxdec.psxvideo.mdec.MdecInputStream;
-import jpsxdec.psxvideo.mdec.MdecInputStream.MdecCode;
/** Encodes a {@link PsxYCbCrImage} into an {@link MdecInputStream}.
* After encoding, the MdecInputStream will most likely be then
@@ -59,6 +59,7 @@ public class MdecEncoder implements Iterable {
private final int _iMacBlockHeight;
/** Used for full frame replace. */
+ @SuppressWarnings("unchecked")
public MdecEncoder(@Nonnull PsxYCbCrImage ycbcr, int iWidth, int iHeight) {
if (ycbcr.getLumaWidth() % 16 != 0 || ycbcr.getLumaHeight() % 16 != 0)
@@ -82,9 +83,10 @@ public MdecEncoder(@Nonnull PsxYCbCrImage ycbcr, int iWidth, int iHeight) {
}
/** Used for partial replace. */
+ @SuppressWarnings("unchecked")
public MdecEncoder(@Nonnull ParsedMdecImage original,
@Nonnull PsxYCbCrImage newYcbcr,
- @Nonnull List replaceMbs)
+ @Nonnull List macroBlocksToReplace)
{
if (newYcbcr.getLumaWidth() % 16 != 0 || newYcbcr.getLumaHeight() % 16 != 0)
@@ -102,7 +104,7 @@ public MdecEncoder(@Nonnull ParsedMdecImage original,
for (int iMbY = 0; iMbY < _iMacBlockHeight; iMbY++) {
p.setLocation(iMbX, iMbY);
Iterable enc;
- if (replaceMbs.contains(p)) {
+ if (macroBlocksToReplace.contains(p)) {
MacroBlockEncoder e = new MacroBlockEncoder(newYcbcr, iMbX, iMbY);
_replaceMbs.add(e);
enc = e;
@@ -144,7 +146,7 @@ public int getPixelHeight() {
return _iPixHeight;
}
- private class EncodedMdecInputStream extends MdecInputStream {
+ private class EncodedMdecInputStream implements MdecInputStream {
private int __iCurMacBlk = 0;
private Iterator __curMb;
@@ -161,7 +163,7 @@ public boolean readMdecCode(@Nonnull MdecCode code) throws MdecException.EndOfSt
__iCurMacBlk++;
__curMb = _aoMacroBlocks[__iCurMacBlk].iterator();
}
- code.set(__curMb.next());
+ code.setFrom(__curMb.next());
return code.isEOD(); // hopefully no bad EOD codes are part of the list
}
diff --git a/jpsxdec/src/jpsxdec/psxvideo/encode/ParsedMdecImage.java b/jpsxdec/src/jpsxdec/psxvideo/encode/ParsedMdecImage.java
index e59ceef..64f9653 100644
--- a/jpsxdec/src/jpsxdec/psxvideo/encode/ParsedMdecImage.java
+++ b/jpsxdec/src/jpsxdec/psxvideo/encode/ParsedMdecImage.java
@@ -46,9 +46,10 @@
import javax.annotation.Nonnull;
import jpsxdec.psxvideo.bitstreams.BitStreamUncompressor;
import jpsxdec.psxvideo.mdec.Calc;
+import jpsxdec.psxvideo.mdec.MdecBlock;
+import jpsxdec.psxvideo.mdec.MdecCode;
import jpsxdec.psxvideo.mdec.MdecException;
import jpsxdec.psxvideo.mdec.MdecInputStream;
-import jpsxdec.psxvideo.mdec.MdecInputStream.MdecCode;
/** Parses and stores a stream of MDEC 16-bit codes in a structure for easier analysis. */
public class ParsedMdecImage {
@@ -56,13 +57,13 @@ public class ParsedMdecImage {
private static final Logger LOG = Logger.getLogger(ParsedMdecImage.class.getName());
private static class MacroBlock implements Iterable {
- public final Block[] _aoBlocks = new Block[6];
+ public final Block[] _aoBlocks = new Block[MdecBlock.count()];
public MacroBlock(@Nonnull MdecInputStream mdecIn)
throws MdecException.EndOfStream, MdecException.ReadCorruption
{
- for (int iBlock = 0; iBlock < 6; iBlock++) {
- _aoBlocks[iBlock] = new Block(iBlock, mdecIn);
+ for (MdecBlock block : MdecBlock.list()) {
+ _aoBlocks[block.ordinal()] = new Block(block, mdecIn);
}
}
@@ -92,7 +93,7 @@ public ArrayList getCodes() {
private int _iBlk = 0;
public boolean hasNext() {
- return _iBlk < 6;
+ return _iBlk < MdecBlock.count();
}
public @Nonnull Block next() {
@@ -110,22 +111,17 @@ public void remove() {
private static class Block {
- private static final String[] BLOCK_NAMES = {
- "Cr", "Cb", "Y1", "Y2", "Y3", "Y4"
- };
-
- private final int _iIndex;
+ @Nonnull
+ private final MdecBlock _block;
@Nonnull
private final MdecCode[] _aoCodes;
/** Only available if source data was a bitstream. -1 if unknown. */
private final int _iBitSize;
- public Block(int iIndex, @Nonnull MdecInputStream mdecIn)
+ public Block(@Nonnull MdecBlock block, @Nonnull MdecInputStream mdecIn)
throws MdecException.EndOfStream, MdecException.ReadCorruption
{
- if (iIndex < 0 || iIndex >= 6)
- throw new IllegalArgumentException("Invalid block index " + iIndex);
- _iIndex = iIndex;
+ _block = block;
ArrayList codes = new ArrayList();
int iBitStart = -1;
@@ -147,10 +143,6 @@ public Block(int iIndex, @Nonnull MdecInputStream mdecIn)
_iBitSize = ((BitStreamUncompressor)mdecIn).getBitPosition() - iBitStart;
}
- public @Nonnull String getName() {
- return BLOCK_NAMES[_iIndex];
- }
-
public @Nonnull MdecCode getMdecCode(int i) {
return _aoCodes[i];
}
@@ -159,18 +151,6 @@ public int getMdecCodeCount() {
return _aoCodes.length;
}
- public boolean isChroma() {
- return _iIndex < 2;
- }
-
- public boolean isLuma() {
- return _iIndex >= 2;
- }
-
- public int getIndex() {
- return _iIndex;
- }
-
public int getQscale() {
return _aoCodes[0].getTop6Bits();
}
@@ -190,7 +170,7 @@ public int getBitSize() {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append(getName()).append(" Q:").append(getQscale());
+ sb.append(_block.name()).append(" Q:").append(getQscale());
if (_iBitSize != -1)
sb.append(" Size=").append(_iBitSize);
return sb.toString();
@@ -199,7 +179,7 @@ public String toString() {
}
- private class MdecReader extends MdecInputStream {
+ private class MdecReader implements MdecInputStream {
// TODO: convert to use iterator?
private int __iCurrentMacroBlock;
@@ -222,7 +202,7 @@ public boolean readMdecCode(@Nonnull MdecCode code) throws MdecException.EndOfSt
Block currentBlk = currentMacBlk.getBlock(__iCurrentBlock);
MdecCode c = currentBlk.getMdecCode(__iCurrentMdecCode);
- code.set(c);
+ code.setFrom(c);
__iCurrentMdecCode++;
diff --git a/jpsxdec/src/jpsxdec/psxvideo/mdec/Ac0Cleaner.java b/jpsxdec/src/jpsxdec/psxvideo/mdec/Ac0Checker.java
similarity index 58%
rename from jpsxdec/src/jpsxdec/psxvideo/mdec/Ac0Cleaner.java
rename to jpsxdec/src/jpsxdec/psxvideo/mdec/Ac0Checker.java
index 12fea8e..10c964e 100644
--- a/jpsxdec/src/jpsxdec/psxvideo/mdec/Ac0Cleaner.java
+++ b/jpsxdec/src/jpsxdec/psxvideo/mdec/Ac0Checker.java
@@ -1,97 +1,124 @@
-/*
- * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
- * Copyright (C) 2015-2019 Michael Sabin
- * All rights reserved.
- *
- * Redistribution and use of the jPSXdec code or any derivative works are
- * permitted provided that the following conditions are met:
- *
- * * Redistributions may not be sold, nor may they be used in commercial
- * or revenue-generating business activities.
- *
- * * Redistributions that are modified from the original source must
- * include the complete source code, including the source code for all
- * components used by a binary built from the modified sources. However, as
- * a special exception, the source code distributed need not include
- * anything that is normally distributed (in either source or binary form)
- * with the major components (compiler, kernel, and so on) of the operating
- * system on which the executable runs, unless that component itself
- * accompanies the executable.
- *
- * * Redistributions must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or
- * other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package jpsxdec.psxvideo.mdec;
-
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/** Filters out MDEC codes where AC=0.
- * Known to happen in FF7 and Judge Dredd videos, but could happen anywhere.
- * MDEC codes where AC=0 are redundant and just waste space.
- * This will merge those codes with adjacent codes by extending zero-run-length.
- */
-public class Ac0Cleaner extends MdecInputStream {
-
- private static final Logger LOG = Logger.getLogger(Ac0Cleaner.class.getName());
-
- private final MdecInputStream _source;
- private boolean _blnNextCodeIsQscaleDC = true;
-
- public Ac0Cleaner(MdecInputStream source) {
- _source = source;
- }
-
- @Override
- public boolean readMdecCode(MdecCode code)
- throws MdecException.EndOfStream, MdecException.ReadCorruption
- {
- boolean blnEod = _source.readMdecCode(code);
-
- if (_blnNextCodeIsQscaleDC) {
- _blnNextCodeIsQscaleDC = false;
- if (blnEod) // there's something very strange going on if this happens
- LOG.log(Level.WARNING, "(qscale,DC) code says is EOD");
- return blnEod;
- }
-
- if (blnEod) {
- _blnNextCodeIsQscaleDC = true;
- return true;
- }
-
- if (code.getBottom10Bits() == 0) {
- LOG.log(Level.INFO, "Found AC=0 code {0}", code);
- final MdecCode nextCode = new MdecCode();
- do {
- blnEod = _source.readMdecCode(nextCode);
- if (blnEod) {
- LOG.log(Level.INFO, "Discarding merge {0} at EOD", code);
- code.set(nextCode);
- _blnNextCodeIsQscaleDC = true;
- return true;
- }
- code.setTop6Bits(code.getTop6Bits() + nextCode.getTop6Bits() + 1);
- code.setBottom10Bits(nextCode.getBottom10Bits());
- LOG.log(Level.INFO, "Merged code {0} into prev AC=0 code to form {1}",
- new Object[] {nextCode, code});
- } while (code.getBottom10Bits() == 0);
- }
- return false;
- }
-
-}
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2015-2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.psxvideo.mdec;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.annotation.Nonnull;
+
+/** Filters out MDEC codes where AC=0.
+ * Known to happen in FF7 and Judge Dredd videos, but could happen anywhere.
+ * MDEC codes where AC=0 are redundant and just waste space.
+ * This will merge those codes with adjacent codes by extending zero-run-length.
+ */
+public class Ac0Checker implements MdecInputStream {
+
+ private static final Logger LOG = Logger.getLogger(Ac0Checker.class.getName());
+
+ public static Ac0Checker wrapWithChecker(@Nonnull MdecInputStream source, boolean blnAlsoClean) {
+ if (source instanceof Ac0Checker)
+ return (Ac0Checker)source;
+ else
+ return new Ac0Checker(source, blnAlsoClean);
+ }
+
+ private final MdecInputStream _source;
+ private final boolean _blnAlsoClean;
+
+ private boolean _blnNextCodeIsQscaleDC = true;
+ private int _iEscapeCodeAc0Count = 0;
+
+ public Ac0Checker(MdecInputStream source, boolean blnAlsoClean) {
+ _source = source;
+ _blnAlsoClean = blnAlsoClean;
+ }
+
+ final public int get0AcCoefficientCount() {
+ return _iEscapeCodeAc0Count;
+ }
+
+ final public void logIfAny0AcCoefficient() {
+ if (_iEscapeCodeAc0Count > 0) {
+ LOG.log(Level.INFO, "Frame had {0} codes 0 AC coefficient", _iEscapeCodeAc0Count);
+ }
+ }
+
+ @Override
+ public boolean readMdecCode(MdecCode code)
+ throws MdecException.EndOfStream, MdecException.ReadCorruption
+ {
+ boolean blnEod = _source.readMdecCode(code);
+
+ if (_blnNextCodeIsQscaleDC) {
+ _blnNextCodeIsQscaleDC = false;
+ if (blnEod) // there's something very strange going on if this happens
+ LOG.log(Level.WARNING, "(qscale,DC) code says it's EOD");
+ } else if (blnEod) {
+ _blnNextCodeIsQscaleDC = true;
+ } else if (code.getBottom10Bits() == 0) {
+ _iEscapeCodeAc0Count++;
+ LOG.log(Level.FINE, "Found AC=0 code {0}", code);
+ if (_blnAlsoClean)
+ blnEod = filter0(code);
+ }
+ return blnEod;
+ }
+
+ private boolean filter0(MdecCode code)
+ throws MdecException.EndOfStream, MdecException.ReadCorruption
+ {
+ boolean blnEod;
+ final MdecCode nextCode = new MdecCode();
+ do {
+ blnEod = _source.readMdecCode(nextCode);
+ if (blnEod) {
+ LOG.log(Level.FINE, "Discarding merge {0} at EOD", code);
+ code.setFrom(nextCode);
+ _blnNextCodeIsQscaleDC = true;
+ break;
+ }
+ code.setTop6Bits(code.getTop6Bits() + nextCode.getTop6Bits() + 1);
+ code.setBottom10Bits(nextCode.getBottom10Bits());
+ LOG.log(Level.FINE, "Merged code {0} into prev AC=0 code to form {1}",
+ new Object[] {nextCode, code});
+ } while (code.getBottom10Bits() == 0);
+
+ return blnEod;
+ }
+
+}
diff --git a/jpsxdec/src/jpsxdec/psxvideo/mdec/Calc.java b/jpsxdec/src/jpsxdec/psxvideo/mdec/Calc.java
index bf6d181..2fc8dae 100644
--- a/jpsxdec/src/jpsxdec/psxvideo/mdec/Calc.java
+++ b/jpsxdec/src/jpsxdec/psxvideo/mdec/Calc.java
@@ -42,7 +42,7 @@ public class Calc {
/** Number of blocks necessary to store pixel size. */
public static int blocks(int iPixelWidth, int iPixelHeight) {
- return macroblocks(iPixelWidth, iPixelHeight) * 6;
+ return macroblocks(iPixelWidth, iPixelHeight) * MdecBlock.count();
}
/** Number of macroblocks necessary to store pixel size. */
public static int macroblocks(int iPixelWidth, int iPixelHeight) {
@@ -59,4 +59,12 @@ public static int macroblockDim(int iPixelDimension) {
return (iPixelDimension + 15) / 16;
}
+ /** A strange value needed for video bitstreams and video sector headers.
+ * It's the number of MDEC codes, divided by two, then rounded up to the
+ * next closest multiple of 32 (if not already a multiple of 32).
+ * In other words, its the number of 32-byte blocks it would take to hold
+ * the MDEC codes. */
+ public static short calculateHalfCeiling32(int iMdecCodeCount) {
+ return (short) ((((iMdecCodeCount + 1) / 2) + 31) & ~31);
+ }
}
diff --git a/jpsxdec/src/jpsxdec/psxvideo/mdec/ChromaUpsample.java b/jpsxdec/src/jpsxdec/psxvideo/mdec/ChromaUpsample.java
new file mode 100644
index 0000000..41c77e9
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/psxvideo/mdec/ChromaUpsample.java
@@ -0,0 +1,122 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2007-2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.psxvideo.mdec;
+
+import com.mortennobel.imagescaling.ResampleFilter;
+import com.mortennobel.imagescaling.ResampleFilters;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import jpsxdec.i18n.I;
+import jpsxdec.i18n.ILocalizedMessage;
+
+public enum ChromaUpsample {
+ /** i.e. Box */
+ NearestNeighbor(I.CHROMA_UPSAMPLE_NEAR_NEIGHBOR_DESCRIPTION(),
+ I.CHROMA_UPSAMPLE_NEAR_NEIGHBOR_CMDLINE(), null),
+
+ /** i.e. Triangle */
+ Bilinear(I.CHROMA_UPSAMPLE_BILINEAR_DESCRIPTION(),
+ I.CHROMA_UPSAMPLE_BILINEAR_CMDLINE(), null),
+
+ Bicubic(I.CHROMA_UPSAMPLE_BICUBIC_DESCRIPTION(),
+ I.CHROMA_UPSAMPLE_BICUBIC_CMDLINE(), ResampleFilters.getBiCubicFilter()),
+
+ Bell(I.CHROMA_UPSAMPLE_BELL_DESCRIPTION(),
+ I.CHROMA_UPSAMPLE_BELL_CMDLINE(), ResampleFilters.getBellFilter()),
+
+ Mitchell(I.CHROMA_UPSAMPLE_MITCHELL_DESCRIPTION(),
+ I.CHROMA_UPSAMPLE_MITCHELL_CMDLINE(), ResampleFilters.getMitchellFilter()),
+
+ BSpline(I.CHROMA_UPSAMPLE_BSPLINE_DESCRIPTION(),
+ I.CHROMA_UPSAMPLE_BSPLINE_CMDLINE(), ResampleFilters.getBSplineFilter()),
+
+ Lanczos3(I.CHROMA_UPSAMPLE_LANCZOS3_DESCRIPTION(),
+ I.CHROMA_UPSAMPLE_LANCZOS3_CMDLINE(), ResampleFilters.getLanczos3Filter()),
+
+ Hermite(I.CHROMA_UPSAMPLE_HERMITE_DESCRIPTION(),
+ I.CHROMA_UPSAMPLE_HERMITE_CMDLINE(), ResampleFilters.getHermiteFilter());
+
+ @Nonnull
+ private final ILocalizedMessage _description;
+ private final ILocalizedMessage _cmdLine;
+ @CheckForNull
+ final ResampleFilter _filter;
+
+ private ChromaUpsample(@Nonnull ILocalizedMessage description,
+ @Nonnull ILocalizedMessage cmdLine,
+ @CheckForNull ResampleFilter filter)
+ {
+ _description = description;
+ _cmdLine = cmdLine;
+ _filter = filter;
+ }
+
+ public static ChromaUpsample fromCmdLine(String sCmdLine) {
+ ChromaUpsample up = null;
+ for (ChromaUpsample upsampler : values()) {
+ if (upsampler.getCmdLine().equalsIgnoreCase(sCmdLine)) {
+ up = upsampler;
+ break;
+ }
+ }
+ return up;
+ }
+
+ public ILocalizedMessage getDescription() {
+ return _description;
+ }
+
+ public ILocalizedMessage getCmdLine() {
+ return _cmdLine;
+ }
+
+ public ILocalizedMessage getCmdLineHelp() {
+ if (_cmdLine.equals(_description))
+ return _cmdLine;
+ else
+ return I.CHROMA_UPSAMPLE_CMDLINE_HELP(_cmdLine, _description);
+ }
+
+ /** {@inheritDoc}
+ *
+ * Used in GUI list so must be localized. */
+ @Override
+ public String toString() {
+ return getDescription().getLocalizedMessage();
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/psxvideo/mdec/MdecBlock.java b/jpsxdec/src/jpsxdec/psxvideo/mdec/MdecBlock.java
new file mode 100644
index 0000000..43c0e6d
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/psxvideo/mdec/MdecBlock.java
@@ -0,0 +1,100 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.psxvideo.mdec;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.Nonnull;
+
+
+/** Macro-block sub blocks, listed in the order accepted by the MDEC chip. */
+public enum MdecBlock {
+ Cr(true),
+ Cb(true),
+ Y1(false),
+ Y2(false),
+ Y3(false),
+ Y4(false);
+
+ private final boolean _blnIsChroma;
+ private MdecBlock _nextBlock;
+
+ private MdecBlock(boolean blnIsChroma) {
+ _blnIsChroma = blnIsChroma;
+ }
+
+ public boolean isChroma() {
+ return _blnIsChroma;
+ }
+
+ public boolean isLuma() {
+ return !_blnIsChroma;
+ }
+
+ /** Never returns null, loops from the last block to the first. */
+ public @Nonnull MdecBlock next() {
+ return _nextBlock;
+ }
+
+ // -------------------------------------------------------------------------
+
+ private static final List VALUES =
+ Collections.unmodifiableList(Arrays.asList(values()));
+
+ static {
+ Cr._nextBlock = Cb;
+ Cb._nextBlock = Y1;
+ Y1._nextBlock = Y2;
+ Y2._nextBlock = Y3;
+ Y3._nextBlock = Y4;
+ Y4._nextBlock = Cr;
+ }
+
+ public static @Nonnull List list() {
+ return VALUES;
+ }
+
+ public static int count() {
+ return VALUES.size();
+ }
+
+ public static @Nonnull MdecBlock first() {
+ return Cr;
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/psxvideo/mdec/MdecCode.java b/jpsxdec/src/jpsxdec/psxvideo/mdec/MdecCode.java
new file mode 100644
index 0000000..b3f003e
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/psxvideo/mdec/MdecCode.java
@@ -0,0 +1,215 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2007-2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.psxvideo.mdec;
+
+import javax.annotation.Nonnull;
+import jpsxdec.util.Misc;
+
+
+/** Represents a 16-bit code readable by the PlayStation MDEC chip.
+ * If the MDEC code is the first of a block, the top 6 bits indicate
+ * the block's quantization scale, and the bottom 10 bits indicate
+ * the "direct current" (DC) coefficient.
+ * If the MDEC code is not the first of a block, and it is
+ * not a {@link #MDEC_END_OF_DATA} code (0xFE00), then the top 6 bits indicate
+ * the number of zeros preceeding an "alternating current" (AC) coefficient,
+ * with the bottom 10 bits indicating a (usually) non-zero AC coefficient. */
+public class MdecCode implements Comparable {
+
+ /** 16-bit MDEC code indicating the end of a block.
+ * The equivalent MDEC value is (63, -512). */
+ public final static int MDEC_END_OF_DATA = 0xFE00;
+ /** Top 6 bits of {@link #MDEC_END_OF_DATA}. */
+ public final static int MDEC_END_OF_DATA_TOP6 = (MDEC_END_OF_DATA >> 10) & 63;
+ /** Bottom 10 bits of {@link #MDEC_END_OF_DATA}. */
+ public final static int MDEC_END_OF_DATA_BOTTOM10 = (short)(MDEC_END_OF_DATA | 0xFC00);
+
+ /** Most significant 6 bits of the 16-bit MDEC code.
+ * Holds either a block's quantization scale or the
+ * count of zero AC coefficients leading up to a non-zero
+ * AC coefficient. */
+ private int _iTop6Bits;
+
+ /** Least significant 10 bits of the 16-bit MDEC code.
+ * Holds either the DC coefficient of a block or
+ * a non-zero AC coefficient. */
+ private int _iBottom10Bits;
+
+ /** Initializes to (0, 0). */
+ public MdecCode() {
+ _iTop6Bits = 0;
+ _iBottom10Bits = 0;
+ }
+
+ public MdecCode(int iTop6Bits, int iBottom10Bits) {
+ if (!validTop(iTop6Bits))
+ throw new IllegalArgumentException("Invalid top 6 bits " + iTop6Bits);
+ if (!validBottom(iBottom10Bits))
+ throw new IllegalArgumentException("Invalid bottom 10 bits " + iBottom10Bits);
+ _iTop6Bits = iTop6Bits;
+ _iBottom10Bits = iBottom10Bits;
+ }
+
+ /** Extract the top 6 bit and bottom 10 bit values from 16 bits */
+ public MdecCode(int iMdecWord) {
+ set(iMdecWord);
+ }
+
+ public void setFrom(@Nonnull MdecCode other) {
+ _iTop6Bits = other._iTop6Bits;
+ _iBottom10Bits = other._iBottom10Bits;
+ }
+
+ public int getBottom10Bits() {
+ return _iBottom10Bits;
+ }
+
+ /** By default does not verify the value for performance. */
+ public void setBottom10Bits(int iBottom10Bits) {
+ assert validBottom(iBottom10Bits);
+ _iBottom10Bits = iBottom10Bits;
+ }
+
+ public int getTop6Bits() {
+ return _iTop6Bits;
+ }
+
+ /** By default does not verify the value for performance. */
+ public void setTop6Bits(int iTop6Bits) {
+ assert validTop(iTop6Bits);
+ _iTop6Bits = iTop6Bits;
+ }
+
+ /** By default does not verify the values for performance. */
+ public void setBits(int iTop6, int iBottom10) {
+ assert validTop(_iTop6Bits) && validBottom(_iBottom10Bits);
+ _iTop6Bits = iTop6;
+ _iBottom10Bits = iBottom10;
+ }
+
+ public void set(int iMdecWord) {
+ _iTop6Bits = ((iMdecWord >> 10) & 63);
+ _iBottom10Bits = (iMdecWord & 0x3FF);
+ if ((_iBottom10Bits & 0x200) == 0x200) { // is it negitive?
+ _iBottom10Bits -= 0x400;
+ }
+ }
+
+ /** Combines the top 6 bits and bottom 10 bits into an unsigned 16 bit value. */
+ public int toMdecWord() {
+ if (isEOD())
+ return MDEC_END_OF_DATA;
+ if (!validTop(_iTop6Bits))
+ throw new IllegalStateException("MDEC code has invalid top 6 bits " + _iTop6Bits);
+ if (!validBottom(_iBottom10Bits))
+ throw new IllegalStateException("MDEC code has invalid bottom 10 bits " + _iBottom10Bits);
+ return ((_iTop6Bits & 63) << 10) | (_iBottom10Bits & 0x3FF);
+ }
+
+ /** Set the MDEC code to the special "End of Data" (EOD) value,
+ * indicating the end of a block.
+ * @see MdecInputStream#MDEC_END_OF_DATA */
+ public @Nonnull MdecCode setToEndOfData() {
+ _iTop6Bits = MDEC_END_OF_DATA_TOP6;
+ _iBottom10Bits = MDEC_END_OF_DATA_BOTTOM10;
+ return this;
+ }
+
+ /** Returns if this MDEC code is setFrom to the special "End of Data" (EOD)
+ value.
+ * @see MdecInputStream#MDEC_END_OF_DATA */
+ public boolean isEOD() {
+ return (_iTop6Bits == MDEC_END_OF_DATA_TOP6 &&
+ _iBottom10Bits == MDEC_END_OF_DATA_BOTTOM10);
+ }
+
+ /** Returns if this MDEC code has valid values.
+ * As an optimization, many parameter checks are disabled, so
+ * this MDEC code could hold values that are be invalid. */
+ public boolean isValid() {
+ return validTop(_iTop6Bits) && validBottom(_iBottom10Bits);
+ }
+
+ /** Checks if the top 6 bits of an MDEC code are valid. */
+ private static boolean validTop(int iTop6Bits) {
+ return iTop6Bits >= 0 && iTop6Bits <= 63;
+ }
+ /** Checks if the bottom 10 bits of an MDEC code are valid. */
+ private static boolean validBottom(int iBottom10Bits) {
+ return iBottom10Bits >= -512 && iBottom10Bits <= 511;
+ }
+
+ public @Nonnull MdecCode copy() {
+ return new MdecCode(_iTop6Bits, _iBottom10Bits);
+ }
+
+ @Override
+ public String toString() {
+ String s = String.format("%04x (%d, %d)", toMdecWord(), _iTop6Bits, _iBottom10Bits);
+ if (isEOD())
+ return s + " EOD";
+ else
+ return s;
+ }
+
+ public int compareTo(MdecCode o) {
+ int i = Misc.intCompare(_iTop6Bits, o._iTop6Bits);
+ if (i != 0)
+ return i;
+ return Misc.intCompare(_iBottom10Bits, o._iBottom10Bits);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final MdecCode other = (MdecCode) obj;
+ return _iTop6Bits == other._iTop6Bits &&
+ _iBottom10Bits == other._iBottom10Bits;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 5;
+ hash = 97 * hash + _iTop6Bits;
+ hash = 97 * hash + _iBottom10Bits;
+ return hash;
+ }
+
+}
diff --git a/jpsxdec/src/jpsxdec/psxvideo/mdec/MdecContext.java b/jpsxdec/src/jpsxdec/psxvideo/mdec/MdecContext.java
new file mode 100644
index 0000000..3685c96
--- /dev/null
+++ b/jpsxdec/src/jpsxdec/psxvideo/mdec/MdecContext.java
@@ -0,0 +1,164 @@
+/*
+ * jPSXdec: PlayStation 1 Media Decoder/Converter in Java
+ * Copyright (C) 2019 Michael Sabin
+ * All rights reserved.
+ *
+ * Redistribution and use of the jPSXdec code or any derivative works are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions may not be sold, nor may they be used in commercial
+ * or revenue-generating business activities.
+ *
+ * * Redistributions that are modified from the original source must
+ * include the complete source code, including the source code for all
+ * components used by a binary built from the modified sources. However, as
+ * a special exception, the source code distributed need not include
+ * anything that is normally distributed (in either source or binary form)
+ * with the major components (compiler, kernel, and so on) of the operating
+ * system on which the executable runs, unless that component itself
+ * accompanies the executable.
+ *
+ * * Redistributions must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jpsxdec.psxvideo.mdec;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/** Tracks MDEC codes, blocks, macro-blocks, and coordinates during
+ * the decoding process. One-time use. */
+public class MdecContext {
+
+ private static final Logger LOG = Logger.getLogger(MdecContext.class.getName());
+
+ private int _iCurrentMacroBlock = 0;
+ @Nonnull
+ private MdecBlock _currentBlock = MdecBlock.first();
+ private int _iCurrentMdecCodeInCurrentBlock = 0;
+
+ private int _iCurrentTotalBlocks = 0;
+ private int _iCurrentTotalMdecCode = 0;
+
+ @CheckForNull
+ private final Integer _oiMacroBlockHeight;
+
+ /** By providing the height of the frame, it allows tracking of what pixel
+ * x/y is being decoded. */
+ public MdecContext(int iFrameMacroBlockHeight) {
+ _oiMacroBlockHeight = Integer.valueOf(iFrameMacroBlockHeight);
+ }
+
+ public MdecContext() {
+ _oiMacroBlockHeight = null;
+ }
+
+ public int getTotalMacroBlocksRead() {
+ return _iCurrentMacroBlock;
+ }
+
+ /** Total number of sub-blocks that have been read thus far. */
+ public int getTotalBlocksRead() {
+ return _iCurrentTotalBlocks;
+ }
+
+ /** Total number of MDEC codes that have been read thus far. */
+ public int getTotalMdecCodesRead() {
+ return _iCurrentTotalMdecCode;
+ }
+
+ public @Nonnull MdecBlock getCurrentBlock() {
+ return _currentBlock;
+ }
+
+ public int getMdecCodesReadInCurrentBlock() {
+ return _iCurrentMdecCodeInCurrentBlock;
+ }
+
+ /** Indicates if the next read should be the Quantization Scale and DC Coefficient. */
+ public boolean atStartOfBlock() {
+ return _iCurrentMdecCodeInCurrentBlock == 0;
+ }
+
+ /** Increments the number of MDEC codes that have been read. */
+ public void nextCode() {
+ _iCurrentTotalMdecCode++;
+ _iCurrentMdecCodeInCurrentBlock++;
+ if (_iCurrentMdecCodeInCurrentBlock > 64)
+ LOG.log(Level.WARNING, "Impossible number of codes in a block {0}", _iCurrentMdecCodeInCurrentBlock);
+ }
+
+ /** Increments the number of MDEC codes that have been read and end the block. */
+ public void nextCodeEndBlock() {
+ _iCurrentTotalMdecCode++;
+ _iCurrentMdecCodeInCurrentBlock = 0;
+ _iCurrentTotalBlocks++;
+ _currentBlock = _currentBlock.next();
+ if (_currentBlock == MdecBlock.first())
+ _iCurrentMacroBlock++;
+ }
+
+ public @Nonnull MdecContext copy() {
+ MdecContext c = new MdecContext();
+ c._iCurrentMacroBlock = _iCurrentMacroBlock;
+ c._currentBlock = _currentBlock;
+ c._iCurrentMdecCodeInCurrentBlock = _iCurrentMdecCodeInCurrentBlock;
+ c._iCurrentTotalBlocks = _iCurrentTotalBlocks;
+ c._iCurrentTotalMdecCode = _iCurrentTotalMdecCode;
+ return c;
+ }
+
+ /** The pixel of the top-left corner of a macro-block. */
+ public static class MacroBlockPixel {
+ public final int x;
+ public final int y;
+
+ private MacroBlockPixel(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ @Override
+ public String toString() {
+ return "(" + x + ", " + y + ")";
+ }
+ }
+
+ /** Returns null if no dimensions were specified in constructor. */
+ public @CheckForNull MacroBlockPixel getMacroBlockPixel() {
+ if (_oiMacroBlockHeight == null)
+ return null;
+ int iMacroBlockHeight = _oiMacroBlockHeight.intValue();
+ return new MacroBlockPixel((_iCurrentMacroBlock / iMacroBlockHeight) * 16, (_iCurrentMacroBlock % iMacroBlockHeight) * 16);
+ }
+
+ @Override
+ public String toString() {
+ String s = String.format("Macro.block.code %d.%s(%d).%d total blocks %d codes %d",
+ _iCurrentMacroBlock, _currentBlock, _currentBlock.ordinal(),
+ _iCurrentMdecCodeInCurrentBlock,
+ _iCurrentTotalBlocks,
+ _iCurrentTotalMdecCode);
+ MacroBlockPixel pixel = getMacroBlockPixel();
+ if (pixel == null)
+ return s;
+ else
+ return s + " " + pixel;
+ }
+}
diff --git a/jpsxdec/src/jpsxdec/psxvideo/mdec/MdecDecoder.java b/jpsxdec/src/jpsxdec/psxvideo/mdec/MdecDecoder.java
index d0c32cc..7174372 100644
--- a/jpsxdec/src/jpsxdec/psxvideo/mdec/MdecDecoder.java
+++ b/jpsxdec/src/jpsxdec/psxvideo/mdec/MdecDecoder.java
@@ -38,25 +38,23 @@
package jpsxdec.psxvideo.mdec;
import java.util.Arrays;
+import javax.annotation.Nonnull;
/** Super class of the two different MDEC decoders: int and double. */
public abstract class MdecDecoder {
public static boolean DEBUG = false;
- protected static final String[] BLOCK_NAMES = {
- "Cr", "Cb", "Y1", "Y2", "Y3", "Y4"
- };
-
protected static boolean debugPrintln(String s) {
System.out.println(s);
return true;
}
- protected final MdecInputStream.MdecCode _code = new MdecInputStream.MdecCode();
+ protected final MdecCode _code = new MdecCode();
- protected final int _iMacBlockWidth;
+ private final int _iMacBlockWidth;
protected final int _iMacBlockHeight;
+ protected final int _iTotalMacBlocks;
/** Luma dimensions. */
protected final int W, H;
@@ -66,14 +64,19 @@ protected static boolean debugPrintln(String s) {
protected final int[] _aiLumaBlkOfsLookup;
protected final int[] _aiChromaMacBlkOfsLookup;
- protected final int[] _aiQuantizationTable =
- MdecInputStream.getDefaultPsxQuantMatrixCopy();
+ protected final int[] _aiQuantizationTable =
+ new int[MdecInputStream.PSX_DEFAULT_QUANTIZATION_MATRIX.length];
protected final int[] _aiDebugPreqantBlock;
protected MdecDecoder(int iWidth, int iHeight) {
+ System.arraycopy(MdecInputStream.PSX_DEFAULT_QUANTIZATION_MATRIX, 0,
+ _aiQuantizationTable, 0,
+ MdecInputStream.PSX_DEFAULT_QUANTIZATION_MATRIX.length);
+
_iMacBlockWidth = Calc.macroblockDim(iWidth);
_iMacBlockHeight = Calc.macroblockDim(iHeight);
+ _iTotalMacBlocks = _iMacBlockWidth * _iMacBlockHeight;
W = _iMacBlockWidth * 16;
H = _iMacBlockHeight * 16;
CW = _iMacBlockWidth * 8;
@@ -100,10 +103,10 @@ protected MdecDecoder(int iWidth, int iHeight) {
}
}
- boolean blnAssert = false;
- assert blnAssert = true;
+ boolean blnAssertsEnabled = false;
+ assert blnAssertsEnabled = true;
- if (blnAssert && DEBUG)
+ if (blnAssertsEnabled && DEBUG)
_aiDebugPreqantBlock = new int[64];
else
_aiDebugPreqantBlock = null;
@@ -134,18 +137,18 @@ protected boolean debugPrintPrequantBlock() {
/** Reads an image from the MdecInputStream and decodes it to an internal
* PSX YCbCr buffer. */
- abstract public void decode(MdecInputStream mdecStream)
+ abstract public void decode(@Nonnull MdecInputStream mdecStream)
throws MdecException.EndOfStream, MdecException.ReadCorruption;
/** Retrieve the contents of the internal PSX YCbCr buffer converted to RGB. */
- abstract public void readDecodedRgb(int iDestWidth, int iDestHeight, int[] aiDest,
+ abstract public void readDecodedRgb(int iDestWidth, int iDestHeight, @Nonnull int[] aiDest,
int iOutStart, int iOutStride);
- public void readDecodedRgb(int iDestWidth, int iDestHeight, int[] aiDest) {
+ public void readDecodedRgb(int iDestWidth, int iDestHeight, @Nonnull int[] aiDest) {
readDecodedRgb(iDestWidth, iDestHeight, aiDest, 0, iDestWidth);
}
- public void setQuantizationTable(int[] aiNewTable) {
+ public void setQuantizationTable(@Nonnull int[] aiNewTable) {
if (aiNewTable.length != _aiQuantizationTable.length)
throw new IllegalArgumentException("Incorrect table size");
System.arraycopy(aiNewTable, 0, _aiQuantizationTable, 0, _aiQuantizationTable.length);
diff --git a/jpsxdec/src/jpsxdec/psxvideo/mdec/MdecDecoder_double.java b/jpsxdec/src/jpsxdec/psxvideo/mdec/MdecDecoder_double.java
index da00a4b..6d6c9e5 100644
--- a/jpsxdec/src/jpsxdec/psxvideo/mdec/MdecDecoder_double.java
+++ b/jpsxdec/src/jpsxdec/psxvideo/mdec/MdecDecoder_double.java
@@ -37,7 +37,9 @@
package jpsxdec.psxvideo.mdec;
+import com.mortennobel.imagescaling.ResampleOp;
import java.util.Arrays;
+import javax.annotation.Nonnull;
import jpsxdec.formats.RGB;
import jpsxdec.formats.Rec601YCbCr;
import jpsxdec.formats.YCbCrImage;
@@ -45,131 +47,156 @@
import jpsxdec.psxvideo.mdec.idct.IDCT_double;
/** A full Java, double-precision, floating point implementation of the
- * PlayStation 1 MDEC chip. This implementation also comes with additional
- * methods for higher quality YUV decoding. */
+ * PlayStation 1 MDEC chip with interpolation used in chroma upsampling.
+ * |