From 31af02d0dcc2e4f80a2f80ca98eef914887f4829 Mon Sep 17 00:00:00 2001 From: "SmallChi(Koike)" <564952747@qq.com> Date: Sat, 22 Aug 2020 23:25:54 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9faac=E7=BC=96=E7=A0=81?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/JT1078.Flv.Test/Audio/AudioTest.cs | 2 +- src/JT1078.Flv.Test/JT1078.Flv.Test.csproj | 6 +- src/JT1078.Flv/Audio/FaacEncoder.cs | 191 +++++++++++++++++- src/JT1078.Flv/FlvEncoder.cs | 11 +- src/JT1078.Flv/JT1078.Flv.csproj | 15 +- .../JT1078.Protocol.Test.csproj | 2 +- 6 files changed, 206 insertions(+), 21 deletions(-) diff --git a/src/JT1078.Flv.Test/Audio/AudioTest.cs b/src/JT1078.Flv.Test/Audio/AudioTest.cs index 0548dc8..8f4f65f 100644 --- a/src/JT1078.Flv.Test/Audio/AudioTest.cs +++ b/src/JT1078.Flv.Test/Audio/AudioTest.cs @@ -28,7 +28,7 @@ namespace JT1078.Flv.Test.Audio { ReadOnlySpan fileData = File.ReadAllBytes(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"Audio/Files/testpacket.pcm")); //注意 这里为了可以判断音频是否可用,因此使用adts,当网络传输的时候不应该使用adts - var faac = new FaacEncoder(8000, 1, 16, true); + 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); diff --git a/src/JT1078.Flv.Test/JT1078.Flv.Test.csproj b/src/JT1078.Flv.Test/JT1078.Flv.Test.csproj index dfff8a5..7116743 100644 --- a/src/JT1078.Flv.Test/JT1078.Flv.Test.csproj +++ b/src/JT1078.Flv.Test/JT1078.Flv.Test.csproj @@ -1,11 +1,10 @@  - netcoreapp3.0 + netcoreapp3.1 - @@ -29,6 +28,9 @@ Always + + + Always diff --git a/src/JT1078.Flv/Audio/FaacEncoder.cs b/src/JT1078.Flv/Audio/FaacEncoder.cs index ba93867..c5c9283 100644 --- a/src/JT1078.Flv/Audio/FaacEncoder.cs +++ b/src/JT1078.Flv/Audio/FaacEncoder.cs @@ -7,18 +7,21 @@ using JT1078.Flv.Extensions; namespace JT1078.Flv.Audio { - public class FaacEncoder : IDisposable + public interface IFaacEncoder:IDisposable + { + byte[] Encode(byte[] bytes); + } + public class FaacEncoder_x86 : IFaacEncoder { private IntPtr faacEncHandle = IntPtr.Zero; private readonly int inputSamples; private readonly int maxOutput; public readonly int frameSize; private List frameCache = new List(); - public FaacEncoder(int sampleRate, int channels, int sampleBit, bool adts = false) + public FaacEncoder_x86(int sampleRate, int channels, int sampleBit, bool adts = false) { var inputSampleBytes = new byte[4]; var maxOutputBytes = new byte[4]; - faacEncHandle = FaacEncOpen(sampleRate, channels, inputSampleBytes, maxOutputBytes); inputSamples = BitConverter.ToInt32(inputSampleBytes, 0); maxOutput = BitConverter.ToInt32(maxOutputBytes, 0); @@ -63,7 +66,186 @@ namespace JT1078.Flv.Audio } } + 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); + + [DllImport(DLLFile, EntryPoint = "faacEncGetCurrentConfiguration", CallingConvention = CallingConvention.StdCall)] + //faacEncConfigurationPtr FAACAPI faacEncGetCurrentConfiguration(faacEncHandle hEncoder); + private extern static 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); + + [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); + + + [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); + + + [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); + [DllImport(DLLFile, EntryPoint = "faacEncEncode", CallingConvention = CallingConvention.StdCall)] + private extern static 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); + + #region 配置结构 + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private struct FaacEncConfiguration + { + /* config version */ + + public int version; + + /* library version */ + public IntPtr name; + + /* copyright string */ + public IntPtr copyright; + + /* MPEG version, 2 or 4 */ + public uint mpegVersion; + + /* AAC object type + * #define MAIN 1 + #define LOW 2 + #define SSR 3 + #define LTP 4 + * */ + + public uint aacObjectType; + + /* Allow mid/side coding */ + public uint allowMidside; + + /* Use one of the channels as LFE channel */ + public uint useLfe; + + /* Use Temporal Noise Shaping */ + public uint useTns; + + /* bitrate / channel of AAC file */ + public uint bitRate; + + /* AAC file frequency bandwidth */ + public uint bandWidth; + + /* Quantizer quality */ + public uint quantqual; + + /* Bitstream output format (0 = Raw; 1 = ADTS) */ + public int outputFormat; + + /* psychoacoustic model list */ + public IntPtr psymodellist; + + /* selected index in psymodellist */ + public int psymodelidx; + + /* + PCM Sample Input Format + 0 FAAC_INPUT_NULL invalid, signifies a misconfigured config + 1 FAAC_INPUT_16BIT native endian 16bit + 2 FAAC_INPUT_24BIT native endian 24bit in 24 bits (not implemented) + 3 FAAC_INPUT_32BIT native endian 24bit in 32 bits (DEFAULT) + 4 FAAC_INPUT_FLOAT 32bit floating point + */ + public int inputFormat; + + /* block type enforcing (SHORTCTL_NORMAL/SHORTCTL_NOSHORT/SHORTCTL_NOLONG) */ + // #define FAAC_INPUT_NULL 0 + //#define FAAC_INPUT_16BIT 1 + //#define FAAC_INPUT_24BIT 2 + //#define FAAC_INPUT_32BIT 3 + //#define FAAC_INPUT_FLOAT 4 + + //#define SHORTCTL_NORMAL 0 + //#define SHORTCTL_NOSHORT 1 + //#define SHORTCTL_NOLONG 2 + public int shortctl; + + /* + Channel Remapping + + Default 0, 1, 2, 3 ... 63 (64 is MAX_CHANNELS in coder.h) + + 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 + */ + [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I4, SizeConst = 64)] + public int[] channel_map; + + } + #endregion + } + public class FaacEncoder_x64 : IFaacEncoder + { + private IntPtr faacEncHandle = IntPtr.Zero; + private readonly int inputSamples; + private readonly int maxOutput; + public readonly int frameSize; + private List frameCache = new List(); + public FaacEncoder_x64(int sampleRate, int channels, int sampleBit, bool adts = false) + { + var inputSampleBytes = new byte[4]; + var maxOutputBytes = new byte[4]; + faacEncHandle = FaacEncOpen(sampleRate, channels, inputSampleBytes, maxOutputBytes); + inputSamples = BitConverter.ToInt32(inputSampleBytes, 0); + maxOutput = BitConverter.ToInt32(maxOutputBytes, 0); + frameSize = inputSamples * channels * sampleBit / 8; + + var ptr = FaacEncGetCurrentConfiguration(faacEncHandle); + var configuration = InteropExtensions.IntPtrToStruct(ptr); + configuration.inputFormat = 1; + configuration.outputFormat = adts ? 1 : 0; + configuration.useTns = 0; + configuration.useLfe = 0; + configuration.aacObjectType = 2; + configuration.shortctl = 0; + configuration.quantqual = 100; + configuration.bandWidth = 0; + configuration.bitRate = 0; + InteropExtensions.IntPtrSetValue(ptr, configuration); + if (FaacEncSetConfiguration(faacEncHandle, ptr) < 0) throw new Exception("set faac configuration failed!"); + } + + public byte[] Encode(byte[] bytes) + { + frameCache.AddRange(bytes); + if (frameCache.Count() < frameSize)//faac必须达到一帧数据后才能正常编码 + return new byte[0]; + var outputBytes = new byte[maxOutput]; + var len = FaacEncEncode(faacEncHandle, frameCache.Take(frameSize).ToArray(), inputSamples, outputBytes, maxOutput); + frameCache = frameCache.Skip(frameSize).ToList(); + if (len <= 0) + return new byte[0]; + return outputBytes.Take(len).ToArray(); + } + + public void Dispose() + { + frameCache = null; + if (faacEncHandle != IntPtr.Zero) + { + FaacEncClose(faacEncHandle); + faacEncHandle = IntPtr.Zero; + } + } const string DLLFile = @"/nativelibs/x64/libfaac.dll"; @@ -71,13 +253,10 @@ namespace JT1078.Flv.Audio //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); - - [DllImport(DLLFile, EntryPoint = "faacEncGetCurrentConfiguration", CallingConvention = CallingConvention.StdCall)] //faacEncConfigurationPtr FAACAPI faacEncGetCurrentConfiguration(faacEncHandle hEncoder); private extern static 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); diff --git a/src/JT1078.Flv/FlvEncoder.cs b/src/JT1078.Flv/FlvEncoder.cs index 2328dfe..c80ddba 100644 --- a/src/JT1078.Flv/FlvEncoder.cs +++ b/src/JT1078.Flv/FlvEncoder.cs @@ -37,11 +37,18 @@ namespace JT1078.Flv /// public class FlvEncoder : IDisposable { - readonly FaacEncoder faacEncoder; + readonly IFaacEncoder faacEncoder; readonly H264Decoder h264Decoder = new H264Decoder(); public FlvEncoder(int sampleRate = 8000, int channels = 1, int sampleBit = 16, bool adts = false) { - faacEncoder = new FaacEncoder(sampleRate, channels, sampleBit, adts); + try + { + faacEncoder = new FaacEncoder_x86(sampleRate, channels, sampleBit, adts); + } + catch + { + faacEncoder = new FaacEncoder_x64(sampleRate, channels, sampleBit, adts); + } } /// diff --git a/src/JT1078.Flv/JT1078.Flv.csproj b/src/JT1078.Flv/JT1078.Flv.csproj index 2442c56..93fac57 100644 --- a/src/JT1078.Flv/JT1078.Flv.csproj +++ b/src/JT1078.Flv/JT1078.Flv.csproj @@ -45,14 +45,11 @@ - - /nativelibs/x64/libfaac.dll - true - - - - true - /nativelibs/x86/libfaac.dll - + + Always + + + Always + diff --git a/src/JT1078.Protocol.Test/JT1078.Protocol.Test.csproj b/src/JT1078.Protocol.Test/JT1078.Protocol.Test.csproj index e292561..67683f4 100644 --- a/src/JT1078.Protocol.Test/JT1078.Protocol.Test.csproj +++ b/src/JT1078.Protocol.Test/JT1078.Protocol.Test.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0 + netcoreapp3.1 false