int caf_desc(caf_reader_t *reader, int64_t chunk_size)
{
    double mSampleRate;
    uint32_t mFormatID, mFormatFlags, mBytesPerPacket, mFramesPerPacket,
             mChannelsPerFrame, mBitsPerChannel;
    pcm_sample_description_t *desc = &reader->sample_format;

    ENSURE(chunk_size >= 32);
    TRY_IO(pcm_scanb(&reader->io, "QLLLLLL", &mSampleRate, &mFormatID,
                     &mFormatFlags, &mBytesPerPacket, &mFramesPerPacket,
                     &mChannelsPerFrame, &mBitsPerChannel) != 7);

    ENSURE(mFormatID == M4AF_FOURCC('l','p','c','m'));
    ENSURE(mSampleRate && mBytesPerPacket &&
           mChannelsPerFrame >= 1 && mChannelsPerFrame <= 8 &&
           mBitsPerChannel && mFramesPerPacket == 1 &&
           mBytesPerPacket % mChannelsPerFrame == 0 &&
           mBytesPerPacket >= mChannelsPerFrame * ((mBitsPerChannel + 7) / 8));

    desc->sample_rate        = mSampleRate;
    desc->bits_per_channel   = mBitsPerChannel;
    desc->bytes_per_frame    = mBytesPerPacket;
    desc->channels_per_frame = mChannelsPerFrame;

    switch (mFormatFlags) {
    case 0: desc->sample_type = PCM_TYPE_SINT_BE;  break;
    case 1: desc->sample_type = PCM_TYPE_FLOAT_BE; break;
    case 2: desc->sample_type = PCM_TYPE_SINT;     break;
    case 3: desc->sample_type = PCM_TYPE_FLOAT;    break;
    default: goto FAIL;
    }

    TRY_IO(pcm_skip(&reader->io, chunk_size - 32));
    return 0;
FAIL:
    return -1;
}
int caf_desc(caf_reader_t *reader, int64_t chunk_size)
{
    double mSampleRate;
    uint32_t mFormatID, mFormatFlags, mBytesPerPacket, mFramesPerPacket,
             mChannelsPerFrame, mBitsPerChannel;
    pcm_sample_description_t *desc = &reader->sample_format;

    ENSURE(chunk_size >= 32);
    TRY_IO(pcm_scanb(&reader->io, "QLLLLLL", &mSampleRate, &mFormatID,
                     &mFormatFlags, &mBytesPerPacket, &mFramesPerPacket,
                     &mChannelsPerFrame, &mBitsPerChannel) != 7);

    ENSURE(mFormatID == M4AF_FOURCC('l','p','c','m'));
    ENSURE(mSampleRate && mBytesPerPacket &&
           mChannelsPerFrame >= 1 && mChannelsPerFrame <= 8 &&
           mBitsPerChannel && mFramesPerPacket == 1 &&
           mBytesPerPacket % mChannelsPerFrame == 0 &&
           mBytesPerPacket >= mChannelsPerFrame * ((mBitsPerChannel + 7) / 8));

    desc->sample_rate        = mSampleRate;
    desc->bits_per_channel   = mBitsPerChannel;
    desc->bytes_per_frame    = mBytesPerPacket;
    desc->channels_per_frame = mChannelsPerFrame;

    switch (mFormatFlags) {
    case 0: desc->sample_type = PCM_TYPE_SINT_BE;  break;
    case 1: desc->sample_type = PCM_TYPE_FLOAT_BE; break;
    case 2: desc->sample_type = PCM_TYPE_SINT;     break;
    case 3: desc->sample_type = PCM_TYPE_FLOAT;    break;
    default: goto FAIL;
    }

    TRY_IO(pcm_skip(&reader->io, chunk_size - 32));
    return 0;
FAIL:
    return -1;
}