Ejemplo n.º 1
0
int
pcmfile_seek_samples(PcmFile *pf, int64_t offset, int whence)
{
    int64_t byte_offset;
    uint64_t newpos, fpos, dst, dsz;

    if(pf == NULL || pf->io.fp == NULL) return -1;
    if(pf->block_align <= 0) return -1;
    if(pf->filepos < pf->data_start) return -1;
    if(pf->data_size == 0) return 0;

    fpos = pf->filepos;
    dst = pf->data_start;
    dsz = pf->data_size;
    byte_offset = offset;
    byte_offset *= pf->block_align;

    // calculate new destination within file
    switch(whence) {
        case PCM_SEEK_SET:
            newpos = dst + CLIP(byte_offset, 0, (int64_t)dsz);
            break;
        case PCM_SEEK_CUR:
            newpos = fpos - MIN(-byte_offset, (int64_t)(fpos - dst));
            newpos = MIN(newpos, dst + dsz);
            break;
        case PCM_SEEK_END:
            newpos = dst + dsz - CLIP(byte_offset, 0, (int64_t)dsz);
            break;
        default: return -1;
    }

    // seek to the destination point
    if(pcmfile_seek_set(pf, newpos)) return -1;

    return 0;
}
Ejemplo n.º 2
0
static int
caff_init(PcmFile *pf)
{
    int id, found_data, format_flags;
    enum PcmSampleFormat src_fmt;
    uint64_t chunksize;

    // read "caff" id
    if (read4be(pf) != CAFF_ID) {
        fprintf(stderr, "CAFF: file type check failed\n");
        return -1;
    }

    // check file version
    if (read2be(pf) != 1) {
        fprintf(stderr, "CAFF: file version check failed\n");
        return -1;
    }

    // skip file flags
    read2be(pf);

    // audio description chunk
    if (read4be(pf) != DESC_ID) {
        fprintf(stderr, "CAFF: 'desc' chunk not present\n");
        return -1;
    }
    chunksize = read8be(pf);
    if (chunksize != 32) {
        fprintf(stderr, "CAFF: invalid 'desc' chunk size\n");
        return -1;
    }
    pf->sample_rate = read_dbl_be(pf);
    pf->internal_fmt = read4be(pf);
    format_flags = read4be(pf);
    pf->order = (format_flags & FLAG_IS_LITTLEENDIAN) ? PCM_BYTE_ORDER_LE: PCM_BYTE_ORDER_BE;
    pf->sample_type = (format_flags & FLAG_IS_FLOAT) ? PCM_SAMPLE_TYPE_FLOAT: PCM_SAMPLE_TYPE_INT;
    pf->block_align = read4be(pf);
    read4be(pf);
    pf->channels = read4be(pf);
    pf->ch_mask = pcm_get_default_ch_mask(pf->channels);
    pf->bit_width = read4be(pf);

    // validate some parameters
    if (pf->sample_rate < 1) {
        fprintf(stderr, "CAFF: Invalid sample rate: %d\n", pf->sample_rate);
        return -1;
    }
    if (pf->block_align < 1) {
        fprintf(stderr, "CAFF: Invalid block align: %d\n", pf->block_align);
        return -1;
    }
    if (pf->channels < 1 || pf->channels > PCM_MAX_CHANNELS) {
        fprintf(stderr, "CAFF: Invalid number of channels: %d\n", pf->channels);
        return -1;
    }
    if (pf->internal_fmt != LPCM_TAG) {
        fprintf(stderr, "CAFF: Unsupported codec: 0x%04X\n", pf->internal_fmt);
        return -1;
    }

    // set audio data format based on bit depth and sample type
    src_fmt = PCM_SAMPLE_FMT_UNKNOWN;
    switch (pf->bit_width) {
        case 8:  src_fmt = PCM_SAMPLE_FMT_S8;  break;
        case 16: src_fmt = PCM_SAMPLE_FMT_S16; break;
        case 20: src_fmt = PCM_SAMPLE_FMT_S20; break;
        case 24: src_fmt = PCM_SAMPLE_FMT_S24; break;
        case 32:
            if (pf->sample_type == PCM_SAMPLE_TYPE_FLOAT)
                src_fmt = PCM_SAMPLE_FMT_FLT;
            else if (pf->sample_type == PCM_SAMPLE_TYPE_INT)
                src_fmt = PCM_SAMPLE_FMT_S32;
            break;
        case 64:
            if (pf->sample_type == PCM_SAMPLE_TYPE_FLOAT) {
                src_fmt = PCM_SAMPLE_FMT_DBL;
            } else {
                fprintf(stderr, "64-bit integer samples not supported\n");
                return -1;
            }
            break;
    }
    pcmfile_set_source_format(pf, src_fmt);

    // read all header chunks. skip unknown chunks.
    found_data = 0;
    while (!found_data) {
        id = read4be(pf);
        chunksize = read8be(pf);
        switch (id) {
            case DATA_ID:
                read4be(pf);
                pf->data_size = chunksize - 4;
                pf->data_start = pf->filepos;
                if (pf->seekable && pf->file_size > 0) {
                    // limit data size to end-of-file
                    if (pf->data_size > 0)
                        pf->data_size = MIN(pf->data_size, pf->file_size - pf->data_start);
                    else
                        pf->data_size = pf->file_size - pf->data_start;
                }
                pf->samples = (pf->data_size / pf->block_align);
                found_data = 1;
                break;
            default:
                // skip unknown chunk
                if (chunksize > 0 && pcmfile_seek_set(pf, pf->filepos + chunksize)) {
                    fprintf(stderr, "error seeking in CAFF file\n");
                    return -1;
                }
        }
    }

    return 0;
}