Sfoglia il codice sorgente

1.将音频编码器从flv库中移到1078协议库中

2.移除掉faac库
3.暂时去掉音频功能
tags/v1.1.0
SmallChi(Koike) 4 anni fa
parent
commit
61a9f7e31d
16 ha cambiato i file con 364 aggiunte e 378 eliminazioni
  1. +22
    -22
      src/JT1078.Flv.Test/Audio/AudioTest.cs
  2. +0
    -123
      src/JT1078.Flv/Audio/G711ACodec.cs
  3. +10
    -38
      src/JT1078.Flv/FlvEncoder.cs
  4. +1
    -9
      src/JT1078.Flv/JT1078.Flv.csproj
  5. +1
    -48
      src/JT1078.Flv/JT1078.Flv.xml
  6. BIN
      src/JT1078.Flv/nativelibs/x64/libfaac.dll
  7. BIN
      src/JT1078.Flv/nativelibs/x86/libfaac.dll
  8. +4
    -2
      src/JT1078.Hls/JT1078.Hls.xml
  9. +116
    -114
      src/JT1078.Protocol/Audio/AdpcmCodec.cs
  10. +47
    -0
      src/JT1078.Protocol/Audio/AudioCodecFactory.cs
  11. +1
    -2
      src/JT1078.Protocol/Audio/FaacEncoder.cs
  12. +114
    -0
      src/JT1078.Protocol/Audio/G711ACodec.cs
  13. +21
    -19
      src/JT1078.Protocol/Audio/G711UCodec.cs
  14. +10
    -0
      src/JT1078.Protocol/Audio/IAudioAttachData.cs
  15. +11
    -0
      src/JT1078.Protocol/Audio/IAudioCodec.cs
  16. +6
    -1
      src/JT1078.Protocol/JT1078.Protocol.csproj

+ 22
- 22
src/JT1078.Flv.Test/Audio/AudioTest.cs Vedi File

@@ -1,5 +1,4 @@
using JT1078.Flv.Audio;
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -26,28 +25,29 @@ namespace JT1078.Flv.Test.Audio
[Fact(DisplayName = "pcm编码aac")]
public void Test1()
{
//todo:音频暂时先放下
ReadOnlySpan<byte> 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_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}毫秒");
}
}
static class Ex


+ 0
- 123
src/JT1078.Flv/Audio/G711ACodec.cs Vedi File

@@ -1,123 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Flv.Audio
{
public class G711ACodec
{
private readonly int SIGN_BIT = 0x80;
private readonly int QUANT_MASK = 0xf;
private readonly int SEG_SHIFT = 4;
private readonly int SEG_MASK = 0x70;
private readonly short[] seg_end = { 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF };

static short Search(short val, short[] table, short size)
{
for (short i = 0; i < size; i++)
{
if (val <= table[i])
{
return i;
}
}
return size;
}

byte LinearToAlaw(short pcm_val)
{
short mask;
short seg;
char aval;
if (pcm_val >= 0)
{
mask = 0xD5;
}
else
{
mask = 0x55;
pcm_val = (short)(-pcm_val - 1);
if (pcm_val < 0)
{
pcm_val = 32767;
}
}

//Convert the scaled magnitude to segment number.
seg = Search(pcm_val, seg_end, 8);

//Combine the sign, segment, and quantization bits.
if (seg >= 8)
{
//out of range, return maximum value.
return (byte)(0x7F ^ mask);
}
else
{
aval = (char)(seg << SEG_SHIFT);
if (seg < 2) aval |= (char)((pcm_val >> 4) & QUANT_MASK);
else aval |= (char)((pcm_val >> (seg + 3)) & QUANT_MASK);
return (byte)(aval ^ mask);
}
}


short AlawToLinear(byte value)
{
short t;
short seg;

value ^= 0x55;

t = (short)((value & QUANT_MASK) << 4);
seg = (short)((value & SEG_MASK) >> SEG_SHIFT);
switch (seg)
{
case 0:
t += 8;
break;
case 1:
t += 0x108;
break;
default:
t += 0x108;
t <<= seg - 1;
break;
}
return (value & SIGN_BIT) != 0 ? t : (short)-t;
}

/// <summary>
/// 转至PCM
/// </summary>
/// <param name="g711data"></param>
/// <returns></returns>
public byte[] ToPcm(byte[] g711data)
{
byte[] pcmdata = new byte[g711data.Length * 2];
for (int i = 0, offset = 0; i < g711data.Length; i++)
{
short value = AlawToLinear(g711data[i]);
pcmdata[offset++] = (byte)(value & 0xff);
pcmdata[offset++] = (byte)((value >> 8) & 0xff);
}
return pcmdata;
}

/// <summary>
/// 转至G711
/// </summary>
/// <param name="pcmdata"></param>
/// <returns></returns>
public byte[] ToG711(byte[] pcmdata)
{
byte[] g711data = new byte[pcmdata.Length / 2];
for (int i = 0, k = 0; i < pcmdata.Length; i += 2, k++)
{
short v = (short)((pcmdata[i + 1] << 8) | (pcmdata[i]));
g711data[k] = LinearToAlaw(v);
}
return g711data;
}
}
}

+ 10
- 38
src/JT1078.Flv/FlvEncoder.cs Vedi File

@@ -4,12 +4,12 @@ using JT1078.Flv.Metadata;
using JT1078.Protocol.Enums;
using JT1078.Protocol.H264;
using JT1078.Protocol.MessagePack;
using JT1078.Flv.Audio;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using JT1078.Protocol;
using JT1078.Protocol.Audio;

[assembly: InternalsVisibleTo("JT1078.Flv.Test")]
namespace JT1078.Flv
@@ -35,20 +35,15 @@ namespace JT1078.Flv
/// 3、<see cref="EncoderVideoTag"/>第二个参数传true
/// 4、<see cref="EncoderAudioTag"/>第二个参数传true
/// </summary>
public class FlvEncoder : IDisposable
public class FlvEncoder
{
readonly IFaacEncoder faacEncoder;
readonly H264Decoder h264Decoder = new H264Decoder();
public FlvEncoder(int sampleRate = 8000, int channels = 1, int sampleBit = 16, bool adts = false)
readonly H264Decoder h264Decoder;
readonly AudioCodecFactory audioCodecFactory;
//public FlvEncoder(int sampleRate = 8000, int channels = 1, int sampleBit = 16, bool adts = false)
public FlvEncoder()
{
try
{
faacEncoder = new FaacEncoder_x86(sampleRate, channels, sampleBit, adts);
}
catch
{
faacEncoder = new FaacEncoder_x64(sampleRate, channels, sampleBit, adts);
}
audioCodecFactory = new AudioCodecFactory();
h264Decoder = new H264Decoder();
}

/// <summary>
@@ -255,6 +250,7 @@ namespace JT1078.Flv
/// <param name="package"></param>
/// <param name="needAacHeader">是否需要首帧音频</param>
/// <returns></returns>
[Obsolete("音频暂时去掉")]
public byte[] EncoderAudioTag(JT1078Package package, bool needAacHeader = false)
{
if (package.Label3.DataType != JT1078DataType.音频帧) throw new Exception("Incorrect parameter, package must be audio frame");
@@ -263,26 +259,7 @@ namespace JT1078.Flv
{
flvMessagePackWriter.WriteArray(EncoderFirstAudioTag(package.Timestamp));
}
byte[] aacFrameData = null;
switch (package.Label2.PT)
{
case JT1078AVType.ADPCM:
ReadOnlySpan<byte> adpcm = package.Bodies;
// 海思芯片编码的音频需要移除海思头,可能还有其他的海思头
if (adpcm.StartsWith(new byte[] { 0x00, 0x01, 0x52, 0x00 })) adpcm = adpcm.Slice(4);
aacFrameData = faacEncoder.Encode(new AdpcmCodec().ToPcm(adpcm.Slice(4).ToArray(), new State()
{
Valprev = (short)((adpcm[1] << 8) | adpcm[0]),
Index = adpcm[2],
Reserved = adpcm[3]
})); break;
case JT1078AVType.G711A:
aacFrameData = faacEncoder.Encode(new G711ACodec().ToPcm(package.Bodies));
break;
case JT1078AVType.AACLC:
aacFrameData = package.Bodies;
break;
}
byte[] aacFrameData = audioCodecFactory.Encode(package.Label2.PT, package.Bodies);
if (aacFrameData != null && aacFrameData.Any())//编码成功,此时为一帧aac音频数据
{
// Data Tag Frame
@@ -372,10 +349,5 @@ namespace JT1078.Flv
FlvArrayPool.Return(buffer);
}
}

public void Dispose()
{
faacEncoder.Dispose();
}
}
}

+ 1
- 9
src/JT1078.Flv/JT1078.Flv.csproj Vedi File

@@ -14,7 +14,7 @@
<licenseUrl>https://github.com/SmallChi/JT1078/blob/master/LICENSE</licenseUrl>
<license>https://github.com/SmallChi/JT1078/blob/master/LICENSE</license>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>1.0.0-preview7</Version>
<Version>1.0.0-preview8</Version>
<SignAssembly>false</SignAssembly>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
@@ -44,12 +44,4 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.7" />
</ItemGroup>
<ItemGroup>
<None Update="nativelibs\x64\libfaac.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="nativelibs\x86\libfaac.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

+ 1
- 48
src/JT1078.Flv/JT1078.Flv.xml Vedi File

@@ -4,53 +4,6 @@
<name>JT1078.Flv</name>
</assembly>
<members>
<member name="P:JT1078.Flv.Audio.State.Valprev">
<summary>
上一个采样数据,当index为0是该值应该为未压缩的原数据
</summary>
</member>
<member name="P:JT1078.Flv.Audio.State.Reserved">
<summary>
保留数据(未使用)
</summary>
</member>
<member name="P:JT1078.Flv.Audio.State.Index">
<summary>
上一个block最后一个index,第一个block的index=0
</summary>
</member>
<member name="M:JT1078.Flv.Audio.AdpcmCodec.ToPcm(System.Byte[],JT1078.Flv.Audio.State)">
<summary>
将adpcm转为pcm
</summary>
<see cref="!:https://github.com/ctuning/ctuning-programs/blob/master/program/cbench-telecom-adpcm-d/adpcm.c"/>
<param name="data"></param>
<returns></returns>
</member>
<member name="M:JT1078.Flv.Audio.AdpcmDecoderExtension.ToWav(System.Byte[],System.UInt32,System.Byte)">
<summary>
添加wav头
仅用于测试pcm是否转成成功,因此没考虑性能,因为播放器可播——#
</summary>
<param name="input">pcm数据</param>
<param name="frequency">采样率</param>
<param name="bitDepth">位深</param>
<returns></returns>
</member>
<member name="M:JT1078.Flv.Audio.G711ACodec.ToPcm(System.Byte[])">
<summary>
转至PCM
</summary>
<param name="g711data"></param>
<returns></returns>
</member>
<member name="M:JT1078.Flv.Audio.G711ACodec.ToG711(System.Byte[])">
<summary>
转至G711
</summary>
<param name="pcmdata"></param>
<returns></returns>
</member>
<member name="T:JT1078.Flv.FlvBufferWriter">
<summary>
<see cref="!:System.Buffers.Writer"/>
@@ -210,7 +163,7 @@
Flv编码器
一个客户端对应一个实例
<para>
当实例不适用时,尽量手动调用下<see cref="M:JT1078.Flv.FlvEncoder.Dispose"/>
当实例不适用时,尽量手动调用下<see cref="!:Dispose"/>
</para>
手动编码


BIN
src/JT1078.Flv/nativelibs/x64/libfaac.dll Vedi File


BIN
src/JT1078.Flv/nativelibs/x86/libfaac.dll Vedi File


+ 4
- 2
src/JT1078.Hls/JT1078.Hls.xml Vedi File

@@ -114,7 +114,8 @@
<summary>
创建M3U8文件
</summary>
<param name="curTsFileInfo"></param>
<param name="curTsFileInfo">当前ts文件信息</param>
<param name="tsFileInfoQueue">ts文件信息队列</param>
</member>
<member name="M:JT1078.Hls.M3U8FileManage.CreateTsFileInfo(System.String)">
<summary>
@@ -123,11 +124,12 @@
<param name="key"></param>
<returns></returns>
</member>
<member name="M:JT1078.Hls.M3U8FileManage.CreateTsFile(System.String,System.Byte[])">
<member name="M:JT1078.Hls.M3U8FileManage.CreateTsFile(System.String,System.String,System.Byte[])">
<summary>
创建TS文件
</summary>
<param name="fileName">ts文件路径</param>
<param name="key">终端号_通道号(用作目录)</param>
<param name="data">文件内容</param>
</member>
<member name="M:JT1078.Hls.M3U8FileManage.Clear(System.String,System.Int32)">


src/JT1078.Flv/Audio/AdpcmCodec.cs → src/JT1078.Protocol/Audio/AdpcmCodec.cs Vedi File

@@ -2,26 +2,9 @@
using System.Collections.Generic;
using System.Text;

namespace JT1078.Flv.Audio
namespace JT1078.Protocol.Audio
{
public class State
{
/// <summary>
/// 上一个采样数据,当index为0是该值应该为未压缩的原数据
/// </summary>
public short Valprev { get; set; }

/// <summary>
/// 保留数据(未使用)
/// </summary>
public byte Reserved { get; set; }

/// <summary>
/// 上一个block最后一个index,第一个block的index=0
/// </summary>
public byte Index { get; set; }
}
public class AdpcmCodec
public class AdpcmCodec: IAudioCodec
{
static readonly int[] indexTable = {
-1, -1, -1, -1, 2, 4, 6, 8,
@@ -39,119 +22,122 @@ namespace JT1078.Flv.Audio
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};
public static byte[] ToAdpcm(short[] indata, State state)
{
int val; /* Current input sample value */
int sign; /* Current adpcm sign bit */
int delta; /* Current adpcm output value */
int diff; /* Difference between val and valprev */
int step; /* Stepsize */
int valpred; /* Predicted output value */
int vpdiff; /* Current change to valpred */
int index; /* Current step change index */
int outputbuffer = 0; /* place to keep previous 4-bit value */
int bufferstep; /* toggle between outputbuffer/output */

List<byte> outp = new List<byte>();
short[] inp = indata;
var len = indata.Length;
valpred = state.Valprev;
index = state.Index;
step = stepsizeTable[index];
//public static byte[] ToAdpcm(short[] indata, AdpcmState state)
//{
// int val; /* Current input sample value */
// int sign; /* Current adpcm sign bit */
// int delta; /* Current adpcm output value */
// int diff; /* Difference between val and valprev */
// int step; /* Stepsize */
// int valpred; /* Predicted output value */
// int vpdiff; /* Current change to valpred */
// int index; /* Current step change index */
// int outputbuffer = 0; /* place to keep previous 4-bit value */
// int bufferstep; /* toggle between outputbuffer/output */

bufferstep = 1;
// List<byte> outp = new List<byte>();
// short[] inp = indata;
// var len = indata.Length;
// valpred = state.Valprev;
// index = state.Index;
// step = stepsizeTable[index];

int k = 0;
for (int i = 0; len > 0; len--, i++)
{
val = inp[i];
// bufferstep = 1;

/* Step 1 - compute difference with previous value */
diff = val - valpred;
sign = (diff < 0) ? 8 : 0;
if (sign != 0) diff = (-diff);
// int k = 0;
// for (int i = 0; len > 0; len--, i++)
// {
// val = inp[i];

/* Step 2 - Divide and clamp */
/* Note:
** This code *approximately* computes:
** delta = diff*4/step;
** vpdiff = (delta+0.5)*step/4;
** but in shift step bits are dropped. The net result of this is
** that even if you have fast mul/div hardware you cannot put it to
** good use since the fixup would be too expensive.
*/
delta = 0;
vpdiff = (step >> 3);
// /* Step 1 - compute difference with previous value */
// diff = val - valpred;
// sign = (diff < 0) ? 8 : 0;
// if (sign != 0) diff = (-diff);

if (diff >= step)
{
delta = 4;
diff -= step;
vpdiff += step;
}
step >>= 1;
if (diff >= step)
{
delta |= 2;
diff -= step;
vpdiff += step;
}
step >>= 1;
if (diff >= step)
{
delta |= 1;
vpdiff += step;
}
// /* Step 2 - Divide and clamp */
// /* Note:
// ** This code *approximately* computes:
// ** delta = diff*4/step;
// ** vpdiff = (delta+0.5)*step/4;
// ** but in shift step bits are dropped. The net result of this is
// ** that even if you have fast mul/div hardware you cannot put it to
// ** good use since the fixup would be too expensive.
// */
// delta = 0;
// vpdiff = (step >> 3);

/* Step 3 - Update previous value */
if (sign != 0)
valpred -= vpdiff;
else
valpred += vpdiff;
// if (diff >= step)
// {
// delta = 4;
// diff -= step;
// vpdiff += step;
// }
// step >>= 1;
// if (diff >= step)
// {
// delta |= 2;
// diff -= step;
// vpdiff += step;
// }
// step >>= 1;
// if (diff >= step)
// {
// delta |= 1;
// vpdiff += step;
// }

/* Step 4 - Clamp previous value to 16 bits */
if (valpred > 32767)
valpred = 32767;
else if (valpred < -32768)
valpred = -32768;
// /* Step 3 - Update previous value */
// if (sign != 0)
// valpred -= vpdiff;
// else
// valpred += vpdiff;

/* Step 5 - Assemble value, update index and step values */
delta |= sign;
// /* Step 4 - Clamp previous value to 16 bits */
// if (valpred > 32767)
// valpred = 32767;
// else if (valpred < -32768)
// valpred = -32768;

index += indexTable[delta];
if (index < 0) index = 0;
if (index > 88) index = 88;
step = stepsizeTable[index];
// /* Step 5 - Assemble value, update index and step values */
// delta |= sign;

/* Step 6 - Output value */
if (bufferstep != 0)
{
outputbuffer = (delta << 4) & 0xf0;
}
else
{
outp.Add((byte)((delta & 0x0f) | outputbuffer));
}
bufferstep = bufferstep == 0 ? 1 : 0;
}
// index += indexTable[delta];
// if (index < 0) index = 0;
// if (index > 88) index = 88;
// step = stepsizeTable[index];

/* Output last step, if needed */
if (bufferstep == 0)
outp.Add((byte)outputbuffer);
// /* Step 6 - Output value */
// if (bufferstep != 0)
// {
// outputbuffer = (delta << 4) & 0xf0;
// }
// else
// {
// outp.Add((byte)((delta & 0x0f) | outputbuffer));
// }
// bufferstep = bufferstep == 0 ? 1 : 0;
// }

state.Valprev = (short)valpred;
state.Index = (byte)index;
return outp.ToArray();
}
// /* Output last step, if needed */
// if (bufferstep == 0)
// outp.Add((byte)outputbuffer);

// state.Valprev = (short)valpred;
// state.Index = (byte)index;
// return outp.ToArray();
//}

/// <summary>
/// 将adpcm转为pcm
/// </summary>
/// <see cref="https://github.com/ctuning/ctuning-programs/blob/master/program/cbench-telecom-adpcm-d/adpcm.c"/>
/// <param name="data"></param>
/// <param name="audio"></param>
/// <param name="audioAttachData"></param>
/// <returns></returns>
public byte[] ToPcm(byte[] data, State state)
public byte[] ToPcm(byte[] audio, IAudioAttachData audioAttachData)
{
AdpcmState state = (AdpcmState)audioAttachData;
// signed char *inp; /* Input buffer pointer */
// short *outp; /* output buffer pointer */
int sign; /* Current adpcm sign bit */
@@ -166,7 +152,7 @@ namespace JT1078.Flv.Audio
step = stepsizeTable[index];

var outdata = new List<byte>();
var len = data.Length * 2;
var len = audio.Length * 2;
for (int i = 0; len > 0; len--)
{
/* Step 1 - get the delta value */
@@ -176,7 +162,7 @@ namespace JT1078.Flv.Audio
}
else
{
inputbuffer = data[i++];
inputbuffer = audio[i++];
delta = (inputbuffer >> 4) & 0xf;
}
bufferstep = !bufferstep;
@@ -222,7 +208,23 @@ namespace JT1078.Flv.Audio
return outdata.ToArray();
}
}
public class AdpcmState : IAudioAttachData
{
/// <summary>
/// 上一个采样数据,当index为0是该值应该为未压缩的原数据
/// </summary>
public short Valprev { get; set; }

/// <summary>
/// 保留数据(未使用)
/// </summary>
public byte Reserved { get; set; }

/// <summary>
/// 上一个block最后一个index,第一个block的index=0
/// </summary>
public byte Index { get; set; }
}
public static class AdpcmDecoderExtension
{
/// <summary>

+ 47
- 0
src/JT1078.Protocol/Audio/AudioCodecFactory.cs Vedi File

@@ -0,0 +1,47 @@
using JT1078.Protocol.Enums;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Protocol.Audio
{
public class AudioCodecFactory
{
private readonly AdpcmCodec adpcmCodec = new AdpcmCodec();
private readonly G711ACodec g711ACodec = new G711ACodec();
private readonly G711UCodec g711UCodec = new G711UCodec();
//海思芯片编码的音频需要移除海思头,可能还有其他的海思头
private static byte[] HI = new byte[] { 0x00, 0x01, 0x52, 0x00 };
public byte[] Encode(JT1078AVType aVType,byte[]bodies)
{
byte[] pcm = null;
switch (aVType)
{
case JT1078AVType.ADPCM:
ReadOnlySpan<byte> adpcm = bodies;
if (adpcm.StartsWith(HI)) adpcm = adpcm.Slice(4);
pcm = adpcmCodec.ToPcm(adpcm.Slice(4).ToArray(), new AdpcmState()
{
Valprev = (short)((adpcm[1] << 8) | adpcm[0]),
Index = adpcm[2],
Reserved = adpcm[3]
});
//todo:编码mp3
return pcm;
case JT1078AVType.G711A:
pcm=g711ACodec.ToPcm(bodies, null);
//todo:编码mp3
return pcm;
case JT1078AVType.AACLC:
//直接AAC出去
return bodies;
case JT1078AVType.MP3:
//直接MP3出去
return bodies;
default:

return bodies;
}
}
}
}

src/JT1078.Flv/Audio/FaacEncoder.cs → src/JT1078.Protocol/Audio/FaacEncoder.cs Vedi File

@@ -3,9 +3,8 @@ using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Runtime.InteropServices;
using JT1078.Flv.Extensions;

namespace JT1078.Flv.Audio
namespace JT1078.Protocol.Audio
{
public interface IFaacEncoder:IDisposable
{

+ 114
- 0
src/JT1078.Protocol/Audio/G711ACodec.cs Vedi File

@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Protocol.Audio
{
public class G711ACodec: IAudioCodec
{
private readonly int SIGN_BIT = 0x80;
private readonly int QUANT_MASK = 0xf;
private readonly int SEG_SHIFT = 4;
private readonly int SEG_MASK = 0x70;
//private readonly short[] seg_end = { 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF };
short AlawToLinear(byte value)
{
short t;
short seg;
value ^= 0x55;
t = (short)((value & QUANT_MASK) << 4);
seg = (short)((value & SEG_MASK) >> SEG_SHIFT);
switch (seg)
{
case 0:
t += 8;
break;
case 1:
t += 0x108;
break;
default:
t += 0x108;
t <<= seg - 1;
break;
}
return (value & SIGN_BIT) != 0 ? t : (short)-t;
}

public byte[] ToPcm(byte[] audio, IAudioAttachData audioAttachData)
{
byte[] pcmdata = new byte[audio.Length * 2];
for (int i = 0, offset = 0; i < audio.Length; i++)
{
short value = AlawToLinear(audio[i]);
pcmdata[offset++] = (byte)(value & 0xff);
pcmdata[offset++] = (byte)((value >> 8) & 0xff);
}
return pcmdata;
}

//static short Search(short val, short[] table, short size)
//{
// for (short i = 0; i < size; i++)
// {
// if (val <= table[i])
// {
// return i;
// }
// }
// return size;
//}

//byte LinearToAlaw(short pcm_val)
//{
// short mask;
// short seg;
// char aval;
// if (pcm_val >= 0)
// {
// mask = 0xD5;
// }
// else
// {
// mask = 0x55;
// pcm_val = (short)(-pcm_val - 1);
// if (pcm_val < 0)
// {
// pcm_val = 32767;
// }
// }

// //Convert the scaled magnitude to segment number.
// seg = Search(pcm_val, seg_end, 8);

// //Combine the sign, segment, and quantization bits.
// if (seg >= 8)
// {
// //out of range, return maximum value.
// return (byte)(0x7F ^ mask);
// }
// else
// {
// aval = (char)(seg << SEG_SHIFT);
// if (seg < 2) aval |= (char)((pcm_val >> 4) & QUANT_MASK);
// else aval |= (char)((pcm_val >> (seg + 3)) & QUANT_MASK);
// return (byte)(aval ^ mask);
// }
//}

///// <summary>
///// 转至G711
///// </summary>
///// <param name="pcmdata"></param>
///// <returns></returns>
//public byte[] ToG711(byte[] pcmdata)
//{
// byte[] g711data = new byte[pcmdata.Length / 2];
// for (int i = 0, k = 0; i < pcmdata.Length; i += 2, k++)
// {
// short v = (short)((pcmdata[i + 1] << 8) | (pcmdata[i]));
// g711data[k] = LinearToAlaw(v);
// }
// return g711data;
//}
}
}

src/JT1078.Flv/Audio/G711UCodec.cs → src/JT1078.Protocol/Audio/G711UCodec.cs Vedi File

@@ -2,13 +2,12 @@
using System.Collections.Generic;
using System.Text;

namespace JT1078.Flv.Audio
namespace JT1078.Protocol.Audio
{
public class G711UCodec
public class G711UCodec: IAudioCodec
{
/* 16384 entries per table (16 bit) */
readonly byte[] linearToUlawTable = new byte[65536];

/* 16384 entries per table (8 bit) */
readonly short[] ulawToLinearTable = new short[256];
readonly int SIGN_BIT = 0x80;
@@ -90,23 +89,26 @@ namespace JT1078.Flv.Audio
return pcmSamples;
}

private byte[] Pcm16ToUlaw(byte[] pcmSamples)
{
short[] dst = new short[pcmSamples.Length / 2];
byte[] ulawSamples = new byte[pcmSamples.Length / 2];
for (int i = 0, k = 0; i < pcmSamples.Length;)
{
dst[k++] = (short)((pcmSamples[i++] & 0xff) | ((pcmSamples[i++] & 0xff) << 8));
}
for (int i = 0, k = 0; i < dst.Length; i++)
{
ulawSamples[k++] = Linear2ulaw(dst[i]);
}
return ulawSamples;
}
//private byte[] Pcm16ToUlaw(byte[] pcmSamples)
//{
// short[] dst = new short[pcmSamples.Length / 2];
// byte[] ulawSamples = new byte[pcmSamples.Length / 2];
// for (int i = 0, k = 0; i < pcmSamples.Length;)
// {
// dst[k++] = (short)((pcmSamples[i++] & 0xff) | ((pcmSamples[i++] & 0xff) << 8));
// }
// for (int i = 0, k = 0; i < dst.Length; i++)
// {
// ulawSamples[k++] = Linear2ulaw(dst[i]);
// }
// return ulawSamples;
//}

public byte[] ToPcm(byte[] data) => UlawToPcm16(data);
//public byte[] ToG711(byte[] data) => Pcm16ToUlaw(data);

public byte[] ToG711(byte[] data) => Pcm16ToUlaw(data);
public byte[] ToPcm(byte[] audio, IAudioAttachData audioAttachData)
{
return UlawToPcm16(audio);
}
}
}

+ 10
- 0
src/JT1078.Protocol/Audio/IAudioAttachData.cs Vedi File

@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Protocol.Audio
{
public interface IAudioAttachData
{
}
}

+ 11
- 0
src/JT1078.Protocol/Audio/IAudioCodec.cs Vedi File

@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Protocol.Audio
{
public interface IAudioCodec
{
byte[] ToPcm(byte[] audio, IAudioAttachData audioAttachData);
}
}

+ 6
- 1
src/JT1078.Protocol/JT1078.Protocol.csproj Vedi File

@@ -14,7 +14,7 @@
<licenseUrl>https://github.com/SmallChi/JT1078/blob/master/LICENSE</licenseUrl>
<license>https://github.com/SmallChi/JT1078/blob/master/LICENSE</license>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>1.0.3</Version>
<Version>1.0.4-preview1</Version>
<SignAssembly>false</SignAssembly>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
@@ -24,6 +24,11 @@
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup>


<ItemGroup>
<Compile Remove="Audio\FaacEncoder.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\LICENSE">


Caricamento…
Annulla
Salva