From 0415735fedd6555cbbde9908b63d17be44992114 Mon Sep 17 00:00:00 2001 From: Pangpang Don <49866401+DonPangPang@users.noreply.github.com> Date: Fri, 3 Dec 2021 23:02:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E9=9F=B3=E9=A2=91=E9=83=A8?= =?UTF-8?q?=E5=88=86=EF=BC=8C=E9=80=82=E7=94=A8=E4=BA=8Ewindows=20x64?= =?UTF-8?q?=E5=92=8Cx86=E5=B9=B3=E5=8F=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/JT1078.Flv.Test/Audio/AudioTest.cs | 52 +++---- .../Audio/AudioCodecFactory.cs | 18 ++- src/JT1078.Protocol/Audio/FaacEncoder.cs | 134 ++++++++++++------ .../Extensions/InteropExtensions.cs | 93 ++++++++++++ src/JT1078.Protocol/JT1078.Protocol.csproj | 5 - 5 files changed, 220 insertions(+), 82 deletions(-) create mode 100644 src/JT1078.Protocol/Extensions/InteropExtensions.cs diff --git a/src/JT1078.Flv.Test/Audio/AudioTest.cs b/src/JT1078.Flv.Test/Audio/AudioTest.cs index 0e54f58..69da6be 100644 --- a/src/JT1078.Flv.Test/Audio/AudioTest.cs +++ b/src/JT1078.Flv.Test/Audio/AudioTest.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Text; +using JT1078.Protocol.Audio; using Xunit; using Xunit.Abstractions; @@ -11,7 +12,7 @@ namespace JT1078.Flv.Test.Audio { public class AudioTest { - readonly ITestOutputHelper output; + private readonly ITestOutputHelper output; public AudioTest(ITestOutputHelper output) { @@ -19,8 +20,8 @@ namespace JT1078.Flv.Test.Audio } /// - /// 8000采样,单通道,16位pcm->aac - /// 8k-1ch-16bit + /// 8000采样,单通道,16位pcm->aac + /// 8k-1ch-16bit /// [Fact(DisplayName = "pcm编码aac")] public void Test1() @@ -28,29 +29,30 @@ namespace JT1078.Flv.Test.Audio //todo:音频暂时先放下 ReadOnlySpan fileData = File.ReadAllBytes(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"Audio/Files/testpacket.pcm")); //注意 这里为了可以判断音频是否可用,因此使用adts,当网络传输的时候不应该使用adts - //var faac = new FaacEncoder_x64(8000, 1, 16, true); - //var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Audio\Files\testpacket.aac"); - //if (File.Exists(path)) File.Delete(path); - //output.WriteLine(path); - //var offset = 0; - //var step = faac.frameSize; - //var totalBytes = 0; - //var stopwatch = new Stopwatch(); - //while (offset + step < fileData.Length) - //{ - // stopwatch.Start(); - // var aacBuff = faac.Encode(fileData.Slice(offset, step).ToArray()); - // stopwatch.Stop(); - // if (aacBuff.Any()) - // aacBuff.AppendBytesToFile(path); - // offset += step; - // totalBytes += aacBuff.Length; - //} - //faac.Dispose(); - //output.WriteLine($"已编码字节数:{offset},剩余未编码字节数:{fileData.Length - offset},编码后字节数:{totalBytes},耗时:{stopwatch.Elapsed.Milliseconds}毫秒"); + var faac = new FaacEncoder(8000, 1, 16, true); + var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Audio\Files\testpacket.aac"); + if (File.Exists(path)) File.Delete(path); + output.WriteLine(path); + var offset = 0; + var step = faac.frameSize; + var totalBytes = 0; + var stopwatch = new Stopwatch(); + while (offset + step < fileData.Length) + { + stopwatch.Start(); + var aacBuff = faac.Encode(fileData.Slice(offset, step).ToArray()); + stopwatch.Stop(); + if (aacBuff.Any()) + aacBuff.AppendBytesToFile(path); + offset += step; + totalBytes += aacBuff.Length; + } + faac.Dispose(); + output.WriteLine($"已编码字节数:{offset},剩余未编码字节数:{fileData.Length - offset},编码后字节数:{totalBytes},耗时:{stopwatch.Elapsed.Milliseconds}毫秒"); } } - static class Ex + + internal static class Ex { public static void AppendBytesToFile(this byte[] fileBytes, string fileName) { @@ -59,4 +61,4 @@ namespace JT1078.Flv.Test.Audio fileStream.Close(); } } -} +} \ No newline at end of file diff --git a/src/JT1078.Protocol/Audio/AudioCodecFactory.cs b/src/JT1078.Protocol/Audio/AudioCodecFactory.cs index 5b7d354..4b93bf2 100644 --- a/src/JT1078.Protocol/Audio/AudioCodecFactory.cs +++ b/src/JT1078.Protocol/Audio/AudioCodecFactory.cs @@ -10,9 +10,13 @@ namespace JT1078.Protocol.Audio private readonly AdpcmCodec adpcmCodec = new AdpcmCodec(); private readonly G711ACodec g711ACodec = new G711ACodec(); private readonly G711UCodec g711UCodec = new G711UCodec(); + + private readonly IFaacEncoder faacEncoder = new FaacEncoder(8000, 1, 16); + //海思芯片编码的音频需要移除海思头,可能还有其他的海思头 private static byte[] HI = new byte[] { 0x00, 0x01, 0x52, 0x00 }; - public byte[] Encode(JT1078AVType aVType,byte[]bodies) + + public byte[] Encode(JT1078AVType aVType, byte[] bodies) { byte[] pcm = null; switch (aVType) @@ -27,21 +31,25 @@ namespace JT1078.Protocol.Audio Reserved = adpcm[3] }); //todo:编码mp3 - return pcm; + return faacEncoder.Encode(pcm); + case JT1078AVType.G711A: - pcm=g711ACodec.ToPcm(bodies, null); + pcm = g711ACodec.ToPcm(bodies, null); //todo:编码mp3 - return pcm; + return faacEncoder.Encode(pcm); + case JT1078AVType.AACLC: //直接AAC出去 return bodies; + case JT1078AVType.MP3: //直接MP3出去 return bodies; + default: return bodies; } } } -} +} \ No newline at end of file diff --git a/src/JT1078.Protocol/Audio/FaacEncoder.cs b/src/JT1078.Protocol/Audio/FaacEncoder.cs index c5adbf9..f994fde 100644 --- a/src/JT1078.Protocol/Audio/FaacEncoder.cs +++ b/src/JT1078.Protocol/Audio/FaacEncoder.cs @@ -3,20 +3,71 @@ using System.Collections.Generic; using System.Text; using System.Linq; using System.Runtime.InteropServices; +using JT1078.Protocol.Extensions; namespace JT1078.Protocol.Audio { - public interface IFaacEncoder:IDisposable + public interface IFaacEncoder : IDisposable { + public int frameSize { get; } + byte[] Encode(byte[] bytes); } + + public class FaacEncoder : IFaacEncoder + { + private IFaacEncoder encoder { get; } + + public int frameSize => encoder.frameSize; + + public FaacEncoder(int sampleRate, int channels, int sampleBit, bool adts = false) + { + switch (Environment.OSVersion.Platform) + { + case PlatformID.Win32NT: + case PlatformID.Win32S: + case PlatformID.Win32Windows: + case PlatformID.WinCE: + if (Environment.Is64BitProcess) + { + encoder = new FaacEncoder_x64(sampleRate, channels, sampleBit, adts); + } + else + { + encoder = new FaacEncoder_x86(sampleRate, channels, sampleBit, adts); + } + break; + + case PlatformID.MacOSX: + case PlatformID.Unix: + //TODO: 适配linux + break; + + default: + throw new ApplicationException("system not support."); + break; + } + } + + public void Dispose() + { + encoder.Dispose(); + } + + public byte[] Encode(byte[] bytes) + { + return encoder.Encode(bytes); + } + } + public class FaacEncoder_x86 : IFaacEncoder { private IntPtr faacEncHandle = IntPtr.Zero; private readonly int inputSamples; private readonly int maxOutput; - public readonly int frameSize; + public int frameSize { get; } private List frameCache = new List(); + public FaacEncoder_x86(int sampleRate, int channels, int sampleBit, bool adts = false) { var inputSampleBytes = new byte[4]; @@ -65,42 +116,34 @@ namespace JT1078.Protocol.Audio } } - const string DLLFile = @"/nativelibs/x86/libfaac.dll"; + private const string DLLFile = @"\nativelibs\x86\libfaac.dll"; [DllImport(DLLFile, EntryPoint = "faacEncGetVersion", CallingConvention = CallingConvention.StdCall)] - //int FAACAPI faacEncGetVersion(char **faac_id_string, char **faac_copyright_string); - private extern static int FaacEncGetVersion(ref IntPtr faac_id_string, ref IntPtr faac_copyright_string); + private static extern int FaacEncGetVersion(ref IntPtr faac_id_string, ref IntPtr faac_copyright_string); [DllImport(DLLFile, EntryPoint = "faacEncGetCurrentConfiguration", CallingConvention = CallingConvention.StdCall)] - //faacEncConfigurationPtr FAACAPI faacEncGetCurrentConfiguration(faacEncHandle hEncoder); - private extern static IntPtr FaacEncGetCurrentConfiguration(IntPtr hEncoder); - + private static extern IntPtr FaacEncGetCurrentConfiguration(IntPtr hEncoder); [DllImport(DLLFile, EntryPoint = "faacEncSetConfiguration", CallingConvention = CallingConvention.StdCall)] - //int FAACAPI faacEncSetConfiguration(faacEncHandle hEncoder,faacEncConfigurationPtr config); - private extern static int FaacEncSetConfiguration(IntPtr hEncoder, IntPtr config); + private static extern int FaacEncSetConfiguration(IntPtr hEncoder, IntPtr config); [DllImport(DLLFile, EntryPoint = "faacEncOpen", CallingConvention = CallingConvention.StdCall)] - //faacEncHandle FAACAPI faacEncOpen(unsigned long sampleRate, unsigned int numChannels, unsigned long *inputSamples, unsigned long *maxOutputBytes); - private extern static IntPtr FaacEncOpen(int sampleRate, int numChannels, byte[] inputSamples, byte[] maxOutputBytes); - + private static extern IntPtr FaacEncOpen(int sampleRate, int numChannels, byte[] inputSamples, byte[] maxOutputBytes); [DllImport(DLLFile, EntryPoint = "faacEncGetDecoderSpecificInfo", CallingConvention = CallingConvention.StdCall)] - //int FAACAPI faacEncGetDecoderSpecificInfo(faacEncHandle hEncoder, unsigned char **ppBuffer,unsigned long *pSizeOfDecoderSpecificInfo); - private extern static IntPtr FaacEncGetDecoderSpecificInfo(IntPtr hEncoder, ref IntPtr ppBuffer, ref int pSizeOfDecoderSpecificInfo); - + private static extern IntPtr FaacEncGetDecoderSpecificInfo(IntPtr hEncoder, ref IntPtr ppBuffer, ref int pSizeOfDecoderSpecificInfo); [DllImport(DLLFile, EntryPoint = "faacEncEncode", CallingConvention = CallingConvention.StdCall)] - //int FAACAPI faacEncEncode(faacEncHandle hEncoder, int32_t * inputBuffer, unsigned int samplesInput, unsigned char *outputBuffer, unsigned int bufferSize); - private extern static int FaacEncEncode(IntPtr hEncoder, IntPtr inputBuffer, int samplesInput, IntPtr outputBuffer, int bufferSize); + private static extern int FaacEncEncode(IntPtr hEncoder, IntPtr inputBuffer, int samplesInput, IntPtr outputBuffer, int bufferSize); + [DllImport(DLLFile, EntryPoint = "faacEncEncode", CallingConvention = CallingConvention.StdCall)] - private extern static int FaacEncEncode(IntPtr hEncoder, byte[] inputBuffer, int samplesInput, byte[] outputBuffer, int bufferSize); + private static extern int FaacEncEncode(IntPtr hEncoder, byte[] inputBuffer, int samplesInput, byte[] outputBuffer, int bufferSize); [DllImport(DLLFile, EntryPoint = "faacEncClose", CallingConvention = CallingConvention.StdCall)] - //int FAACAPI faacEncClose(faacEncHandle hEncoder); - private extern static IntPtr FaacEncClose(IntPtr hEncoder); + private static extern IntPtr FaacEncClose(IntPtr hEncoder); #region 配置结构 + [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct FaacEncConfiguration { @@ -183,21 +226,24 @@ namespace JT1078.Protocol.Audio WAVE 4.0 2, 0, 1, 3 WAVE 5.0 2, 0, 1, 3, 4 WAVE 5.1 2, 0, 1, 4, 5, 3 - AIFF 5.1 2, 0, 3, 1, 4, 5 + AIFF 5.1 2, 0, 3, 1, 4, 5 */ + [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I4, SizeConst = 64)] public int[] channel_map; - } - #endregion + + #endregion 配置结构 } + public class FaacEncoder_x64 : IFaacEncoder { private IntPtr faacEncHandle = IntPtr.Zero; private readonly int inputSamples; private readonly int maxOutput; - public readonly int frameSize; + public int frameSize { get; } private List frameCache = new List(); + public FaacEncoder_x64(int sampleRate, int channels, int sampleBit, bool adts = false) { var inputSampleBytes = new byte[4]; @@ -246,41 +292,34 @@ namespace JT1078.Protocol.Audio } } - const string DLLFile = @"/nativelibs/x64/libfaac.dll"; + private const string DLLFile = @"\nativelibs\x64\libfaac.dll"; [DllImport(DLLFile, EntryPoint = "faacEncGetVersion", CallingConvention = CallingConvention.StdCall)] - //int FAACAPI faacEncGetVersion(char **faac_id_string, char **faac_copyright_string); - private extern static int FaacEncGetVersion(ref IntPtr faac_id_string, ref IntPtr faac_copyright_string); + private static extern int FaacEncGetVersion(ref IntPtr faac_id_string, ref IntPtr faac_copyright_string); [DllImport(DLLFile, EntryPoint = "faacEncGetCurrentConfiguration", CallingConvention = CallingConvention.StdCall)] - //faacEncConfigurationPtr FAACAPI faacEncGetCurrentConfiguration(faacEncHandle hEncoder); - private extern static IntPtr FaacEncGetCurrentConfiguration(IntPtr hEncoder); + private static extern IntPtr FaacEncGetCurrentConfiguration(IntPtr hEncoder); [DllImport(DLLFile, EntryPoint = "faacEncSetConfiguration", CallingConvention = CallingConvention.StdCall)] - //int FAACAPI faacEncSetConfiguration(faacEncHandle hEncoder,faacEncConfigurationPtr config); - private extern static int FaacEncSetConfiguration(IntPtr hEncoder, IntPtr config); + private static extern int FaacEncSetConfiguration(IntPtr hEncoder, IntPtr config); [DllImport(DLLFile, EntryPoint = "faacEncOpen", CallingConvention = CallingConvention.StdCall)] - //faacEncHandle FAACAPI faacEncOpen(unsigned long sampleRate, unsigned int numChannels, unsigned long *inputSamples, unsigned long *maxOutputBytes); - private extern static IntPtr FaacEncOpen(int sampleRate, int numChannels, byte[] inputSamples, byte[] maxOutputBytes); - + private static extern IntPtr FaacEncOpen(int sampleRate, int numChannels, byte[] inputSamples, byte[] maxOutputBytes); [DllImport(DLLFile, EntryPoint = "faacEncGetDecoderSpecificInfo", CallingConvention = CallingConvention.StdCall)] - //int FAACAPI faacEncGetDecoderSpecificInfo(faacEncHandle hEncoder, unsigned char **ppBuffer,unsigned long *pSizeOfDecoderSpecificInfo); - private extern static IntPtr FaacEncGetDecoderSpecificInfo(IntPtr hEncoder, ref IntPtr ppBuffer, ref int pSizeOfDecoderSpecificInfo); - + private static extern IntPtr FaacEncGetDecoderSpecificInfo(IntPtr hEncoder, ref IntPtr ppBuffer, ref int pSizeOfDecoderSpecificInfo); [DllImport(DLLFile, EntryPoint = "faacEncEncode", CallingConvention = CallingConvention.StdCall)] - //int FAACAPI faacEncEncode(faacEncHandle hEncoder, int32_t * inputBuffer, unsigned int samplesInput, unsigned char *outputBuffer, unsigned int bufferSize); - private extern static int FaacEncEncode(IntPtr hEncoder, IntPtr inputBuffer, int samplesInput, IntPtr outputBuffer, int bufferSize); + private static extern int FaacEncEncode(IntPtr hEncoder, IntPtr inputBuffer, int samplesInput, IntPtr outputBuffer, int bufferSize); + [DllImport(DLLFile, EntryPoint = "faacEncEncode", CallingConvention = CallingConvention.StdCall)] - private extern static int FaacEncEncode(IntPtr hEncoder, byte[] inputBuffer, int samplesInput, byte[] outputBuffer, int bufferSize); + private static extern int FaacEncEncode(IntPtr hEncoder, byte[] inputBuffer, int samplesInput, byte[] outputBuffer, int bufferSize); [DllImport(DLLFile, EntryPoint = "faacEncClose", CallingConvention = CallingConvention.StdCall)] - //int FAACAPI faacEncClose(faacEncHandle hEncoder); - private extern static IntPtr FaacEncClose(IntPtr hEncoder); + private static extern IntPtr FaacEncClose(IntPtr hEncoder); #region 配置结构 + [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct FaacEncConfiguration { @@ -363,12 +402,13 @@ namespace JT1078.Protocol.Audio WAVE 4.0 2, 0, 1, 3 WAVE 5.0 2, 0, 1, 3, 4 WAVE 5.1 2, 0, 1, 4, 5, 3 - AIFF 5.1 2, 0, 3, 1, 4, 5 + AIFF 5.1 2, 0, 3, 1, 4, 5 */ + [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I4, SizeConst = 64)] public int[] channel_map; - } - #endregion + + #endregion 配置结构 } -} +} \ No newline at end of file diff --git a/src/JT1078.Protocol/Extensions/InteropExtensions.cs b/src/JT1078.Protocol/Extensions/InteropExtensions.cs new file mode 100644 index 0000000..d3e021c --- /dev/null +++ b/src/JT1078.Protocol/Extensions/InteropExtensions.cs @@ -0,0 +1,93 @@ +using System; +using System.Runtime.InteropServices; + +namespace JT1078.Protocol.Extensions +{ + public static class InteropExtensions + { + public static T BytesToStruct(byte[] bytes, int startIndex, int length) + { + T local; + T local2; + if (bytes == null) + { + local2 = default; + local = local2; + } + else if (bytes.Length <= 0) + { + local2 = default; + local = local2; + } + else + { + IntPtr destination = Marshal.AllocHGlobal(length); + try + { + Marshal.Copy(bytes, startIndex, destination, length); + local = (T)Marshal.PtrToStructure(destination, typeof(T)); + } + catch (Exception exception) + { + throw new Exception("Error in BytesToStruct ! " + exception.Message); + } + finally + { + Marshal.FreeHGlobal(destination); + } + } + return local; + } + + public static void IntPtrSetValue(IntPtr intptr, object structObj) + { + IntPtrSetValue(intptr, StructToBytes(structObj)); + } + + public static void IntPtrSetValue(IntPtr intptr, byte[] bytes) + { + Marshal.Copy(bytes, 0, intptr, bytes.Length); + } + + public static T IntPtrToStruct(IntPtr intptr) + { + int index = 0; + return IntPtrToStruct(intptr, index, Marshal.SizeOf(typeof(T))); + } + + public static T IntPtrToStruct(IntPtr intptr, int index, int length) + { + byte[] destination = new byte[length]; + Marshal.Copy(intptr, destination, index, length); + return BytesToStruct(destination, 0, destination.Length); + } + + public static byte[] StructToBytes(object structObj) + { + int size = Marshal.SizeOf(structObj); + return StructToBytes(structObj, size); + } + + public static byte[] StructToBytes(object structObj, int size) + { + byte[] buffer2; + IntPtr ptr = Marshal.AllocHGlobal(size); + try + { + Marshal.StructureToPtr(structObj, ptr, false); + byte[] destination = new byte[size]; + Marshal.Copy(ptr, destination, 0, size); + buffer2 = destination; + } + catch (Exception exception) + { + throw new Exception("Error in StructToBytes ! " + exception.Message); + } + finally + { + Marshal.FreeHGlobal(ptr); + } + return buffer2; + } + } +} \ No newline at end of file diff --git a/src/JT1078.Protocol/JT1078.Protocol.csproj b/src/JT1078.Protocol/JT1078.Protocol.csproj index 1114317..a94366f 100644 --- a/src/JT1078.Protocol/JT1078.Protocol.csproj +++ b/src/JT1078.Protocol/JT1078.Protocol.csproj @@ -25,11 +25,6 @@ - - - - -