2012-10-04 28 views
6

2つのAACファイルを1つに結合しようとしていますが、AACファイルでヘッダ要素がFF8バイトまで存在し、次の4バイトがAAC私は1つのヘッダー配列を維持し、2つのAACファイルのサイズを追加し、次に2つのファイルのデータバッファーを追加してみました。Javaを使用して2つのAACファイルを結合する

結果のファイルは最初のAACファイルのみを再生しました。コードスニペットは次のとおりです。

FileInputStream fs = new FileInputStream("./res/after.aac"); 

dis = new DataInputStream(fs); 
headerData = new byte[0xFF8]; 
dis.read(headerData); 


int lengthTotal = dis.readInt(); 
System.out.println("Length of After == "+lengthTotal); 
dis.readInt(); 


data = new byte[dis.available()]; 

dis.readFully(data); 
dis.close(); 
dis = null; 
fs.close(); 
fs = null; 


fs = new FileInputStream("./res/continue.aac"); 
dis = new DataInputStream(fs); 

dis.skipBytes(0xFF8); 

int length = dis.readInt(); 
System.out.println("Length of Ahead == "+length); 
lengthTotal = lengthTotal + length -8; 
System.out.println("Total Length== "+lengthTotal); 
dis.readInt(); 
newData = new byte[dis.available()]; 
dis.read(newData); 

FileOutputStream fos = new FileOutputStream("./res/combine.aac"); 
DataOutputStream dos = new DataOutputStream(fos); 

dos.write(headerData); 
dos.writeInt(lengthTotal); 
dos.writeBytes("mdat"); 
dos.write(data); 
dos.write(newData); 

私は第56バイトでAACファイルの持続時間についての情報があることを知っているが、私はそれを把握することができないのです。誰かがここで私を助けることができますか?

+0

私は同じことを試みています...あなたはそれを修正しましたか?すべてのソリューション? –

答えて

1

あなたが何を間違っているのかは分かりません。しかし、私はあなたがしたいことをする方法を伝えることができます。

まず一般的なヘルパー関数を作成します。

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ファイルを作成し、その後、2番目のAACファイルから1つずつチャンクを読み込み、中間ファイルに追加します。

注、上記のコードは、C#で、あなただけ交換することにより、C#のref効果をシミュレートするためにラッピングを使用する必要がありますので:

ref Type variable_name 

と:

_<Type> variable_name 
+0

これでもまだ十分ではありません。なぜなら、インテリジェントに組み合わされなければならないMPEG4メタデータ( 'stsz'サンプルサイズテーブルのような)があるからです。 – duskwuff

+0

あなたが提案していることは、MP4コンテナの範囲に入っています。すべてのチャンク内の「ADTSHeader」は、デコーダがオーディオを正しく復号するのに十分な情報を提供する。これはAAC rawファイルである。 @duskwuff –

+0

サンプルコードの '' mdat "'への参照は、実際には間違った拡張子を持つMPEG4だと思います。 – duskwuff

1

私はあなたをお勧めしますjaadライブラリでaacファイルがどのように解析されるかを見るために、特に興味深いのは、ADTS処理コードhereとADIFヘッダー解析hereです。

関連する問題