Decoding ima4 audio format

前端 未结 2 1856
囚心锁ツ
囚心锁ツ 2021-02-08 12:24

To reduce the download size of an iPhone application I\'m compressing some audio files. Specifically I\'m using afconvert on the command line to change .wav format to .caf form

2条回答
  •  不知归路
    2021-02-08 13:02

    The term "packet" refers to a group of compressed audio samples with a header. You need the header to decode the data immediately following. If you consider your ima4 file to be a book, then each packet is a page. At the top are the values needed to decode that page, followed by the compressed audio.

    That's why you need to calculate the size of the unpacked data (and then make space for it) -- since it's compressed, you need to convert data from compressed audio to uncompressed audio before you can output it. In order to allocate an output buffer, you need to know how big it has to be (note: you may need to output in chunks that are larger than a single packet at a time).

    It looks like the typical structure, per the earlier "Overview" section, is that sets of 64 samples, each 16 bits (so 128 bytes) are translated to a 2-byte header and a 32-byte set of compressed samples (34 bytes in all). So, in the typical case, you can produce your expected output datasize by taking the input data size, dividing by 34 to get the number of packets, then multiplying by 128 bytes for the uncompressed audio per packet.

    You shouldn't do that, though. It looks like you should instead query kAudioFilePropertyDataFormat to get the mBytesPerPacket -- this is the "34" value above, and mFramesPerPacket -- this is the 64, above, that gets multiplied by 2 (for 16-byte samples) to make 128 bytes of output.

    Then, for each packet, you will need to run through the decoding described in the post. In somewhat longer pseudo C-code, assuming you are getting arrays of bytes, to handle the header:

    packet = GetPacket();
    Header = (packet[0] << 8) | packet[1]; //Big-endian 16-bit value
    step_index = Header & 0x007f; //Lower seven bits
    predictor = Header & 0xff80; //Upper nine bits
    for (i = 2; i < mBytesPerPacket; i++)
    {
        nibble = packet[i] & 0x0f; //Low Nibble
        process that nibble, per the blogpost -- be careful on sign-extension!
        nibble = (packet[i] & 0xf0) >> 4; //High Nibble
        process that nibble, per the blogpost -- be careful on sign-extension!
    }
    

    The sign-extension above refers to the fact that the post involves handling each nibble both in an unsigned and a signed way. If the high bit of a nibble (bit 3) is a 1, then it is negative; additionally the bit-shift may do sign-extension. This is not handled in the above pseudocode.

提交回复
热议问题