2012-10-04 20 views
6

Tôi đang cố gắng kết hợp 2 tệp AAC thành một, tôi phát hiện thấy trong tệp AAC - phần tử tiêu đề có mặt cho đến byte FF8, và sau đó 4 byte tiếp theo chứa độ dài của dữ liệu AAC. Tôi đã cố gắng duy trì 1 mảng tiêu đề, thêm kích thước của 2 tệp AAC, và sau đó thêm bộ đệm dữ liệu của hai tệp sau cái kia.Kết hợp 2 tệp AAC bằng cách sử dụng Java

Tệp kết quả chỉ phát tệp AAC đầu tiên. Đây là đoạn mã.

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

Tôi biết rằng có thông tin về khoảng thời gian của tệp AAC trong byte thứ 56, nhưng tôi không thể xác định được. Ai đó có thể giúp tôi ở đây không?

+0

Tôi đang cố gắng tương tự ... Bạn đã sửa chưa? Bất kỳ giải pháp nào? –

Trả lời

1

Vâng, tôi không thể cho bạn biết bạn đang làm gì sai. Nhưng tôi có thể cho bạn biết làm thế nào để làm những gì bạn muốn làm.

Đầu tiên tạo ra một chức năng chung Helper:

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

Bây giờ thực hiện âm thanh Helper Class và Interface:

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

Bây giờ những gì bạn cần phải làm một mình được, đọc khối từng người một từ tệp AAC đầu tiên và viết chúng, sau đó, đọc từng phần một từ tệp AAC thứ hai và nối chúng vào tệp trung gian.

Lưu ý, các mã trên là C#, vì vậy bạn sẽ phải sử dụng gói để mô phỏng ref hiệu lực thi hành C# 's, chỉ bằng cách thay thế:

ref Type variable_name 

với:

_<Type> variable_name 
+0

Thậm chí điều đó vẫn chưa đủ, vì có một loạt siêu dữ liệu MPEG4 (như bảng kích thước mẫu 'stsz') phải được kết hợp một cách thông minh. – duskwuff

+0

Những gì bạn đang đề xuất đến trong phạm vi của vùng chứa MP4. 'ADTSHeader' trong mỗi đoạn cung cấp đủ thông tin cho bộ giải mã để giải mã âm thanh chính xác, đó là tập tin nguyên AAC. @duskwuff –

+0

Tham chiếu đến '" mdat "' trong mã mẫu làm cho tôi nghĩ rằng nó thực sự là một MPEG4 với phần mở rộng sai. – duskwuff

1

tôi sẽ đề nghị bạn để xem các tệp aac được phân tích cú pháp như thế nào trong thư viện jaad, đặc biệt thú vị là mã xử lý ADTS here và phân tích cú pháp tiêu đề ADIF here.