private void audioStreamInfo(AviSynthClip x) { if (x.SampleType == AudioSampleType.FLOAT) // New for float output { raiseEvent(m_job, new EncoderCallbackEventArgs(string.Format("Channels={0}, BitsPerSample={1} float, SampleRate={2}Hz", x.ChannelsCount, x.BitsPerSample, x.AudioSampleRate))); } else { raiseEvent(m_job, new EncoderCallbackEventArgs(string.Format("Channels={0}, BitsPerSample={1} int, SampleRate={2}Hz", x.ChannelsCount, x.BitsPerSample, x.AudioSampleRate))); } }
private void readAudioStreamInfo(AviSynthClip x) { m_nSampleCount = x.SamplesCount; m_nSizeInBytes = m_nSampleCount; m_nSizeInBytes *= x.BytesPerSample; m_nSizeInBytes *= x.ChannelsCount; m_nFormatTag = 1; // 1 for int, 3 for float if (x.SampleType == AudioSampleType.FLOAT) { m_nFormatTag = 3; } }
private void createEncoderProcess(AviSynthClip x) { try { m_process = new Process(); ProcessStartInfo info = new ProcessStartInfo(); // Command line arguments, to be passed to encoder // {0} means output file name // {1} means samplerate in Hz // {2} means bits per sample // {3} means channel count // {4} means samplecount // {5} means size in bytes // {6} means format (1 int, 3 float) info.Arguments = string.Format(m_commandLine, m_output, x.AudioSampleRate, x.BitsPerSample, x.ChannelsCount, m_nSampleCount, m_nSizeInBytes, m_nFormatTag); info.FileName = m_encoder; raiseEvent(m_job, new EncoderCallbackEventArgs(string.Format("{0} {1}", m_encoder, info.Arguments))); info.UseShellExecute = false; info.RedirectStandardInput = true; info.RedirectStandardOutput = true; info.RedirectStandardError = true; info.CreateNoWindow = true; m_process.StartInfo = info; m_process.Start(); m_process.PriorityClass = m_processPriority; m_readFromStdOutThread = new Thread(new ThreadStart(readStdOut)); m_readFromStdErrThread = new Thread(new ThreadStart(readStdErr)); m_readFromStdOutThread.Start(); m_readFromStdOutThread.Priority = ThreadPriority.Normal; m_readFromStdErrThread.Start(); m_readFromStdErrThread.Priority = ThreadPriority.Normal; } catch (Exception e) { throw new ApplicationException("Can't start encoder: " + e.Message, e); } }
private void writeHeader(Stream target, AviSynthClip x) { const uint FAAD_MAGIC_VALUE = 0xFFFFFF00; bool Greater4GB = m_nSizeInBytes >= (uint.MaxValue - 68); bool WExtHeader = m_ChannelMask >= 0; uint HeaderSize = (uint)(WExtHeader ? 60 : 36); int[] defmask = { 0, 4, 3, 7, 51, 55, 63, 319, 1599, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (m_HeaderType == 1) // W64 { HeaderSize = (uint)(WExtHeader ? 128 : 112); target.Write(System.Text.Encoding.ASCII.GetBytes("riff"), 0, 4); target.Write(BitConverter.GetBytes((uint)0x11CF912E), 0, 4); // GUID target.Write(BitConverter.GetBytes((uint)0xDB28D6A5), 0, 4); target.Write(BitConverter.GetBytes((uint)0x0000C104), 0, 4); target.Write(BitConverter.GetBytes((m_nSizeInBytes + HeaderSize)), 0, 8); target.Write(System.Text.Encoding.ASCII.GetBytes("wave"), 0, 4); target.Write(BitConverter.GetBytes((uint)0x11D3ACF3), 0, 4); // GUID target.Write(BitConverter.GetBytes((uint)0xC000D18C), 0, 4); target.Write(BitConverter.GetBytes((uint)0x8ADB8E4F), 0, 4); target.Write(System.Text.Encoding.ASCII.GetBytes("fmt "), 0, 4); target.Write(BitConverter.GetBytes((uint)0x11D3ACF3), 0, 4); // GUID target.Write(BitConverter.GetBytes((uint)0xC000D18C), 0, 4); target.Write(BitConverter.GetBytes((uint)0x8ADB8E4F), 0, 4); target.Write(BitConverter.GetBytes(WExtHeader ? (ulong)64 : (ulong)48), 0, 8); } else if (m_HeaderType == 2) // RF64 { HeaderSize += 36; target.Write(System.Text.Encoding.ASCII.GetBytes("RF64"), 0, 4); target.Write(BitConverter.GetBytes((uint)0xFFFFFFFF), 0, 4); target.Write(System.Text.Encoding.ASCII.GetBytes("WAVE"), 0, 4); target.Write(System.Text.Encoding.ASCII.GetBytes("ds64"), 0, 4); // new ds64 chunk 36 bytes target.Write(BitConverter.GetBytes((uint)28), 0, 4); target.Write(BitConverter.GetBytes((m_nSizeInBytes + HeaderSize)), 0, 8); target.Write(BitConverter.GetBytes((m_nSizeInBytes)), 0, 8); target.Write(BitConverter.GetBytes((m_nSampleCount)), 0, 8); target.Write(BitConverter.GetBytes((uint)0x0000), 0, 4); target.Write(System.Text.Encoding.ASCII.GetBytes("fmt "), 0, 4); target.Write(BitConverter.GetBytes(WExtHeader ? (uint)40 : (uint)16), 0, 4); } else //WAV { target.Write(System.Text.Encoding.ASCII.GetBytes("RIFF"), 0, 4); target.Write(BitConverter.GetBytes(Greater4GB ? (FAAD_MAGIC_VALUE + HeaderSize):(uint)(m_nSizeInBytes + HeaderSize)), 0, 4); target.Write(System.Text.Encoding.ASCII.GetBytes("WAVE"), 0, 4); target.Write(System.Text.Encoding.ASCII.GetBytes("fmt "), 0, 4); target.Write(BitConverter.GetBytes(WExtHeader ? (uint)40 : (uint)16), 0, 4); } // fmt chunk common target.Write(BitConverter.GetBytes(WExtHeader ? (uint)0xFFFE : m_nFormatTag), 0, 2); target.Write(BitConverter.GetBytes(x.ChannelsCount), 0, 2); target.Write(BitConverter.GetBytes(x.AudioSampleRate), 0, 4); target.Write(BitConverter.GetBytes(x.BitsPerSample * x.AudioSampleRate * x.ChannelsCount / 8), 0, 4); target.Write(BitConverter.GetBytes(x.ChannelsCount * x.BitsPerSample / 8), 0, 2); target.Write(BitConverter.GetBytes(x.BitsPerSample), 0, 2); // if WAVE_FORMAT_EXTENSIBLE continue fmt chunk if (WExtHeader) { if (m_ChannelMask == 0) { m_ChannelMask = defmask[x.ChannelsCount]; } target.Write(BitConverter.GetBytes((uint)0x16), 0, 2); target.Write(BitConverter.GetBytes(x.BitsPerSample), 0, 2); target.Write(BitConverter.GetBytes(m_ChannelMask), 0, 4); target.Write(BitConverter.GetBytes(m_nFormatTag), 0, 4); target.Write(BitConverter.GetBytes((uint)0x00100000), 0, 4); // GUID target.Write(BitConverter.GetBytes((uint)0xAA000080), 0, 4); target.Write(BitConverter.GetBytes((uint)0x719B3800), 0, 4); } // data chunk if (m_HeaderType == 1) // W64 { if (!WExtHeader) { target.Write(BitConverter.GetBytes((uint)0x0000D000), 0, 4); // pad target.Write(BitConverter.GetBytes((uint)0x0000D000), 0, 4); } target.Write(System.Text.Encoding.ASCII.GetBytes("data"), 0, 4); target.Write(BitConverter.GetBytes((uint)0x11D3ACF3), 0, 4); // GUID target.Write(BitConverter.GetBytes((uint)0xC000D18C), 0, 4); target.Write(BitConverter.GetBytes((uint)0x8ADB8E4F), 0, 4); target.Write(BitConverter.GetBytes(m_nSizeInBytes + 24), 0, 8); } else if (m_HeaderType == 2) // RF64 { target.Write(System.Text.Encoding.ASCII.GetBytes("data"), 0, 4); target.Write(BitConverter.GetBytes((uint)0xFFFFFFFF), 0, 4); } else // WAV { target.Write(System.Text.Encoding.ASCII.GetBytes("data"), 0, 4); target.Write(BitConverter.GetBytes(Greater4GB ? FAAD_MAGIC_VALUE : (uint)m_nSizeInBytes), 0, 4); } }
private void encode() { try { string sTempFileName = saveScriptToTempFile(); try { using (AviSynthScriptEnvironment env = new AviSynthScriptEnvironment()) { using (AviSynthClip x = env.ParseScript(m_script)) { //.OpenScriptFile(sTempFileName)) if (0 == x.SamplesCount) { throw new ApplicationException("Can't find audio stream!"); } audioStreamFound(); readAudioStreamInfo(x); audioStreamInfo(x); const int MAX_SAMPLES_PER_ONCE = 4096; int frameSample = 0; int samplesRead = 0; int frameBufferTotalSize = MAX_SAMPLES_PER_ONCE * x.ChannelsCount * x.BitsPerSample / 8; int bytesRead = 0; //frameBufferTotalSize; byte[] frameBuffer = new byte[frameBufferTotalSize]; bool WExtHeader = m_ChannelMask >= 0; bool Greater4GB = m_nSizeInBytes >= (uint.MaxValue - 68); if ((Greater4GB) && (m_HeaderType > 2)) { m_HeaderType -= 2; } if (m_encoder != null) { createEncoderProcess(x); } try { using (Stream target = getOutputStream()) { // let's write WAV Header if (m_sendHeader) { if (m_HeaderType == 1) // Useful for debug { if (WExtHeader) { raiseEvent(m_job, new EncoderCallbackEventArgs("Writing W64_EXT header to encoder's StdIn")); } else { raiseEvent(m_job, new EncoderCallbackEventArgs("Writing W64 header to encoder's StdIn")); } } else if (m_HeaderType == 2) { if (WExtHeader) { raiseEvent(m_job, new EncoderCallbackEventArgs("Writing RF64_EXT header to encoder's StdIn")); } else { raiseEvent(m_job, new EncoderCallbackEventArgs("Writing RF64 header to encoder's StdIn")); } } else { if (WExtHeader) { raiseEvent(m_job, new EncoderCallbackEventArgs("Writing RIFF_EXT header to encoder's StdIn")); } else { raiseEvent(m_job, new EncoderCallbackEventArgs("Writing RIFF header to encoder's StdIn")); } } writeHeader(target, x); } raiseEvent(m_job, new EncoderCallbackEventArgs("Writing PCM data to encoder's StdIn")); GCHandle h = GCHandle.Alloc(frameBuffer, GCHandleType.Pinned); try { while (frameSample < x.SamplesCount) { if (m_process != null) { if (m_process.HasExited) { throw new ApplicationException("Abnormal encoder termination " + m_process.ExitCode.ToString()); } } samplesRead = 0; bytesRead = 0; int nHowMany = Math.Min((int)(x.SamplesCount - frameSample), MAX_SAMPLES_PER_ONCE); x.ReadAudio(h.AddrOfPinnedObject(), frameSample, nHowMany); bytesRead = nHowMany * x.BytesPerSample * x.ChannelsCount; samplesRead = nHowMany; //setProgress((100*(double)frameSample / x.SamplesCount)); m_job.Progress = (int)(100 * (double)frameSample / x.SamplesCount); target.Write(frameBuffer, 0, bytesRead); if (m_process != null) { target.Flush(); } frameSample += samplesRead; Thread.Sleep(0); } } finally { h.Free(); } //setProgress(100); m_job.Progress = 100; } if (m_process != null) { raiseEvent(m_job, new EncoderCallbackEventArgs("Finalizing encoder")); m_process.WaitForExit(); m_readFromStdErrThread.Join(); m_readFromStdOutThread.Join(); if (0 != m_process.ExitCode) { throw new ApplicationException("Abnormal encoder termination " + m_process.ExitCode.ToString()); } } } finally { if (m_process != null) { if (!m_process.HasExited) { m_process.Kill(); m_process.WaitForExit(); m_readFromStdErrThread.Join(); m_readFromStdOutThread.Join(); } } m_readFromStdErrThread = null; m_readFromStdOutThread = null; } } } } finally { File.Delete(sTempFileName); } } catch (Exception e) { clearOutput(); if (e is ThreadAbortException) { raiseEvent(m_job, new EncoderCallbackEventArgs(EncoderCallbackEventArgs.EventType.Terminated)); } else { raiseEvent(m_job, new EncoderCallbackEventArgs(e)); } return; } raiseEvent(m_job, new EncoderCallbackEventArgs(EncoderCallbackEventArgs.EventType.Done)); }