PyObject* FlacDecoder_read(decoders_FlacDecoder* self, PyObject *args) { uint16_t crc16 = 0; int channel; struct flac_frame_header frame_header; PyObject* framelist; 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; } } 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); 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); 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) { 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); PyErr_SetString(PyExc_IOError, "EOF reading frame"); br_etry(self->bitstream); return NULL; } br_etry(self->bitstream); 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 (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; } }