disc subsystem progress
This commit is contained in:
parent
a91c8ecbd7
commit
646dd59ad6
|
@ -3,7 +3,7 @@
|
|||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.21022</ProductVersion>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{197D4314-8A9F-49BA-977D-54ACEFAEB6BA}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
|
@ -44,6 +44,8 @@
|
|||
<Reference Include="System.Core">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml.Linq">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
|
@ -159,6 +161,13 @@
|
|||
<Compile Include="Consoles\Gameboy\Mappers.cs" />
|
||||
<Compile Include="Database\CRC32.cs" />
|
||||
<Compile Include="Database\Database.cs" />
|
||||
<Compile Include="Disc\CCD_format.cs" />
|
||||
<Compile Include="Disc\CUE_format.cs" />
|
||||
<Compile Include="Disc\Disc.cs" />
|
||||
<Compile Include="Disc\DiscTOC.cs" />
|
||||
<Compile Include="Disc\ECM.cs" />
|
||||
<Compile Include="Disc\FFmpeg.cs" />
|
||||
<Compile Include="Disc\TOC_format.cs" />
|
||||
<Compile Include="Interfaces\Base Implementations\Game.cs" />
|
||||
<Compile Include="Interfaces\Base Implementations\IPS.cs" />
|
||||
<Compile Include="Interfaces\Base Implementations\Movies.cs" />
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Disc
|
||||
{
|
||||
//TBD CCD format
|
||||
public class CCDFormat
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,416 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Disc
|
||||
{
|
||||
partial class Disc
|
||||
{
|
||||
void FromCuePathInternal(string cuePath)
|
||||
{
|
||||
string cueDir = Path.GetDirectoryName(cuePath);
|
||||
var cue = new Cue();
|
||||
cue.LoadFromPath(cuePath);
|
||||
|
||||
var session = new DiscTOC.Session();
|
||||
session.num = 1;
|
||||
TOC.Sessions.Add(session);
|
||||
|
||||
int track_counter = 1;
|
||||
int curr_lba = 0;
|
||||
foreach (var cue_file in cue.Files)
|
||||
{
|
||||
//make a raw file blob for the source binfile
|
||||
Blob_RawFile blob = new Blob_RawFile();
|
||||
blob.PhysicalPath = Path.Combine(cueDir, cue_file.Path);
|
||||
Blobs.Add(blob);
|
||||
|
||||
//structural validation
|
||||
if (cue_file.Tracks.Count < 1) throw new Cue.CueBrokenException("Found a cue file with no tracks");
|
||||
|
||||
//structural validation: every track must be the same type with cue/bin (i think)
|
||||
var trackType = cue_file.Tracks[0].TrackType;
|
||||
for (int i = 1; i < cue_file.Tracks.Count; i++)
|
||||
{
|
||||
if (cue_file.Tracks[i].TrackType != trackType) throw new Cue.CueBrokenException("cue has different track types per datafile (not supported now; maybe never)");
|
||||
}
|
||||
|
||||
//structural validaton: make sure file is a correct size and analyze its length
|
||||
long flen = new FileInfo(blob.PhysicalPath).Length;
|
||||
int numlba;
|
||||
int leftover = 0;
|
||||
switch (trackType)
|
||||
{
|
||||
case Cue.ECueTrackType.Audio:
|
||||
numlba = (int)(flen / 2352);
|
||||
leftover = (int)(flen - numlba * 2352);
|
||||
break;
|
||||
|
||||
case Cue.ECueTrackType.Mode1_2352:
|
||||
case Cue.ECueTrackType.Mode2_2352:
|
||||
if (flen % 2352 != 0) throw new Cue.CueBrokenException("Found a modeN_2352 cue file that is wrongly-sized");
|
||||
numlba = (int)(flen / 2352);
|
||||
break;
|
||||
case Cue.ECueTrackType.Mode1_2048:
|
||||
if (flen % 2048 != 0) throw new Cue.CueBrokenException("Found a modeN_2048 cue file that is wrongly-sized");
|
||||
numlba = (int)(flen / 2048);
|
||||
break;
|
||||
|
||||
default: throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
List<DiscTOC.Track> new_toc_tracks = new List<DiscTOC.Track>();
|
||||
for (int i = 0; i < cue_file.Tracks.Count; i++)
|
||||
{
|
||||
bool last_track = (i == cue_file.Tracks.Count - 1);
|
||||
|
||||
var cue_track = cue_file.Tracks[i];
|
||||
if (cue_track.TrackNum != track_counter) throw new Cue.CueBrokenException("Missing a track in the middle of the cue");
|
||||
track_counter++;
|
||||
|
||||
DiscTOC.Track toc_track = new DiscTOC.Track();
|
||||
toc_track.num = track_counter;
|
||||
session.Tracks.Add(toc_track);
|
||||
new_toc_tracks.Add(toc_track);
|
||||
|
||||
//analyze indices
|
||||
int idx;
|
||||
for (idx = 0; idx <= 99; idx++)
|
||||
{
|
||||
if (!cue_track.Indexes.ContainsKey(idx))
|
||||
{
|
||||
if (idx == 0) continue;
|
||||
if (idx == 1) throw new Cue.CueBrokenException("cue track is missing an index 1");
|
||||
break;
|
||||
}
|
||||
var cue_index = cue_track.Indexes[idx];
|
||||
//todo - add pregap/postgap from cue?
|
||||
|
||||
DiscTOC.Index toc_index = new DiscTOC.Index();
|
||||
toc_index.num = idx;
|
||||
toc_track.Indexes.Add(toc_index);
|
||||
toc_index.lba = cue_index.Timestamp.LBA + curr_lba;
|
||||
}
|
||||
|
||||
//look for extra indices (i.e. gaps)
|
||||
for (; idx <= 99; idx++)
|
||||
{
|
||||
if (cue_track.Indexes.ContainsKey(idx))
|
||||
throw new Cue.CueBrokenException("cue track is has an index gap");
|
||||
}
|
||||
} //track loop
|
||||
|
||||
//analyze length of each track and index
|
||||
DiscTOC.Index last_toc_index = null;
|
||||
foreach (var toc_track in new_toc_tracks)
|
||||
{
|
||||
foreach (var toc_index in toc_track.Indexes)
|
||||
{
|
||||
if (last_toc_index != null)
|
||||
last_toc_index.length_lba = toc_index.lba - last_toc_index.lba;
|
||||
last_toc_index = toc_index;
|
||||
}
|
||||
}
|
||||
if (last_toc_index != null)
|
||||
last_toc_index.length_lba = (curr_lba + numlba) - last_toc_index.lba;
|
||||
|
||||
//generate the sectors from this file
|
||||
long curr_src_addr = 0;
|
||||
for (int i = 0; i < numlba; i++)
|
||||
{
|
||||
ISector sector;
|
||||
switch (trackType)
|
||||
{
|
||||
case Cue.ECueTrackType.Audio:
|
||||
//all 2352 bytes are present
|
||||
case Cue.ECueTrackType.Mode1_2352:
|
||||
//2352 bytes are present, containing 2048 bytes of user data as well as ECM
|
||||
case Cue.ECueTrackType.Mode2_2352:
|
||||
//2352 bytes are present, containing 2336 bytes of user data, replacing ECM
|
||||
{
|
||||
Sector_RawBlob sector_rawblob = new Sector_RawBlob();
|
||||
sector_rawblob.Blob = blob;
|
||||
sector_rawblob.Offset = curr_src_addr;
|
||||
curr_src_addr += 2352;
|
||||
Sector_Raw sector_raw = new Sector_Raw();
|
||||
sector_raw.BaseSector = sector_rawblob;
|
||||
if (i == numlba - 1 && leftover != 0)
|
||||
{
|
||||
Sector_ZeroPad sector_zeropad = new Sector_ZeroPad();
|
||||
sector_zeropad.BaseSector = sector_rawblob;
|
||||
sector_zeropad.BaseLength = 2352 - leftover;
|
||||
sector_raw.BaseSector = sector_zeropad;
|
||||
}
|
||||
sector = sector_raw;
|
||||
break;
|
||||
}
|
||||
case Cue.ECueTrackType.Mode1_2048:
|
||||
//2048 bytes are present. ECM needs to be generated to create a full sector
|
||||
{
|
||||
var sector_2048 = new Sector_Mode1_2048(i + 150);
|
||||
sector_2048.Blob = new ECMCacheBlob(blob);
|
||||
sector_2048.Offset = curr_src_addr;
|
||||
curr_src_addr += 2048;
|
||||
sector = sector_2048;
|
||||
break;
|
||||
}
|
||||
default: throw new InvalidOperationException();
|
||||
}
|
||||
SectorEntry se = new SectorEntry();
|
||||
se.Sector = sector;
|
||||
Sectors.Add(se);
|
||||
}
|
||||
|
||||
curr_lba += numlba;
|
||||
|
||||
} //done analyzing cue datafiles
|
||||
|
||||
TOC.AnalyzeLengthsFromIndexLengths();
|
||||
}
|
||||
}
|
||||
|
||||
public class Cue
|
||||
{
|
||||
//TODO - export from isobuster and observe the SESSION directive, as well as the MSF directive.
|
||||
|
||||
public string DebugPrint()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach (CueFile cf in Files)
|
||||
{
|
||||
sb.AppendFormat("FILE \"{0}\"", cf.Path);
|
||||
if (cf.Binary) sb.Append(" BINARY");
|
||||
sb.AppendLine();
|
||||
foreach (CueTrack ct in cf.Tracks)
|
||||
{
|
||||
sb.AppendFormat(" TRACK {0:D2} {1}\n", ct.TrackNum, ct.TrackType.ToString().Replace("_", "/").ToUpper());
|
||||
foreach (CueTrackIndex cti in ct.Indexes.Values)
|
||||
{
|
||||
sb.AppendFormat(" INDEX {0:D2} {1}\n", cti.IndexNum, cti.Timestamp.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public class CueFile
|
||||
{
|
||||
public string Path;
|
||||
public bool Binary;
|
||||
public List<CueTrack> Tracks = new List<CueTrack>();
|
||||
}
|
||||
|
||||
public List<CueFile> Files = new List<CueFile>();
|
||||
|
||||
public enum ECueTrackType
|
||||
{
|
||||
Mode1_2352,
|
||||
Mode1_2048,
|
||||
Mode2_2352,
|
||||
Audio
|
||||
}
|
||||
|
||||
public class CueTrack
|
||||
{
|
||||
public ECueTrackType TrackType;
|
||||
public int TrackNum;
|
||||
public Dictionary<int, CueTrackIndex> Indexes = new Dictionary<int, CueTrackIndex>();
|
||||
}
|
||||
|
||||
public class CueTimestamp
|
||||
{
|
||||
public CueTimestamp(string value) {
|
||||
this.Value = value;
|
||||
MIN = int.Parse(value.Substring(0, 2));
|
||||
SEC = int.Parse(value.Substring(3, 2));
|
||||
FRAC = int.Parse(value.Substring(6, 2));
|
||||
LBA = MIN * 60 * 75 + SEC * 75 + FRAC;
|
||||
}
|
||||
public readonly string Value;
|
||||
public readonly int MIN, SEC, FRAC, LBA;
|
||||
}
|
||||
|
||||
public class CueTrackIndex
|
||||
{
|
||||
public int IndexNum;
|
||||
public CueTimestamp Timestamp;
|
||||
}
|
||||
|
||||
public class CueBrokenException : Exception
|
||||
{
|
||||
public CueBrokenException(string why)
|
||||
: base(why)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadFromPath(string cuePath)
|
||||
{
|
||||
FileInfo fiCue = new FileInfo(cuePath);
|
||||
if (!fiCue.Exists) throw new FileNotFoundException();
|
||||
File.ReadAllText(cuePath);
|
||||
TextReader tr = new StreamReader(cuePath);
|
||||
|
||||
CueFile currFile = null;
|
||||
CueTrack currTrack = null;
|
||||
int state = 0;
|
||||
for (; ; )
|
||||
{
|
||||
string line = tr.ReadLine();
|
||||
if (line == null) break;
|
||||
if (line == "") continue;
|
||||
line = line.Trim();
|
||||
var clp = new CueLineParser(line);
|
||||
|
||||
string key = clp.ReadToken().ToUpper();
|
||||
switch (key)
|
||||
{
|
||||
case "REM":
|
||||
break;
|
||||
|
||||
case "FILE":
|
||||
{
|
||||
currTrack = null;
|
||||
currFile = new CueFile();
|
||||
Files.Add(currFile);
|
||||
currFile.Path = clp.ReadPath().Trim('"');
|
||||
if (!clp.EOF)
|
||||
{
|
||||
string temp = clp.ReadToken().ToUpper();
|
||||
if (temp == "BINARY")
|
||||
currFile.Binary = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "TRACK":
|
||||
{
|
||||
if (currFile == null) throw new CueBrokenException("invalid cue structure");
|
||||
if (clp.EOF) throw new CueBrokenException("invalid cue structure");
|
||||
string strtracknum = clp.ReadToken();
|
||||
int tracknum;
|
||||
if (!int.TryParse(strtracknum, out tracknum))
|
||||
throw new CueBrokenException("malformed track number");
|
||||
if (clp.EOF) throw new CueBrokenException("invalid cue structure");
|
||||
string strtracktype = clp.ReadToken().ToUpper();
|
||||
currTrack = new CueTrack();
|
||||
switch (strtracktype)
|
||||
{
|
||||
case "MODE1/2352": currTrack.TrackType = ECueTrackType.Mode1_2352; break;
|
||||
case "MODE1/2048": currTrack.TrackType = ECueTrackType.Mode1_2048; break;
|
||||
case "MODE2/2352": currTrack.TrackType = ECueTrackType.Mode2_2352; break;
|
||||
case "AUDIO": currTrack.TrackType = ECueTrackType.Audio; break;
|
||||
default:
|
||||
throw new CueBrokenException("unhandled track type");
|
||||
}
|
||||
currTrack.TrackNum = tracknum;
|
||||
currFile.Tracks.Add(currTrack);
|
||||
break;
|
||||
}
|
||||
case "INDEX":
|
||||
{
|
||||
if (currTrack == null) throw new CueBrokenException("invalid cue structure");
|
||||
if (clp.EOF) throw new CueBrokenException("invalid cue structure");
|
||||
string strindexnum = clp.ReadToken();
|
||||
int indexnum;
|
||||
if (!int.TryParse(strindexnum, out indexnum))
|
||||
throw new CueBrokenException("malformed index number");
|
||||
if (clp.EOF) throw new CueBrokenException("invalid cue structure (missing index timestamp)");
|
||||
string str_timestamp = clp.ReadToken();
|
||||
CueTrackIndex cti = new CueTrackIndex();
|
||||
cti.Timestamp = new CueTimestamp(str_timestamp); ;
|
||||
cti.IndexNum = indexnum;
|
||||
currTrack.Indexes[indexnum] = cti;
|
||||
break;
|
||||
}
|
||||
case "PREGAP":
|
||||
case "POSTGAP":
|
||||
throw new CueBrokenException("cue postgap/pregap command not supported yet");
|
||||
default:
|
||||
throw new CueBrokenException("unsupported cue command: " + key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class CueLineParser
|
||||
{
|
||||
int index;
|
||||
string str;
|
||||
public bool EOF;
|
||||
public CueLineParser(string line)
|
||||
{
|
||||
this.str = line;
|
||||
}
|
||||
|
||||
public string ReadPath() { return ReadToken(true); }
|
||||
public string ReadToken() { return ReadToken(false); }
|
||||
|
||||
public string ReadToken(bool isPath)
|
||||
{
|
||||
if (EOF) return null;
|
||||
int startIndex = index;
|
||||
bool inToken = false;
|
||||
bool inQuote = false;
|
||||
for (; ; )
|
||||
{
|
||||
bool done = false;
|
||||
char c = str[index];
|
||||
bool isWhiteSpace = (c == ' ' || c == '\t');
|
||||
|
||||
if (isWhiteSpace)
|
||||
{
|
||||
if (inQuote)
|
||||
index++;
|
||||
else
|
||||
{
|
||||
if (inToken)
|
||||
done = true;
|
||||
else
|
||||
index++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool startedQuote = false;
|
||||
if (!inToken)
|
||||
{
|
||||
startIndex = index;
|
||||
if (isPath && c == '"')
|
||||
startedQuote = inQuote = true;
|
||||
inToken = true;
|
||||
}
|
||||
switch (str[index])
|
||||
{
|
||||
case '"':
|
||||
index++;
|
||||
if (inQuote && !startedQuote)
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
index++;
|
||||
break;
|
||||
|
||||
default:
|
||||
index++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index == str.Length)
|
||||
{
|
||||
EOF = true;
|
||||
done = true;
|
||||
}
|
||||
if (done) break;
|
||||
}
|
||||
|
||||
return str.Substring(startIndex, index - startIndex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,313 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
|
||||
//TODO - reading big files across the network is slow due to the small sector read sizes. make some kind of read-ahead thing
|
||||
//TODO - add lead-in generation (so we can clarify the LBA addresses and have a place to put subcode perhaps)
|
||||
//the bin dumper will need to start at LBA 150
|
||||
|
||||
//http://www.pctechguide.com/iso-9660-data-format-for-cds-cd-roms-cd-rs-and-cd-rws
|
||||
//http://linux.die.net/man/1/cue2toc
|
||||
|
||||
//apparently cdrdao is the ultimate linux tool for doing this stuff but it doesnt support DAO96 (or other DAO modes) that would be necessary to extract P-Q subchannels
|
||||
//(cdrdao only supports R-W)
|
||||
|
||||
//good
|
||||
//http://linux-sxs.org/bedtime/cdapi.html
|
||||
//http://en.wikipedia.org/wiki/Track_%28CD%29
|
||||
//http://docs.google.com/viewer?a=v&q=cache:imNKye05zIEJ:www.13thmonkey.org/documentation/SCSI/mmc-r10a.pdf+q+subchannel+TOC+format&hl=en&gl=us&pid=bl&srcid=ADGEEShtYqlluBX2lgxTL3pVsXwk6lKMIqSmyuUCX4RJ3DntaNq5vI2pCvtkyze-fumj7vvrmap6g1kOg5uAVC0IxwU_MRhC5FB0c_PQ2BlZQXDD7P3GeNaAjDeomelKaIODrhwOoFNb&sig=AHIEtbRXljAcFjeBn3rMb6tauHWjSNMYrw
|
||||
//r:\consoles\~docs\yellowbook
|
||||
//http://digitalx.org/cue-sheet/examples/
|
||||
//
|
||||
|
||||
//"qemu cdrom emulator"
|
||||
//http://www.koders.com/c/fid7171440DEC7C18B932715D671DEE03743111A95A.aspx
|
||||
|
||||
//less good
|
||||
//http://www.cyberciti.biz/faq/getting-volume-information-from-cds-iso-images/
|
||||
//http://www.cims.nyu.edu/cgi-systems/man.cgi?section=7I&topic=cdio
|
||||
|
||||
//ideas:
|
||||
/*
|
||||
* do some stuff asynchronously. for example, decoding mp3 sectors.
|
||||
* keep a list of 'blobs' (giant bins or decoded wavs likely) which can reference the disk
|
||||
* keep a list of sectors and the blob/offset from which they pull -- also whether the sector is available
|
||||
* if it is not available and something requests it then it will have to block while that sector gets generated
|
||||
* perhaps the blobs know how to resolve themselves and the requested sector can be immediately resolved (priority boost)
|
||||
* mp3 blobs should be hashed and dropped in %TEMP% as a wav decode
|
||||
*/
|
||||
|
||||
//here is an MIT licensed C mp3 decoder
|
||||
//http://core.fluendo.com/gstreamer/src/gst-fluendo-mp3/
|
||||
|
||||
/*information on saturn TOC and session data structures is on pdf page 58 of System Library User's Manual;
|
||||
* as seen in yabause, there are 1000 u32s in this format:
|
||||
* Ctrl[4bit] Adr[4bit] StartFrameAddressFAD[24bit] (nonexisting tracks are 0xFFFFFFFF)
|
||||
* Followed by Fist Track Information, Last Track Information..
|
||||
* Ctrl[4bit] Adr[4bit] FirstTrackNumber/LastTrackNumber[8bit] and then some stuff I dont understand
|
||||
* ..and Read Out Information:
|
||||
* Ctrl[4bit] Adr[4bit] ReadOutStartFrameAddress[24bit]
|
||||
*
|
||||
* Also there is some stuff about FAD of sessions.
|
||||
* This should be generated by the saturn core, but we need to make sure we pass down enough information to do it
|
||||
*/
|
||||
|
||||
//2048 bytes packed into 2352:
|
||||
//12 bytes sync(00 ff ff ff ff ff ff ff ff ff ff 00)
|
||||
//3 bytes sector address (min+A0),sec,frac //does this correspond to ccd `point` field in the TOC entries?
|
||||
//sector mode byte (0: silence; 1: 2048Byte mode (EDC,ECC,CIRC), 2: 2352Byte mode (CIRC only)
|
||||
//user data: 2336 bytes
|
||||
//cue sheets may use mode1_2048 (and the error coding needs to be regenerated to get accurate raw data) or mode1_2352 (the entire sector is present)
|
||||
//mode2_2352 is the only kind of mode2, by necessity
|
||||
//audio is a different mode, seems to be just 2352 bytes with no sync, header or error correction. i guess the CIRC error correction is still there
|
||||
|
||||
namespace BizHawk.Disc
|
||||
{
|
||||
|
||||
public partial class Disc
|
||||
{
|
||||
public interface ISector
|
||||
{
|
||||
int Read(byte[] buffer, int offset);
|
||||
}
|
||||
|
||||
public interface IBlob
|
||||
{
|
||||
int Read(long byte_pos, byte[] buffer, int offset, int count);
|
||||
void Dispose();
|
||||
}
|
||||
|
||||
class Blob_RawFile : IBlob
|
||||
{
|
||||
public string PhysicalPath;
|
||||
public long Offset;
|
||||
|
||||
FileStream fs;
|
||||
public void Dispose()
|
||||
{
|
||||
if (fs != null)
|
||||
{
|
||||
fs.Dispose();
|
||||
fs = null;
|
||||
}
|
||||
}
|
||||
public int Read(long byte_pos, byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (fs == null)
|
||||
fs = new FileStream(PhysicalPath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
long target = byte_pos + Offset;
|
||||
if(fs.Position != target)
|
||||
fs.Position = target;
|
||||
return fs.Read(buffer, offset, count);
|
||||
}
|
||||
}
|
||||
|
||||
class Sector_RawSilence : ISector
|
||||
{
|
||||
public int Read(byte[] buffer, int offset)
|
||||
{
|
||||
Array.Clear(buffer, 0, 2352);
|
||||
return 2352;
|
||||
}
|
||||
}
|
||||
|
||||
class Sector_RawBlob : ISector
|
||||
{
|
||||
public IBlob Blob;
|
||||
public long Offset;
|
||||
public int Read(byte[] buffer, int offset)
|
||||
{
|
||||
return Blob.Read(Offset, buffer, offset, 2352);
|
||||
}
|
||||
}
|
||||
|
||||
class Sector_ZeroPad : ISector
|
||||
{
|
||||
public ISector BaseSector;
|
||||
public int BaseLength;
|
||||
public int Read(byte[] buffer, int offset)
|
||||
{
|
||||
int read = BaseSector.Read(buffer, offset);
|
||||
if(read < BaseLength) return read;
|
||||
for (int i = BaseLength; i < 2352; i++)
|
||||
buffer[offset + i] = 0;
|
||||
return 2352;
|
||||
}
|
||||
}
|
||||
|
||||
class Sector_Raw : ISector
|
||||
{
|
||||
public ISector BaseSector;
|
||||
public int Read(byte[] buffer, int offset)
|
||||
{
|
||||
return BaseSector.Read(buffer, offset);
|
||||
}
|
||||
}
|
||||
|
||||
protected static byte BCD_Byte(byte val)
|
||||
{
|
||||
byte ret = (byte)(val % 10);
|
||||
ret += (byte)(16 * (val / 10));
|
||||
return ret;
|
||||
}
|
||||
|
||||
//a blob that also has an ECM cache associated with it. maybe one day.
|
||||
class ECMCacheBlob
|
||||
{
|
||||
public ECMCacheBlob(IBlob blob)
|
||||
{
|
||||
BaseBlob = blob;
|
||||
}
|
||||
public IBlob BaseBlob;
|
||||
}
|
||||
|
||||
class Sector_Mode1_2048 : ISector
|
||||
{
|
||||
public Sector_Mode1_2048(int LBA)
|
||||
{
|
||||
byte lba_min = (byte)(LBA / 60 / 75);
|
||||
byte lba_sec = (byte)((LBA / 75) % 60);
|
||||
byte lba_frac = (byte)(LBA % 75);
|
||||
bcd_lba_min = BCD_Byte(lba_min);
|
||||
bcd_lba_sec = BCD_Byte(lba_sec);
|
||||
bcd_lba_frac = BCD_Byte(lba_frac);
|
||||
}
|
||||
byte bcd_lba_min, bcd_lba_sec, bcd_lba_frac;
|
||||
|
||||
public ECMCacheBlob Blob;
|
||||
public long Offset;
|
||||
byte[] extra_data;
|
||||
bool has_extra_data;
|
||||
public int Read(byte[] buffer, int offset)
|
||||
{
|
||||
//user data
|
||||
int read = Blob.BaseBlob.Read(Offset, buffer, offset + 16, 2048);
|
||||
|
||||
//if we read the 2048 physical bytes OK, then return the complete sector
|
||||
if (read == 2048 && has_extra_data)
|
||||
{
|
||||
Buffer.BlockCopy(extra_data, 0, buffer, offset, 16);
|
||||
Buffer.BlockCopy(extra_data, 16, buffer, offset + 2064, 4 + 8 + 172 + 104);
|
||||
return 2352;
|
||||
}
|
||||
|
||||
//sync
|
||||
buffer[offset + 0] = 0x00; buffer[offset + 1] = 0xFF; buffer[offset + 2] = 0xFF; buffer[offset + 3] = 0xFF;
|
||||
buffer[offset + 4] = 0xFF; buffer[offset + 5] = 0xFF; buffer[offset + 6] = 0xFF; buffer[offset + 7] = 0xFF;
|
||||
buffer[offset + 8] = 0xFF; buffer[offset + 9] = 0xFF; buffer[offset + 10] = 0xFF; buffer[offset + 11] = 0x00;
|
||||
//sector address
|
||||
buffer[offset + 12] = bcd_lba_min;
|
||||
buffer[offset + 13] = bcd_lba_sec;
|
||||
buffer[offset + 14] = bcd_lba_frac;
|
||||
//mode 1
|
||||
buffer[offset + 15] = 1;
|
||||
//EDC
|
||||
ECM.edc_computeblock(buffer, offset+2064, buffer, offset+2064);
|
||||
//intermediate
|
||||
for (int i = 0; i < 8; i++) buffer[offset + 2068 + i] = 0;
|
||||
//ECC
|
||||
ECM.ecc_generate(buffer, offset, false, buffer, offset+2076);
|
||||
|
||||
//if we read the 2048 physical bytes OK, then return the complete sector
|
||||
if (read == 2048)
|
||||
{
|
||||
extra_data = new byte[16 + 4 + 8 + 172 + 104];
|
||||
Buffer.BlockCopy(buffer, 0, extra_data, 0, 16);
|
||||
Buffer.BlockCopy(buffer, 2064, extra_data, 16, 4 + 8 + 172 + 104);
|
||||
has_extra_data = true;
|
||||
return 2352;
|
||||
}
|
||||
//otherwise, return a smaller value to indicate an error
|
||||
else return read;
|
||||
}
|
||||
}
|
||||
|
||||
//this is a physical 2352 byte sector.
|
||||
public class SectorEntry
|
||||
{
|
||||
public ISector Sector;
|
||||
}
|
||||
|
||||
public List<IBlob> Blobs = new List<IBlob>();
|
||||
public List<SectorEntry> Sectors = new List<SectorEntry>();
|
||||
public DiscTOC TOC = new DiscTOC();
|
||||
|
||||
void FromIsoPathInternal(string isoPath)
|
||||
{
|
||||
var session = new DiscTOC.Session();
|
||||
session.num = 1;
|
||||
TOC.Sessions.Add(session);
|
||||
var track = new DiscTOC.Track();
|
||||
track.num = 1;
|
||||
session.Tracks.Add(track);
|
||||
var index = new DiscTOC.Index();
|
||||
index.num = 0;
|
||||
track.Indexes.Add(index);
|
||||
index = new DiscTOC.Index();
|
||||
index.num = 1;
|
||||
track.Indexes.Add(index);
|
||||
|
||||
var fiIso = new FileInfo(isoPath);
|
||||
Blob_RawFile blob = new Blob_RawFile();
|
||||
blob.PhysicalPath = fiIso.FullName;
|
||||
Blobs.Add(blob);
|
||||
int num_lba = (int)(fiIso.Length / 2048);
|
||||
index.length_lba = num_lba;
|
||||
if (fiIso.Length % 2048 != 0)
|
||||
throw new InvalidOperationException("invalid iso file (size not multiple of 2048)");
|
||||
|
||||
var ecmCacheBlob = new ECMCacheBlob(blob);
|
||||
for (int i = 0; i < num_lba; i++)
|
||||
{
|
||||
Sector_Mode1_2048 sector = new Sector_Mode1_2048(i+150);
|
||||
sector.Blob = ecmCacheBlob;
|
||||
sector.Offset = i * 2048;
|
||||
SectorEntry se = new SectorEntry();
|
||||
se.Sector = sector;
|
||||
Sectors.Add(se);
|
||||
}
|
||||
|
||||
TOC.AnalyzeLengthsFromIndexLengths();
|
||||
}
|
||||
|
||||
public void DumpBin_2352(string binPath)
|
||||
{
|
||||
byte[] temp = new byte[2352];
|
||||
using(FileStream fs = new FileStream(binPath,FileMode.Create,FileAccess.Write,FileShare.None))
|
||||
for (int i = 0; i < Sectors.Count; i++)
|
||||
{
|
||||
ReadLBA(i, temp, 0);
|
||||
fs.Write(temp, 0, 2352);
|
||||
}
|
||||
}
|
||||
|
||||
//main api for reading a 2352-byte LBA from a disc
|
||||
public void ReadLBA(int fad, byte[] buffer, int offset)
|
||||
{
|
||||
Sectors[fad].Sector.Read(buffer, offset);
|
||||
}
|
||||
|
||||
//main api for reading the TOC from a disc
|
||||
public DiscTOC ReadTOC()
|
||||
{
|
||||
return TOC;
|
||||
}
|
||||
|
||||
public static Disc FromCuePath(string cuePath)
|
||||
{
|
||||
var ret = new Disc();
|
||||
ret.FromCuePathInternal(cuePath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Disc FromIsoPath(string isoPath)
|
||||
{
|
||||
var ret = new Disc();
|
||||
ret.FromIsoPathInternal(isoPath);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Disc
|
||||
{
|
||||
|
||||
public class DiscTOC
|
||||
{
|
||||
public class Session
|
||||
{
|
||||
public int num;
|
||||
public List<Track> Tracks = new List<Track>();
|
||||
|
||||
//the length of the track (should be the sum of all track lengths)
|
||||
public int length_lba;
|
||||
}
|
||||
|
||||
public class Track
|
||||
{
|
||||
public int num;
|
||||
public List<Index> Indexes = new List<Index>();
|
||||
|
||||
//the length of the track (should be the sum of all index lengths)
|
||||
public int length_lba;
|
||||
}
|
||||
|
||||
public class Index
|
||||
{
|
||||
public int num;
|
||||
public int lba;
|
||||
|
||||
//the length of the section
|
||||
public int length_lba;
|
||||
}
|
||||
|
||||
public static string FormatLBA(int lba)
|
||||
{
|
||||
return string.Format("{0} ({1:D2}:{2:D2}:{3:D2})", lba, lba / 60 / 75, (lba / 75) % 60, lba % 75);
|
||||
}
|
||||
|
||||
public string DebugPrint()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach (var session in Sessions)
|
||||
{
|
||||
sb.AppendFormat("SESSION {0:D2} (length={1})\n", session.num, session.length_lba);
|
||||
foreach (var track in session.Tracks)
|
||||
{
|
||||
sb.AppendFormat(" TRACK {0:D2} (length={1})\n", track.num, track.length_lba);
|
||||
foreach (var index in track.Indexes)
|
||||
{
|
||||
sb.AppendFormat(" INDEX {0:D2}: {1}\n", index.num, FormatLBA(index.lba));
|
||||
}
|
||||
}
|
||||
sb.AppendFormat("-EOF-\n");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public List<Session> Sessions = new List<Session>();
|
||||
public int length_lba;
|
||||
|
||||
public void AnalyzeLengthsFromIndexLengths()
|
||||
{
|
||||
foreach (var session in Sessions)
|
||||
{
|
||||
foreach (var track in session.Tracks)
|
||||
{
|
||||
int track_size = 0;
|
||||
foreach (var index in track.Indexes)
|
||||
track_size += index.length_lba;
|
||||
track.length_lba += track_size;
|
||||
session.length_lba += track_size;
|
||||
length_lba += track_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
namespace BizHawk.Disc
|
||||
{
|
||||
static class ECM
|
||||
{
|
||||
static byte[] ecc_f_lut = new byte[256];
|
||||
static byte[] ecc_b_lut = new byte[256];
|
||||
static uint[] edc_lut = new uint[256];
|
||||
|
||||
static ECM()
|
||||
{
|
||||
uint i, j, edc;
|
||||
for(i = 0; i < 256; i++)
|
||||
{
|
||||
j = (uint)((i << 1) ^ (((i & 0x80) != 0) ? 0x11D : 0));
|
||||
ecc_f_lut[i] = (byte)j;
|
||||
ecc_b_lut[i ^ j] = (byte)i;
|
||||
edc = i;
|
||||
for (j = 0; j < 8; j++)
|
||||
edc = (edc >> 1) ^ (((edc & 1) != 0) ? 0xD8018001 : 0);
|
||||
edc_lut[i] = edc;
|
||||
}
|
||||
}
|
||||
|
||||
static uint edc_partial_computeblock(uint edc, byte[] src, int count)
|
||||
{
|
||||
int i = 0;
|
||||
while (count-- != 0) edc = (edc >> 8) ^ edc_lut[(edc ^ (src[i++])) & 0xFF];
|
||||
return edc;
|
||||
}
|
||||
|
||||
public static void edc_computeblock(byte[] src, int count, byte[] dest, int dest_offset)
|
||||
{
|
||||
uint edc = edc_partial_computeblock(0, src, count);
|
||||
dest[dest_offset + 0] = (byte)((edc >> 0) & 0xFF);
|
||||
dest[dest_offset + 1] = (byte)((edc >> 8) & 0xFF);
|
||||
dest[dest_offset + 2] = (byte)((edc >> 16) & 0xFF);
|
||||
dest[dest_offset + 3] = (byte)((edc >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
static void ecc_computeblock(byte[] src, int src_offset, uint major_count, uint minor_count,uint major_mult, uint minor_inc, byte[] dest, int dest_offset)
|
||||
{
|
||||
uint size = major_count * minor_count;
|
||||
uint major, minor;
|
||||
for (major = 0; major < major_count; major++)
|
||||
{
|
||||
uint index = (major >> 1) * major_mult + (major & 1);
|
||||
byte ecc_a = 0;
|
||||
byte ecc_b = 0;
|
||||
for (minor = 0; minor < minor_count; minor++)
|
||||
{
|
||||
byte temp = src[src_offset+index];
|
||||
index += minor_inc;
|
||||
if (index >= size) index -= size;
|
||||
ecc_a ^= temp;
|
||||
ecc_b ^= temp;
|
||||
ecc_a = ecc_f_lut[ecc_a];
|
||||
//System.Console.WriteLine("{0} {1}", ecc_a, ecc_b);
|
||||
}
|
||||
ecc_a = ecc_b_lut[ecc_f_lut[ecc_a] ^ ecc_b];
|
||||
dest[dest_offset + major] = ecc_a;
|
||||
dest[dest_offset + major + major_count] = (byte)(ecc_a ^ ecc_b);
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe static void ecc_generate(byte[] sector, int sector_offset, bool zeroaddress, byte[] dest, int dest_offset)
|
||||
{
|
||||
byte address0=0,address1=0,address2=0,address3=0;
|
||||
byte i;
|
||||
/* Save the address and zero it out */
|
||||
if(zeroaddress)
|
||||
{
|
||||
address0 = sector[sector_offset + 12 + 0]; sector[sector_offset + 12 + 0] = 0;
|
||||
address1 = sector[sector_offset + 12 + 1]; sector[sector_offset + 12 + 1] = 0;
|
||||
address2 = sector[sector_offset + 12 + 2]; sector[sector_offset + 12 + 2] = 0;
|
||||
address3 = sector[sector_offset + 12 + 3]; sector[sector_offset + 12 + 3] = 0;
|
||||
}
|
||||
/* Compute ECC P code */
|
||||
ecc_computeblock(sector, sector_offset + 0xC, 86, 24, 2, 86, dest, dest_offset);
|
||||
/* Compute ECC Q code */
|
||||
ecc_computeblock(sector, sector_offset + 0xC, 52, 43, 86, 88, dest, dest_offset+172);
|
||||
/* Restore the address */
|
||||
if (zeroaddress)
|
||||
{
|
||||
sector[sector_offset + 12 + 0] = address0;
|
||||
sector[sector_offset + 12 + 3] = address1;
|
||||
sector[sector_offset + 12 + 2] = address2;
|
||||
sector[sector_offset + 12 + 1] = address3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,426 @@
|
|||
////http://jasonjano.wordpress.com/2010/02/09/a-simple-c-wrapper-for-ffmpeg/
|
||||
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Linq;
|
||||
//using System.Web;
|
||||
//using System.IO;
|
||||
//using System.Diagnostics;
|
||||
//using System.Configuration;
|
||||
//using System.Text.RegularExpressions;
|
||||
|
||||
//namespace ffMpeg
|
||||
//{
|
||||
// public class Converter
|
||||
// {
|
||||
// #region Properties
|
||||
// public string _ffExe;
|
||||
|
||||
// //i.e. temp
|
||||
// public string WorkingPath;
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region Constructors
|
||||
// public Converter()
|
||||
// {
|
||||
// Initialize();
|
||||
// }
|
||||
// public Converter(string ffmpegExePath)
|
||||
// {
|
||||
// _ffExe = ffmpegExePath;
|
||||
// Initialize();
|
||||
// }
|
||||
// #endregion
|
||||
|
||||
// #region Initialization
|
||||
// private void Initialize()
|
||||
// {
|
||||
// }
|
||||
|
||||
// private string GetWorkingFile()
|
||||
// {
|
||||
// //try the stated directory
|
||||
// if (File.Exists(_ffExe))
|
||||
// {
|
||||
// return _ffExe;
|
||||
// }
|
||||
|
||||
// //oops, that didn't work, try the base directory
|
||||
// if (File.Exists(Path.GetFileName(_ffExe)))
|
||||
// {
|
||||
// return Path.GetFileName(_ffExe);
|
||||
// }
|
||||
|
||||
// //well, now we are really unlucky, let's just return null
|
||||
// return null;
|
||||
// }
|
||||
// #endregion
|
||||
|
||||
// #region Get the File without creating a file lock
|
||||
// public static System.Drawing.Image LoadImageFromFile(string fileName)
|
||||
// {
|
||||
// System.Drawing.Image theImage = null;
|
||||
// using (FileStream fileStream = new FileStream(fileName, FileMode.Open,
|
||||
// FileAccess.Read))
|
||||
// {
|
||||
// byte[] img;
|
||||
// img = new byte[fileStream.Length];
|
||||
// fileStream.Read(img, 0, img.Length);
|
||||
// fileStream.Close();
|
||||
// theImage = System.Drawing.Image.FromStream(new MemoryStream(img));
|
||||
// img = null;
|
||||
// }
|
||||
// GC.Collect();
|
||||
// return theImage;
|
||||
// }
|
||||
|
||||
// public static MemoryStream LoadMemoryStreamFromFile(string fileName)
|
||||
// {
|
||||
// MemoryStream ms = null;
|
||||
// using (FileStream fileStream = new FileStream(fileName, FileMode.Open,
|
||||
// FileAccess.Read))
|
||||
// {
|
||||
// byte[] fil;
|
||||
// fil = new byte[fileStream.Length];
|
||||
// fileStream.Read(fil, 0, fil.Length);
|
||||
// fileStream.Close();
|
||||
// ms = new MemoryStream(fil);
|
||||
// }
|
||||
// GC.Collect();
|
||||
// return ms;
|
||||
// }
|
||||
// #endregion
|
||||
|
||||
// #region Run the process
|
||||
// private string RunProcess(string Parameters)
|
||||
// {
|
||||
// //create a process info
|
||||
// ProcessStartInfo oInfo = new ProcessStartInfo(this._ffExe, Parameters);
|
||||
// oInfo.UseShellExecute = false;
|
||||
// oInfo.CreateNoWindow = true;
|
||||
// oInfo.RedirectStandardOutput = true;
|
||||
// oInfo.RedirectStandardError = true;
|
||||
|
||||
// //Create the output and streamreader to get the output
|
||||
// string output = null; StreamReader srOutput = null;
|
||||
|
||||
// //try the process
|
||||
// try
|
||||
// {
|
||||
// //run the process
|
||||
// Process proc = System.Diagnostics.Process.Start(oInfo);
|
||||
|
||||
// proc.WaitForExit();
|
||||
|
||||
// //get the output
|
||||
// srOutput = proc.StandardError;
|
||||
|
||||
// //now put it in a string
|
||||
// output = srOutput.ReadToEnd();
|
||||
|
||||
// proc.Close();
|
||||
// }
|
||||
// catch (Exception)
|
||||
// {
|
||||
// output = string.Empty;
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// //now, if we succeded, close out the streamreader
|
||||
// if (srOutput != null)
|
||||
// {
|
||||
// srOutput.Close();
|
||||
// srOutput.Dispose();
|
||||
// }
|
||||
// }
|
||||
// return output;
|
||||
// }
|
||||
// #endregion
|
||||
|
||||
// #region GetVideoInfo
|
||||
// public VideoFile GetVideoInfo(MemoryStream inputFile, string Filename)
|
||||
// {
|
||||
// string tempfile = Path.Combine(this.WorkingPath, System.Guid.NewGuid().ToString() + Path.GetExtension(Filename));
|
||||
// FileStream fs = File.Create(tempfile);
|
||||
// inputFile.WriteTo(fs);
|
||||
// fs.Flush();
|
||||
// fs.Close();
|
||||
// GC.Collect();
|
||||
|
||||
// VideoFile vf = null;
|
||||
// try
|
||||
// {
|
||||
// vf = new VideoFile(tempfile);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// throw ex;
|
||||
// }
|
||||
|
||||
// GetVideoInfo(vf);
|
||||
|
||||
// try
|
||||
// {
|
||||
// File.Delete(tempfile);
|
||||
// }
|
||||
// catch (Exception)
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
// return vf;
|
||||
// }
|
||||
// public VideoFile GetVideoInfo(string inputPath)
|
||||
// {
|
||||
// VideoFile vf = null;
|
||||
// try
|
||||
// {
|
||||
// vf = new VideoFile(inputPath);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// throw ex;
|
||||
// }
|
||||
// GetVideoInfo(vf);
|
||||
// return vf;
|
||||
// }
|
||||
// public void GetVideoInfo(VideoFile input)
|
||||
// {
|
||||
// //set up the parameters for video info
|
||||
// string Params = string.Format("-i {0}", input.Path);
|
||||
// string output = RunProcess(Params);
|
||||
// input.RawInfo = output;
|
||||
|
||||
// //get duration
|
||||
// Regex re = new Regex("[D|d]uration:.((\\d|:|\\.)*)");
|
||||
// Match m = re.Match(input.RawInfo);
|
||||
|
||||
// if (m.Success)
|
||||
// {
|
||||
// string duration = m.Groups[1].Value;
|
||||
// string[] timepieces = duration.Split(new char[] { ':', '.' });
|
||||
// if (timepieces.Length == 4)
|
||||
// {
|
||||
// input.Duration = new TimeSpan(0, Convert.ToInt16(timepieces[0]), Convert.ToInt16(timepieces[1]), Convert.ToInt16(timepieces[2]), Convert.ToInt16(timepieces[3]));
|
||||
// }
|
||||
// }
|
||||
|
||||
// //get audio bit rate
|
||||
// re = new Regex("[B|b]itrate:.((\\d|:)*)");
|
||||
// m = re.Match(input.RawInfo);
|
||||
// double kb = 0.0;
|
||||
// if (m.Success)
|
||||
// {
|
||||
// Double.TryParse(m.Groups[1].Value, out kb);
|
||||
// }
|
||||
// input.BitRate = kb;
|
||||
|
||||
// //get the audio format
|
||||
// re = new Regex("[A|a]udio:.*");
|
||||
// m = re.Match(input.RawInfo);
|
||||
// if (m.Success)
|
||||
// {
|
||||
// input.AudioFormat = m.Value;
|
||||
// }
|
||||
|
||||
// //get the video format
|
||||
// re = new Regex("[V|v]ideo:.*");
|
||||
// m = re.Match(input.RawInfo);
|
||||
// if (m.Success)
|
||||
// {
|
||||
// input.VideoFormat = m.Value;
|
||||
// }
|
||||
|
||||
// //get the video format
|
||||
// re = new Regex("(\\d{2,3})x(\\d{2,3})");
|
||||
// m = re.Match(input.RawInfo);
|
||||
// if (m.Success)
|
||||
// {
|
||||
// int width = 0; int height = 0;
|
||||
// int.TryParse(m.Groups[1].Value, out width);
|
||||
// int.TryParse(m.Groups[2].Value, out height);
|
||||
// input.Width = width;
|
||||
// input.Height = height;
|
||||
// }
|
||||
// input.infoGathered = true;
|
||||
// }
|
||||
// #endregion
|
||||
|
||||
// #region Convert to FLV
|
||||
// public OutputPackage ConvertToFLV(MemoryStream inputFile, string Filename)
|
||||
// {
|
||||
// string tempfile = Path.Combine(this.WorkingPath, System.Guid.NewGuid().ToString() + Path.GetExtension(Filename));
|
||||
// FileStream fs = File.Create(tempfile);
|
||||
// inputFile.WriteTo(fs);
|
||||
// fs.Flush();
|
||||
// fs.Close();
|
||||
// GC.Collect();
|
||||
|
||||
// VideoFile vf = null;
|
||||
// try
|
||||
// {
|
||||
// vf = new VideoFile(tempfile);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// throw ex;
|
||||
// }
|
||||
|
||||
// OutputPackage oo = ConvertToFLV(vf);
|
||||
|
||||
// try
|
||||
// {
|
||||
// File.Delete(tempfile);
|
||||
// }
|
||||
// catch (Exception)
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
// return oo;
|
||||
// }
|
||||
// public OutputPackage ConvertToFLV(string inputPath)
|
||||
// {
|
||||
// VideoFile vf = null;
|
||||
// try
|
||||
// {
|
||||
// vf = new VideoFile(inputPath);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// throw ex;
|
||||
// }
|
||||
|
||||
// OutputPackage oo = ConvertToFLV(vf);
|
||||
// return oo;
|
||||
// }
|
||||
// public OutputPackage ConvertToFLV(VideoFile input)
|
||||
// {
|
||||
// if (!input.infoGathered)
|
||||
// {
|
||||
// GetVideoInfo(input);
|
||||
// }
|
||||
// OutputPackage ou = new OutputPackage();
|
||||
|
||||
// //set up the parameters for getting a previewimage
|
||||
// string filename = System.Guid.NewGuid().ToString() + ".jpg";
|
||||
// int secs;
|
||||
|
||||
// //divide the duration in 3 to get a preview image in the middle of the clip
|
||||
// //instead of a black image from the beginning.
|
||||
// secs = (int)Math.Round(TimeSpan.FromTicks(input.Duration.Ticks / 3).TotalSeconds, 0);
|
||||
|
||||
// string finalpath = Path.Combine(this.WorkingPath, filename);
|
||||
// string Params = string.Format("-i {0} {1} -vcodec mjpeg -ss {2} -vframes 1 -an -f rawvideo", input.Path, finalpath, secs);
|
||||
// string output = RunProcess(Params);
|
||||
|
||||
// ou.RawOutput = output;
|
||||
|
||||
// if (File.Exists(finalpath))
|
||||
// {
|
||||
// ou.PreviewImage = LoadImageFromFile(finalpath);
|
||||
// try
|
||||
// {
|
||||
// File.Delete(finalpath);
|
||||
// }
|
||||
// catch (Exception) { }
|
||||
// }
|
||||
// else
|
||||
// { //try running again at frame 1 to get something
|
||||
// Params = string.Format("-i {0} {1} -vcodec mjpeg -ss {2} -vframes 1 -an -f rawvideo", input.Path, finalpath, 1);
|
||||
// output = RunProcess(Params);
|
||||
|
||||
// ou.RawOutput = output;
|
||||
|
||||
// if (File.Exists(finalpath))
|
||||
// {
|
||||
// ou.PreviewImage = LoadImageFromFile(finalpath);
|
||||
// try
|
||||
// {
|
||||
// File.Delete(finalpath);
|
||||
// }
|
||||
// catch (Exception) { }
|
||||
// }
|
||||
// }
|
||||
|
||||
// finalpath = Path.Combine(this.WorkingPath, filename);
|
||||
// filename = System.Guid.NewGuid().ToString() + ".flv";
|
||||
// Params = string.Format("-i {0} -y -ar 22050 -ab 64 -f flv {1}", input.Path, finalpath);
|
||||
// output = RunProcess(Params);
|
||||
|
||||
// if (File.Exists(finalpath))
|
||||
// {
|
||||
// ou.VideoStream = LoadMemoryStreamFromFile(finalpath);
|
||||
// try
|
||||
// {
|
||||
// File.Delete(finalpath);
|
||||
// }
|
||||
// catch (Exception) { }
|
||||
// }
|
||||
// return ou;
|
||||
// }
|
||||
// #endregion
|
||||
// }
|
||||
|
||||
// public class VideoFile
|
||||
// {
|
||||
// #region Properties
|
||||
// private string _Path;
|
||||
// public string Path
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return _Path;
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// _Path = value;
|
||||
// }
|
||||
// }
|
||||
|
||||
// public TimeSpan Duration { get; set; }
|
||||
// public double BitRate { get; set; }
|
||||
// public string AudioFormat { get; set; }
|
||||
// public string VideoFormat { get; set; }
|
||||
// public int Height { get; set; }
|
||||
// public int Width { get; set; }
|
||||
// public string RawInfo { get; set; }
|
||||
// public bool infoGathered { get; set; }
|
||||
// #endregion
|
||||
|
||||
// #region Constructors
|
||||
// public VideoFile(string path)
|
||||
// {
|
||||
// _Path = path;
|
||||
// Initialize();
|
||||
// }
|
||||
// #endregion
|
||||
|
||||
// #region Initialization
|
||||
// private void Initialize()
|
||||
// {
|
||||
// this.infoGathered = false;
|
||||
// //first make sure we have a value for the video file setting
|
||||
// if (string.IsNullOrEmpty(_Path))
|
||||
// {
|
||||
// throw new Exception("Could not find the location of the video file");
|
||||
// }
|
||||
|
||||
// //Now see if the video file exists
|
||||
// if (!File.Exists(_Path))
|
||||
// {
|
||||
// throw new Exception("The video file " + _Path + " does not exist.");
|
||||
// }
|
||||
// }
|
||||
// #endregion
|
||||
// }
|
||||
|
||||
// public class OutputPackage
|
||||
// {
|
||||
// public MemoryStream VideoStream { get; set; }
|
||||
// public System.Drawing.Image PreviewImage { get; set; }
|
||||
// public string RawOutput { get; set; }
|
||||
// public bool Success { get; set; }
|
||||
// }
|
||||
//}
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Disc
|
||||
{
|
||||
//TBD TOC format
|
||||
public class TOCFormat
|
||||
{
|
||||
}
|
||||
}
|
|
@ -69,7 +69,8 @@
|
|||
public string LuaPath = ".\\Lua";
|
||||
public string WatchPath = ".";
|
||||
public string AVIPath = ".";
|
||||
|
||||
|
||||
public string FFMpegPath = "ffmpeg.exe";
|
||||
|
||||
// General Client Settings
|
||||
public int TargetZoomFactor = 2;
|
||||
|
|
10
BizHawk.sln
10
BizHawk.sln
|
@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizHawk.Util", "BizHawk.Uti
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizHawk.MultiClient", "BizHawk.MultiClient\BizHawk.MultiClient.csproj", "{DD448B37-BA3F-4544-9754-5406E8094723}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscoHawk", "DiscoHawk\DiscoHawk.csproj", "{C4366030-6D03-424B-AE53-F4F43BB217C3}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -25,10 +27,10 @@ Global
|
|||
{DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DD448B37-BA3F-4544-9754-5406E8094723}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DD448B37-BA3F-4544-9754-5406E8094723}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C43F8BCA-CB5F-47CF-A0BD-B32ED49423BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C43F8BCA-CB5F-47CF-A0BD-B32ED49423BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C43F8BCA-CB5F-47CF-A0BD-B32ED49423BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C43F8BCA-CB5F-47CF-A0BD-B32ED49423BA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace BizHawk
|
||||
{
|
||||
class DiscoHawk
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
new DiscoHawk().Run(args);
|
||||
}
|
||||
|
||||
void Run(string[] args)
|
||||
{
|
||||
//string testfile = @"d:\Radiant Silvergun (J)\Radiant Silvergun (J).cue";
|
||||
//var disc = Disc.Disc.FromCuePath(testfile);
|
||||
|
||||
//string testfile = @"r:\isos\memtest86-3.2.iso";
|
||||
//var disc = Disc.Disc.FromIsoPath(testfile);
|
||||
|
||||
//Console.WriteLine(disc.ReadTOC().DebugPrint());
|
||||
//disc.DumpBin_2352("d:\\test.2352");
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{C4366030-6D03-424B-AE53-F4F43BB217C3}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>DiscoHawk</RootNamespace>
|
||||
<AssemblyName>DiscoHawk</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\BizHawk.MultiClient\output\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BizHawk.Emulation\BizHawk.Emulation.csproj">
|
||||
<Project>{197D4314-8A9F-49BA-977D-54ACEFAEB6BA}</Project>
|
||||
<Name>BizHawk.Emulation</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\BizHawk.Util\BizHawk.Util.csproj">
|
||||
<Project>{EE135301-08B3-4EFC-A61C-1C53E1C65CB9}</Project>
|
||||
<Name>BizHawk.Util</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="DiscoHawk.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in New Issue