何が間違っているのかはわかりません。でも、やりたいことのやり方は教えてくれる。
まず、一般的なヘルパー関数を作成します。
public static class General {
public static void CopyBytes(byte[] dst, int dstOffset, byte[] src) {
Buffer.BlockCopy(src, 0, dst, dstOffset, src.Length);
}
}
public static class BitHelper {
public static int Read(ref ulong x, int length) {
int r = (int)(x >> (64 - length));
x <<= length;
return r;
}
public static int Read(byte[] bytes, ref int offset, int length) {
int startByte = offset / 8;
int endByte = (offset + length - 1) / 8;
int skipBits = offset % 8;
ulong bits = 0;
for (int i = 0; i <= Math.Min(endByte - startByte, 7); i++) {
bits |= (ulong)bytes[startByte + i] << (56 - (i * 8));
}
if (skipBits != 0) Read(ref bits, skipBits);
offset += length;
return Read(ref bits, length);
}
public static void Write(ref ulong x, int length, int value) {
ulong mask = 0xFFFFFFFFFFFFFFFF >> (64 - length);
x = (x << length) | ((ulong)value & mask);
}
public static byte[] CopyBlock(byte[] bytes, int offset, int length) {
int startByte = offset / 8;
int endByte = (offset + length - 1) / 8;
int shiftA = offset % 8;
int shiftB = 8 - shiftA;
byte[] dst = new byte[(length + 7) / 8];
if (shiftA == 0) {
Buffer.BlockCopy(bytes, startByte, dst, 0, dst.Length);
}
else {
int i;
for (i = 0; i < endByte - startByte; i++) {
dst[i] = (byte)((bytes[startByte + i] << shiftA) | (bytes[startByte + i + 1] >> shiftB));
}
if (i < dst.Length) {
dst[i] = (byte)(bytes[startByte + i] << shiftA);
}
}
dst[dst.Length - 1] &= (byte)(0xFF << ((dst.Length * 8) - length));
return dst;
}
}
public static class BitConverterBE {
public static ulong ToUInt64(byte[] value, int startIndex) {
return
((ulong)value[startIndex ] << 56) |
((ulong)value[startIndex + 1] << 48) |
((ulong)value[startIndex + 2] << 40) |
((ulong)value[startIndex + 3] << 32) |
((ulong)value[startIndex + 4] << 24) |
((ulong)value[startIndex + 5] << 16) |
((ulong)value[startIndex + 6] << 8) |
((ulong)value[startIndex + 7] );
}
public static uint ToUInt32(byte[] value, int startIndex) {
return
((uint)value[startIndex ] << 24) |
((uint)value[startIndex + 1] << 16) |
((uint)value[startIndex + 2] << 8) |
((uint)value[startIndex + 3] );
}
public static ushort ToUInt16(byte[] value, int startIndex) {
return (ushort)(
(value[startIndex ] << 8) |
(value[startIndex + 1] ));
}
public static byte[] GetBytes(ulong value) {
byte[] buff = new byte[8];
buff[0] = (byte)(value >> 56);
buff[1] = (byte)(value >> 48);
buff[2] = (byte)(value >> 40);
buff[3] = (byte)(value >> 32);
buff[4] = (byte)(value >> 24);
buff[5] = (byte)(value >> 16);
buff[6] = (byte)(value >> 8);
buff[7] = (byte)(value );
return buff;
}
public static byte[] GetBytes(uint value) {
byte[] buff = new byte[4];
buff[0] = (byte)(value >> 24);
buff[1] = (byte)(value >> 16);
buff[2] = (byte)(value >> 8);
buff[3] = (byte)(value );
return buff;
}
public static byte[] GetBytes(ushort value) {
byte[] buff = new byte[2];
buff[0] = (byte)(value >> 8);
buff[1] = (byte)(value );
return buff;
}
}
public static class BitConverterLE {
public static byte[] GetBytes(ulong value) {
byte[] buff = new byte[8];
buff[0] = (byte)(value );
buff[1] = (byte)(value >> 8);
buff[2] = (byte)(value >> 16);
buff[3] = (byte)(value >> 24);
buff[4] = (byte)(value >> 32);
buff[5] = (byte)(value >> 40);
buff[6] = (byte)(value >> 48);
buff[7] = (byte)(value >> 56);
return buff;
}
public static byte[] GetBytes(uint value) {
byte[] buff = new byte[4];
buff[0] = (byte)(value );
buff[1] = (byte)(value >> 8);
buff[2] = (byte)(value >> 16);
buff[3] = (byte)(value >> 24);
return buff;
}
public static byte[] GetBytes(ushort value) {
byte[] buff = new byte[2];
buff[0] = (byte)(value );
buff[1] = (byte)(value >> 8);
return buff;
}
}
オーディオ ヘルパー クラスとインターフェイスを実装します。
interface IAudioWriter
{
void WriteChunk(byte[] chunk, uint timeStamp);
void Finish();
string Path { get; }
}
class AACWriter : IAudioWriter
{
string _path;
FileStream _fs;
int _aacProfile;
int _sampleRateIndex;
int _channelConfig;
public AACWriter(string path) {
_path = path;
_fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, 65536);
}
public void WriteChunk(byte[] chunk, uint timeStamp)
{
if (chunk.Length < 1) return;
if (chunk[0] == 0) { // Header
if (chunk.Length < 3) return;
ulong bits = (ulong)BitConverterBE.ToUInt16(chunk, 1) << 48;
_aacProfile = BitHelper.Read(ref bits, 5) - 1;
_sampleRateIndex = BitHelper.Read(ref bits, 4);
_channelConfig = BitHelper.Read(ref bits, 4);
if ((_aacProfile < 0) || (_aacProfile > 3))
throw new Exception("Unsupported AAC profile.");
if (_sampleRateIndex > 12)
throw new Exception("Invalid AAC sample rate index.");
if (_channelConfig > 6)
throw new Exception("Invalid AAC channel configuration.");
}
else { // Audio data
int dataSize = chunk.Length - 1;
ulong bits = 0;
// Reference: WriteADTSHeader from FAAC's bitstream.c
BitHelper.Write(ref bits, 12, 0xFFF);
BitHelper.Write(ref bits, 1, 0);
BitHelper.Write(ref bits, 2, 0);
BitHelper.Write(ref bits, 1, 1);
BitHelper.Write(ref bits, 2, _aacProfile);
BitHelper.Write(ref bits, 4, _sampleRateIndex);
BitHelper.Write(ref bits, 1, 0);
BitHelper.Write(ref bits, 3, _channelConfig);
BitHelper.Write(ref bits, 1, 0);
BitHelper.Write(ref bits, 1, 0);
BitHelper.Write(ref bits, 1, 0);
BitHelper.Write(ref bits, 1, 0);
BitHelper.Write(ref bits, 13, 7 + dataSize);
BitHelper.Write(ref bits, 11, 0x7FF);
BitHelper.Write(ref bits, 2, 0);
_fs.Write(BitConverterBE.GetBytes(bits), 1, 7);
_fs.Write(chunk, 1, dataSize);
}
}
public void Finish() {
_fs.Close();
}
public string Path {
get {
return _path;
}
}
}
ここで、自分で行う必要があるのは、最初の AAC ファイルからチャンクを 1 つずつ読み取って書き込み、その後、2 番目の AAC ファイルからチャンクを 1 つずつ読み取って中間ファイルに追加することです。
上記のコードは C# であるため、C# のref
効果をシミュレートするには、以下を置き換えるだけでラッピングを使用する必要があることに注意してください。
ref Type variable_name
と:
_<Type> variable_name