some work on the disc system

This commit is contained in:
zeromus 2011-06-20 09:09:21 +00:00
parent ca628e6278
commit 35f2691666
8 changed files with 895 additions and 557 deletions

View File

@ -4,6 +4,8 @@ using System.Text.RegularExpressions;
using System.IO;
using System.Collections.Generic;
//this rule is not supported correctly: `The first track number can be greater than one, but all track numbers after the first must be sequential.`
namespace BizHawk.Disc
{
partial class Disc
@ -17,157 +19,202 @@ namespace BizHawk.Disc
var session = new DiscTOC.Session();
session.num = 1;
TOC.Sessions.Add(session);
var pregap_sector = new Sector_Zero();
int curr_track = 1;
int track_counter = 1;
int curr_lba = 0;
foreach (var cue_file in cue.Files)
{
//make a raw file blob for the source binfile
//structural validation
if (cue_file.Tracks.Count < 1) throw new Cue.CueBrokenException("`You must specify at least one track per file.`");
int blob_sectorsize = Cue.BINSectorSizeForTrackType(cue_file.Tracks[0].TrackType);
//make a blob for the file
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");
int blob_length_lba = (int)(blob.Length / blob_sectorsize);
int blob_leftover = (int)(blob.Length - blob_length_lba * blob_sectorsize);
//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++)
//TODO - make CueTimestamp better, and also make it a struct, and also just make it DiscTimestamp
//TODO - wav handling
//TODO - mp3 decode
//start timekeeping for the blob. every time we hit an index, this will advance
int blob_timestamp = 0;
//for each track within the file, create an index 0 if it is missing.
//also check to make sure there is an index 1
for (int t = 0; t < cue_file.Tracks.Count; t++)
{
if (cue_file.Tracks[i].TrackType != trackType) throw new Cue.CueBrokenException("cue has different track types per datafile (not supported now; maybe never)");
var cue_track = cue_file.Tracks[t];
if (!cue_track.Indexes.ContainsKey(1))
throw new Cue.CueBrokenException("Track was missing an index 01");
if (!cue_track.Indexes.ContainsKey(0))
{
//index 0 will default to the same as index 1.
//i am not sure whether it is valid to have two indexes with the same timestamp.
//we will do this to simplify some processing, but we can purge it in a later pass if we need to.
var cti = new Cue.CueTrackIndex(0);
cue_track.Indexes[0] = cti;
cti.Timestamp = cue_track.Indexes[1].Timestamp;
}
}
//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)
//validate that the first index in the file is 00:00:00
if (cue_file.Tracks[0].Indexes[0].Timestamp.LBA != 0) throw new Cue.CueBrokenException("`The first index of a file must start at 00:00:00.`");
//for each track within the file:
for (int t = 0; t < cue_file.Tracks.Count; t++)
{
case Cue.ECueTrackType.Audio:
numlba = (int)(flen / 2352);
leftover = (int)(flen - numlba * 2352);
break;
var cue_track = cue_file.Tracks[t];
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;
//record the disc LBA that this sector started on
int track_disc_lba_start = Sectors.Count;
default: throw new InvalidOperationException();
}
//record the pregap location. it will default to the start of the track unless we supplied a pregap command
int track_disc_pregap_lba = track_disc_lba_start;
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);
//enforce a rule of our own: every track within the file must have the same sector size
//we do know that files can change between track types within a file, but we're not sure what to do if the sector size changes
if (Cue.BINSectorSizeForTrackType(cue_track.TrackType) != blob_sectorsize) throw new Cue.CueBrokenException("Found different sector sizes within a cue file. We don't know how to handle that.");
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;
//check integrity of track sequence and setup data structures
//TODO - check for skipped tracks in cue parser instead
if (cue_track.TrackNum != curr_track) throw new Cue.CueBrokenException("Found a cue with skipped tracks");
var toc_track = new DiscTOC.Track();
toc_track.num = curr_track;
toc_track.TrackType = cue_track.TrackType;
session.Tracks.Add(toc_track);
new_toc_tracks.Add(toc_track);
//analyze indices
int idx;
for (idx = 0; idx <= 99; idx++)
//check whether a pregap is requested.
//when this happens for the first track in a file, some empty sectors are generated
//when it happens for any other track, its just another way of specifying index 0 LBA
if (cue_track.PreGap.LBA > 0)
{
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?
if (t == 0)
for (int i = 0; i < cue_track.PreGap.LBA; i++)
{
Sectors.Add(new SectorEntry(pregap_sector));
}
else track_disc_pregap_lba -= cue_track.PreGap.LBA;
}
DiscTOC.Index toc_index = new DiscTOC.Index();
toc_index.num = idx;
//look ahead to the next track's index 0 so we can see how long this track's last index is
//or, for the last track, use the length of the file
int track_length_lba;
if (t == cue_file.Tracks.Count - 1)
track_length_lba = blob_length_lba - blob_timestamp;
else track_length_lba = cue_file.Tracks[t + 1].Indexes[0].Timestamp.LBA - blob_timestamp;
//toc_track.length_lba = track_length_lba; //xxx
//find out how many indexes we have
int num_indexes = 0;
for (num_indexes = 0; num_indexes <= 99; num_indexes++)
if (!cue_track.Indexes.ContainsKey(num_indexes)) break;
//for each index, calculate length of index and then emit it
for (int index = 0; index < num_indexes; index++)
{
bool is_last_index = index == num_indexes - 1;
//install index into hierarchy
var toc_index = new DiscTOC.Index();
toc_index.num = index;
toc_track.Indexes.Add(toc_index);
toc_index.lba = cue_index.Timestamp.LBA + curr_lba;
if (index == 0) toc_index.lba = track_disc_pregap_lba;
else toc_index.lba = Sectors.Count;
//toc_index.lba += 150; //TODO - consider whether to add 150 here
//calculate length of the index
//if it is the last index then we use our calculation from before, otherwise we check the next index
int index_length_lba;
if (is_last_index)
index_length_lba = track_disc_lba_start + track_length_lba - blob_timestamp;
else index_length_lba = cue_track.Indexes[index + 1].Timestamp.LBA - blob_timestamp;
//emit sectors
for (int lba = 0; lba < index_length_lba; lba++)
{
bool is_last_lba_in_index = (lba == index_length_lba-1);
bool is_last_lba_in_track = is_last_lba_in_index && is_last_index;
switch (cue_track.TrackType)
{
case ETrackType.Audio: //all 2352 bytes are present
case ETrackType.Mode1_2352: //2352 bytes are present, containing 2048 bytes of user data as well as ECM
case ETrackType.Mode2_2352: //2352 bytes are present, containing 2336 bytes of user data, with no ECM
{
//these cases are all 2352 bytes
//in all these cases, either no ECM is present or ECM is provided.
//so we just emit a Sector_Raw
Sector_RawBlob sector_rawblob = new Sector_RawBlob();
sector_rawblob.Blob = blob;
sector_rawblob.Offset = (long)blob_timestamp * 2352;
Sector_Raw sector_raw = new Sector_Raw();
sector_raw.BaseSector = sector_rawblob;
//take care to handle final sectors that are too short.
if (is_last_lba_in_track && blob_leftover>0)
{
Sector_ZeroPad sector_zeropad = new Sector_ZeroPad();
sector_zeropad.BaseSector = sector_rawblob;
sector_zeropad.BaseLength = 2352 - blob_leftover;
sector_raw.BaseSector = sector_zeropad;
Sectors.Add(new SectorEntry(sector_raw));
}
Sectors.Add(new SectorEntry(sector_raw));
break;
}
case ETrackType.Mode1_2048:
//2048 bytes are present. ECM needs to be generated to create a full sector
{
//ECM needs to know the sector number so we have to record that here
int curr_disc_lba = Sectors.Count;
var sector_2048 = new Sector_Mode1_2048(curr_disc_lba + 150);
sector_2048.Blob = new ECMCacheBlob(blob);
sector_2048.Offset = (long)blob_timestamp * 2048;
if (blob_leftover > 0) throw new Cue.CueBrokenException("TODO - Incomplete 2048 byte/sector bin files (iso files) not yet supported.");
break;
}
} //switch(TrackType)
//we've emitted an LBA, so consume it from the blob
blob_timestamp++;
} //lba emit loop
} //index loop
//check whether a postgap is requested. if it is, we need to generate silent sectors
for (int i = 0; i < cue_track.PostGap.LBA; i++)
{
Sectors.Add(new SectorEntry(pregap_sector));
}
//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");
}
//we're done with the track now.
//record its length:
toc_track.length_lba = Sectors.Count - track_disc_lba_start;
curr_track++;
} //track loop
} //file 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();
//finally, analyze the length of the sessions and the entire disc by summing the lengths of the tracks
//this is a little more complex than it looks, because the length of a thing is not determined by summing it
//but rather by the difference in lbas between start and end
TOC.length_lba = 0;
foreach (var toc_session in TOC.Sessions)
{
var firstTrack = toc_session.Tracks[0];
var lastTrack = toc_session.Tracks[toc_session.Tracks.Count - 1];
session.length_lba = lastTrack.Indexes[1].lba + lastTrack.length_lba - firstTrack.Indexes[0].lba;
TOC.length_lba += toc_session.length_lba;
}
}
}
@ -205,23 +252,69 @@ namespace BizHawk.Disc
public List<CueFile> Files = new List<CueFile>();
public enum ECueTrackType
public static int BINSectorSizeForTrackType(ETrackType type)
{
Mode1_2352,
Mode1_2048,
Mode2_2352,
Audio
switch(type)
{
case ETrackType.Mode1_2352:
case ETrackType.Mode2_2352:
case ETrackType.Audio:
return 2352;
case ETrackType.Mode1_2048:
return 2048;
default:
throw new ArgumentOutOfRangeException();
}
}
public static string TrackTypeStringForTrackType(ETrackType type)
{
switch (type)
{
case ETrackType.Mode1_2352: return "MODE1/2352";
case ETrackType.Mode2_2352: return "MODE2/2352";
case ETrackType.Audio: return "AUDIO";
case ETrackType.Mode1_2048: return "MODE1/2048";
default:
throw new ArgumentOutOfRangeException();
}
}
public static string RedumpTypeStringForTrackType(ETrackType type)
{
switch (type)
{
case ETrackType.Mode1_2352: return "Data/Mode 1";
case ETrackType.Mode1_2048: throw new InvalidOperationException("guh dunno what to put here");
case ETrackType.Mode2_2352: return "Data/Mode 2";
case ETrackType.Audio: return "Audio";
default:
throw new ArgumentOutOfRangeException();
}
}
public class CueTrack
{
public ECueTrackType TrackType;
public ETrackType TrackType;
public int TrackNum;
public CueTimestamp PreGap = new CueTimestamp();
public CueTimestamp PostGap = new CueTimestamp();
public Dictionary<int, CueTrackIndex> Indexes = new Dictionary<int, CueTrackIndex>();
}
public class CueTimestamp
{
/// <summary>
/// creates timestamp of 00:00:00
/// </summary>
public CueTimestamp()
{
Value = "00:00:00";
}
/// <summary>
/// creates a timestamp from a string in the form mm:ss:ff
/// </summary>
public CueTimestamp(string value) {
this.Value = value;
MIN = int.Parse(value.Substring(0, 2));
@ -231,12 +324,26 @@ namespace BizHawk.Disc
}
public readonly string Value;
public readonly int MIN, SEC, FRAC, LBA;
/// <summary>
/// creates timestamp from supplied LBA
/// </summary>
public CueTimestamp(int LBA)
{
this.LBA = LBA;
MIN = LBA / (60*75);
SEC = (LBA / 75)%60;
FRAC = LBA % 75;
Value = string.Format("{0:D2}:{1:D2}:{2:D2}", MIN, SEC, FRAC);
}
}
public class CueTrackIndex
{
public CueTrackIndex(int num) { IndexNum = num; }
public int IndexNum;
public CueTimestamp Timestamp;
public int ZeroLBA;
}
public class CueBrokenException : Exception
@ -254,6 +361,9 @@ namespace BizHawk.Disc
File.ReadAllText(cuePath);
TextReader tr = new StreamReader(cuePath);
bool track_has_pregap = false;
bool track_has_postgap = false;
int last_index_num = -1;
CueFile currFile = null;
CueTrack currTrack = null;
int state = 0;
@ -294,44 +404,60 @@ namespace BizHawk.Disc
if (!int.TryParse(strtracknum, out tracknum))
throw new CueBrokenException("malformed track number");
if (clp.EOF) throw new CueBrokenException("invalid cue structure");
if (tracknum < 0 || tracknum > 99) throw new CueBrokenException("`All track numbers must be between 1 and 99 inclusive.`");
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;
case "MODE1/2352": currTrack.TrackType = ETrackType.Mode1_2352; break;
case "MODE1/2048": currTrack.TrackType = ETrackType.Mode1_2048; break;
case "MODE2/2352": currTrack.TrackType = ETrackType.Mode2_2352; break;
case "AUDIO": currTrack.TrackType = ETrackType.Audio; break;
default:
throw new CueBrokenException("unhandled track type");
}
currTrack.TrackNum = tracknum;
currFile.Tracks.Add(currTrack);
track_has_pregap = false;
track_has_postgap = false;
last_index_num = -1;
break;
}
case "INDEX":
{
if (currTrack == null) throw new CueBrokenException("invalid cue structure");
if (clp.EOF) throw new CueBrokenException("invalid cue structure");
if (track_has_postgap) throw new CueBrokenException("`The POSTGAP command must appear after all INDEX commands for the current track.`");
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); ;
if(indexnum <0 || indexnum>99) throw new CueBrokenException("`All index numbers must be between 0 and 99 inclusive.`");
if (indexnum != 1 && indexnum != last_index_num + 1) throw new CueBrokenException("`The first index must be 0 or 1 with all other indexes being sequential to the first one.`");
last_index_num = indexnum;
CueTrackIndex cti = new CueTrackIndex(indexnum);
cti.Timestamp = new CueTimestamp(str_timestamp);
cti.IndexNum = indexnum;
currTrack.Indexes[indexnum] = cti;
break;
}
case "PREGAP":
if (track_has_pregap) throw new CueBrokenException("`Only one PREGAP command is allowed per track.`");
if (currTrack.Indexes.Count > 0) throw new CueBrokenException("`The PREGAP command must appear after a TRACK command, but before any INDEX commands.`");
currTrack.PreGap = new CueTimestamp(clp.ReadToken());
track_has_pregap = true;
break;
case "POSTGAP":
throw new CueBrokenException("cue postgap/pregap command not supported yet");
if (track_has_pregap) throw new CueBrokenException("`Only one POSTGAP command is allowed per track.`");
track_has_postgap = true;
currTrack.PostGap = new CueTimestamp(clp.ReadToken());
break;
default:
throw new CueBrokenException("unsupported cue command: " + key);
}
}
} //end cue parsing loop
}

View File

@ -14,6 +14,9 @@ using System.Collections.Generic;
//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)
//here is a featureset list of windows cd burning programs (useful for cuesheet compatibility info)
//http://www.dcsoft.com/cue_mastering_progs.htm
//good
//http://linux-sxs.org/bedtime/cdapi.html
//http://en.wikipedia.org/wiki/Track_%28CD%29
@ -65,7 +68,6 @@ using System.Collections.Generic;
namespace BizHawk.Disc
{
public partial class Disc
{
//TODO - separate these into Read_2352 and Read_2048 (optimizations can be made by ISector implementors depending on what is requested)
@ -83,10 +85,20 @@ namespace BizHawk.Disc
class Blob_RawFile : IBlob
{
public string PhysicalPath;
public string PhysicalPath {
get { return physicalPath; }
set
{
physicalPath = value;
length = new FileInfo(physicalPath).Length;
}
}
string physicalPath;
long length;
public long Offset;
FileStream fs;
BufferedStream fs;
public void Dispose()
{
if (fs != null)
@ -97,13 +109,22 @@ namespace BizHawk.Disc
}
public int Read(long byte_pos, byte[] buffer, int offset, int count)
{
//use quite a large buffer, because normally we will be reading these sequentially
const int buffersize = 2352 * 75 * 2;
if (fs == null)
fs = new FileStream(PhysicalPath, FileMode.Open, FileAccess.Read, FileShare.Read);
fs = new BufferedStream(new FileStream(physicalPath, FileMode.Open, FileAccess.Read, FileShare.Read), buffersize);
long target = byte_pos + Offset;
if(fs.Position != target)
fs.Position = target;
return fs.Read(buffer, offset, count);
}
public long Length
{
get
{
return length;
}
}
}
class Sector_RawSilence : ISector
@ -125,6 +146,16 @@ namespace BizHawk.Disc
}
}
class Sector_Zero : ISector
{
public int Read(byte[] buffer, int offset)
{
for (int i = 0; i < 2352; i++)
buffer[offset + i] = 0;
return 2352;
}
}
class Sector_ZeroPad : ISector
{
public ISector BaseSector;
@ -229,6 +260,7 @@ namespace BizHawk.Disc
//this is a physical 2352 byte sector.
public class SectorEntry
{
public SectorEntry(ISector sec) { this.Sector = sec; }
public ISector Sector;
}
@ -256,7 +288,7 @@ namespace BizHawk.Disc
blob.PhysicalPath = fiIso.FullName;
Blobs.Add(blob);
int num_lba = (int)(fiIso.Length / 2048);
index.length_lba = num_lba;
//index.length_lba = num_lba;
if (fiIso.Length % 2048 != 0)
throw new InvalidOperationException("invalid iso file (size not multiple of 2048)");
@ -266,21 +298,76 @@ namespace BizHawk.Disc
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);
Sectors.Add(new SectorEntry(sector));
}
TOC.AnalyzeLengthsFromIndexLengths();
}
public CueBin DumpCueBin(string baseName, CueBinPrefs prefs)
{
if (TOC.Sessions.Count > 1)
throw new NotSupportedException("can't dump cue+bin with more than 1 session yet");
CueBin ret = new CueBin();
ret.baseName = baseName;
ret.disc = this;
if (!prefs.OneBinPerTrack)
{
string cue = TOC.GenerateCUE(prefs);
var bfd = new CueBin.BinFileDescriptor();
bfd.name = baseName + ".bin";
ret.cue = string.Format("FILE \"{0}\" BINARY\n", bfd.name) + cue;
ret.bins.Add(bfd);
for (int i = 0; i < TOC.length_lba; i++)
{
bfd.lbas.Add(i+150);
bfd.lba_zeros.Add(false);
}
}
else
{
StringBuilder sbCue = new StringBuilder();
for (int i = 0; i < TOC.Sessions[0].Tracks.Count; i++)
{
var track = TOC.Sessions[0].Tracks[i];
var bfd = new CueBin.BinFileDescriptor();
bfd.name = baseName + string.Format(" (Track {0:D2}).bin", track.num);
ret.bins.Add(bfd);
int lba=0;
for (; lba < track.length_lba; lba++)
{
int thislba = track.Indexes[0].lba + lba;
bfd.lbas.Add(thislba + 150);
bfd.lba_zeros.Add(false);
}
sbCue.AppendFormat("FILE \"{0}\" BINARY\n", bfd.name);
sbCue.AppendFormat(" TRACK {0:D2} {1}\n", track.num, Cue.TrackTypeStringForTrackType(track.TrackType));
foreach (var index in track.Indexes)
{
int x = index.lba - track.Indexes[0].lba;
sbCue.AppendFormat(" INDEX {0:D2} {1}\n", index.num, new Cue.CueTimestamp(x).Value);
}
}
ret.cue = sbCue.ToString();
}
return ret;
}
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_2352(i, temp, 0);
ReadLBA_2352(150+i, temp, 0);
fs.Write(temp, 0, 2352);
}
}
@ -300,4 +387,129 @@ namespace BizHawk.Disc
}
}
public enum ETrackType
{
Mode1_2352,
Mode1_2048,
Mode2_2352,
Audio
}
public class CueBinPrefs
{
/// <summary>
/// Controls general operations: should the output be split into several bins, or just use one?
/// </summary>
public bool OneBinPerTrack;
/// <summary>
/// turn this on to dump bins instead of just cues
/// </summary>
public bool ReallyDumpBin;
/// <summary>
/// generate remarks and other annotations to help humans understand whats going on, but which will confuse many cue parsers
/// </summary>
public bool AnnotateCue;
/// <summary>
/// you may find that some cue parsers are upset by index 00
/// if thats the case, then we can emit pregaps instead.
/// you might also want to use this to save disk space (without pregap commands, the pregap must be stored as empty sectors)
/// </summary>
public bool PreferPregapCommand = false;
/// <summary>
/// some cue parsers cant handle sessions. better not emit a session command then. multi-session discs will then be broken
/// </summary>
public bool SingleSession;
}
/// <summary>
/// Encapsulates an in-memory cue+bin (complete cuesheet and a little registry of files)
/// it will be based on a disc (fro mwhich it can read sectors to avoid burning through extra memory)
/// TODO - we must merge this with whatever reads in cue+bin
/// </summary>
public class CueBin
{
public string cue;
public string baseName;
public Disc disc;
public class BinFileDescriptor
{
public string name;
public List<int> lbas = new List<int>();
public List<bool> lba_zeros = new List<bool>();
}
public List<BinFileDescriptor> bins = new List<BinFileDescriptor>();
public string CreateRedumpReport()
{
if (disc.TOC.Sessions[0].Tracks.Count != bins.Count)
throw new InvalidOperationException("Cannot generate redump report on CueBin lacking OneBinPerTrack property");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < disc.TOC.Sessions[0].Tracks.Count; i++)
{
var track = disc.TOC.Sessions[0].Tracks[i];
var bfd = bins[i];
//dump the track
byte[] dump = new byte[track.length_lba * 2352];
for (int lba = 0; lba < track.length_lba; lba++)
disc.ReadLBA_2352(bfd.lbas[lba],dump,lba*2352);
string crc32 = string.Format("{0:X8}", CRC32.Calculate(dump));
string md5 = Util.Hash_MD5(dump, 0, dump.Length);
string sha1 = Util.Hash_SHA1(dump, 0, dump.Length);
int pregap = track.Indexes[1].lba - track.Indexes[0].lba;
Cue.CueTimestamp pregap_ts = new Cue.CueTimestamp(pregap);
Cue.CueTimestamp len_ts = new Cue.CueTimestamp(track.length_lba);
sb.AppendFormat("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\n",
i,
Cue.RedumpTypeStringForTrackType(track.TrackType),
pregap_ts.Value,
len_ts.Value,
track.length_lba,
track.length_lba*Cue.BINSectorSizeForTrackType(track.TrackType),
crc32,
md5,
sha1
);
}
return sb.ToString();
}
public void Dump(string directory, CueBinPrefs prefs)
{
string cuePath = Path.Combine(directory, baseName + ".cue");
File.WriteAllText(cuePath, cue);
if(prefs.ReallyDumpBin)
foreach (var bfd in bins)
{
byte[] temp = new byte[2352];
byte[] empty = new byte[2352];
string trackBinFile = bfd.name;
string trackBinPath = Path.Combine(directory, trackBinFile);
using (FileStream fs = new FileStream(trackBinPath, FileMode.Create, FileAccess.Write, FileShare.None))
{
for(int i=0;i<bfd.lbas.Count;i++)
{
int lba = bfd.lbas[i];
if (bfd.lba_zeros[i])
{
fs.Write(empty, 0, 2352);
}
else
{
disc.ReadLBA_2352(lba, temp, 0);
fs.Write(temp, 0, 2352);
}
}
}
}
}
}
}

View File

@ -16,15 +16,18 @@ namespace BizHawk.Disc
//the length of the track (should be the sum of all track lengths)
public int length_lba;
public Cue.CueTimestamp FriendlyLength { get { return new Cue.CueTimestamp(length_lba); } }
}
public class Track
{
public ETrackType TrackType;
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 Cue.CueTimestamp FriendlyLength { get { return new Cue.CueTimestamp(length_lba); } }
}
public class Index
@ -33,29 +36,33 @@ namespace BizHawk.Disc
public int lba;
//the length of the section
public int length_lba;
//public int length_lba;
//public Cue.CueTimestamp FriendlyLength { get { return new Cue.CueTimestamp(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()
public string GenerateCUE(CueBinPrefs prefs)
{
StringBuilder sb = new StringBuilder();
foreach (var session in Sessions)
{
sb.AppendFormat("SESSION {0:D2} (length={1})\n", session.num, session.length_lba);
if (!prefs.SingleSession)
{
//dont want to screw around with sessions for now
if (prefs.AnnotateCue) sb.AppendFormat("SESSION {0:D2} (length={1})\n", session.num, session.length_lba);
else sb.AppendFormat("SESSION {0:D2}\n", session.num);
}
foreach (var track in session.Tracks)
{
sb.AppendFormat(" TRACK {0:D2} (length={1})\n", track.num, track.length_lba);
if (prefs.AnnotateCue) sb.AppendFormat(" TRACK {0:D2} {1} (length={2})\n", track.num, Cue.TrackTypeStringForTrackType(track.TrackType), track.length_lba);
else sb.AppendFormat(" TRACK {0:D2} {1}\n", track.num, Cue.TrackTypeStringForTrackType(track.TrackType));
foreach (var index in track.Indexes)
{
sb.AppendFormat(" INDEX {0:D2}: {1}\n", index.num, FormatLBA(index.lba));
//if (prefs.PreferPregapCommand && index.num == 0)
// sb.AppendFormat(" PREGAP {0}\n", new Cue.CueTimestamp(index.length_lba).Value);
//else
sb.AppendFormat(" INDEX {0:D2} {1}\n", index.num, new Cue.CueTimestamp(index.lba).Value);
}
}
sb.AppendFormat("-EOF-\n");
}
return sb.ToString();
@ -66,17 +73,15 @@ namespace BizHawk.Disc
public void AnalyzeLengthsFromIndexLengths()
{
//this is a little more complex than it looks, because the length of a thing is not determined by summing it
//but rather by the difference in lbas between start and end
length_lba = 0;
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;
}
var firstTrack = session.Tracks[0];
var lastTrack = session.Tracks[session.Tracks.Count - 1];
session.length_lba = lastTrack.Indexes[0].lba + lastTrack.length_lba - firstTrack.Indexes[0].lba;
length_lba += session.length_lba;
}
}
}

View File

@ -65,7 +65,7 @@
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;
//byte i;
/* Save the address and zero it out */
if(zeroaddress)
{

View File

@ -1,426 +1,373 @@
////http://jasonjano.wordpress.com/2010/02/09/a-simple-c-wrapper-for-ffmpeg/
//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;
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;
namespace ffMpeg
{
public class Converter
{
public static string _ffExe;
public string WorkingPath; //i.e. temp
// //i.e. temp
// public string WorkingPath;
public Converter()
{
Initialize();
}
// #endregion
#region Initialization
private void Initialize()
{
}
// #region Constructors
// public Converter()
// {
// Initialize();
// }
// public Converter(string ffmpegExePath)
// {
// _ffExe = ffmpegExePath;
// Initialize();
// }
// #endregion
private string GetWorkingFile()
{
//try the stated directory
if (File.Exists(_ffExe))
{
return _ffExe;
}
// #region Initialization
// private void Initialize()
// {
// }
//oops, that didn't work, try the base directory
if (File.Exists(Path.GetFileName(_ffExe)))
{
return Path.GetFileName(_ffExe);
}
// private string GetWorkingFile()
// {
// //try the stated directory
// if (File.Exists(_ffExe))
// {
// return _ffExe;
// }
//well, now we are really unlucky, let's just return null
return null;
}
#endregion
// //oops, that didn't work, try the base directory
// if (File.Exists(Path.GetFileName(_ffExe)))
// {
// return Path.GetFileName(_ffExe);
// }
#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;
}
// //well, now we are really unlucky, let's just return null
// return null;
// }
// #endregion
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 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;
// }
#region Run the process
private string RunProcess(string Parameters)
{
//create a process info
ProcessStartInfo oInfo = new ProcessStartInfo(_ffExe, Parameters);
oInfo.UseShellExecute = false;
oInfo.CreateNoWindow = true;
oInfo.RedirectStandardOutput = true;
oInfo.RedirectStandardError = true;
// 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
//Create the output and streamreader to get the output
string output = null; StreamReader srOutput = null;
// #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;
//try the process
try
{
//run the process
Process proc = System.Diagnostics.Process.Start(oInfo);
// //Create the output and streamreader to get the output
// string output = null; StreamReader srOutput = null;
proc.WaitForExit();
// //try the process
// try
// {
// //run the process
// Process proc = System.Diagnostics.Process.Start(oInfo);
//get the output
srOutput = proc.StandardError;
// proc.WaitForExit();
//now put it in a string
output = srOutput.ReadToEnd();
// //get the output
// srOutput = proc.StandardError;
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
// //now put it in a string
// output = srOutput.ReadToEnd();
#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();
// 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
VideoFile vf = null;
try
{
vf = new VideoFile(tempfile);
}
catch (Exception ex)
{
throw ex;
}
// #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();
GetVideoInfo(vf);
// VideoFile vf = null;
// try
// {
// vf = new VideoFile(tempfile);
// }
// catch (Exception ex)
// {
// throw ex;
// }
try
{
File.Delete(tempfile);
}
catch (Exception)
{
// 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);
// 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;
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 duration
// Regex re = new Regex("[D|d]uration:.((\\d|:|\\.)*)");
// Match m = re.Match(input.RawInfo);
//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;
// 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 the audio format
re = new Regex("[A|a]udio:.*");
m = re.Match(input.RawInfo);
if (m.Success)
{
input.AudioFormat = m.Value;
}
// //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 video format
re = new Regex("[V|v]ideo:.*");
m = re.Match(input.RawInfo);
if (m.Success)
{
input.VideoFormat = m.Value;
}
// //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("(\\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
// //get the video format
// re = new Regex("[V|v]ideo:.*");
// m = re.Match(input.RawInfo);
// if (m.Success)
// {
// input.VideoFormat = m.Value;
// }
#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();
// //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
VideoFile vf = null;
try
{
vf = new VideoFile(tempfile);
}
catch (Exception ex)
{
throw ex;
}
// #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();
OutputPackage oo = ConvertToFLV(vf);
// VideoFile vf = null;
// try
// {
// vf = new VideoFile(tempfile);
// }
// catch (Exception ex)
// {
// throw ex;
// }
try
{
File.Delete(tempfile);
}
catch (Exception)
{
// 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();
// return oo;
// }
// public OutputPackage ConvertToFLV(string inputPath)
// {
// VideoFile vf = null;
// try
// {
// vf = new VideoFile(inputPath);
// }
// catch (Exception ex)
// {
// throw ex;
// }
string filename = System.Guid.NewGuid().ToString() + ".flv";
string finalpath = Path.Combine(this.WorkingPath, filename);
string Params = string.Format("-i \"{0}\" -y -ar 22050 -ab 64 -f flv \"{1}\"", input.Path, finalpath);
string output = RunProcess(Params);
// OutputPackage oo = ConvertToFLV(vf);
// return oo;
// }
// public OutputPackage ConvertToFLV(VideoFile input)
// {
// if (!input.infoGathered)
// {
// GetVideoInfo(input);
// }
// OutputPackage ou = new OutputPackage();
if (File.Exists(finalpath))
{
ou.VideoStream = LoadMemoryStreamFromFile(finalpath);
try
{
File.Delete(finalpath);
}
catch (Exception) { }
}
return ou;
}
#endregion
}
// //set up the parameters for getting a previewimage
// string filename = System.Guid.NewGuid().ToString() + ".jpg";
// int secs;
public class VideoFile
{
#region Properties
private string _Path;
public string Path
{
get
{
return _Path;
}
set
{
_Path = value;
}
}
// //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);
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
// 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);
#region Constructors
public VideoFile(string path)
{
_Path = path;
Initialize();
}
#endregion
// ou.RawOutput = output;
#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");
}
// 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);
//Now see if the video file exists
if (!File.Exists(_Path))
{
throw new Exception("The video file " + _Path + " does not exist.");
}
}
#endregion
}
// 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; }
// }
//}
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; }
}
}

View File

@ -73,14 +73,14 @@ namespace BizHawk.MultiClient
//we could background thread this later instead if we wanted to be real clever
NES.BootGodDB.GetDatabaseBytes = () =>
{
using (HawkFile NesCartFile = new HawkFile(PathManager.GetExePathAbsolute() + "\\NesCarts.7z").BindFirst())
using (HawkFile NesCartFile = new HawkFile(PathManager.GetExeDirectoryAbsolute() + "\\NesCarts.7z").BindFirst())
return Util.ReadAllBytes(NesCartFile.GetStream());
};
Global.MainForm = this;
Global.CoreInputComm = new CoreInputComm();
SyncCoreInputComm();
Database.LoadDatabase(PathManager.GetExePathAbsolute() + "\\gamedb.txt");
Database.LoadDatabase(PathManager.GetExeDirectoryAbsolute() + "\\gamedb.txt");
SyncPresentationMode();

View File

@ -2,6 +2,17 @@
using System.Collections.Generic;
using System.IO;
//cue format preferences notes
//pcejin -
//does not like session commands
//it can handle binpercue
//it seems not to be able to handle binpertrack, or maybe i am doing something wrong (still havent ruled it out)
//isobuster -
//does not like onebinpertrack images with index 00
namespace BizHawk
{
class DiscoHawk
@ -13,8 +24,41 @@ namespace BizHawk
void Run(string[] args)
{
//string testfile = @"d:\Radiant Silvergun (J)\Radiant Silvergun (J).cue";
//var disc = Disc.Disc.FromCuePath(testfile);
//string exedir = BizHawk.MultiClient.PathManager.GetExeDirectoryAbsolute();
//ffMpeg.Converter._ffExe = Path.Combine(exedir, "ffmpeg.exe");
////cue+bin+mp3 tests
//var conv = new ffMpeg.Converter();
////conv.WorkingPath = Environment.GetEnvironmentVariable("TEMP");
////var vf = conv.GetVideoInfo(@"D:\isos\scd\persia\Prince of Persia 01.mp3");
//var o = conv.ConvertToFLV(@"D:\isos\scd\persia\Prince of Persia 01.mp3");
////-i mp3file.mp3 -f wav outfile.wav
//Disc.CueBin munged;
//Disc.CueBinPrefs prefs = new Disc.CueBinPrefs();
//prefs.SingleSession = true;
//Disc.Disc disc;
//string testfile = @"D:\isos\pcecd\cosmicfantasy2\Cosmic Fantasy II [U][CD][WTG990301][Telenet Japan][1992][PCE][thx-1138-darkwater].cue";
//disc = Disc.Disc.FromCuePath(testfile);
//prefs.ReallyDumpBin = true;
//prefs.AnnotateCue = false;
//prefs.OneBinPerTrack = true;
//prefs.PreferPregapCommand = false;
//munged = disc.DumpCueBin("test", prefs);
//munged.Dump("d:\\test", prefs);
//File.WriteAllText("d:\\test\\redump.txt", munged.CreateRedumpReport());
//try roundtripping back to one file
//disc = Disc.Disc.FromCuePath("d:\\test\\test.cue");
//prefs.ReallyDumpBin = false;
//prefs.OneBinPerTrack = false;
//prefs.PreferPregapCommand = true;
//munged = disc.DumpCueBin("one", prefs);
//munged.Dump("d:\\test", prefs);
//string testfile = @"r:\isos\memtest86-3.2.iso";
//var disc = Disc.Disc.FromIsoPath(testfile);
@ -22,7 +66,7 @@ namespace BizHawk
//Console.WriteLine(disc.ReadTOC().DebugPrint());
//disc.DumpBin_2352("d:\\test.2352");
//test reading the subcode data. unfortunately we don't have lead-in subcode so we have no TOC
////test reading the subcode data. unfortunately we don't have lead-in subcode so we have no TOC
//using (FileStream fs = File.OpenRead("c:\\bof4.sub"))
//{
// Disc.SubcodeStream stream = new Disc.SubcodeStream(fs, 0);

View File

@ -45,6 +45,10 @@
<Project>{197D4314-8A9F-49BA-977D-54ACEFAEB6BA}</Project>
<Name>BizHawk.Emulation</Name>
</ProjectReference>
<ProjectReference Include="..\BizHawk.MultiClient\BizHawk.MultiClient.csproj">
<Project>{DD448B37-BA3F-4544-9754-5406E8094723}</Project>
<Name>BizHawk.MultiClient</Name>
</ProjectReference>
<ProjectReference Include="..\BizHawk.Util\BizHawk.Util.csproj">
<Project>{EE135301-08B3-4EFC-A61C-1C53E1C65CB9}</Project>
<Name>BizHawk.Util</Name>