Exemplo n.º 1
0
static PyObject*
FlacDecoder_seek(decoders_FlacDecoder* self, PyObject *args)
{
    long long seeked_offset;

    const array_o* seektable = self->seektable;
    uint64_t pcm_frames_offset = 0;
    uint64_t byte_offset = 0;
    unsigned i;

    if (self->closed) {
        PyErr_SetString(PyExc_ValueError, "cannot seek closed stream");
        return NULL;
    }

    if (!PyArg_ParseTuple(args, "L", &seeked_offset))
        return NULL;

    if (seeked_offset < 0) {
        PyErr_SetString(PyExc_ValueError, "cannot seek to negative value");
        return NULL;
    }

    self->stream_finalized = 0;

    /*find latest seekpoint whose first sample is <= seeked_offset
      or 0 if there are no seekpoints in the seektable*/
    for (i = 0; i < seektable->len; i++) {
        struct flac_SEEKPOINT* seekpoint = seektable->_[i];
        if (seekpoint->sample_number <= seeked_offset) {
            pcm_frames_offset = seekpoint->sample_number;
            byte_offset = seekpoint->byte_offset;
        } else {
            break;
        }
    }

    /*position bitstream to indicated value in file*/
    self->bitstream->rewind(self->bitstream);
    while (byte_offset) {
        /*perform this in chunks in case seeked distance
          is longer than a "long" taken by fseek*/
        const uint64_t seek = MIN(byte_offset, LONG_MAX);
        fseek(self->file, (long)seek, SEEK_CUR);
        byte_offset -= seek;
    }

    /*reset stream's total remaining frames*/
    self->remaining_samples = (self->streaminfo.total_samples -
                               pcm_frames_offset);

    if (pcm_frames_offset == 0) {
        /*if pcm_frames_offset is 0, reset MD5 validation*/
        audiotools__MD5Init(&(self->md5));
        self->perform_validation = 1;
    } else {
        /*otherwise, disable MD5 validation altogether at end of stream*/
        self->perform_validation = 0;
    }

    /*return actual PCM frames position in file*/
    return Py_BuildValue("K", pcm_frames_offset);
}
Exemplo n.º 2
0
int
FlacDecoder_init(decoders_FlacDecoder *self,
                 PyObject *args, PyObject *kwds)
{
    char* filename;
    int stream_offset = 0;

    self->filename = NULL;
    self->file = NULL;
    self->bitstream = NULL;

    self->seektable = array_o_new((ARRAY_COPY_FUNC)seekpoint_copy,
                                  free,
                                  NULL);

    self->subframe_data = array_ia_new();
    self->residuals = array_i_new();
    self->qlp_coeffs = array_i_new();
    self->framelist_data = array_i_new();
    self->audiotools_pcm = NULL;
    self->remaining_samples = 0;

    if (!PyArg_ParseTuple(args, "si|i",
                          &filename,
                          &(self->channel_mask),
                          &stream_offset))
        return -1;

    if (self->channel_mask < 0) {
        PyErr_SetString(PyExc_ValueError, "channel_mask must be >= 0");
        return -1;
    }
    if (stream_offset < 0) {
        PyErr_SetString(PyExc_ValueError, "stream offset must be >= 0");
        return -1;
    }

    /*open the flac file*/
    self->file = fopen(filename, "rb");
    if (self->file == NULL) {
        PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename);
        return -1;
    } else {
        self->bitstream = br_open(self->file, BS_BIG_ENDIAN);
    }

    /*skip the given number of bytes, if any*/
    if (stream_offset != 0)
        fseek(self->file, stream_offset, SEEK_SET);

    self->filename = strdup(filename);

    /*read the STREAMINFO block, SEEKTABLE block
      and setup the total number of samples to read*/
    if (flacdec_read_metadata(self->bitstream,
                              &(self->streaminfo),
                              self->seektable)) {
        self->streaminfo.channels = 0;
        return -1;
    }

    self->remaining_samples = self->streaminfo.total_samples;

    /*initialize the output MD5 sum*/
    audiotools__MD5Init(&(self->md5));
    self->perform_validation = 1;
    self->stream_finalized = 0;

    /*setup a framelist generator function*/
    if ((self->audiotools_pcm = open_audiotools_pcm()) == NULL)
        return -1;

    /*place mark at beginning of stream in case seeking is needed*/
    self->bitstream->mark(self->bitstream);

    /*mark stream as not closed and ready for reading*/
    self->closed = 0;

    return 0;
}
Exemplo n.º 3
0
int
OggFlacDecoder_init(decoders_OggFlacDecoder *self,
                    PyObject *args, PyObject *kwds) {
    char* filename;
    ogg_status result;
    uint16_t header_packets;

    self->ogg_stream = NULL;
    self->ogg_file = NULL;
    self->subframe_data = aa_int_new();
    self->residuals = a_int_new();
    self->qlp_coeffs = a_int_new();
    self->framelist_data = a_int_new();
    self->audiotools_pcm = NULL;
    self->packet = br_substream_new(BS_BIG_ENDIAN);
    self->stream_finalized = 0;

    if (!PyArg_ParseTuple(args, "si", &filename, &(self->channel_mask)))
        return -1;

    if (self->channel_mask < 0) {
        PyErr_SetString(PyExc_ValueError, "channel_mask must be >= 0");
        return -1;
    }

    self->ogg_file = fopen(filename, "rb");
    if (self->ogg_file == NULL) {
        PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename);
        return -1;
    } else {
        self->ogg_stream = oggreader_open(self->ogg_file);
    }

    /*the first packet should be the FLAC's STREAMINFO*/
    if ((result = oggreader_next_packet(self->ogg_stream,
                                        self->packet)) == OGG_OK) {
        if (!oggflac_read_streaminfo(self->packet,
                                     &(self->streaminfo),
                                     &header_packets))
            return -1;
    } else {
        PyErr_SetString(ogg_exception(result), ogg_strerror(result));
        return -1;
    }

    /*skip subsequent header packets*/
    for (; header_packets > 0; header_packets--) {
        if ((result = oggreader_next_packet(self->ogg_stream,
                                            self->packet)) != OGG_OK) {
            PyErr_SetString(ogg_exception(result), ogg_strerror(result));
            return -1;
        }
    }

    /*initialize the output MD5 sum*/
    audiotools__MD5Init(&(self->md5));

    /*add callback for CRC16 calculation*/
    br_add_callback(self->packet, (bs_callback_f)flac_crc16, &(self->crc16));

    /*setup a framelist generator function*/
    if ((self->audiotools_pcm = open_audiotools_pcm()) == NULL)
        return -1;

    /*mark stream as not closed and ready for reading*/
    self->closed = 0;

    return 0;
}
Exemplo n.º 4
0
int
FlacDecoder_init(decoders_FlacDecoder *self,
                 PyObject *args, PyObject *kwds)
{
    self->file = NULL;
    self->bitstream = NULL;

    self->seektable = a_obj_new((ARRAY_COPY_FUNC)seekpoint_copy,
                                free,
                                NULL);

    self->subframe_data = aa_int_new();
    self->residuals = a_int_new();
    self->qlp_coeffs = a_int_new();
    self->framelist_data = a_int_new();
    self->audiotools_pcm = NULL;
    self->remaining_samples = 0;

    if (!PyArg_ParseTuple(args, "O", &self->file)) {
        return -1;
    } else {
        Py_INCREF(self->file);
    }

    /*open BitstreamReader from FLAC file stream
      based on whether it's a low-level file object*/
    if (PyFile_Check(self->file)) {
        /*open bitstream through file object*/
        self->bitstream = br_open(PyFile_AsFile(self->file), BS_BIG_ENDIAN);
    } else {
        /*treat file as Python-implemented file-like object*/
        self->bitstream = br_open_external(
            self->file,
            BS_BIG_ENDIAN,
            4096,
            (ext_read_f)br_read_python,
            (ext_close_f)bs_close_python,
            (ext_free_f)bs_free_python_nodecref);
    }

    /*read the STREAMINFO block, SEEKTABLE block
      and setup the total number of samples to read*/
    if (flacdec_read_metadata(self->bitstream,
                              &(self->streaminfo),
                              self->seektable,
                              &(self->channel_mask))) {
        self->streaminfo.channels = 0;
        return -1;
    }

    if (PyFile_Check(self->file)) {
        /*place mark at beginning of stream but after metadata
          in case seeking is needed*/
        self->bitstream->mark(self->bitstream);
    }

    self->remaining_samples = self->streaminfo.total_samples;

    /*initialize the output MD5 sum*/
    audiotools__MD5Init(&(self->md5));
    self->perform_validation = 1;
    self->stream_finalized = 0;

    /*setup a framelist generator function*/
    if ((self->audiotools_pcm = open_audiotools_pcm()) == NULL)
        return -1;

    /*mark stream as not closed and ready for reading*/
    self->closed = 0;

    return 0;
}
Exemplo n.º 5
0
int main(int argc, char* argv[]) {
    FILE* ogg_file;
    OggReader* ogg_stream = NULL;
    BitstreamReader* packet = NULL;
    struct flac_STREAMINFO streaminfo;
    uint16_t header_packets;
    a_int* residuals = NULL;
    a_int* qlp_coeffs = NULL;
    aa_int* subframe_data = NULL;
    a_int* framelist_data = NULL;
    ogg_status result;
    uint16_t crc16 = 0;

    FrameList_int_to_char_converter converter;
    unsigned pcm_size;
    unsigned output_data_size = 1;
    uint8_t* output_data = NULL;

    audiotools__MD5Context md5;
    unsigned char stream_md5sum[16];
    const static unsigned char blank_md5sum[16] = {0, 0, 0, 0, 0, 0, 0, 0,
                                                   0, 0, 0, 0, 0, 0, 0, 0};

    if (argc < 2) {
        fprintf(stderr, "*** Usage: %s <file.oga>\n", argv[0]);
        return 1;
    }

    /*open input file for reading*/
    if ((ogg_file = fopen(argv[1], "rb")) == NULL) {
        fprintf(stderr, "*** %s: %s\n", argv[1], strerror(errno));
        return 1;
    } else {
        /*open bitstream and setup temporary arrays/buffers*/
        ogg_stream = oggreader_open(ogg_file);
        packet = br_substream_new(BS_BIG_ENDIAN);
        subframe_data = aa_int_new();
        residuals = a_int_new();
        qlp_coeffs = a_int_new();
        framelist_data = a_int_new();
        output_data = malloc(output_data_size);
    }

    /*the first packet should be the FLAC's STREAMINFO*/
    if ((result = oggreader_next_packet(ogg_stream, packet)) == OGG_OK) {
        if (!oggflac_read_streaminfo(packet, &streaminfo, &header_packets)) {
            goto error;
        } else {
            converter = FrameList_get_int_to_char_converter(
                streaminfo.bits_per_sample, 0, 1);
        }
    } else {
        fprintf(stderr, "*** Error: %s\n", ogg_strerror(result));
        goto error;
    }

    /*skip subsequent header packets*/
    for (; header_packets > 0; header_packets--) {
        if ((result = oggreader_next_packet(ogg_stream, packet)) != OGG_OK) {
            fprintf(stderr, "*** Error: %s\n", ogg_strerror(result));
            goto error;
        }
    }

    /*initialize the output MD5 sum*/
    audiotools__MD5Init(&md5);

    /*add callback for CRC16 calculation*/
    br_add_callback(packet, (bs_callback_f)flac_crc16, &crc16);

    /*decode the next FrameList from the stream*/
    result = oggreader_next_packet(ogg_stream, packet);

    while (result != OGG_STREAM_FINISHED) {
        if (result == OGG_OK) {
            flac_status flac_status;
            struct flac_frame_header frame_header;
            unsigned channel;

            subframe_data->reset(subframe_data);

            if (!setjmp(*br_try(packet))) {
                /*read frame header*/
                if ((flac_status =
                     flacdec_read_frame_header(packet,
                                               &streaminfo,
                                               &frame_header)) != OK) {
                    fprintf(stderr, "*** Error: %s\n",
                            FlacDecoder_strerror(flac_status));
                    br_etry(packet);
                    goto error;
                }

                /*read 1 subframe per channel*/
                for (channel = 0;
                     channel < frame_header.channel_count;
                     channel++)
                    if ((flac_status = flacdec_read_subframe(
                        packet,
                        qlp_coeffs,
                        residuals,
                        frame_header.block_size,
                        flacdec_subframe_bits_per_sample(&frame_header,
                                                         channel),
                        subframe_data->append(subframe_data))) != OK) {
                        fprintf(stderr, "*** Error: %s\n",
                                FlacDecoder_strerror(flac_status));
                        br_etry(packet);
                        goto error;
                    }

                br_etry(packet);
            } else {
                br_etry(packet);
                fprintf(stderr, "*** I/O Error reading FLAC frame\n");
                goto error;
            }

            /*handle difference channels, if any*/
            flacdec_decorrelate_channels(frame_header.channel_assignment,
                                         subframe_data,
                                         framelist_data);

            /*check CRC-16*/
            packet->byte_align(packet);
            packet->read(packet, 16);
            if (crc16 != 0) {
                fprintf(stderr, "*** Error: invalid checksum in frame\n");
                goto error;
            }

            /*turn FrameList into string of output*/
            pcm_size = (streaminfo.bits_per_sample / 8) * framelist_data->len;
            if (pcm_size > output_data_size) {
                output_data_size = pcm_size;
                output_data = realloc(output_data, output_data_size);
            }
            FrameList_samples_to_char(output_data,
                                      framelist_data->_,
                                      converter,
                                      framelist_data->len,
                                      streaminfo.bits_per_sample);

            /*update MD5 sum*/
            audiotools__MD5Update(&md5, output_data, pcm_size);

            /*output string to stdout*/
            fwrite(output_data, sizeof(unsigned char), pcm_size, stdout);

            result = oggreader_next_packet(ogg_stream, packet);
        } else {
            /*some error reading Ogg stream*/
            fprintf(stderr, "*** Error: %s\n", ogg_strerror(result));
            goto error;
        }
    }

    /*Ogg stream is finished so verify stream's MD5 sum*/
    audiotools__MD5Final(stream_md5sum, &md5);

    if (!((memcmp(streaminfo.md5sum, blank_md5sum, 16) == 0) ||
          (memcmp(stream_md5sum, streaminfo.md5sum, 16) == 0))) {
        fprintf(stderr, "*** MD5 mismatch at end of stream\n");
        goto error;
    }

    /*close streams, temporary buffers*/
    oggreader_close(ogg_stream);
    packet->close(packet);
    subframe_data->del(subframe_data);
    residuals->del(residuals);
    qlp_coeffs->del(qlp_coeffs);
    framelist_data->del(framelist_data);
    free(output_data);

    return 0;

error:
    oggreader_close(ogg_stream);
    packet->close(packet);
    subframe_data->del(subframe_data);
    residuals->del(residuals);
    qlp_coeffs->del(qlp_coeffs);
    framelist_data->del(framelist_data);
    free(output_data);

    return 1;
}