static PyObject* FlacDecoder_offsets(decoders_FlacDecoder* self, PyObject *args) { int channel; struct flac_frame_header frame_header; flac_status error; PyObject* offsets = PyList_New(0); PyObject* offset_pair; uint32_t samples; long offset; PyThreadState *thread_state = PyEval_SaveThread(); while (self->remaining_samples > 0) { self->subframe_data->reset(self->subframe_data); offset = br_ftell(self->bitstream); if (!setjmp(*br_try(self->bitstream))) { /*read frame header*/ if ((error = flacdec_read_frame_header(self->bitstream, &(self->streaminfo), &frame_header)) != OK) { PyEval_RestoreThread(thread_state); PyErr_SetString(PyExc_ValueError, FlacDecoder_strerror(error)); goto error; } samples = frame_header.block_size; /*read 1 subframe per channel*/ for (channel = 0; channel < frame_header.channel_count; channel++) if ((error = flacdec_read_subframe( self->bitstream, self->qlp_coeffs, self->residuals, (unsigned int)MIN(frame_header.block_size, self->remaining_samples), flacdec_subframe_bits_per_sample(&frame_header, channel), self->subframe_data->append(self->subframe_data))) != OK) { PyEval_RestoreThread(thread_state); PyErr_SetString(PyExc_ValueError, FlacDecoder_strerror(error)); goto error; } /*read CRC-16*/ self->bitstream->byte_align(self->bitstream); self->bitstream->read(self->bitstream, 16); /*decrement remaining samples*/ self->remaining_samples -= frame_header.block_size; /*add offset pair to our list*/ PyEval_RestoreThread(thread_state); offset_pair = Py_BuildValue("(i, I)", offset, samples); PyList_Append(offsets, offset_pair); Py_DECREF(offset_pair); thread_state = PyEval_SaveThread(); } else { /*handle I/O error during read*/ PyEval_RestoreThread(thread_state); PyErr_SetString(PyExc_IOError, "EOF reading frame"); goto error; } br_etry(self->bitstream); } self->stream_finalized = 1; PyEval_RestoreThread(thread_state); return offsets; error: Py_XDECREF(offsets); br_etry(self->bitstream); return NULL; }
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; }
PyObject* FlacDecoder_read(decoders_FlacDecoder* self, PyObject *args) { uint16_t crc16 = 0; int channel; struct flac_frame_header frame_header; PyObject* framelist; PyThreadState *thread_state; flac_status error; if (self->closed) { PyErr_SetString(PyExc_ValueError, "cannot read closed stream"); return NULL; } self->subframe_data->reset(self->subframe_data); /*if all samples have been read, return an empty FrameList*/ if (self->stream_finalized) { return empty_FrameList(self->audiotools_pcm, self->streaminfo.channels, self->streaminfo.bits_per_sample); } if (self->remaining_samples < 1) { self->stream_finalized = 1; if (FlacDecoder_verify_okay(self)) { return empty_FrameList(self->audiotools_pcm, self->streaminfo.channels, self->streaminfo.bits_per_sample); } else { PyErr_SetString(PyExc_ValueError, "MD5 mismatch at end of stream"); return NULL; } } thread_state = PyEval_SaveThread(); if (!setjmp(*br_try(self->bitstream))) { /*add callback for CRC16 calculation*/ br_add_callback(self->bitstream, (bs_callback_f)flac_crc16, &crc16); /*read frame header*/ if ((error = flacdec_read_frame_header(self->bitstream, &(self->streaminfo), &frame_header)) != OK) { br_pop_callback(self->bitstream, NULL); PyEval_RestoreThread(thread_state); PyErr_SetString(PyExc_ValueError, FlacDecoder_strerror(error)); br_etry(self->bitstream); return NULL; } /*read 1 subframe per channel*/ for (channel = 0; channel < frame_header.channel_count; channel++) if ((error = flacdec_read_subframe( self->bitstream, self->qlp_coeffs, self->residuals, (unsigned int)MIN(frame_header.block_size, self->remaining_samples), flacdec_subframe_bits_per_sample(&frame_header, channel), self->subframe_data->append(self->subframe_data))) != OK) { br_pop_callback(self->bitstream, NULL); PyEval_RestoreThread(thread_state); PyErr_SetString(PyExc_ValueError, FlacDecoder_strerror(error)); br_etry(self->bitstream); return NULL; } /*handle difference channels, if any*/ flacdec_decorrelate_channels(frame_header.channel_assignment, self->subframe_data, self->framelist_data); /*check CRC-16*/ self->bitstream->byte_align(self->bitstream); self->bitstream->read(self->bitstream, 16); br_pop_callback(self->bitstream, NULL); if (crc16 != 0) { PyEval_RestoreThread(thread_state); PyErr_SetString(PyExc_ValueError, "invalid checksum in frame"); br_etry(self->bitstream); return NULL; } /*decrement remaining samples*/ self->remaining_samples -= frame_header.block_size; } else { /*handle I/O error during read*/ br_pop_callback(self->bitstream, NULL); PyEval_RestoreThread(thread_state); PyErr_SetString(PyExc_IOError, "EOF reading frame"); br_etry(self->bitstream); return NULL; } br_etry(self->bitstream); PyEval_RestoreThread(thread_state); framelist = array_i_to_FrameList(self->audiotools_pcm, self->framelist_data, frame_header.channel_count, frame_header.bits_per_sample); if (framelist != NULL) { /*update MD5 sum*/ if (FlacDecoder_update_md5sum(self, framelist) == OK) /*return pcm.FrameList Python object*/ return framelist; else { Py_DECREF(framelist); return NULL; } } else { return NULL; } }
static PyObject* OggFlacDecoder_read(decoders_OggFlacDecoder *self, PyObject *args) { ogg_status ogg_status; flac_status flac_status; struct flac_frame_header frame_header; int channel; PyObject *framelist; PyThreadState *thread_state; if (self->closed) { PyErr_SetString(PyExc_ValueError, "cannot read closed stream"); return NULL; } self->subframe_data->reset(self->subframe_data); /*if all samples have been read, return an empty FrameList*/ if (self->stream_finalized) { return empty_FrameList(self->audiotools_pcm, self->streaminfo.channels, self->streaminfo.bits_per_sample); } thread_state = PyEval_SaveThread(); ogg_status = oggreader_next_packet(self->ogg_stream, self->packet); PyEval_RestoreThread(thread_state); if (ogg_status == OGG_OK) { /*decode the next FrameList from the stream*/ thread_state = PyEval_SaveThread(); self->crc16 = 0; if (!setjmp(*br_try(self->packet))) { /*read frame header*/ if ((flac_status = flacdec_read_frame_header(self->packet, &(self->streaminfo), &frame_header)) != OK) { PyEval_RestoreThread(thread_state); PyErr_SetString(PyExc_ValueError, FlacDecoder_strerror(flac_status)); br_etry(self->packet); return NULL; } /*read 1 subframe per channel*/ for (channel = 0; channel < frame_header.channel_count; channel++) if ((flac_status = flacdec_read_subframe( self->packet, self->qlp_coeffs, self->residuals, frame_header.block_size, flacdec_subframe_bits_per_sample(&frame_header, channel), self->subframe_data->append(self->subframe_data))) != OK) { PyEval_RestoreThread(thread_state); PyErr_SetString(PyExc_ValueError, FlacDecoder_strerror(flac_status)); br_etry(self->packet); return NULL; } br_etry(self->packet); /*handle difference channels, if any*/ flacdec_decorrelate_channels(frame_header.channel_assignment, self->subframe_data, self->framelist_data); /*check CRC-16*/ self->packet->byte_align(self->packet); self->packet->read(self->packet, 16); if (self->crc16 != 0) { PyEval_RestoreThread(thread_state); PyErr_SetString(PyExc_ValueError, "invalid checksum in frame"); return NULL; } PyEval_RestoreThread(thread_state); framelist = a_int_to_FrameList(self->audiotools_pcm, self->framelist_data, frame_header.channel_count, frame_header.bits_per_sample); if (framelist != NULL) { /*update MD5 sum*/ if (OggFlacDecoder_update_md5sum(self, framelist) == 1) /*return pcm.FrameList Python object*/ return framelist; else { Py_DECREF(framelist); return NULL; } } else { return NULL; } } else { /*read error decoding FLAC frame*/ PyEval_RestoreThread(thread_state); PyErr_SetString(PyExc_IOError, "I/O error decoding FLAC frame"); br_etry(self->packet); return NULL; } } else if (ogg_status == OGG_STREAM_FINISHED) { /*Ogg stream is finished so verify stream's MD5 sum then return an empty FrameList if it matches correctly*/ if (OggFlacDecoder_verify_okay(self)) { self->stream_finalized = 1; return empty_FrameList(self->audiotools_pcm, self->streaminfo.channels, self->streaminfo.bits_per_sample); } else { PyErr_SetString(PyExc_ValueError, "MD5 mismatch at end of stream"); return NULL; } } else { /*error reading the next Ogg packet, so raise the appropriate exception*/ PyErr_SetString(ogg_exception(ogg_status), ogg_strerror(ogg_status)); return NULL; } }