diff --git a/CUETools.Codecs.LAME/LameWriter.cs b/CUETools.Codecs.LAME/LameWriter.cs index c4a998a..aa4af3b 100644 --- a/CUETools.Codecs.LAME/LameWriter.cs +++ b/CUETools.Codecs.LAME/LameWriter.cs @@ -280,7 +280,7 @@ namespace CUETools.Codecs.LAME public void Delete() { - if (this.outputPath != null) + if (this.outputPath == null) { throw new InvalidOperationException("This writer was not created from file."); } diff --git a/CUETools.Codecs.WMA/CUETools.Codecs.WMA.csproj b/CUETools.Codecs.WMA/CUETools.Codecs.WMA.csproj index 3ee6bbb..3a3c1bd 100644 --- a/CUETools.Codecs.WMA/CUETools.Codecs.WMA.csproj +++ b/CUETools.Codecs.WMA/CUETools.Codecs.WMA.csproj @@ -67,6 +67,7 @@ True Resources.resx + diff --git a/CUETools.Codecs.WMA/WMAWriter.cs b/CUETools.Codecs.WMA/WMAWriter.cs new file mode 100644 index 0000000..41e359f --- /dev/null +++ b/CUETools.Codecs.WMA/WMAWriter.cs @@ -0,0 +1,261 @@ +using System; +using System.Runtime.InteropServices; +using CUETools.Codecs; +using System.IO; +using WindowsMediaLib; +using WindowsMediaLib.Defs; +using System.Runtime.InteropServices; + +namespace CUETools.Codecs.WMA +{ + public class WMAWriterSettings + { + public WMAWriterSettings() { } + } + + + [AudioEncoderClass("windows", "wma", true, "", "", 1, typeof(WMAWriterSettings))] + public class WMAWriter : IAudioDest + { + IWMProfileManager m_pProfileManager; + IWMWriter m_pWriter; + int m_iCodec, m_iFormat; + + private string outputPath; + + private bool closed = false; + private AudioPCMConfig pcm; + private long sampleCount, finalSampleCount; + + public long BlockSize + { + set { } + } + + public virtual int CompressionLevel + { + get { return 0; } + set { } + } + + public long FinalSampleCount + { + set + { + this.finalSampleCount = value; + } + } + + public AudioPCMConfig PCM + { + get { return this.pcm; } + } + + public long Padding + { + set { } + } + + public string Path + { + get { return this.outputPath; } + } + + public virtual object Settings + { + get; set; + } + + public WMAWriter(string path, AudioPCMConfig pcm) + { + this.CheckPCMConfig(pcm); + this.pcm = pcm; + this.outputPath = path; + + try + { + WMUtils.WMCreateProfileManager(out m_pProfileManager); + var pCodecInfo3 = m_pProfileManager as IWMCodecInfo3; + int cCodecs; + pCodecInfo3.GetCodecInfoCount(MediaType.Audio, out cCodecs); + bool codecFound = false; + for (int iCodec = 0; iCodec < cCodecs; iCodec++) + { + //if (codec != WMAvoice) + try + { + pCodecInfo3.SetCodecEnumerationSetting(MediaType.Audio, iCodec, Constants.g_wszVBREnabled, AttrDataType.BOOL, new byte[] {1, 0, 0, 0}, 4); + //pCodecInfo3.SetCodecEnumerationSetting(MediaType.Audio, iCodec, Constants.g_wszNumPasses, AttrDataType.DWORD, new byte[] {1, 0, 0, 0}, 4); + } + catch (COMException) + { + } + + int cFormat; + pCodecInfo3.GetCodecFormatCount(MediaType.Audio, iCodec, out cFormat); + for (int iFormat = 0; iFormat < cFormat; iFormat++) + { + IWMStreamConfig pStreamConfig; + pCodecInfo3.GetCodecFormat(MediaType.Audio, iCodec, iFormat, out pStreamConfig); + try + { + var pProps = pStreamConfig as IWMMediaProps; + int cbType = 0; + AMMediaType pMediaType = null; + pProps.GetMediaType(pMediaType, ref cbType); + pMediaType = new AMMediaType(); + pMediaType.formatSize = cbType - Marshal.SizeOf(typeof(AMMediaType)); + pProps.GetMediaType(pMediaType, ref cbType); + try + { + if (pMediaType.majorType == MediaType.Audio && pMediaType.formatType == FormatType.WaveEx && pMediaType.subType == MediaSubType.WMAudio_Lossless) + { + WaveFormatEx pWfx = new WaveFormatEx(); + Marshal.PtrToStructure(pMediaType.formatPtr, pWfx); + if (pWfx.nChannels == pcm.ChannelCount && pWfx.wBitsPerSample == pcm.BitsPerSample && pWfx.nSamplesPerSec == pcm.SampleRate) + { + m_iCodec = iCodec; + m_iFormat = iFormat; + codecFound = true; + } + } + } + finally + { + WMUtils.FreeWMMediaType(pMediaType); + } + } + finally + { + Marshal.ReleaseComObject(pStreamConfig); + } + } + } + if (!codecFound) + throw new NotSupportedException("codec not found"); + IWMStreamConfig pStreamConfig1; + pCodecInfo3.GetCodecFormat(MediaType.Audio, m_iCodec, m_iFormat, out pStreamConfig1); + try + { + pStreamConfig1.SetStreamNumber(1); + IWMProfile pProfile; + m_pProfileManager.CreateEmptyProfile(WMVersion.V9_0, out pProfile); + try + { + pProfile.AddStream(pStreamConfig1); + WMUtils.WMCreateWriter(IntPtr.Zero, out m_pWriter); + m_pWriter.SetProfile(pProfile); + int cInputs; + m_pWriter.GetInputCount(out cInputs); + //for (int iInput = 0; iInput < cInputs; iInput++) + //{ + //} + //IWMInputMediaProps pInput; + //pWriter.GetInputProps(0, out pInput); + //pInput.GetMediaType(pType, ref cbType); + // fill (WAVEFORMATEX*)pType->pbFormat + // WAVEFORMATEXTENSIBLE if needed (dwChannelMask, wValidBitsPerSample) + // if (chg) + //pInput.SetMediaType(pType); + //pWriter.SetInputProps(0, pInput); + + //{ DWORD dwFormatCount = 0; hr = pWriter->GetInputFormatCount(0, &dwFormatCount); TEST(hr); TESTB(dwFormatCount > 0); } + //// GetInputFormatCount failed previously for multichannel formats, before ...mask = guessChannelMask() added. Leave this check j.i.c. + m_pWriter.SetOutputFilename(outputPath); + m_pWriter.BeginWriting(); + } + finally + { + Marshal.ReleaseComObject(pProfile); + } + } + finally + { + Marshal.ReleaseComObject(pStreamConfig1); + } + } + catch (Exception ex) + { + if (m_pWriter != null) + { + Marshal.ReleaseComObject(m_pWriter); + m_pWriter = null; + } + if (m_pProfileManager != null) + { + Marshal.ReleaseComObject(m_pProfileManager); + m_pProfileManager = null; + } + throw ex; + } + } + + private void CheckPCMConfig(AudioPCMConfig pcm) + { + if (pcm.BitsPerSample != 16) + { + throw new ArgumentException("LAME only supports 16 bits/sample."); + } + } + + public void Close() + { + if (!this.closed) + { + try + { + m_pWriter.EndWriting(); + } + finally + { + if (m_pWriter != null) + { + Marshal.ReleaseComObject(m_pWriter); + m_pWriter = null; + } + if (m_pProfileManager != null) + { + Marshal.ReleaseComObject(m_pProfileManager); + m_pProfileManager = null; + } + } + + this.closed = true; + } + } + + public void Delete() + { + if (this.outputPath == null) + { + throw new InvalidOperationException("This writer was not created from file."); + } + + if (!closed) + { + this.Close(); + File.Delete(this.outputPath); + } + } + + public void Write(AudioBuffer buffer) + { + if (this.closed) + { + throw new InvalidOperationException("Writer already closed."); + } + + buffer.Prepare(this); + INSSBuffer pSample; + m_pWriter.AllocateSample(buffer.ByteLength, out pSample); + IntPtr pdwBuffer; + pSample.GetBuffer(out pdwBuffer); + pSample.SetLength(buffer.ByteLength); + Marshal.Copy(buffer.Bytes, 0, pdwBuffer, buffer.ByteLength); + long cnsSampleTime = sampleCount * 10000000L / pcm.SampleRate; + m_pWriter.WriteSample(0, cnsSampleTime, SampleFlag.CleanPoint, pSample); + Marshal.ReleaseComObject(pSample); + sampleCount += buffer.Length; + } + } +}