Add support for dumping ISRC and MCN.

This commit is contained in:
2018-02-04 22:43:37 +00:00
parent a14476671f
commit 4818765c5d
3 changed files with 274 additions and 159 deletions

View File

@@ -57,7 +57,7 @@ namespace DiscImageChef.Core.Devices.Dumping
/// <summary> /// <summary>
/// Implement dumping Compact Discs /// Implement dumping Compact Discs
/// </summary> /// </summary>
// TODO: ISRC, MCN and pregaps // TODO: Barcode and pregaps
static class CompactDisc static class CompactDisc
{ {
/// <summary> /// <summary>
@@ -757,6 +757,29 @@ namespace DiscImageChef.Core.Devices.Dumping
outputPlugin.WriteSectorTag(new[] {kvp.Value}, track.TrackStartSector, SectorTagType.CdTrackFlags); outputPlugin.WriteSectorTag(new[] {kvp.Value}, track.TrackStartSector, SectorTagType.CdTrackFlags);
} }
// Set MCN
sense = dev.ReadMcn(out string mcn, out _, out _, dev.Timeout, out _);
if(!sense && mcn != null && mcn != "0000000000000")
if(outputPlugin.WriteMediaTag(Encoding.ASCII.GetBytes(mcn), MediaTagType.CD_MCN))
{
DicConsole.WriteLine("Setting disc Media Catalogue Number to {0}", mcn);
dumpLog.WriteLine("Setting disc Media Catalogue Number to {0}", mcn);
}
// Set ISRCs
foreach(Track trk in tracks)
{
sense = dev.ReadIsrc((byte)trk.TrackSequence, out string isrc, out _, out _, dev.Timeout, out _);
if(sense || isrc == null || isrc == "000000000000") continue;
if(outputPlugin.WriteSectorTag(Encoding.ASCII.GetBytes(isrc), trk.TrackStartSector,
SectorTagType.CdTrackIsrc))
{
DicConsole.WriteLine("Setting ISRC for track {0} to {1}", trk.TrackSequence, isrc);
dumpLog.WriteLine("Setting ISRC for track {0} to {1}", trk.TrackSequence, isrc);
}
}
if(resume.NextBlock > 0) dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock); if(resume.NextBlock > 0) dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
double imageWriteDuration = 0; double imageWriteDuration = 0;

View File

@@ -31,6 +31,7 @@
// ****************************************************************************/ // ****************************************************************************/
using System; using System;
using System.Text;
using DiscImageChef.Console; using DiscImageChef.Console;
namespace DiscImageChef.Devices namespace DiscImageChef.Devices
@@ -127,7 +128,8 @@ namespace DiscImageChef.Devices
/// <param name="agid">AGID used in medium copy protection</param> /// <param name="agid">AGID used in medium copy protection</param>
/// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param> /// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param>
public bool ReadDiscStructure(out byte[] buffer, out byte[] senseBuffer, MmcDiscStructureMediaType mediaType, public bool ReadDiscStructure(out byte[] buffer, out byte[] senseBuffer, MmcDiscStructureMediaType mediaType,
uint address, byte layerNumber, MmcDiscStructureFormat format, byte agid, uint address, byte layerNumber, MmcDiscStructureFormat format,
byte agid,
uint timeout, out double duration) uint timeout, out double duration)
{ {
senseBuffer = new byte[32]; senseBuffer = new byte[32];
@@ -353,7 +355,8 @@ namespace DiscImageChef.Devices
/// <param name="dataType">Which disc information to read</param> /// <param name="dataType">Which disc information to read</param>
/// <param name="timeout">Timeout in seconds.</param> /// <param name="timeout">Timeout in seconds.</param>
/// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param> /// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param>
public bool ReadDiscInformation(out byte[] buffer, out byte[] senseBuffer, MmcDiscInformationDataTypes dataType, public bool ReadDiscInformation(out byte[] buffer, out byte[] senseBuffer,
MmcDiscInformationDataTypes dataType,
uint timeout, out double duration) uint timeout, out double duration)
{ {
senseBuffer = new byte[32]; senseBuffer = new byte[32];
@@ -398,7 +401,8 @@ namespace DiscImageChef.Devices
/// <param name="edcEcc">If set to <c>true</c> we request the EDC/ECC fields for data sectors.</param> /// <param name="edcEcc">If set to <c>true</c> we request the EDC/ECC fields for data sectors.</param>
/// <param name="c2Error">C2 error options.</param> /// <param name="c2Error">C2 error options.</param>
/// <param name="subchannel">Subchannel selection.</param> /// <param name="subchannel">Subchannel selection.</param>
public bool ReadCd(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, uint transferLength, public bool ReadCd(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize,
uint transferLength,
MmcSectorTypes expectedSectorType, bool dap, bool relAddr, bool sync, MmcSectorTypes expectedSectorType, bool dap, bool relAddr, bool sync,
MmcHeaderCodes headerCodes, bool userData, bool edcEcc, MmcErrorField c2Error, MmcHeaderCodes headerCodes, bool userData, bool edcEcc, MmcErrorField c2Error,
MmcSubchannel subchannel, uint timeout, out double duration) MmcSubchannel subchannel, uint timeout, out double duration)
@@ -454,9 +458,12 @@ namespace DiscImageChef.Devices
/// <param name="edcEcc">If set to <c>true</c> we request the EDC/ECC fields for data sectors.</param> /// <param name="edcEcc">If set to <c>true</c> we request the EDC/ECC fields for data sectors.</param>
/// <param name="c2Error">C2 error options.</param> /// <param name="c2Error">C2 error options.</param>
/// <param name="subchannel">Subchannel selection.</param> /// <param name="subchannel">Subchannel selection.</param>
public bool ReadCdMsf(out byte[] buffer, out byte[] senseBuffer, uint startMsf, uint endMsf, uint blockSize, public bool ReadCdMsf(out byte[] buffer, out byte[] senseBuffer, uint startMsf,
MmcSectorTypes expectedSectorType, bool dap, bool sync, MmcHeaderCodes headerCodes, uint endMsf, uint blockSize,
bool userData, bool edcEcc, MmcErrorField c2Error, MmcSubchannel subchannel, uint timeout, MmcSectorTypes expectedSectorType, bool dap, bool sync,
MmcHeaderCodes headerCodes,
bool userData, bool edcEcc, MmcErrorField c2Error,
MmcSubchannel subchannel, uint timeout,
out double duration) out double duration)
{ {
senseBuffer = new byte[32]; senseBuffer = new byte[32];
@@ -542,7 +549,8 @@ namespace DiscImageChef.Devices
} }
public bool StartStopUnit(out byte[] senseBuffer, bool immediate, byte formatLayer, byte powerConditions, public bool StartStopUnit(out byte[] senseBuffer, bool immediate, byte formatLayer, byte powerConditions,
bool changeFormatLayer, bool loadEject, bool start, uint timeout, out double duration) bool changeFormatLayer, bool loadEject, bool start, uint timeout,
out double duration)
{ {
senseBuffer = new byte[32]; senseBuffer = new byte[32];
byte[] cdb = new byte[6]; byte[] cdb = new byte[6];
@@ -560,6 +568,7 @@ namespace DiscImageChef.Devices
if(loadEject) cdb[4] += 0x02; if(loadEject) cdb[4] += 0x02;
if(start) cdb[4] += 0x01; if(start) cdb[4] += 0x01;
} }
cdb[4] += (byte)((powerConditions & 0x0F) << 4); cdb[4] += (byte)((powerConditions & 0x0F) << 4);
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration,
@@ -570,5 +579,60 @@ namespace DiscImageChef.Devices
return sense; return sense;
} }
public bool ReadMcn(out string mcn, out byte[] buffer, out byte[] senseBuffer, uint timeout,
out double duration)
{
senseBuffer = new byte[32];
byte[] cdb = new byte[10];
mcn = null;
cdb[0] = (byte)ScsiCommands.ReadSubChannel;
cdb[1] = 0;
cdb[2] = 0x40;
cdb[3] = 0x02;
cdb[7] = (23 & 0xFF00) >> 8;
cdb[8] = 23 & 0xFF;
buffer = new byte[23];
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense);
Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "READ READ SUB-CHANNEL (MCN) took {0} ms.", duration);
if(!sense && (buffer[8] & 0x80) == 0x80) mcn = Encoding.ASCII.GetString(buffer, 9, 13);
return sense;
}
public bool ReadIsrc(byte trackNumber, out string isrc, out byte[] buffer, out byte[] senseBuffer, uint timeout,
out double duration)
{
senseBuffer = new byte[32];
byte[] cdb = new byte[10];
isrc = null;
cdb[0] = (byte)ScsiCommands.ReadSubChannel;
cdb[1] = 0;
cdb[2] = 0x40;
cdb[3] = 0x03;
cdb[6] = trackNumber;
cdb[7] = (23 & 0xFF00) >> 8;
cdb[8] = 23 & 0xFF;
buffer = new byte[23];
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense);
Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "READ READ SUB-CHANNEL (ISRC) took {0} ms.", duration);
if(!sense && (buffer[8] & 0x80) == 0x80) isrc = Encoding.ASCII.GetString(buffer, 9, 12);
return sense;
}
} }
} }

View File

@@ -280,6 +280,7 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Media has {0} blocks of {1} bytes/each. (for a total of {2} bytes)", DicConsole.WriteLine("Media has {0} blocks of {1} bytes/each. (for a total of {2} bytes)",
blocks, blockSize, blocks * blockSize); blocks, blockSize, blocks * blockSize);
} }
break; break;
case PeripheralDeviceTypes.SequentialAccess: case PeripheralDeviceTypes.SequentialAccess:
byte[] medBuf; byte[] medBuf;
@@ -318,6 +319,7 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Medium types currently inserted in device:"); DicConsole.WriteLine("Medium types currently inserted in device:");
DicConsole.WriteLine(DensitySupport.PrettifyMediumType(meds)); DicConsole.WriteLine(DensitySupport.PrettifyMediumType(meds));
} }
DicConsole.WriteLine(DensitySupport.PrettifyMediumType(seqBuf)); DicConsole.WriteLine(DensitySupport.PrettifyMediumType(seqBuf));
} }
} }
@@ -628,6 +630,7 @@ namespace DiscImageChef.Commands
"SCSI READ DISC STRUCTURE", cmdBuf); "SCSI READ DISC STRUCTURE", cmdBuf);
DicConsole.WriteLine("Disc Definition Structure:\n{0}", DDS.Prettify(cmdBuf)); DicConsole.WriteLine("Disc Definition Structure:\n{0}", DDS.Prettify(cmdBuf));
} }
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0,
MmcDiscStructureFormat.DvdramMediumStatus, 0, dev.Timeout, out _); MmcDiscStructureFormat.DvdramMediumStatus, 0, dev.Timeout, out _);
if(sense) if(sense)
@@ -639,6 +642,7 @@ namespace DiscImageChef.Commands
"SCSI READ DISC STRUCTURE", cmdBuf); "SCSI READ DISC STRUCTURE", cmdBuf);
DicConsole.WriteLine("Medium Status:\n{0}", Cartridge.Prettify(cmdBuf)); DicConsole.WriteLine("Medium Status:\n{0}", Cartridge.Prettify(cmdBuf));
} }
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0,
MmcDiscStructureFormat.DvdramSpareAreaInformation, 0, dev.Timeout, MmcDiscStructureFormat.DvdramSpareAreaInformation, 0, dev.Timeout,
out _); out _);
@@ -651,6 +655,7 @@ namespace DiscImageChef.Commands
"SCSI READ DISC STRUCTURE", cmdBuf); "SCSI READ DISC STRUCTURE", cmdBuf);
DicConsole.WriteLine("Spare Area Information:\n{0}", Spare.Prettify(cmdBuf)); DicConsole.WriteLine("Spare Area Information:\n{0}", Spare.Prettify(cmdBuf));
} }
break; break;
case MediaType.DVDR: case MediaType.DVDR:
case MediaType.HDDVDR: case MediaType.HDDVDR:
@@ -914,6 +919,7 @@ namespace DiscImageChef.Commands
"SCSI READ DISC STRUCTURE", cmdBuf); "SCSI READ DISC STRUCTURE", cmdBuf);
DicConsole.WriteLine("Blu-ray Disc Information:\n{0}", DI.Prettify(cmdBuf)); DicConsole.WriteLine("Blu-ray Disc Information:\n{0}", DI.Prettify(cmdBuf));
} }
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0, sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0,
MmcDiscStructureFormat.Pac, 0, dev.Timeout, out _); MmcDiscStructureFormat.Pac, 0, dev.Timeout, out _);
if(sense) if(sense)
@@ -941,6 +947,7 @@ namespace DiscImageChef.Commands
"SCSI READ DISC STRUCTURE", cmdBuf); "SCSI READ DISC STRUCTURE", cmdBuf);
DicConsole.WriteLine("Blu-ray Burst Cutting Area:\n{0}", BCA.Prettify(cmdBuf)); DicConsole.WriteLine("Blu-ray Burst Cutting Area:\n{0}", BCA.Prettify(cmdBuf));
} }
break; break;
#endregion BD-ROM only #endregion BD-ROM only
@@ -961,6 +968,7 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Blu-ray Disc Definition Structure:\n{0}", DicConsole.WriteLine("Blu-ray Disc Definition Structure:\n{0}",
Decoders.Bluray.DDS.Prettify(cmdBuf)); Decoders.Bluray.DDS.Prettify(cmdBuf));
} }
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0, sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0,
MmcDiscStructureFormat.CartridgeStatus, 0, dev.Timeout, out _); MmcDiscStructureFormat.CartridgeStatus, 0, dev.Timeout, out _);
if(sense) if(sense)
@@ -973,6 +981,7 @@ namespace DiscImageChef.Commands
"SCSI READ DISC STRUCTURE", cmdBuf); "SCSI READ DISC STRUCTURE", cmdBuf);
DicConsole.WriteLine("Blu-ray Cartridge Status:\n{0}", DI.Prettify(cmdBuf)); DicConsole.WriteLine("Blu-ray Cartridge Status:\n{0}", DI.Prettify(cmdBuf));
} }
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0, sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0,
MmcDiscStructureFormat.BdSpareAreaInformation, 0, dev.Timeout, MmcDiscStructureFormat.BdSpareAreaInformation, 0, dev.Timeout,
out _); out _);
@@ -986,6 +995,7 @@ namespace DiscImageChef.Commands
"SCSI READ DISC STRUCTURE", cmdBuf); "SCSI READ DISC STRUCTURE", cmdBuf);
DicConsole.WriteLine("Blu-ray Spare Area Information:\n{0}", DI.Prettify(cmdBuf)); DicConsole.WriteLine("Blu-ray Spare Area Information:\n{0}", DI.Prettify(cmdBuf));
} }
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0, sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0,
MmcDiscStructureFormat.RawDfl, 0, dev.Timeout, out _); MmcDiscStructureFormat.RawDfl, 0, dev.Timeout, out _);
if(sense) if(sense)
@@ -1005,6 +1015,7 @@ namespace DiscImageChef.Commands
DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscinformation_001b.bin", DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscinformation_001b.bin",
"SCSI READ DISC INFORMATION", cmdBuf); "SCSI READ DISC INFORMATION", cmdBuf);
} }
sense = dev.ReadDiscInformation(out cmdBuf, out senseBuf, sense = dev.ReadDiscInformation(out cmdBuf, out senseBuf,
MmcDiscInformationDataTypes.PowResources, dev.Timeout, out _); MmcDiscInformationDataTypes.PowResources, dev.Timeout, out _);
if(sense) if(sense)
@@ -1016,6 +1027,7 @@ namespace DiscImageChef.Commands
DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscinformation_010b.bin", DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscinformation_010b.bin",
"SCSI READ DISC INFORMATION", cmdBuf); "SCSI READ DISC INFORMATION", cmdBuf);
} }
break; break;
#endregion Writable Blu-ray only #endregion Writable Blu-ray only
@@ -1127,8 +1139,10 @@ namespace DiscImageChef.Commands
foreach(TOC.CDTOCTrackDataDescriptor track in toc.Value.TrackDescriptors) foreach(TOC.CDTOCTrackDataDescriptor track in toc.Value.TrackDescriptors)
{ {
if(track.TrackNumber == 1 && if(track.TrackNumber == 1 &&
((TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrack || ((TocControl)(track.CONTROL & 0x0D) ==
(TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrackIncremental)) TocControl.DataTrack ||
(TocControl)(track.CONTROL & 0x0D) ==
TocControl.DataTrackIncremental))
allFirstSessionTracksAreAudio &= firstTrackLastSession != 1; allFirstSessionTracksAreAudio &= firstTrackLastSession != 1;
if((TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrack || if((TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrack ||
@@ -1163,9 +1177,9 @@ namespace DiscImageChef.Commands
if(fullToc.HasValue) if(fullToc.HasValue)
{ {
FullTOC.TrackDataDescriptor a0Track = FullTOC.TrackDataDescriptor a0Track =
fullToc.Value.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA0 && t.ADR == 1); fullToc.Value.TrackDescriptors
.FirstOrDefault(t => t.POINT == 0xA0 && t.ADR == 1);
if(a0Track.POINT == 0xA0) if(a0Track.POINT == 0xA0)
{
switch(a0Track.PSEC) switch(a0Track.PSEC)
{ {
case 0x10: case 0x10:
@@ -1177,7 +1191,7 @@ namespace DiscImageChef.Commands
} }
} }
} }
}
sense = dev.ReadPma(out cmdBuf, out senseBuf, dev.Timeout, out _); sense = dev.ReadPma(out cmdBuf, out senseBuf, dev.Timeout, out _);
if(sense) if(sense)
DicConsole.DebugWriteLine("Media-Info command", "READ TOC/PMA/ATIP: PMA\n{0}", DicConsole.DebugWriteLine("Media-Info command", "READ TOC/PMA/ATIP: PMA\n{0}",
@@ -1200,6 +1214,16 @@ namespace DiscImageChef.Commands
if(CDTextOnLeadIn.Decode(cmdBuf).HasValue) if(CDTextOnLeadIn.Decode(cmdBuf).HasValue)
DicConsole.WriteLine("CD-TEXT on Lead-In:\n{0}", CDTextOnLeadIn.Prettify(cmdBuf)); DicConsole.WriteLine("CD-TEXT on Lead-In:\n{0}", CDTextOnLeadIn.Prettify(cmdBuf));
} }
sense = dev.ReadMcn(out string mcn, out _, out _, dev.Timeout, out _);
if(!sense && mcn != null && mcn != "0000000000000") DicConsole.WriteLine("MCN: {0}", mcn);
for(byte i = toc.Value.FirstTrack; i <= toc.Value.LastTrack; i++)
{
sense = dev.ReadIsrc(i, out string isrc, out _, out _, dev.Timeout, out _);
if(!sense && isrc != null && isrc != "000000000000")
DicConsole.WriteLine("Track's {0} ISRC: {1}", i, isrc);
}
} }
break; break;
@@ -1294,7 +1318,8 @@ namespace DiscImageChef.Commands
} }
totalSize = (ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3]); totalSize = (ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3]);
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd,
0, 0,
MmcDiscStructureFormat.PhysicalInformation, 0, 0, out _); MmcDiscStructureFormat.PhysicalInformation, 0, 0, out _);
if(sense) if(sense)
{ {
@@ -1346,7 +1371,8 @@ namespace DiscImageChef.Commands
} }
totalSize = (ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3]); totalSize = (ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3]);
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd,
0, 0,
MmcDiscStructureFormat.PhysicalInformation, 0, 0, out _); MmcDiscStructureFormat.PhysicalInformation, 0, 0, out _);
if(sense) if(sense)
{ {
@@ -1357,8 +1383,10 @@ namespace DiscImageChef.Commands
DicConsole.DebugWriteLine("Dump-media command", "Unlocked total size: {0} sectors", DicConsole.DebugWriteLine("Dump-media command", "Unlocked total size: {0} sectors",
totalSize); totalSize);
middleZone = middleZone =
totalSize - (PFI.Decode(cmdBuf).Value.Layer0EndPSN - totalSize -
PFI.Decode(cmdBuf).Value.DataAreaStartPSN + 1) - gameSize + 1; (PFI.Decode(cmdBuf).Value.Layer0EndPSN -
PFI.Decode(cmdBuf).Value.DataAreaStartPSN + 1) -
gameSize + 1;
totalSize = l0Video + l1Video + middleZone * 2 + gameSize; totalSize = l0Video + l1Video + middleZone * 2 + gameSize;
layerBreak = l0Video + middleZone + gameSize / 2; layerBreak = l0Video + middleZone + gameSize / 2;