Separated CD offset calculation from dump.

This commit is contained in:
2019-12-31 19:40:29 +00:00
parent 6e22116fb0
commit 34619ab1c2
4 changed files with 241 additions and 200 deletions

View File

@@ -291,6 +291,7 @@
<e p="MMC.cs" t="Include" /> <e p="MMC.cs" t="Include" />
</e> </e>
<e p="Info" t="Include"> <e p="Info" t="Include">
<e p="CompactDisc.cs" t="Include" />
<e p="ScsiInfo.cs" t="Include" /> <e p="ScsiInfo.cs" t="Include" />
<e p="XgdInfo.cs" t="Include" /> <e p="XgdInfo.cs" t="Include" />
</e> </e>

View File

@@ -1329,206 +1329,9 @@ namespace DiscImageChef.Core.Devices.Dumping
// Check offset // Check offset
if(_fixOffset) if(_fixOffset)
{ {
if(dskType != MediaType.VideoNowColor) _fixOffset = Media.Info.CompactDisc.GetOffset(cdOffset, _dbDev, _debug, _dev, dskType, _dumpLog,
{ out offsetBytes, readcd, out sectorsForOffset, tracks,
if(tracks.All(t => t.TrackType != TrackType.Audio)) UpdateStatus);
{
// 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.");
_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);
if(dataTrack.TrackSequence != 0)
{
dataTrack.TrackStartSector += 151;
// Calculate MSF
ulong minute = dataTrack.TrackStartSector / 4500;
ulong second = (dataTrack.TrackStartSector - (minute * 4500)) / 75;
ulong frame = dataTrack.TrackStartSector - (minute * 4500) - (second * 75);
dataTrack.TrackStartSector -= 151;
// 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;
// Scramble M and S
minute ^= 0x01;
second ^= 0x80;
// 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.TrackStartSector, 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.TrackStartSector,
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
{
if(offsetFound)
{
_dumpLog.
WriteLine($"Disc offsets is {offsetBytes - (cdOffset.Offset * 4)} bytes ({(offsetBytes / 4) - cdOffset.Offset} samples)");
UpdateStatus?.
Invoke($"Disc offsets is {offsetBytes - (cdOffset.Offset * 4)} bytes ({(offsetBytes / 4) - cdOffset.Offset} samples)");
}
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 * 4;
}
_dumpLog.WriteLine($"Offset is {offsetBytes} bytes.");
UpdateStatus?.Invoke($"Offset is {offsetBytes} bytes.");
}
}
}
else
{
byte[] videoNowColorFrame = new byte[9 * sectorSize];
sense = _dev.ReadCd(out cmdBuf, out senseBuf, 0, sectorSize, 9, MmcSectorTypes.AllTypes, false,
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.");
}
}
sectorsForOffset = offsetBytes / (int)sectorSize;
if(sectorsForOffset < 0)
sectorsForOffset *= -1;
if(offsetBytes % sectorSize != 0)
sectorsForOffset++;
} }
else if(tracks.Any(t => t.TrackType == TrackType.Audio)) else if(tracks.Any(t => t.TrackType == TrackType.Audio))
{ {

View File

@@ -61,6 +61,7 @@
<Compile Include="GetPluginBase.cs" /> <Compile Include="GetPluginBase.cs" />
<Compile Include="ImageInfo.cs" /> <Compile Include="ImageInfo.cs" />
<Compile Include="Media\Detection\MMC.cs" /> <Compile Include="Media\Detection\MMC.cs" />
<Compile Include="Media\Info\CompactDisc.cs" />
<Compile Include="Media\Info\ScsiInfo.cs" /> <Compile Include="Media\Info\ScsiInfo.cs" />
<Compile Include="Media\Info\XgdInfo.cs" /> <Compile Include="Media\Info\XgdInfo.cs" />
<Compile Include="Options.cs" /> <Compile Include="Options.cs" />

View File

@@ -0,0 +1,236 @@
using System;
using System.Linq;
using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Structs;
using DiscImageChef.Core.Logging;
using DiscImageChef.Core.Media.Detection;
using DiscImageChef.Database.Models;
using DiscImageChef.Devices;
using Device = DiscImageChef.Database.Models.Device;
namespace DiscImageChef.Core.Media.Info
{
public static class CompactDisc
{
/// <summary>Gets the offset bytes from a Compact Disc</summary>
/// <param name="cdOffset">Offset entry from database</param>
/// <param name="dbDev">Device entry from database</param>
/// <param name="debug">Debug</param>
/// <param name="dev">Opened device</param>
/// <param name="dskType">Detected disk type</param>
/// <param name="dumpLog">Dump log if applicable</param>
/// <param name="offsetBytes">Set to combined offset, in bytes</param>
/// <param name="readcd">If device supports READ CD command</param>
/// <param name="sectorsForOffset">Sectors needed to fix offset</param>
/// <param name="tracks">Disc track list</param>
/// <param name="updateStatus">UpdateStatus event</param>
/// <returns><c>true</c> if offset could be found, <c>false</c> otherwise</returns>
public static bool GetOffset(CdOffset cdOffset, Device dbDev, bool debug, DiscImageChef.Devices.Device dev,
MediaType dskType, DumpLog dumpLog, out int offsetBytes, bool readcd,
out int sectorsForOffset, Track[] tracks, UpdateStatusHandler updateStatus)
{
byte[] cmdBuf;
bool sense;
bool offsetFound = false;
const uint sectorSize = 2352;
offsetBytes = 0;
sectorsForOffset = 0;
if(dskType != MediaType.VideoNowColor)
{
if(tracks.All(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.");
return false;
}
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.");
return false;
}
if(tracks.Any(t => t.TrackType != TrackType.Audio))
{
Track dataTrack = tracks.FirstOrDefault(t => t.TrackType != TrackType.Audio);
if(dataTrack.TrackSequence != 0)
{
dataTrack.TrackStartSector += 151;
// Calculate MSF
ulong minute = dataTrack.TrackStartSector / 4500;
ulong second = (dataTrack.TrackStartSector - (minute * 4500)) / 75;
ulong frame = dataTrack.TrackStartSector - (minute * 4500) - (second * 75);
dataTrack.TrackStartSector -= 151;
// 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;
// Scramble M and S
minute ^= 0x01;
second ^= 0x80;
// Build sync
byte[] sectorSync =
{
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, (byte)minute,
(byte)second, (byte)frame
};
byte[] 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 _, (uint)dataTrack.TrackStartSector, 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 _, (uint)dataTrack.TrackStartSector, 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.");
return false;
}
}
else
{
if(offsetFound)
{
dumpLog.
WriteLine($"Disc offsets is {offsetBytes - (cdOffset.Offset * 4)} bytes ({(offsetBytes / 4) - cdOffset.Offset} samples)");
updateStatus?.
Invoke($"Disc offsets is {offsetBytes - (cdOffset.Offset * 4)} bytes ({(offsetBytes / 4) - cdOffset.Offset} samples)");
}
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 * 4;
}
dumpLog?.WriteLine($"Offset is {offsetBytes} bytes.");
updateStatus?.Invoke($"Offset is {offsetBytes} bytes.");
}
}
else
{
byte[] videoNowColorFrame = new byte[9 * sectorSize];
sense = dev.ReadCd(out cmdBuf, out _, 0, sectorSize, 9, MmcSectorTypes.AllTypes, false, false, true,
MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None,
dev.Timeout, out _);
if(sense || dev.Error)
{
sense = dev.ReadCd(out cmdBuf, out _, 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.");
}
}
sectorsForOffset = offsetBytes / (int)sectorSize;
if(sectorsForOffset < 0)
sectorsForOffset *= -1;
if(offsetBytes % sectorSize != 0)
sectorsForOffset++;
return offsetFound;
}
}
}