Skip to content

Commit

Permalink
v1.03 rev3953 (15 Dec 2019)
Browse files Browse the repository at this point in the history
Bug fixes:
- Some videos in EA games are still not detected
  • Loading branch information
m35 committed Dec 15, 2019
1 parent e1ba2bb commit afbc4ea
Show file tree
Hide file tree
Showing 10 changed files with 152 additions and 110 deletions.
28 changes: 14 additions & 14 deletions jpsxdec/PSXListOFGames.txt
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ Status
[ ] SLUS-01172 Frogger 2 - Swampy's Revenge
[ ] SLUS-01011 Front Mission 3
[ ] SLUS-90034 Future Cop - L.A.P.D. [Demo]
[ ] SLUS-00739 Future Cop L.A.P.D.
[+] SLUS-00739 Future Cop L.A.P.D.
[ ] SLUS-80690 G Darius, Devil Dice, Brunswick Circuit Bowling (Trade) [Demo]
[ ] SLUS-01258 Galaga - Destination Earth
[ ] SLUS-90077 Galerians [Demo]
Expand Down Expand Up @@ -791,7 +791,7 @@ Status
[ ] SLUS-01306 M & M's Shell Shocked
[ ] SLUS-00383 Machine Head
[ ] SLUS-00470 Machine Hunter
[ ] SLUS-00961 Madden NFL 2000
[+] SLUS-00961 Madden NFL 2000
[ ] SLUS-01241 Madden NFL 2001
[ ] SLUS-01402 Madden NFL 2002
[ ] SLUS-01482 Madden NFL 2003
Expand Down Expand Up @@ -915,19 +915,19 @@ Status
[ ] SLUS-00416 Namco Museum Vol.4
[ ] SLUS-00417 Namco Museum Vol.5
[ ] SLUS-00325 Nanotek Warrior
[ ] SLUS-00962 NASCAR 2000
[ ] SLUS-01263 NASCAR 2001
[ ] SLUS-00521 NASCAR '98
[ ] SLUS-00647 NASCAR '98 - Collector's Edition
[ ] SLUS-00740 NASCAR '99
[ ] SLUS-00883 NASCAR '99 Legacy
[+] SLUS-00962 NASCAR 2000
[+] SLUS-01263 NASCAR 2001
[+] SLUS-00521 NASCAR '98
[+] SLUS-00647 NASCAR '98 - Collector's Edition
[+] SLUS-00740 NASCAR '99
[+] SLUS-00883 NASCAR '99 Legacy
[ ] SLUS-01166 NASCAR Heat
[ ] SLUS-01050 NASCAR Racers
[ ] SLUS-00374 NASCAR Racing
[+] SLUS-01068 NASCAR Rumble
[ ] SLUS-01403 NASCAR Thunder 2002
[ ] SLUS-01502 NASCAR Thunder 2003
[ ] SLUS-01571 NASCAR Thunder 2004
[+] SLUS-01403 NASCAR Thunder 2002
[+] SLUS-01502 NASCAR Thunder 2003
[+] SLUS-01571 NASCAR Thunder 2004
[ ] SLUS-00926 NBA Basketball 2000
[ ] SLUS-00492 NBA Fastbreak '98
[ ] SLUS-00329 NBA Hangtime
Expand Down Expand Up @@ -1315,7 +1315,7 @@ Status
[ ] SLUS-00565 Riven - The Sequel to Myst [Disc4of5]
[ ] SLUS-00580 Riven - The Sequel to Myst [Disc5of5]
[ ] SLUS-00035 Road Rash
[ ] SLUS-01053 Road Rash - Jailbreak
[+] SLUS-01053 Road Rash - Jailbreak
[+] SLUS-00524 Road Rash 3D
[ ] SLUS-01024 Roadsters
[ ] SLUS-00316 Robo-Pit
Expand Down Expand Up @@ -1489,8 +1489,8 @@ Status
[o] SLUS-00418 Super Puzzle Fighter II Turbo
[ ] SLUS-01464 Super Shot Soccer
[ ] SLUS-01052 Superbikes 2000
[ ] SLUS-01005 SuperCross 2000
[ ] SLUS-01319 SuperCross 2001
[+] SLUS-01005 SuperCross 2000
[+] SLUS-01319 SuperCross 2001
[ ] SCUS-94453 SuperCross Circuit
[ ] SCUS-94396 Supercross Circuit [Demo]
[ ] SLUS-00712 Superman
Expand Down
2 changes: 1 addition & 1 deletion jpsxdec/build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<!-- ====== global build properties ====== -->

<property name="jpsxdec.ver" value="v1-02_rev3950"/>
<property name="jpsxdec.ver" value="v1-03_rev3953"/>

<!-- sources -->
<property name="src.dir.rel" location="src" relative="true"/>
Expand Down
3 changes: 3 additions & 0 deletions jpsxdec/doc/CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
v1.03 rev3953 (15 Dec 2019)
Bug fixes:
- Some videos in EA games are still not detected
v1.02 rev3950 (13 Dec 2019)
- Added support for Jackie Chan Stuntmaster videos
Bug fixes:
Expand Down
2 changes: 1 addition & 1 deletion jpsxdec/src/jpsxdec/Version.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

public class Version {

public final static String Version = "1.02 (beta)";
public final static String Version = "1.03 (beta)";
public final static String IndexHeader = "[jPSXdec v"+Version+"]";

}
9 changes: 7 additions & 2 deletions jpsxdec/src/jpsxdec/modules/eavideo/DiscIndexerEAVideo.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public MovieBuilder(int iStartSector) {
_iEndSector = iStartSector;
}

public void addPacket(@Nonnull EAVideoPacketSectors packet, int iStartSector) throws BinaryDataNotRecognized {
public void addPacket(@Nonnull EAVideoPacketSectors packet) throws BinaryDataNotRecognized {
_iEndSector = packet.iEndSector;
if (packet.packet instanceof EAVideoPacket.AU) {
EAVideoPacket.AU au = (EAVideoPacket.AU)packet.packet;
Expand Down Expand Up @@ -170,7 +170,12 @@ public void feedPacket(@Nonnull EAVideoPacketSectors packet, @Nonnull ILocalized
}
_movieBuilder = new MovieBuilder(packet.iStartSector);
} else {
_movieBuilder.addPacket(packet, 0);
if (packet.packet instanceof EAVideoPacket.VLC0) {
endVideo(log);
_movieBuilder = new MovieBuilder(packet.iStartSector);
} else {
_movieBuilder.addPacket(packet);
}
}
} catch (BinaryDataNotRecognized ex) {
LOG.log(Level.SEVERE, "EA video data corruption", ex);
Expand Down
146 changes: 76 additions & 70 deletions jpsxdec/src/jpsxdec/modules/eavideo/EAVideoPacket.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,10 @@

/**
* Support for videos found in several Electronic Arts games.
* Most of the time videos are found in files with .WVE extention.
* Known games:
* - Road Rash 3D
* - PlayStation Magazine Demo Disc 14
* - NASCAR Rumble
* - Madden 99
* It takes a unique approach to bitstreams, every movie has its own unique VLC table.
* There's a lot of big-endian data in here.
* Many of the videos are found in files with .WVE extention.
* Many of the EA Sports titles use this video format.
*
* It takes a unique approach to bitstreams: every movie has its own unique VLC table.
*/
public abstract class EAVideoPacket {

Expand All @@ -78,7 +74,7 @@ public abstract class EAVideoPacket {
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) // assert
if (SAMPLE_FRAMES_PER_SECOND % 150 != 0) // assert sanity check
throw new RuntimeException("EA video sample rate doesn't cleanly divide by sector rate");
}

Expand All @@ -93,59 +89,53 @@ public abstract class EAVideoPacket {
/** 10 minutes. */
private static final int MAX_PRESENTATION_SAMPLE_FRAME = SAMPLE_FRAMES_PER_SECOND * 60 * 10;
/** 10 minutes. */
private static final int MAX_FRAME_NUMBER = FRAMES_PER_SECOND * 60* 10;
private static final int MAX_FRAME_NUMBER = FRAMES_PER_SECOND * 60 * 10;
private static final int MIN_FRAME_DIMENSIONS = 16;
private static final int MAX_FRAME_DIMENSIONS = 640;

// Every packet begins with one of these magic values (big-endian)
public static final long MAGIC_VLC0 = 0x564c4330;
private static final long MAGIC_MDEC = 0x4d444543;
private static final long MAGIC_au00 = 0x61753030;
private static final long MAGIC_au01 = 0x61753031;

public static final AudioFormat EA_VIDEO_AUDIO_FORMAT = new AudioFormat(SAMPLE_FRAMES_PER_SECOND, 16, 2, true, false);
public static @Nonnull Type readHeaderType(@Nonnull InputStream is)
throws EOFException, IOException, BinaryDataNotRecognized
{
long lngPacketType = IO.readUInt32BE(is);
if (lngPacketType == MAGIC_au00)
return Type.au00;
if (lngPacketType == MAGIC_au01)
return Type.au01;
if (lngPacketType == MAGIC_MDEC)
return Type.MDEC;
if (lngPacketType == 0)
return Type.ZEROES;
if (lngPacketType == MAGIC_VLC0)
return Type.VLC0;
throw new BinaryDataNotRecognized("Unknown packet type %08x", lngPacketType);
}

public static enum Type {
VLC0,
MDEC,
au00,
au01,
ZEROES; // basically means there's no more data

private static int _iMinPacketSize = Integer.MAX_VALUE;
private static int _iMaxPacketSize = 0;
public static final int SIZEOF = 4;

public static class Header {
public static final int SIZEOF = 8;
public int bytesNeededToFinishHeader() {
return 4;
}

public static Header read(@Nonnull InputStream is)
throws EOFException, IOException, BinaryDataNotRecognized
{
return read(is, true);
public @Nonnull Header readHeader(@Nonnull InputStream is) throws EOFException, IOException, BinaryDataNotRecognized {
return doReadHeader(is, true);
}

private static Header read(@Nonnull InputStream is, boolean blnThrowEx)
private @CheckForNull Header doReadHeader(@Nonnull InputStream is, boolean blnThrowEx)
throws EOFException, IOException, BinaryDataNotRecognized
{
long lngPacketType = IO.readUInt32BE(is);

// check for all zeroes, will mean the end
if (lngPacketType == 0) {
int iHeaderPacketSize = IO.readSInt32BE(is);
if (iHeaderPacketSize != 0) {
if (blnThrowEx)
throw new BinaryDataNotRecognized("0 packet type with non zero header %08x", iHeaderPacketSize);
else
return null;
}

return new Header(0, 0);
}

if (lngPacketType != MAGIC_VLC0 &&
lngPacketType != MAGIC_au00 &&
lngPacketType != MAGIC_au01 &&
lngPacketType != MAGIC_MDEC)
{
if (blnThrowEx)
throw new BinaryDataNotRecognized("Unknown packet type %08x", lngPacketType);
else
return null;
}

int iHeaderPacketSize = IO.readSInt32BE(is);
if (iHeaderPacketSize % 4 != 0) {
if (blnThrowEx)
Expand All @@ -165,48 +155,53 @@ private static Header read(@Nonnull InputStream is, boolean blnThrowEx)
if (iHeaderPacketSize > _iMaxPacketSize)
_iMaxPacketSize = iHeaderPacketSize;

return new Header(lngPacketType, iHeaderPacketSize);
return new Header(this, iHeaderPacketSize);
}
}

public static final AudioFormat EA_VIDEO_AUDIO_FORMAT = new AudioFormat(SAMPLE_FRAMES_PER_SECOND, 16, 2, true, false);

private static int _iMinPacketSize = Integer.MAX_VALUE;
private static int _iMaxPacketSize = 0;

public static class Header {

private final long _lngPacketType; // @0 4 bytes (BE)
@Nonnull
private final Type _packetType; // @0 4 bytes BE
private final int _iHeaderPacketSize; // @4 4 bytes BE

private Header(long lngPacketType, int iHeaderPacketSize) {
_lngPacketType = lngPacketType;
private Header(@Nonnull Type type, int iHeaderPacketSize) {
_packetType = type;
_iHeaderPacketSize = iHeaderPacketSize;
}

public long getPacketType() {
return _lngPacketType;
public @Nonnull Type getPacketType() {
return _packetType;
}

public int getPayloadSize() {
return _iHeaderPacketSize - 8;
}

public boolean isEndPacket() {
return _iHeaderPacketSize == 0;
}

public @Nonnull EAVideoPacket readPacket(@Nonnull InputStream is)
throws EOFException, IOException, BinaryDataNotRecognized
{
if (_lngPacketType == MAGIC_au00 || _lngPacketType == MAGIC_au01) {
if (_packetType == Type.au00 || _packetType == Type.au01) {
return new AU(this, is);
}
if (_lngPacketType == MAGIC_MDEC) {
if (_packetType == Type.MDEC) {
return new MDEC(this, is);
}
if (_lngPacketType == MAGIC_VLC0) {
if (_packetType == Type.VLC0) {
return VLC0.read(this, is, true);
}

throw new BinaryDataNotRecognized("Trying to read not a packet " + this);
throw new RuntimeException("?");
}

@Override
public String toString() {
return String.format("Header %08x size %d", _lngPacketType, _iHeaderPacketSize);
return String.format("Header %s size %d", _packetType, _iHeaderPacketSize);
}
}

Expand All @@ -220,8 +215,8 @@ private EAVideoPacket(@Nonnull Header header) {
_header = header;
}

public long getPacketType() {
return _header._lngPacketType;
public @Nonnull Type getPacketType() {
return _header._packetType;
}

public int getPacketSizeInHeader() {
Expand All @@ -234,7 +229,11 @@ public int getPacketSizeInHeader() {
public static @CheckForNull VLC0 readVlc0(@Nonnull InputStream is) throws EOFException, IOException {

try {
Header header = Header.read(is, false);
Type type = readHeaderType(is);
if (type != Type.VLC0)
return null;

Header header = type.doReadHeader(is, false);
if (header == null)
return null;

Expand All @@ -251,7 +250,10 @@ public int getPacketSizeInHeader() {
*/
public static class VLC0 extends EAVideoPacket {

public static final int SIZEOF = Header.SIZEOF + EA_VIDEO_BIT_CODE_ORDER.length * 2;
// 4 bytes for packet type
// + 4 bytes for packet size
// + size of VLC table (should always be the same)
public static final int SIZEOF = Type.SIZEOF + 4 + EA_VIDEO_BIT_CODE_ORDER.length * 2;

private static VLC0 read(@Nonnull Header header, @Nonnull InputStream is, boolean blnThrowEx)
throws BinaryDataNotRecognized, EOFException, IOException
Expand Down Expand Up @@ -324,6 +326,7 @@ public void printCodes() {
public String toString() {
return "VLC0";
}

}

// #########################################################################
Expand Down Expand Up @@ -367,11 +370,13 @@ public AU(@Nonnull Header header, @Nonnull InputStream is)
if (i512 != 512)
throw new BinaryDataNotRecognized("%d != 512", i512);

// -8 for header magic + header size
// -8 for 2048 and 512
_abCompressedSpu = IO.readByteArray(is, header._iHeaderPacketSize - 8 - 8);
}

public boolean isLastAudioPacket() {
return getPacketType() == MAGIC_au01;
return getPacketType() == Type.au01;
}

public int calcSampleFramesGenerated() {
Expand All @@ -398,7 +403,7 @@ public int getSpuSoundUnitPairCount() {
}
}

if (out.size() != calcSampleFramesGenerated() * 4)
if (out.size() != calcSampleFramesGenerated() * 4) // sanity check
throw new RuntimeException();

Fraction presentationSector = new Fraction(_iPresentationSampleFrame, SAMPLE_FRAMES_PER_SECTOR);
Expand All @@ -408,8 +413,8 @@ public int getSpuSoundUnitPairCount() {

@Override
public String toString() {
return String.format("au0%c start sample frame:%d sample frames:%d",
isLastAudioPacket() ? '1' : '0',
return String.format("%s start sample frame:%d sample frames:%d",
getPacketType().name(),
_iPresentationSampleFrame, calcSampleFramesGenerated());
}

Expand All @@ -434,6 +439,7 @@ public String toString() {
// Maybe the leftover 2 bytes in some audio packets?
// Maybe the timestamp?
// More debugging is nedded
// In any case, it's not necessary for just decoding the audio
abSpuSoundUnit[1] = 0;
System.arraycopy(abPayload, iBytesUsed+1, abSpuSoundUnit, 2, 14);
units.add(new SpuAdpcmSoundUnit(abSpuSoundUnit));
Expand Down Expand Up @@ -527,7 +533,7 @@ public int getQuantizationScale() {
return _strHeader.getQuantizationScale();
}

public byte[] getBitstream() {
public @Nonnull byte[] getBitstream() {
return _abBitstream;
}

Expand Down
Loading

0 comments on commit afbc4ea

Please sign in to comment.