use super::{ogg_vorbis_stream_mangler::OggVorbisStreamMangler, Settings, VorbisStreamState};
pub(super) fn granule_position_for_packet<M: OggVorbisStreamMangler>(
packet_sample_block_size: Option<u16>,
packet_number: usize,
packet_page_granule_position: u64,
is_last_stream_packet: bool,
remuxer_settings: &Settings<M>,
stream_state: &mut VorbisStreamState
) -> i64 {
match (
stream_state.last_written_packet_granule_position,
stream_state.last_written_packet_sample_block_size,
stream_state.original_last_audio_packet_in_first_audio_page_granule_position,
packet_number,
is_last_stream_packet
) {
(_, _, _, 0..=2, _) => {
0
}
(None, None, None, 3, _) => {
stream_state.last_written_packet_granule_position = Some(0);
stream_state.last_written_packet_sample_block_size =
Some(packet_sample_block_size.unwrap());
0
}
(
None,
None,
Some((_, final_packet_in_first_audio_page_number)),
processed_packet_count @ 3,
_
) if final_packet_in_first_audio_page_number != processed_packet_count => {
stream_state.last_written_packet_granule_position = Some(0);
stream_state.last_written_packet_sample_block_size =
Some(packet_sample_block_size.unwrap());
0
}
(
None,
None,
Some((first_audio_page_granule_position, final_packet_in_first_audio_page_number)),
processed_packet_count @ 3,
_
) if final_packet_in_first_audio_page_number == processed_packet_count => {
#[allow(clippy::identity_op)]
let start_granule_position_offset = first_audio_page_granule_position - 0;
let actual_granule_position =
0i64.wrapping_add(if remuxer_settings.ignore_start_sample_offset {
0
} else {
start_granule_position_offset
});
stream_state.start_granule_position_offset = Some(start_granule_position_offset);
stream_state.last_written_packet_granule_position = Some(actual_granule_position);
stream_state.last_written_packet_sample_block_size =
Some(packet_sample_block_size.unwrap());
actual_granule_position
}
(
Some(last_written_packet_granule_position),
Some(last_written_packet_sample_block_size),
None,
4..,
false
) => {
let packet_sample_block_size = packet_sample_block_size.unwrap();
let calculated_granule_position = calculate_granule_position(
last_written_packet_granule_position,
last_written_packet_sample_block_size,
packet_sample_block_size
);
stream_state.last_written_packet_granule_position = Some(calculated_granule_position);
stream_state.last_written_packet_sample_block_size = Some(packet_sample_block_size);
calculated_granule_position
}
(
Some(last_written_packet_granule_position),
Some(last_written_packet_sample_block_size),
Some((_, final_packet_in_first_audio_page_number)),
processed_packet_count @ 4..,
false
) if final_packet_in_first_audio_page_number != processed_packet_count => {
let packet_sample_block_size = packet_sample_block_size.unwrap();
let calculated_granule_position = calculate_granule_position(
last_written_packet_granule_position,
last_written_packet_sample_block_size,
packet_sample_block_size
);
stream_state.last_written_packet_granule_position = Some(calculated_granule_position);
stream_state.last_written_packet_sample_block_size = Some(packet_sample_block_size);
calculated_granule_position
}
(
Some(last_written_packet_granule_position),
Some(last_written_packet_sample_block_size),
Some((first_audio_page_granule_position, final_packet_in_first_audio_page_number)),
processed_packet_count @ 4..,
false
) if final_packet_in_first_audio_page_number == processed_packet_count => {
let packet_sample_block_size = packet_sample_block_size.unwrap();
let calculated_granule_position = calculate_granule_position(
last_written_packet_granule_position,
last_written_packet_sample_block_size,
packet_sample_block_size
);
let start_granule_position_offset =
first_audio_page_granule_position.saturating_sub(calculated_granule_position);
let actual_granule_position = calculated_granule_position.wrapping_add(
if remuxer_settings.ignore_start_sample_offset {
0
} else {
start_granule_position_offset
}
);
stream_state.start_granule_position_offset = Some(start_granule_position_offset);
stream_state.last_written_packet_granule_position = Some(actual_granule_position);
stream_state.last_written_packet_sample_block_size = Some(packet_sample_block_size);
actual_granule_position
}
(
Some(last_written_packet_granule_position),
Some(last_written_packet_sample_block_size),
_,
_,
true
) => {
let packet_sample_block_size = packet_sample_block_size.unwrap();
let calculated_granule_position = calculate_granule_position(
last_written_packet_granule_position,
last_written_packet_sample_block_size,
packet_sample_block_size
);
let original_granule_position = packet_page_granule_position as i64;
let start_granule_position_offset =
stream_state.start_granule_position_offset.unwrap_or(0);
let minimum_expected_granule_position = if remuxer_settings.ignore_start_sample_offset {
last_written_packet_granule_position
.wrapping_add(start_granule_position_offset)
.wrapping_add(1)
} else {
last_written_packet_granule_position.wrapping_add(1)
};
let maximum_expected_granule_position = if remuxer_settings.ignore_start_sample_offset {
calculated_granule_position.wrapping_add(start_granule_position_offset)
} else {
calculated_granule_position
};
if (minimum_expected_granule_position..=maximum_expected_granule_position)
.contains(&original_granule_position)
{
if remuxer_settings.ignore_start_sample_offset {
original_granule_position.wrapping_sub(start_granule_position_offset)
} else {
original_granule_position
}
} else {
calculated_granule_position
}
}
_ => unreachable!()
}
}
const fn calculate_granule_position(
last_written_packet_granule_position: i64,
last_written_packet_sample_block_size: u16,
packet_sample_block_size: u16
) -> i64 {
last_written_packet_granule_position.wrapping_add(
(last_written_packet_sample_block_size as i64 + packet_sample_block_size as i64) / 4
)
}