(MioInput): limit EriFile wrapper lifetime to constructor.

This commit is contained in:
morkt
2015-06-01 00:55:31 +04:00
parent ef0f5f9eaf
commit 1a5300a26b

View File

@@ -58,7 +58,6 @@ namespace GameRes.Formats.Entis
public class MioInput : SoundInput public class MioInput : SoundInput
{ {
EriFile m_erif;
MioInfoHeader m_info; MioInfoHeader m_info;
long m_stream_pos; long m_stream_pos;
int m_bitrate; int m_bitrate;
@@ -91,44 +90,43 @@ namespace GameRes.Formats.Entis
public MioInput (Stream file) : base (file) public MioInput (Stream file) : base (file)
{ {
file.Position = 0x40; file.Position = 0x40;
m_erif = new EriFile (file); using (var erif = new EriFile (file))
try
{ {
var section = m_erif.ReadSection(); var section = erif.ReadSection();
if (section.Id != "Header " || section.Length <= 0 || section.Length > int.MaxValue) if (section.Id != "Header " || section.Length <= 0 || section.Length > int.MaxValue)
throw new InvalidFormatException(); throw new InvalidFormatException();
m_stream_pos = 0x50 + section.Length; m_stream_pos = 0x50 + section.Length;
int header_size = (int)section.Length; int header_size = (int)section.Length;
while (header_size > 8) while (header_size > 8)
{ {
section = m_erif.ReadSection(); section = erif.ReadSection();
header_size -= 8; header_size -= 8;
if (section.Length <= 0 || section.Length > header_size) if (section.Length <= 0 || section.Length > header_size)
break; break;
if ("SoundInf" == section.Id) if ("SoundInf" == section.Id)
{ {
m_info = new MioInfoHeader(); m_info = new MioInfoHeader();
m_info.Version = m_erif.ReadInt32(); m_info.Version = erif.ReadInt32();
m_info.Transformation = (CvType)m_erif.ReadInt32(); m_info.Transformation = (CvType)erif.ReadInt32();
m_info.Architecture = (EriCode)m_erif.ReadInt32(); m_info.Architecture = (EriCode)erif.ReadInt32();
m_info.ChannelCount = m_erif.ReadInt32(); m_info.ChannelCount = erif.ReadInt32();
m_info.SamplesPerSec = m_erif.ReadUInt32(); m_info.SamplesPerSec = erif.ReadUInt32();
m_info.BlocksetCount = m_erif.ReadUInt32(); m_info.BlocksetCount = erif.ReadUInt32();
m_info.SubbandDegree = m_erif.ReadInt32(); m_info.SubbandDegree = erif.ReadInt32();
m_info.AllSampleCount = m_erif.ReadUInt32(); m_info.AllSampleCount = erif.ReadUInt32();
m_info.LappedDegree = m_erif.ReadUInt32(); m_info.LappedDegree = erif.ReadUInt32();
m_info.BitsPerSample = m_erif.ReadUInt32(); m_info.BitsPerSample = erif.ReadUInt32();
break; break;
} }
header_size -= (int)section.Length; header_size -= (int)section.Length;
m_erif.BaseStream.Seek (section.Length, SeekOrigin.Current); erif.BaseStream.Seek (section.Length, SeekOrigin.Current);
} }
if (null == m_info) if (null == m_info)
throw new InvalidFormatException ("MIO sound header not found"); throw new InvalidFormatException ("MIO sound header not found");
m_erif.BaseStream.Position = m_stream_pos; erif.BaseStream.Position = m_stream_pos;
var stream_size = m_erif.FindSection ("Stream "); var stream_size = erif.FindSection ("Stream ");
m_stream_pos = m_erif.BaseStream.Position; m_stream_pos = erif.BaseStream.Position;
m_pmiod = new MioDecoder (m_info); m_pmiod = new MioDecoder (m_info);
if (EriCode.Nemesis != m_info.Architecture) if (EriCode.Nemesis != m_info.Architecture)
@@ -136,7 +134,7 @@ namespace GameRes.Formats.Entis
else else
throw new NotImplementedException ("MIO Nemesis encoding not implemented"); throw new NotImplementedException ("MIO Nemesis encoding not implemented");
int pcm_bitrate = (int)m_info.SamplesPerSec * 16 * ChannelCount; int pcm_bitrate = (int)(m_info.SamplesPerSec * BitsPerSample * ChannelCount);
var format = new GameRes.WaveFormat(); var format = new GameRes.WaveFormat();
format.FormatTag = 1; format.FormatTag = 1;
format.Channels = (ushort)ChannelCount; format.Channels = (ushort)ChannelCount;
@@ -145,18 +143,13 @@ namespace GameRes.Formats.Entis
format.BlockAlign = (ushort)(BitsPerSample/8*format.Channels); format.BlockAlign = (ushort)(BitsPerSample/8*format.Channels);
format.AverageBytesPerSecond = (uint)pcm_bitrate/8; format.AverageBytesPerSecond = (uint)pcm_bitrate/8;
this.Format = format; this.Format = format;
m_decoded_stream = LoadChunks(); m_decoded_stream = LoadChunks (erif);
if (0 != m_total_samples) if (0 != m_total_samples)
m_bitrate = (int)(stream_size * 8 * m_info.SamplesPerSec / m_total_samples); m_bitrate = (int)(stream_size * 8 * m_info.SamplesPerSec / m_total_samples);
this.PcmSize = m_total_samples * ChannelCount * BitsPerSample / 8; this.PcmSize = m_total_samples * ChannelCount * BitsPerSample / 8;
m_decoded_stream.Position = 0; m_decoded_stream.Position = 0;
} }
catch
{
m_erif.Dispose();
throw;
}
} }
class MioChunk : MioDataHeader class MioChunk : MioDataHeader
@@ -234,29 +227,29 @@ namespace GameRes.Formats.Entis
} }
} }
private Stream LoadChunks () private Stream LoadChunks (EriFile erif)
{ {
uint current_sample = 0; uint current_sample = 0;
List<MioChunk> chunks = new List<MioChunk>(); List<MioChunk> chunks = new List<MioChunk>();
try try
{ {
m_erif.BaseStream.Position = m_stream_pos; erif.BaseStream.Position = m_stream_pos;
for (;;) for (;;)
{ {
long chunk_length = m_erif.FindSection ("SoundStm"); long chunk_length = erif.FindSection ("SoundStm");
if (chunk_length > int.MaxValue) if (chunk_length > int.MaxValue)
throw new FileSizeException(); throw new FileSizeException();
var chunk = new MioChunk(); var chunk = new MioChunk();
chunk.FirstSample = current_sample; chunk.FirstSample = current_sample;
chunk.Version = m_erif.ReadByte(); chunk.Version = erif.ReadByte();
chunk.Flags = m_erif.ReadByte(); chunk.Flags = erif.ReadByte();
m_erif.ReadInt16(); erif.ReadInt16();
chunk.SampleCount = m_erif.ReadUInt32(); chunk.SampleCount = erif.ReadUInt32();
chunk.Position = m_erif.BaseStream.Position; chunk.Position = erif.BaseStream.Position;
chunk.Size = (uint)(chunk_length - 8); chunk.Size = (uint)(chunk_length - 8);
current_sample += chunk.SampleCount; current_sample += chunk.SampleCount;
chunks.Add (chunk); chunks.Add (chunk);
m_erif.BaseStream.Seek (chunk.Size, SeekOrigin.Current); erif.BaseStream.Seek (chunk.Size, SeekOrigin.Current);
} }
} }
catch (EndOfStreamException) { /* ignore EOF errors */ } catch (EndOfStreamException) { /* ignore EOF errors */ }
@@ -270,6 +263,8 @@ namespace GameRes.Formats.Entis
var total_bytes = m_total_samples * sample_bytes; var total_bytes = m_total_samples * sample_bytes;
m_wait_handles = new WaitHandle[2] { m_available_chunk, m_decode_complete }; m_wait_handles = new WaitHandle[2] { m_available_chunk, m_decode_complete };
m_chunk_queue = new ConcurrentQueue<byte[]>();
m_worker = new BackgroundWorker();
m_worker.WorkerSupportsCancellation = true; m_worker.WorkerSupportsCancellation = true;
m_worker.DoWork += DoWork_Decode; m_worker.DoWork += DoWork_Decode;
m_worker.RunWorkerAsync (chunks); m_worker.RunWorkerAsync (chunks);
@@ -281,8 +276,8 @@ namespace GameRes.Formats.Entis
AutoResetEvent m_available_chunk = new AutoResetEvent (false); AutoResetEvent m_available_chunk = new AutoResetEvent (false);
WaitHandle[] m_wait_handles; WaitHandle[] m_wait_handles;
ConcurrentQueue<byte[]> m_chunk_queue = new ConcurrentQueue<byte[]>(); ConcurrentQueue<byte[]> m_chunk_queue;
BackgroundWorker m_worker = new BackgroundWorker(); BackgroundWorker m_worker;
Exception m_decode_error = null; Exception m_decode_error = null;
private void DoWork_Decode (object sender, DoWorkEventArgs e) private void DoWork_Decode (object sender, DoWorkEventArgs e)
@@ -366,9 +361,10 @@ namespace GameRes.Formats.Entis
} }
#region IDisposable Members #region IDisposable Members
bool _mio_disposed = false;
protected override void Dispose (bool disposing) protected override void Dispose (bool disposing)
{ {
if (null != m_erif) if (!_mio_disposed)
{ {
if (disposing) if (disposing)
{ {
@@ -377,13 +373,12 @@ namespace GameRes.Formats.Entis
m_worker.CancelAsync(); m_worker.CancelAsync();
m_decode_complete.WaitOne(); m_decode_complete.WaitOne();
} }
m_erif.Dispose();
if (m_decoded_stream != null) if (m_decoded_stream != null)
m_decoded_stream.Dispose(); m_decoded_stream.Dispose();
m_decode_complete.Dispose(); m_decode_complete.Dispose();
m_available_chunk.Dispose(); m_available_chunk.Dispose();
} }
m_erif = null; _mio_disposed = true;
base.Dispose (disposing); base.Dispose (disposing);
} }
} }