mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Detect VideoNow Color offset.
This commit is contained in:
@@ -857,7 +857,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
|||||||
false, false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None,
|
false, false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None,
|
||||||
MmcSubchannel.None, _dev.Timeout, out _);
|
MmcSubchannel.None, _dev.Timeout, out _);
|
||||||
|
|
||||||
if(sense || !_dev.Error)
|
if(sense || _dev.Error)
|
||||||
{
|
{
|
||||||
videoNowColorFrame = null;
|
videoNowColorFrame = null;
|
||||||
|
|
||||||
@@ -1323,153 +1323,188 @@ namespace DiscImageChef.Core.Devices.Dumping
|
|||||||
// Check offset
|
// Check offset
|
||||||
if(_fixOffset)
|
if(_fixOffset)
|
||||||
{
|
{
|
||||||
// TODO: VideoNow
|
if(dskType != MediaType.VideoNowColor)
|
||||||
|
|
||||||
if(tracks.All(t => t.TrackType != TrackType.Audio))
|
|
||||||
{
|
{
|
||||||
// No audio tracks so no need to fix offset
|
if(tracks.All(t => t.TrackType != TrackType.Audio))
|
||||||
_dumpLog.WriteLine("No audio tracks, disabling offset fix.");
|
|
||||||
UpdateStatus?.Invoke("No audio tracks, disabling offset fix.");
|
|
||||||
|
|
||||||
_fixOffset = false;
|
|
||||||
}
|
|
||||||
else if(!readcd)
|
|
||||||
{
|
|
||||||
_dumpLog.WriteLine("READ CD command is not supported, disabling offset fix. Dump may not be correct.");
|
|
||||||
|
|
||||||
UpdateStatus?.
|
|
||||||
Invoke("READ CD command is not supported, disabling offset fix. Dump may not be correct.");
|
|
||||||
|
|
||||||
_fixOffset = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool offsetFound = false;
|
|
||||||
|
|
||||||
if(tracks.Any(t => t.TrackType != TrackType.Audio))
|
|
||||||
{
|
{
|
||||||
Track dataTrack = tracks.FirstOrDefault(t => t.TrackType != TrackType.Audio);
|
// No audio tracks so no need to fix offset
|
||||||
|
_dumpLog.WriteLine("No audio tracks, disabling offset fix.");
|
||||||
|
UpdateStatus?.Invoke("No audio tracks, disabling offset fix.");
|
||||||
|
|
||||||
if(dataTrack.TrackSequence != 0)
|
_fixOffset = false;
|
||||||
{
|
|
||||||
dataTrack.TrackEndSector += 149;
|
|
||||||
|
|
||||||
// Calculate MSF
|
|
||||||
ulong minute = dataTrack.TrackEndSector / 4500;
|
|
||||||
ulong second = (dataTrack.TrackEndSector - (minute * 4500)) / 75;
|
|
||||||
ulong frame = dataTrack.TrackEndSector - (minute * 4500) - (second * 75);
|
|
||||||
|
|
||||||
dataTrack.TrackEndSector -= 149;
|
|
||||||
|
|
||||||
// Convert to BCD
|
|
||||||
ulong remainder = minute % 10;
|
|
||||||
minute = ((minute / 10) * 16) + remainder;
|
|
||||||
remainder = second % 10;
|
|
||||||
second = ((second / 10) * 16) + remainder;
|
|
||||||
remainder = frame % 10;
|
|
||||||
frame = ((frame / 10) * 16) + remainder;
|
|
||||||
|
|
||||||
// Build sync
|
|
||||||
byte[] sectorSync =
|
|
||||||
{
|
|
||||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, (byte)minute,
|
|
||||||
(byte)second, (byte)frame
|
|
||||||
};
|
|
||||||
|
|
||||||
tmpBuf = new byte[sectorSync.Length];
|
|
||||||
|
|
||||||
// Plextor READ CDDA
|
|
||||||
if(dbDev?.ATAPI?.RemovableMedias?.Any(d => d.SupportsPlextorReadCDDA == true) == true ||
|
|
||||||
dbDev?.SCSI?.RemovableMedias?.Any(d => d.SupportsPlextorReadCDDA == true) == true ||
|
|
||||||
_dev.Manufacturer.ToLowerInvariant() == "plextor")
|
|
||||||
{
|
|
||||||
sense = _dev.PlextorReadCdDa(out cmdBuf, out senseBuf,
|
|
||||||
(uint)dataTrack.TrackEndSector - 2, sectorSize, 3,
|
|
||||||
PlextorSubchannel.None, _dev.Timeout, out _);
|
|
||||||
|
|
||||||
if(!sense &&
|
|
||||||
!_dev.Error)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < cmdBuf.Length - sectorSync.Length; i++)
|
|
||||||
{
|
|
||||||
Array.Copy(cmdBuf, i, tmpBuf, 0, sectorSync.Length);
|
|
||||||
|
|
||||||
if(!tmpBuf.SequenceEqual(sectorSync))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
offsetBytes = i - 2352;
|
|
||||||
offsetFound = true;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_debug ||
|
|
||||||
dbDev?.ATAPI?.RemovableMedias?.Any(d => d.CanReadCdScrambled == true) == true ||
|
|
||||||
dbDev?.SCSI?.RemovableMedias?.Any(d => d.CanReadCdScrambled == true) == true ||
|
|
||||||
_dev.Manufacturer.ToLowerInvariant() == "hl-dt-st")
|
|
||||||
{
|
|
||||||
sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)(dataTrack.TrackEndSector - 2),
|
|
||||||
sectorSize, 3, MmcSectorTypes.Cdda, false, false, false,
|
|
||||||
MmcHeaderCodes.None, true, false, MmcErrorField.None,
|
|
||||||
MmcSubchannel.None, _dev.Timeout, out _);
|
|
||||||
|
|
||||||
if(!sense &&
|
|
||||||
!_dev.Error)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < cmdBuf.Length - sectorSync.Length; i++)
|
|
||||||
{
|
|
||||||
Array.Copy(cmdBuf, i, tmpBuf, 0, sectorSync.Length);
|
|
||||||
|
|
||||||
if(!tmpBuf.SequenceEqual(sectorSync))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
offsetBytes = i - 2352;
|
|
||||||
offsetFound = true;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if(!readcd)
|
||||||
if(cdOffset is null)
|
|
||||||
{
|
{
|
||||||
if(offsetFound)
|
_dumpLog.
|
||||||
{
|
WriteLine("READ CD command is not supported, disabling offset fix. Dump may not be correct.");
|
||||||
_dumpLog.WriteLine($"Combined disc and drive offsets are {offsetBytes} bytes");
|
|
||||||
UpdateStatus?.Invoke($"Combined disc and drive offsets are {offsetBytes} bytes");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_dumpLog.
|
|
||||||
WriteLine("Drive read offset is unknown, disabling offset fix. Dump may not be correct.");
|
|
||||||
|
|
||||||
UpdateStatus?.
|
UpdateStatus?.
|
||||||
Invoke("Drive read offset is unknown, disabling offset fix. Dump may not be correct.");
|
Invoke("READ CD command is not supported, disabling offset fix. Dump may not be correct.");
|
||||||
|
|
||||||
_fixOffset = false;
|
_fixOffset = false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(offsetFound)
|
bool offsetFound = false;
|
||||||
|
|
||||||
|
if(tracks.Any(t => t.TrackType != TrackType.Audio))
|
||||||
{
|
{
|
||||||
_dumpLog.WriteLine($"Disc offsets is {offsetBytes - (cdOffset.Offset * 2 * -1)}");
|
Track dataTrack = tracks.FirstOrDefault(t => t.TrackType != TrackType.Audio);
|
||||||
UpdateStatus?.Invoke($"Disc offsets is {offsetBytes - (cdOffset.Offset * 2 * -1)}");
|
|
||||||
|
if(dataTrack.TrackSequence != 0)
|
||||||
|
{
|
||||||
|
dataTrack.TrackEndSector += 149;
|
||||||
|
|
||||||
|
// Calculate MSF
|
||||||
|
ulong minute = dataTrack.TrackEndSector / 4500;
|
||||||
|
ulong second = (dataTrack.TrackEndSector - (minute * 4500)) / 75;
|
||||||
|
ulong frame = dataTrack.TrackEndSector - (minute * 4500) - (second * 75);
|
||||||
|
|
||||||
|
dataTrack.TrackEndSector -= 149;
|
||||||
|
|
||||||
|
// Convert to BCD
|
||||||
|
ulong remainder = minute % 10;
|
||||||
|
minute = ((minute / 10) * 16) + remainder;
|
||||||
|
remainder = second % 10;
|
||||||
|
second = ((second / 10) * 16) + remainder;
|
||||||
|
remainder = frame % 10;
|
||||||
|
frame = ((frame / 10) * 16) + remainder;
|
||||||
|
|
||||||
|
// Build sync
|
||||||
|
byte[] sectorSync =
|
||||||
|
{
|
||||||
|
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
|
||||||
|
(byte)minute, (byte)second, (byte)frame
|
||||||
|
};
|
||||||
|
|
||||||
|
tmpBuf = new byte[sectorSync.Length];
|
||||||
|
|
||||||
|
// Plextor READ CDDA
|
||||||
|
if(dbDev?.ATAPI?.RemovableMedias?.Any(d => d.SupportsPlextorReadCDDA == true) == true ||
|
||||||
|
dbDev?.SCSI?.RemovableMedias?.Any(d => d.SupportsPlextorReadCDDA == true) == true ||
|
||||||
|
_dev.Manufacturer.ToLowerInvariant() ==
|
||||||
|
"plextor")
|
||||||
|
{
|
||||||
|
sense = _dev.PlextorReadCdDa(out cmdBuf, out senseBuf,
|
||||||
|
(uint)dataTrack.TrackEndSector - 2, sectorSize, 3,
|
||||||
|
PlextorSubchannel.None, _dev.Timeout, out _);
|
||||||
|
|
||||||
|
if(!sense &&
|
||||||
|
!_dev.Error)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < cmdBuf.Length - sectorSync.Length; i++)
|
||||||
|
{
|
||||||
|
Array.Copy(cmdBuf, i, tmpBuf, 0, sectorSync.Length);
|
||||||
|
|
||||||
|
if(!tmpBuf.SequenceEqual(sectorSync))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
offsetBytes = i - 2352;
|
||||||
|
offsetFound = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_debug ||
|
||||||
|
dbDev?.ATAPI?.RemovableMedias?.Any(d => d.CanReadCdScrambled == true) == true ||
|
||||||
|
dbDev?.SCSI?.RemovableMedias?.Any(d => d.CanReadCdScrambled == true) == true ||
|
||||||
|
_dev.Manufacturer.ToLowerInvariant() == "hl-dt-st")
|
||||||
|
{
|
||||||
|
sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)(dataTrack.TrackEndSector - 2),
|
||||||
|
sectorSize, 3, MmcSectorTypes.Cdda, false, false, false,
|
||||||
|
MmcHeaderCodes.None, true, false, MmcErrorField.None,
|
||||||
|
MmcSubchannel.None, _dev.Timeout, out _);
|
||||||
|
|
||||||
|
if(!sense &&
|
||||||
|
!_dev.Error)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < cmdBuf.Length - sectorSync.Length; i++)
|
||||||
|
{
|
||||||
|
Array.Copy(cmdBuf, i, tmpBuf, 0, sectorSync.Length);
|
||||||
|
|
||||||
|
if(!tmpBuf.SequenceEqual(sectorSync))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
offsetBytes = i - 2352;
|
||||||
|
offsetFound = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cdOffset is null)
|
||||||
|
{
|
||||||
|
if(offsetFound)
|
||||||
|
{
|
||||||
|
_dumpLog.WriteLine($"Combined disc and drive offsets are {offsetBytes} bytes");
|
||||||
|
UpdateStatus?.Invoke($"Combined disc and drive offsets are {offsetBytes} bytes");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_dumpLog.
|
||||||
|
WriteLine("Drive read offset is unknown, disabling offset fix. Dump may not be correct.");
|
||||||
|
|
||||||
|
UpdateStatus?.
|
||||||
|
Invoke("Drive read offset is unknown, disabling offset fix. Dump may not be correct.");
|
||||||
|
|
||||||
|
_fixOffset = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_dumpLog.WriteLine("Disc write offset is unknown, dump may not be correct.");
|
if(offsetFound)
|
||||||
UpdateStatus?.Invoke("Disc write offset is unknown, dump may not be correct.");
|
{
|
||||||
|
_dumpLog.WriteLine($"Disc offsets is {offsetBytes - (cdOffset.Offset * 2 * -1)}");
|
||||||
|
UpdateStatus?.Invoke($"Disc offsets is {offsetBytes - (cdOffset.Offset * 2 * -1)}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_dumpLog.WriteLine("Disc write offset is unknown, dump may not be correct.");
|
||||||
|
UpdateStatus?.Invoke("Disc write offset is unknown, dump may not be correct.");
|
||||||
|
|
||||||
offsetBytes = cdOffset.Offset * 2 * -1;
|
offsetBytes = cdOffset.Offset * 2 * -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dumpLog.WriteLine($"Offset is {offsetBytes} bytes.");
|
||||||
|
UpdateStatus?.Invoke($"Offset is {offsetBytes} bytes.");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
byte[] videoNowColorFrame = new byte[9 * sectorSize];
|
||||||
|
|
||||||
_dumpLog.WriteLine($"Offset is {offsetBytes} bytes.");
|
sense = _dev.ReadCd(out cmdBuf, out senseBuf, 0, sectorSize, 9, MmcSectorTypes.AllTypes, false,
|
||||||
UpdateStatus?.Invoke($"Offset is {offsetBytes} bytes.");
|
false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
|
||||||
|
MmcSubchannel.None, _dev.Timeout, out _);
|
||||||
|
|
||||||
|
if(sense || _dev.Error)
|
||||||
|
{
|
||||||
|
sense = _dev.ReadCd(out cmdBuf, out senseBuf, 0, sectorSize, 9, MmcSectorTypes.Cdda, false,
|
||||||
|
false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None,
|
||||||
|
MmcSubchannel.None, _dev.Timeout, out _);
|
||||||
|
|
||||||
|
if(sense || _dev.Error)
|
||||||
|
{
|
||||||
|
videoNowColorFrame = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(videoNowColorFrame is null)
|
||||||
|
{
|
||||||
|
_dumpLog.WriteLine("Could not find VideoNow Color frame offset, dump may not be correct.");
|
||||||
|
UpdateStatus?.Invoke("Could not find VideoNow Color frame offset, dump may not be correct.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
offsetBytes = MMC.GetVideoNowColorOffset(videoNowColorFrame);
|
||||||
|
_dumpLog.WriteLine($"VideoNow Color frame is offset {offsetBytes} bytes.");
|
||||||
|
UpdateStatus?.Invoke($"VideoNow Color frame is offset {offsetBytes} bytes.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,79 +37,112 @@ namespace DiscImageChef.Core.Media.Detection
|
|||||||
{
|
{
|
||||||
public static class MMC
|
public static class MMC
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>This is some kind of header. Every 10 bytes there's an audio byte.</summary>
|
||||||
/// This is some kind of header. Every 10 bytes there's an audio byte.
|
|
||||||
/// </summary>
|
|
||||||
static readonly byte[] VideoNowColorFrameMarker =
|
static readonly byte[] VideoNowColorFrameMarker =
|
||||||
{
|
{
|
||||||
0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81,
|
0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3,
|
||||||
0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7,
|
0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81,
|
||||||
0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81,
|
0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7,
|
||||||
0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3,
|
0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3,
|
||||||
0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7,
|
0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00,
|
||||||
0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3,
|
0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3,
|
||||||
0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7,
|
0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81,
|
||||||
0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81,
|
0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7,
|
||||||
0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3,
|
0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3,
|
||||||
0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00,
|
0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00,
|
||||||
0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81,
|
0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3,
|
||||||
0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7,
|
0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81,
|
||||||
0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81,
|
0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7,
|
||||||
0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x81, 0xE3, 0xE3, 0xC7, 0xC7, 0x81, 0x81, 0xE3,
|
0xC7, 0x81, 0x81, 0xE3, 0xC7, 0x00, 0x00, 0x00, 0x02, 0x01, 0x04, 0x02, 0x06, 0x03, 0xFF, 0x00, 0x08, 0x04,
|
||||||
0xC7, 0x00, 0x00, 0x00, 0x02, 0x01, 0x04, 0x02, 0x06, 0x03, 0xFF, 0x00, 0x08, 0x04, 0x0A, 0x05, 0x0C,
|
0x0A, 0x05, 0x0C, 0x06, 0x0E, 0x07, 0xFF, 0x00, 0x11, 0x08, 0x13, 0x09, 0x15, 0x0A, 0x17, 0x0B, 0xFF, 0x00,
|
||||||
0x06, 0x0E, 0x07, 0xFF, 0x00, 0x11, 0x08, 0x13, 0x09, 0x15, 0x0A, 0x17, 0x0B, 0xFF, 0x00, 0x19, 0x0C,
|
0x19, 0x0C, 0x1B, 0x0D, 0x1D, 0x0E, 0x1F, 0x0F, 0xFF, 0x00, 0x00, 0x28, 0x02, 0x29, 0x04, 0x2A, 0x06, 0x2B,
|
||||||
0x1B, 0x0D, 0x1D, 0x0E, 0x1F, 0x0F, 0xFF, 0x00, 0x00, 0x28, 0x02, 0x29, 0x04, 0x2A, 0x06, 0x2B, 0xFF,
|
0xFF, 0x00, 0x08, 0x2C, 0x0A, 0x2D, 0x0C, 0x2E, 0x0E, 0x2F, 0xFF, 0x00, 0x11, 0x30, 0x13, 0x31, 0x15, 0x32,
|
||||||
0x00, 0x08, 0x2C, 0x0A, 0x2D, 0x0C, 0x2E, 0x0E, 0x2F, 0xFF, 0x00, 0x11, 0x30, 0x13, 0x31, 0x15, 0x32,
|
0x17, 0x33, 0xFF, 0x00, 0x19, 0x34, 0x1B, 0x35, 0x1D, 0x36, 0x1F, 0x37, 0xFF, 0x00, 0x00, 0x38, 0x02, 0x39,
|
||||||
0x17, 0x33, 0xFF, 0x00, 0x19, 0x34, 0x1B, 0x35, 0x1D, 0x36, 0x1F, 0x37, 0xFF, 0x00, 0x00, 0x38, 0x02,
|
0x04, 0x3A, 0x06, 0x3B, 0xFF, 0x00, 0x08, 0x3C, 0x0A, 0x3D, 0x0C, 0x3E, 0x0E, 0x3F, 0xFF, 0x00, 0x11, 0x40,
|
||||||
0x39, 0x04, 0x3A, 0x06, 0x3B, 0xFF, 0x00, 0x08, 0x3C, 0x0A, 0x3D, 0x0C, 0x3E, 0x0E, 0x3F, 0xFF, 0x00,
|
0x13, 0x41, 0x15, 0x42, 0x17, 0x43, 0xFF, 0x00, 0x19, 0x44, 0x1B, 0x45, 0x1D, 0x46, 0x1F, 0x47, 0xFF, 0x00,
|
||||||
0x11, 0x40, 0x13, 0x41, 0x15, 0x42, 0x17, 0x43, 0xFF, 0x00, 0x19, 0x44, 0x1B, 0x45, 0x1D, 0x46, 0x1F,
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
0x47, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF,
|
0xFF, 0xFF, 0xFF, 0x00
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>Checks if the media corresponds to CD-i.</summary>
|
||||||
/// Checks if the media corresponds to CD-i.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sector0">Contents of LBA 0, with all headers.</param>
|
/// <param name="sector0">Contents of LBA 0, with all headers.</param>
|
||||||
/// <param name="sector16">Contents of LBA 0, with all headers.</param>
|
/// <param name="sector16">Contents of LBA 0, with all headers.</param>
|
||||||
/// <returns><c>true</c> if it corresponds to a CD-i, <c>false</c>otherwise.</returns>
|
/// <returns><c>true</c> if it corresponds to a CD-i, <c>false</c>otherwise.</returns>
|
||||||
public static bool IsCdi(byte[] sector0, byte[] sector16)
|
public static bool IsCdi(byte[] sector0, byte[] sector16)
|
||||||
{
|
{
|
||||||
if(sector0?.Length != 2352 || sector16?.Length != 2352) return false;
|
if(sector0?.Length != 2352 ||
|
||||||
|
sector16?.Length != 2352)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
byte[] syncMark =
|
||||||
|
{
|
||||||
|
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
byte[] cdiMark =
|
||||||
|
{
|
||||||
|
0x01, 0x43, 0x44, 0x2D
|
||||||
|
};
|
||||||
|
|
||||||
byte[] syncMark = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
|
||||||
byte[] cdiMark = {0x01, 0x43, 0x44, 0x2D};
|
|
||||||
byte[] testMark = new byte[12];
|
byte[] testMark = new byte[12];
|
||||||
Array.Copy(sector0, 0, testMark, 0, 12);
|
Array.Copy(sector0, 0, testMark, 0, 12);
|
||||||
|
|
||||||
bool hiddenData = syncMark.SequenceEqual(testMark) &&
|
bool hiddenData = syncMark.SequenceEqual(testMark) &&
|
||||||
(sector0[0xF] == 0 || sector0[0xF] == 1 || sector0[0xF] == 2);
|
(sector0[0xF] == 0 || sector0[0xF] == 1 || sector0[0xF] == 2);
|
||||||
|
|
||||||
if(!hiddenData || sector0[0xF] != 2) return false;
|
if(!hiddenData ||
|
||||||
|
sector0[0xF] != 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
testMark = new byte[4];
|
testMark = new byte[4];
|
||||||
Array.Copy(sector16, 24, testMark, 0, 4);
|
Array.Copy(sector16, 24, testMark, 0, 4);
|
||||||
|
|
||||||
return cdiMark.SequenceEqual(testMark);
|
return cdiMark.SequenceEqual(testMark);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsVideoNowColor(byte[] videoFrame)
|
public static bool IsVideoNowColor(byte[] videoFrame)
|
||||||
{
|
{
|
||||||
if(videoFrame is null || videoFrame.Length < VideoNowColorFrameMarker.Length) return false;
|
if(videoFrame is null ||
|
||||||
|
videoFrame.Length < VideoNowColorFrameMarker.Length)
|
||||||
|
return false;
|
||||||
|
|
||||||
byte[] buffer = new byte[VideoNowColorFrameMarker.Length];
|
byte[] buffer = new byte[VideoNowColorFrameMarker.Length];
|
||||||
|
|
||||||
for(int framePosition = 0; framePosition + buffer.Length < videoFrame.Length; framePosition++)
|
for(int framePosition = 0; framePosition + buffer.Length < videoFrame.Length; framePosition++)
|
||||||
{
|
{
|
||||||
Array.Copy(videoFrame, framePosition, buffer, 0, buffer.Length);
|
Array.Copy(videoFrame, framePosition, buffer, 0, buffer.Length);
|
||||||
|
|
||||||
for(int ab = 9; ab < buffer.Length; ab += 10) buffer[ab] = 0;
|
for(int ab = 9; ab < buffer.Length; ab += 10)
|
||||||
|
buffer[ab] = 0;
|
||||||
|
|
||||||
if(!VideoNowColorFrameMarker.SequenceEqual(buffer)) continue;
|
if(!VideoNowColorFrameMarker.SequenceEqual(buffer))
|
||||||
|
continue;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int GetVideoNowColorOffset(byte[] data)
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[VideoNowColorFrameMarker.Length];
|
||||||
|
|
||||||
|
for(int framePosition = 0; framePosition + buffer.Length < data.Length; framePosition++)
|
||||||
|
{
|
||||||
|
Array.Copy(data, framePosition, buffer, 0, buffer.Length);
|
||||||
|
|
||||||
|
for(int ab = 9; ab < buffer.Length; ab += 10)
|
||||||
|
buffer[ab] = 0;
|
||||||
|
|
||||||
|
if(!VideoNowColorFrameMarker.SequenceEqual(buffer))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return 18032 - framePosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user