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 @@
-
-
-
-
-