unsigned
buf_skip(struct bs_buffer *stream, unsigned data_size)
{
    const buf_size_t to_read = MIN(data_size, buf_window_size(stream));
    stream->window_start += to_read;
    return to_read;
}
unsigned
buf_read(struct bs_buffer *stream, uint8_t *data, unsigned data_size)
{
    const buf_size_t to_read = MIN(data_size, buf_window_size(stream));
    memcpy(data, buf_window_start(stream), to_read);
    stream->window_start += to_read;
    return to_read;
}
void
buf_resize(struct bs_buffer *stream, unsigned additional_bytes)
{
    /*only perform resize if space actually needed*/
    if (additional_bytes > buf_unused_size(stream)) {
        if (stream->window_start > 0) {
            /*shift window down before extending buffer to add more space*/
            if (buf_window_size(stream)) {
                memmove(stream->data,
                        buf_window_start(stream),
                        buf_window_size(stream));
            }
            stream->window_end -= stream->window_start;
            stream->window_start = 0;
        }

        while (additional_bytes > buf_unused_size(stream)) {
            stream->data_size *= 2;
        }

        stream->data = realloc(stream->data, stream->data_size);
    }
}
static int
read_audio_packet(DVDA_Packet_Reader* packets,
                  DVDA_Packet* packet, struct bs_buffer* packet_data)
{
    if (packets->total_sectors) {
        BitstreamReader* reader = packets->reader;
        struct bs_buffer* buffer = reader->input.substream;
        buf_reset(buffer);
        if (!read_sector(packets->sectors, buffer)) {
            if (buf_window_size(buffer) == 0) {
                return 0;
            }

            if (!setjmp(*br_try(reader))) {
                unsigned sync_bytes;
                unsigned pad[6];
                unsigned PTS_high;
                unsigned PTS_mid;
                unsigned PTS_low;
                unsigned SCR_extension;
                unsigned bitrate;
                unsigned stuffing_count;
                int audio_packet_found = 0;

                /*read pack header*/
                reader->parse(reader,
                              "32u 2u 3u 1u 15u 1u 15u 1u 9u 1u 22u 2u 5p 3u",
                              &sync_bytes, &(pad[0]), &PTS_high,
                              &(pad[1]), &PTS_mid, &(pad[2]),
                              &PTS_low, &(pad[3]), &SCR_extension,
                              &(pad[4]), &bitrate, &(pad[5]),
                              &stuffing_count);
                if (sync_bytes != 0x000001BA) {
                    br_etry(reader);
                    return 1;
                }

                if ((pad[0] != 1) || (pad[1] != 1) || (pad[2] != 1) ||
                    (pad[3] != 1) || (pad[4] != 1) || (pad[5] != 3)) {
                    br_etry(reader);
                    return 1;
                }

                for (; stuffing_count; stuffing_count--) {
                    reader->skip(reader, 8);
                }

                /*read packets from sector until sector is empty*/
                while (buf_window_size(buffer) > 0) {
                    unsigned start_code;
                    unsigned stream_id;
                    unsigned packet_length;

                    reader->parse(reader, "24u 8u 16u",
                                  &start_code, &stream_id, &packet_length);

                    if (start_code != 0x000001) {
                        br_etry(reader);
                        return 1;
                    }

                    if (stream_id == 0xBD) {
                        /*audio packets are forwarded to packet*/
                        unsigned pad1_size;
                        unsigned pad2_size;

                        reader->parse(reader, "16p 8u", &pad1_size);
                        reader->skip_bytes(reader, pad1_size);
                        reader->parse(reader, "8u 8u 8p 8u",
                                      &(packet->codec_ID),
                                      &(packet->CRC),
                                      &pad2_size);

                        if (packet->codec_ID == 0xA0) { /*PCM*/
                            reader->parse(reader,
                                          "16u 8p 4u 4u 4u 4u 8p 8u 8p 8u",
                                          &(packet->PCM.first_audio_frame),
                                          &(packet->PCM.group_1_bps),
                                          &(packet->PCM.group_2_bps),
                                          &(packet->PCM.group_1_rate),
                                          &(packet->PCM.group_2_rate),
                                          &(packet->PCM.channel_assignment),
                                          &(packet->PCM.CRC));
                            reader->skip_bytes(reader, pad2_size - 9);
                        } else {                        /*probably MLP*/
                            reader->skip_bytes(reader, pad2_size);
                        }

                        packet_length -= 3 + pad1_size + 4 + pad2_size;

                        buf_reset(packet_data);
                        while (packet_length) {
                            static uint8_t buffer[4096];
                            const unsigned to_read = MIN(packet_length, 4096);
                            reader->read_bytes(reader, buffer, to_read);
                            buf_write(packet_data, buffer, to_read);
                            packet_length -= to_read;
                        }

                        audio_packet_found = 1;
                    } else {
                        /*other packets are ignored*/
                        reader->skip_bytes(reader, packet_length);
                    }
                }

                /*return success if an audio packet was read*/
                br_etry(reader);
                if (audio_packet_found) {
                    return 0;
                } else {
                    return 1;
                }
            } else {
                /*error reading sector*/
                br_etry(reader);
                return 1;
            }
        } else {
            /*error reading sector*/
            return 1;
        }
    } else {
        /*no more sectors, so return EOF*/
        return 0;
    }
}