2012-10-04 8 views
6

Ich versuche, 2 AAC-Dateien zu einem zu kombinieren, fand ich heraus, dass in AAC-Dateien - das Header-Element bis zum FF8-Byte vorhanden ist, und dann die nächsten 4 Bytes die Länge der Daten enthalten die AAC. Ich habe versucht, 1 Header-Array beizubehalten, die Größe der 2 AAC-Dateien hinzuzufügen und dann den Datenpuffer der beiden Dateien nacheinander hinzuzufügen.Kombiniere 2 AAC-Dateien mit Java

Die resultierende Datei spielte nur die erste AAC-Datei. Hier ist das Code-Snippet.

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); 

Ich weiß, dass es Informationen über Zeitdauer der AAC-Datei in dem 56th Byte ist, aber ich bin nicht aus in der Lage, es Figur. Kann mir hier jemand helfen?

+0

Ich versuche das gleiche ... Hast du es behoben? Irgendwelche Lösungen? –

Antwort

1

Nun, ich kann dir nicht sagen, was du falsch machst. Aber ich kann dir sagen, wie du das machst, was du tun willst.

zunächst eine allgemeine Hilfsfunktionen erstellen:

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; 
    } 
} 

Jetzt Audio Helper Class und Interface implementieren:

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; 
     } 
    } 
} 

Nun, was Sie selbst tun müssen, ist, Stücke eins nach dem anderen aus dem Lese erste AAC-Datei und schreibe sie, nach dem Lesen, Stücke nacheinander aus der zweiten AAC-Datei und anhängen sie an die Zwischendatei.

Hinweis, der obige Code ist C#, so dass Sie Verpackung verwenden, um C# 's ref Effekt, nur durch den Ersatz zu simulieren:

ref Type variable_name 

mit:

_<Type> variable_name 
+0

Auch das wird immer noch nicht ausreichen, da es eine Reihe von MPEG4 Metadaten (wie die 'stsz' Beispielgrößentabelle) gibt, die intelligent kombiniert werden müssen. – duskwuff

+0

Was Sie vorschlagen, kommt in den Anwendungsbereich von MP4-Container. 'ADTSHeader' in jedem Chunk liefert genug Informationen, damit der Decoder das Audio korrekt dekodieren kann, was eine AAC-Rohdatei ist. @duskwuff –

+0

Der Verweis auf '" mdat "' im Beispielcode lässt mich denken, dass es eigentlich ein MPEG4 mit der falschen Erweiterung ist. – duskwuff

1

Ich würde vorschlagen, Sie Um zu sehen, wie AAC-Dateien in der Bibliothek jaad analysiert werden, besonders interessant sind ADTS-Handling-Code here und ADIF Header-Parsing here.