use byteorder::{BigEndian, ReadBytesExt};
use std::io::{Cursor, Read};
pub struct BigEndianReader<'a> {
cursor: Cursor<&'a [u8]>,
}
impl<'a> BigEndianReader<'a> {
pub fn new(data: &'a [u8]) -> Self {
Self {
cursor: Cursor::new(data),
}
}
#[inline]
pub fn position(&self) -> usize {
self.cursor.position() as usize
}
#[inline]
pub fn set_position(&mut self, pos: usize) {
self.cursor.set_position(pos as u64);
}
#[inline]
pub fn remaining(&self) -> usize {
self.cursor.get_ref().len() - self.position()
}
#[inline]
pub fn read_u8(&mut self) -> Option<u8> {
self.cursor.read_u8().ok()
}
#[inline]
pub fn read_u16(&mut self) -> Option<u16> {
self.cursor.read_u16::<BigEndian>().ok()
}
#[inline]
pub fn read_u24(&mut self) -> Option<u32> {
let mut buf = [0u8; 3];
self.cursor.read_exact(&mut buf).ok()?;
Some(((buf[0] as u32) << 16) | ((buf[1] as u32) << 8) | (buf[2] as u32))
}
#[inline]
pub fn read_u32(&mut self) -> Option<u32> {
self.cursor.read_u32::<BigEndian>().ok()
}
#[inline]
pub fn read_bytes(&mut self, len: usize) -> Option<Vec<u8>> {
let mut buf = vec![0u8; len];
self.cursor.read_exact(&mut buf).ok()?;
Some(buf)
}
#[inline]
pub fn skip(&mut self, len: usize) -> bool {
let new_pos = self.position() + len;
if new_pos <= self.cursor.get_ref().len() {
self.cursor.set_position(new_pos as u64);
true
} else {
false
}
}
}
#[inline]
pub fn ycbcr_to_rgba(y: u8, cb: u8, cr: u8, a: u8) -> u32 {
let y = y as f32;
let cb = (cb as f32) - 128.0;
let cr = (cr as f32) - 128.0;
let r = clamp((y + 1.40200 * cr).round() as i32, 0, 255) as u8;
let g = clamp((y - 0.34414 * cb - 0.71414 * cr).round() as i32, 0, 255) as u8;
let b = clamp((y + 1.77200 * cb).round() as i32, 0, 255) as u8;
u32::from_le_bytes([r, g, b, a])
}
#[inline]
pub fn rgb_to_rgba(r: u8, g: u8, b: u8, a: u8) -> u32 {
u32::from_le_bytes([r, g, b, a])
}
#[inline]
pub fn clamp<T: Ord>(value: T, min: T, max: T) -> T {
if value < min {
min
} else if value > max {
max
} else {
value
}
}
pub fn binary_search_timestamp(timestamps: &[u32], target: u32) -> usize {
if timestamps.is_empty() {
return 0;
}
let mut low = 0;
let mut high = timestamps.len();
while low < high {
let mid = low + (high - low) / 2;
if timestamps[mid] <= target {
low = mid + 1;
} else {
high = mid;
}
}
if low > 0 { low - 1 } else { 0 }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_binary_search_timestamp() {
let timestamps = vec![0, 1000, 2000, 3000, 4000];
assert_eq!(binary_search_timestamp(×tamps, 0), 0);
assert_eq!(binary_search_timestamp(×tamps, 500), 0);
assert_eq!(binary_search_timestamp(×tamps, 1000), 1);
assert_eq!(binary_search_timestamp(×tamps, 1500), 1);
assert_eq!(binary_search_timestamp(×tamps, 4500), 4);
}
#[test]
fn test_ycbcr_to_rgba() {
let white = ycbcr_to_rgba(255, 128, 128, 255);
let bytes = white.to_le_bytes();
assert_eq!(bytes[0], 255); assert_eq!(bytes[1], 255); assert_eq!(bytes[2], 255); assert_eq!(bytes[3], 255); }
}