mirror of
https://github.com/crskycode/GARbro.git
synced 2024-10-23 15:48:16 +08:00
implemented WMA audio.
This commit is contained in:
parent
4151c15cd6
commit
7b50e35783
@ -91,6 +91,7 @@
|
|||||||
<Compile Include="ArcARCX.cs" />
|
<Compile Include="ArcARCX.cs" />
|
||||||
<Compile Include="ArcCG.cs" />
|
<Compile Include="ArcCG.cs" />
|
||||||
<Compile Include="Artemis\ArcPFS.cs" />
|
<Compile Include="Artemis\ArcPFS.cs" />
|
||||||
|
<Compile Include="AudioWMA.cs" />
|
||||||
<Compile Include="BlackRainbow\ArcDX.cs" />
|
<Compile Include="BlackRainbow\ArcDX.cs" />
|
||||||
<Compile Include="Cadath\ArcKAR.cs" />
|
<Compile Include="Cadath\ArcKAR.cs" />
|
||||||
<Compile Include="Cadath\ImageKGF.cs" />
|
<Compile Include="Cadath\ImageKGF.cs" />
|
||||||
|
@ -26,6 +26,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.ComponentModel.Composition;
|
using System.ComponentModel.Composition;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.InteropServices.ComTypes;
|
||||||
|
using NAudio.CoreAudioApi.Interfaces;
|
||||||
|
using NAudio.MediaFoundation;
|
||||||
|
using NAudio.Utils;
|
||||||
using NAudio.Wave;
|
using NAudio.Wave;
|
||||||
|
|
||||||
namespace GameRes.Formats
|
namespace GameRes.Formats
|
||||||
@ -66,15 +71,20 @@ namespace GameRes.Formats
|
|||||||
|
|
||||||
public WmaInput (Stream file) : base (file)
|
public WmaInput (Stream file) : base (file)
|
||||||
{
|
{
|
||||||
m_reader = new StreamMediaFoundationReader (file);
|
var reader = new CustomMediaFoundationReader (file);
|
||||||
m_bitrate = m_reader.WaveFormat.AverageBytesPerSecond * 8;
|
if (reader.Duration != 0)
|
||||||
var format = new GameRes.WaveFormat();
|
m_bitrate = (int)(file.Length * 80000000L / reader.Duration);
|
||||||
format.FormatTag = (ushort)m_reader.WaveFormat.Encoding;
|
else
|
||||||
format.Channels = (ushort)m_reader.WaveFormat.Channels;
|
m_bitrate = reader.WaveFormat.AverageBytesPerSecond * 8;
|
||||||
format.SamplesPerSecond = (uint)m_reader.WaveFormat.SampleRate;
|
m_reader = reader;
|
||||||
format.BitsPerSample = (ushort)m_reader.WaveFormat.BitsPerSample;
|
var format = new GameRes.WaveFormat {
|
||||||
format.BlockAlign = (ushort)m_reader.BlockAlign;
|
FormatTag = (ushort)m_reader.WaveFormat.Encoding,
|
||||||
format.AverageBytesPerSecond = (uint)m_reader.WaveFormat.AverageBytesPerSecond;
|
Channels = (ushort)m_reader.WaveFormat.Channels,
|
||||||
|
SamplesPerSecond = (uint)m_reader.WaveFormat.SampleRate,
|
||||||
|
BitsPerSample = (ushort)m_reader.WaveFormat.BitsPerSample,
|
||||||
|
BlockAlign = (ushort)m_reader.BlockAlign,
|
||||||
|
AverageBytesPerSecond = (uint)m_reader.WaveFormat.AverageBytesPerSecond,
|
||||||
|
};
|
||||||
this.Format = format;
|
this.Format = format;
|
||||||
this.PcmSize = m_reader.Length;
|
this.PcmSize = m_reader.Length;
|
||||||
}
|
}
|
||||||
@ -100,4 +110,156 @@ namespace GameRes.Formats
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Custom implementation of MediaFoundationReader.
|
||||||
|
/// NAudio uses MFCreateMFByteStreamOnStreamEx API call which is not available in Windows 7.
|
||||||
|
/// </summary>
|
||||||
|
internal class CustomMediaFoundationReader : MediaFoundationReader
|
||||||
|
{
|
||||||
|
private readonly Stream m_stream;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the duration of a presentation, in 100-nanosecond units.
|
||||||
|
/// </summary>
|
||||||
|
public long Duration { get; private set; }
|
||||||
|
|
||||||
|
public CustomMediaFoundationReader (Stream stream, MediaFoundationReaderSettings settings = null)
|
||||||
|
{
|
||||||
|
m_stream = stream;
|
||||||
|
Init (settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IMFSourceReader CreateReader (MediaFoundationReaderSettings settings)
|
||||||
|
{
|
||||||
|
IMFByteStream byteStream;
|
||||||
|
MFCreateMFByteStreamOnStream (new ComStream (m_stream), out byteStream);
|
||||||
|
var source_reader = MediaFoundationApi.CreateSourceReaderFromByteStream (byteStream);
|
||||||
|
|
||||||
|
source_reader.SetStreamSelection (-2, false);
|
||||||
|
source_reader.SetStreamSelection (-3, true);
|
||||||
|
source_reader.SetCurrentMediaType (-3, IntPtr.Zero, new MediaType
|
||||||
|
{
|
||||||
|
MajorType = MediaTypes.MFMediaType_Audio,
|
||||||
|
SubType = settings.RequestFloatOutput ? AudioSubtypes.MFAudioFormat_Float : AudioSubtypes.MFAudioFormat_PCM
|
||||||
|
}.MediaFoundationObject);
|
||||||
|
|
||||||
|
Duration = GetDuration (source_reader);
|
||||||
|
|
||||||
|
return source_reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long GetDuration (IMFSourceReader reader)
|
||||||
|
{
|
||||||
|
var variantPtr = Marshal.AllocHGlobal (MarshalHelpers.SizeOf<PropVariant>());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int hResult = reader.GetPresentationAttribute (MediaFoundationInterop.MF_SOURCE_READER_MEDIASOURCE,
|
||||||
|
MediaFoundationAttributes.MF_PD_DURATION, variantPtr);
|
||||||
|
if (hResult == MediaFoundationErrors.MF_E_ATTRIBUTENOTFOUND)
|
||||||
|
return 0;
|
||||||
|
if (hResult != 0)
|
||||||
|
Marshal.ThrowExceptionForHR (hResult);
|
||||||
|
|
||||||
|
var variant = MarshalHelpers.PtrToStructure<PropVariant> (variantPtr);
|
||||||
|
return (long)variant.Value;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
PropVariant.Clear (variantPtr);
|
||||||
|
Marshal.FreeHGlobal (variantPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = false)]
|
||||||
|
static extern void MFCreateMFByteStreamOnStream (IStream pStream, out IMFByteStream ppByteStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implementation of Com IStream.
|
||||||
|
/// NAudio implementation is inaccessible (private).
|
||||||
|
/// </summary>
|
||||||
|
internal class ComStream : ProxyStream, IStream
|
||||||
|
{
|
||||||
|
public ComStream (Stream stream) : base (Synchronized (stream))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void IStream.Clone (out IStream ppstm)
|
||||||
|
{
|
||||||
|
ppstm = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IStream.Commit (int grfCommitFlags)
|
||||||
|
{
|
||||||
|
Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IStream.CopyTo (IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void IStream.LockRegion (long libOffset, long cb, int dwLockType)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void IStream.Read (byte[] pv, int cb, IntPtr pcbRead)
|
||||||
|
{
|
||||||
|
if (!CanRead)
|
||||||
|
throw new InvalidOperationException ("Stream is not readable.");
|
||||||
|
int read = Read (pv, 0, cb);
|
||||||
|
if (pcbRead != IntPtr.Zero)
|
||||||
|
Marshal.WriteInt32 (pcbRead, read);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IStream.Revert()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void IStream.Seek (long dlibMove, int dwOrigin, IntPtr plibNewPosition)
|
||||||
|
{
|
||||||
|
SeekOrigin origin = (SeekOrigin) dwOrigin;
|
||||||
|
long val = Seek (dlibMove, origin);
|
||||||
|
if (plibNewPosition != IntPtr.Zero)
|
||||||
|
Marshal.WriteInt64 (plibNewPosition, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IStream.SetSize (long libNewSize)
|
||||||
|
{
|
||||||
|
SetLength (libNewSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IStream.Stat (out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag)
|
||||||
|
{
|
||||||
|
const int STGM_READ = 0x00000000;
|
||||||
|
const int STGM_WRITE = 0x00000001;
|
||||||
|
const int STGM_READWRITE = 0x00000002;
|
||||||
|
|
||||||
|
var tmp = new System.Runtime.InteropServices.ComTypes.STATSTG { type = 2, cbSize = Length, grfMode = 0 };
|
||||||
|
|
||||||
|
if (CanWrite && CanRead)
|
||||||
|
tmp.grfMode |= STGM_READWRITE;
|
||||||
|
else if (CanRead)
|
||||||
|
tmp.grfMode |= STGM_READ;
|
||||||
|
else if (CanWrite)
|
||||||
|
tmp.grfMode |= STGM_WRITE;
|
||||||
|
else
|
||||||
|
throw new ObjectDisposedException ("Stream");
|
||||||
|
|
||||||
|
pstatstg = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IStream.UnlockRegion (long libOffset, long cb, int dwLockType)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void IStream.Write (byte[] pv, int cb, IntPtr pcbWritten)
|
||||||
|
{
|
||||||
|
if (!CanWrite)
|
||||||
|
throw new InvalidOperationException ("Stream is not writeable.");
|
||||||
|
Write (pv, 0, cb);
|
||||||
|
if (pcbWritten != IntPtr.Zero)
|
||||||
|
Marshal.WriteInt32 (pcbWritten, cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user