disc: cue+mp3/mpc/flac decoding
This commit is contained in:
parent
d92c27f89d
commit
1f541be6df
|
@ -194,6 +194,7 @@
|
||||||
<Compile Include="DiscSystem\CUE_format.cs">
|
<Compile Include="DiscSystem\CUE_format.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="DiscSystem\Decoding.cs" />
|
||||||
<Compile Include="DiscSystem\Disc.API.cs">
|
<Compile Include="DiscSystem\Disc.API.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -206,9 +207,6 @@
|
||||||
<Compile Include="DiscSystem\ECM.cs">
|
<Compile Include="DiscSystem\ECM.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="DiscSystem\FFmpeg.cs">
|
|
||||||
<SubType>Code</SubType>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="DiscSystem\Subcode.cs">
|
<Compile Include="DiscSystem\Subcode.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
|
@ -23,13 +23,23 @@ namespace BizHawk.DiscSystem
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Load(byte[] waveData)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public void Load(string wavePath)
|
public void Load(string wavePath)
|
||||||
|
{
|
||||||
|
var stream = new FileStream(wavePath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||||
|
Load(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Load(Stream stream)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
RiffSource = null;
|
RiffSource = null;
|
||||||
var rm = new RiffMaster();
|
var rm = new RiffMaster();
|
||||||
rm.LoadFile(wavePath);
|
rm.LoadStream(stream);
|
||||||
RiffSource = rm;
|
RiffSource = rm;
|
||||||
|
|
||||||
//analyze the file to make sure its an OK wave file
|
//analyze the file to make sure its an OK wave file
|
||||||
|
@ -69,6 +79,7 @@ namespace BizHawk.DiscSystem
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
Dispose();
|
Dispose();
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,12 +18,11 @@ class RiffMaster : IDisposable
|
||||||
WriteStream(fs);
|
WriteStream(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileStream BaseStream;
|
public Stream BaseStream;
|
||||||
public void LoadFile(string fname)
|
public void LoadFile(string fname)
|
||||||
{
|
{
|
||||||
Dispose();
|
var fs = new FileStream(fname, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||||
BaseStream = new FileStream(fname, FileMode.Open, FileAccess.Read, FileShare.Read);
|
LoadStream(fs);
|
||||||
LoadStream(BaseStream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -330,8 +329,13 @@ class RiffMaster : IDisposable
|
||||||
riff.WriteStream(s);
|
riff.WriteStream(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// takes posession of the supplied stream
|
||||||
|
/// </summary>
|
||||||
public void LoadStream(Stream s)
|
public void LoadStream(Stream s)
|
||||||
{
|
{
|
||||||
|
Dispose();
|
||||||
|
BaseStream = s;
|
||||||
readCounter = 0;
|
readCounter = 0;
|
||||||
BinaryReader br = new BinaryReader(s);
|
BinaryReader br = new BinaryReader(s);
|
||||||
RiffChunk chunk = ReadChunk(br);
|
RiffChunk chunk = ReadChunk(br);
|
||||||
|
|
|
@ -48,23 +48,35 @@ namespace BizHawk.DiscSystem
|
||||||
else if (cue_file.FileType == Cue.CueFileType.Wave)
|
else if (cue_file.FileType == Cue.CueFileType.Wave)
|
||||||
{
|
{
|
||||||
Blob_WaveFile blob = new Blob_WaveFile();
|
Blob_WaveFile blob = new Blob_WaveFile();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
blob.Load(blobPath);
|
//check for the specified file
|
||||||
|
if (!File.Exists(blobPath))
|
||||||
|
{
|
||||||
|
//if it doesn't exist, then it may be encoded.
|
||||||
|
AudioDecoder dec = new AudioDecoder();
|
||||||
|
byte[] buf = dec.AcquireWaveData(blobPath);
|
||||||
|
blob.Load(new MemoryStream(buf));
|
||||||
|
WasSlowLoad = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blob.Load(blobPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
throw new DiscReferenceException(blobPath, ex);
|
throw new DiscReferenceException(blobPath, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
blob_length_lba = (int)(blob.Length / blob_sectorsize);
|
blob_length_lba = (int) (blob.Length/blob_sectorsize);
|
||||||
blob_leftover = (int)(blob.Length - blob_length_lba * blob_sectorsize);
|
blob_leftover = (int) (blob.Length - blob_length_lba*blob_sectorsize);
|
||||||
cue_blob = blob;
|
cue_blob = blob;
|
||||||
}
|
}
|
||||||
else throw new DiscReferenceException(blobPath, new InvalidOperationException("unknown cue file type: " + cue_file.StrFileType));
|
else throw new DiscReferenceException(blobPath, new InvalidOperationException("unknown cue file type: " + cue_file.StrFileType));
|
||||||
|
|
||||||
//TODO - make CueTimestamp better, and also make it a struct, and also just make it DiscTimestamp
|
//TODO - make CueTimestamp better, and also make it a struct, and also just make it DiscTimestamp
|
||||||
//TODO - wav handling
|
|
||||||
//TODO - mp3 decode
|
//TODO - mp3 decode
|
||||||
|
|
||||||
//start timekeeping for the blob. every time we hit an index, this will advance
|
//start timekeeping for the blob. every time we hit an index, this will advance
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace BizHawk.DiscSystem
|
||||||
|
{
|
||||||
|
public class FFMpeg
|
||||||
|
{
|
||||||
|
public static string FFMpegPath;
|
||||||
|
|
||||||
|
public class AudioQueryResult
|
||||||
|
{
|
||||||
|
public bool IsAudio;
|
||||||
|
}
|
||||||
|
|
||||||
|
static string[] Escape(string[] args)
|
||||||
|
{
|
||||||
|
return args.Select(s => s.Contains(" ") ? string.Format("\"{0}\"", s) : s).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Regex rxHasAudio = new Regex(@"Stream \#(\d*\.\d*)\: Audio", RegexOptions.Compiled);
|
||||||
|
public AudioQueryResult QueryAudio(string path)
|
||||||
|
{
|
||||||
|
var ret = new AudioQueryResult();
|
||||||
|
string stdout = Run("-i", path);
|
||||||
|
ret.IsAudio = rxHasAudio.Matches(stdout).Count > 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
string Run(params string[] args)
|
||||||
|
{
|
||||||
|
args = Escape(args);
|
||||||
|
StringBuilder sbCmdline = new StringBuilder();
|
||||||
|
for (int i = 0; i < args.Length; i++)
|
||||||
|
{
|
||||||
|
sbCmdline.Append(args[i]);
|
||||||
|
if (i != args.Length - 1) sbCmdline.Append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessStartInfo oInfo = new ProcessStartInfo(FFMpegPath, sbCmdline.ToString());
|
||||||
|
oInfo.UseShellExecute = false;
|
||||||
|
oInfo.CreateNoWindow = true;
|
||||||
|
oInfo.RedirectStandardOutput = true;
|
||||||
|
oInfo.RedirectStandardError = true;
|
||||||
|
|
||||||
|
Process proc = System.Diagnostics.Process.Start(oInfo);
|
||||||
|
proc.WaitForExit();
|
||||||
|
string result = proc.StandardError.ReadToEnd();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] DecodeAudio(string path)
|
||||||
|
{
|
||||||
|
string tempfile = Path.GetTempFileName();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string runResults = Run("-i", path, "-f", "wav", "-y", tempfile);
|
||||||
|
byte[] ret = File.ReadAllBytes(tempfile);
|
||||||
|
if (ret.Length == 0)
|
||||||
|
throw new InvalidOperationException("Failure running ffmpeg for audio decode. here was its output:\r\n" + runResults);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
File.Delete(tempfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AudioDecoder
|
||||||
|
{
|
||||||
|
public class AudioDecoder_Exception : Exception
|
||||||
|
{
|
||||||
|
public AudioDecoder_Exception(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AudioDecoder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckForAudio(string path)
|
||||||
|
{
|
||||||
|
FFMpeg ffmpeg = new FFMpeg();
|
||||||
|
var qa = ffmpeg.QueryAudio(path);
|
||||||
|
return qa.IsAudio;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// finds audio at a path similar to the provided path (i.e. finds Track01.mp3 for Track01.wav)
|
||||||
|
/// </summary>
|
||||||
|
string FindAudio(string audioPath)
|
||||||
|
{
|
||||||
|
string basePath = Path.GetFileNameWithoutExtension(audioPath);
|
||||||
|
//look for potential candidates
|
||||||
|
var di = new DirectoryInfo(Path.GetDirectoryName(audioPath));
|
||||||
|
var fis = di.GetFiles();
|
||||||
|
//first, look for the file type we actually asked for
|
||||||
|
foreach (var fi in fis)
|
||||||
|
{
|
||||||
|
if (fi.FullName.ToUpper() == audioPath.ToUpper())
|
||||||
|
if (CheckForAudio(fi.FullName))
|
||||||
|
return fi.FullName;
|
||||||
|
}
|
||||||
|
//then look for any other type
|
||||||
|
foreach (var fi in fis)
|
||||||
|
{
|
||||||
|
if (Path.GetFileNameWithoutExtension(fi.FullName) == basePath)
|
||||||
|
{
|
||||||
|
if (CheckForAudio(fi.FullName))
|
||||||
|
return fi.FullName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] AcquireWaveData(string audioPath)
|
||||||
|
{
|
||||||
|
string path = FindAudio(audioPath);
|
||||||
|
if (path == null)
|
||||||
|
{
|
||||||
|
throw new AudioDecoder_Exception("Could not find source audio for: " + Path.GetFileName(audioPath));
|
||||||
|
}
|
||||||
|
FFMpeg ffmpeg = new FFMpeg();
|
||||||
|
return ffmpeg.DecodeAudio(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -76,16 +76,27 @@ namespace BizHawk.DiscSystem
|
||||||
Array.Copy(temp, 16, buffer, offset, 2048);
|
Array.Copy(temp, 16, buffer, offset, 2048);
|
||||||
}
|
}
|
||||||
|
|
||||||
//main API to determine how many LBA sectors are available
|
/// <summary>
|
||||||
|
/// main API to determine how many LBA sectors are available
|
||||||
|
/// </summary>
|
||||||
public int LBACount { get { return Sectors.Count; } }
|
public int LBACount { get { return Sectors.Count; } }
|
||||||
|
|
||||||
//main api for reading the TOC from a disc
|
/// <summary>
|
||||||
|
/// indicates whether this disc took significant work to load from the disc (i.e. decoding of ECM or audio data)
|
||||||
|
/// In this case, the user may appreciate a prompt to export the disc so that it won't take so long next time.
|
||||||
|
/// </summary>
|
||||||
|
public bool WasSlowLoad { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// main api for reading the TOC from a disc
|
||||||
|
/// </summary>
|
||||||
public DiscTOC ReadTOC()
|
public DiscTOC ReadTOC()
|
||||||
{
|
{
|
||||||
return TOC;
|
return TOC;
|
||||||
}
|
}
|
||||||
|
|
||||||
// converts LBA to minute:second:frame format.
|
// converts LBA to minute:second:frame format.
|
||||||
|
//TODO - somewhat redundant with CueTimestamp, which is due for refactoring into something not cue-related
|
||||||
public static void ConvertLBAtoMSF(int lba, out byte m, out byte s, out byte f)
|
public static void ConvertLBAtoMSF(int lba, out byte m, out byte s, out byte f)
|
||||||
{
|
{
|
||||||
m = (byte) (lba / 75 / 60);
|
m = (byte) (lba / 75 / 60);
|
||||||
|
|
|
@ -1,373 +0,0 @@
|
||||||
//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
|
|
||||||
{
|
|
||||||
public static string _ffExe;
|
|
||||||
public string WorkingPath; //i.e. temp
|
|
||||||
|
|
||||||
public Converter()
|
|
||||||
{
|
|
||||||
Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
#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(_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();
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
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; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -90,7 +90,7 @@
|
||||||
//BIOS Paths
|
//BIOS Paths
|
||||||
public string PathPCEBios = ".\\PCECDBios.pce"; //TODO: better default filename
|
public string PathPCEBios = ".\\PCECDBios.pce"; //TODO: better default filename
|
||||||
|
|
||||||
public string FFMpegPath = "ffmpeg.exe";
|
public string FFMpegPath = "%exe%/ffmpeg.exe";
|
||||||
|
|
||||||
// General Client Settings
|
// General Client Settings
|
||||||
public int TargetZoomFactor = 2;
|
public int TargetZoomFactor = 2;
|
||||||
|
|
|
@ -73,6 +73,7 @@ namespace BizHawk.MultiClient
|
||||||
LogConsole.ShowConsole();
|
LogConsole.ShowConsole();
|
||||||
displayLogWindowToolStripMenuItem.Checked = true;
|
displayLogWindowToolStripMenuItem.Checked = true;
|
||||||
}
|
}
|
||||||
|
DiscSystem.FFMpeg.FFMpegPath = PathManager.MakeProgramRelativePath(Global.Config.FFMpegPath);
|
||||||
|
|
||||||
Global.CheatList = new CheatList();
|
Global.CheatList = new CheatList();
|
||||||
UpdateStatusSlots();
|
UpdateStatusSlots();
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
@ -13,9 +14,20 @@ namespace BizHawk
|
||||||
{
|
{
|
||||||
class DiscoHawk
|
class DiscoHawk
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public static string GetExeDirectoryAbsolute()
|
||||||
|
{
|
||||||
|
string p = Path.GetDirectoryName(Assembly.GetEntryAssembly().GetName().CodeBase);
|
||||||
|
if (p.Substring(0, 6) == "file:\\")
|
||||||
|
p = p.Remove(0, 6);
|
||||||
|
string z = p;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
[STAThread]
|
[STAThread]
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
DiscSystem.FFMpeg.FFMpegPath = Path.Combine(GetExeDirectoryAbsolute(), "ffmpeg.exe");
|
||||||
new DiscoHawk().Run(args);
|
new DiscoHawk().Run(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +103,18 @@ namespace BizHawk
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//DiscSystem.Disc disc = DiscSystem.Disc.FromCuePath(@"D:\discs\Bomberman_'94_Taikenban_(SCD)(JPN)_-_wav'd\Bomberman '94 Taikenban (SCD)(JPN)_hawked.cue");
|
//DiscSystem.Disc disc = DiscSystem.Disc.FromCuePath(@"D:\discs\Bomberman_'94_Taikenban_(SCD)(JPN)_-_wav'd\Bomberman '94 Taikenban (SCD)(JPN)_hawked.cue");
|
||||||
DiscSystem.Disc disc = DiscSystem.Disc.FromCuePath(@"D:\discs\Bomberman_'94_Taikenban_(SCD)(JPN)_-_wav'd\Bomberman '94 Taikenban (SCD)(JPN).cue");
|
//DiscSystem.Disc disc = DiscSystem.Disc.FromCuePath(@"D:\discs\Bomberman_'94_Taikenban_(SCD)(JPN)_-_wav'd\Bomberman '94 Taikenban (SCD)(JPN).cue");
|
||||||
|
//var prefs = new DiscSystem.CueBinPrefs();
|
||||||
|
//prefs.AnnotateCue = false;
|
||||||
|
//prefs.OneBlobPerTrack = false;
|
||||||
|
//prefs.ReallyDumpBin = true;
|
||||||
|
//prefs.OmitRedundantIndex0 = true;
|
||||||
|
//prefs.SingleSession = true;
|
||||||
|
////var cueBin = disc.DumpCueBin("Bomberman '94 Taikenban (SCD)(JPN)_hawked_hawked", prefs);
|
||||||
|
//var cueBin = disc.DumpCueBin("Bomberman '94 Taikenban (SCD)(JPN)_hawked", prefs);
|
||||||
|
//cueBin.Dump(@"D:\discs\Bomberman_'94_Taikenban_(SCD)(JPN)_-_wav'd", prefs);
|
||||||
|
|
||||||
|
DiscSystem.Disc disc = DiscSystem.Disc.FromCuePath(@"D:\discs\Angels II - Holy Night (J)[Prototype]\Angels II - Holy Night (J)[Prototype].cue");
|
||||||
var prefs = new DiscSystem.CueBinPrefs();
|
var prefs = new DiscSystem.CueBinPrefs();
|
||||||
prefs.AnnotateCue = false;
|
prefs.AnnotateCue = false;
|
||||||
prefs.OneBlobPerTrack = false;
|
prefs.OneBlobPerTrack = false;
|
||||||
|
@ -99,8 +122,8 @@ namespace BizHawk
|
||||||
prefs.OmitRedundantIndex0 = true;
|
prefs.OmitRedundantIndex0 = true;
|
||||||
prefs.SingleSession = true;
|
prefs.SingleSession = true;
|
||||||
//var cueBin = disc.DumpCueBin("Bomberman '94 Taikenban (SCD)(JPN)_hawked_hawked", prefs);
|
//var cueBin = disc.DumpCueBin("Bomberman '94 Taikenban (SCD)(JPN)_hawked_hawked", prefs);
|
||||||
var cueBin = disc.DumpCueBin("Bomberman '94 Taikenban (SCD)(JPN)_hawked", prefs);
|
var cueBin = disc.DumpCueBin("test", prefs);
|
||||||
cueBin.Dump(@"D:\discs\Bomberman_'94_Taikenban_(SCD)(JPN)_-_wav'd", prefs);
|
cueBin.Dump(@"D:\discs\Angels II - Holy Night (J)[Prototype]", prefs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue