+use std::time::Instant;
+
+#[derive(Default)]
+pub struct OSD {
+ time: Option<Instant>,
+ text: Vec<u8>,
+ text_stride: usize,
+}
+
+impl OSD {
+ pub fn new() -> Self { Self::default() }
+ pub fn toggle(&mut self) {
+ if self.time.is_none() {
+ self.time = Some(Instant::now());
+ } else {
+ self.time = None;
+ }
+ }
+ pub fn update(&mut self) {
+ if let Some(time) = self.time {
+ if time.elapsed().as_millis() > 3000 {
+ self.time = None;
+ }
+ }
+ }
+ pub fn is_active(&self) -> bool { self.time.is_some() }
+ pub fn prepare(&mut self, ts: u64) {
+ self.update();
+ if !self.is_active() {
+ return;
+ }
+ let time_str = format_time(ts);
+ let mut w = 0;
+ let mut syms = Vec::with_capacity(time_str.len());
+ for chr in time_str.chars() {
+ let sym_idx = OSD_GLYPHS.iter().position(|el| el.sym == chr).unwrap_or(0);
+ w += OSD_GLYPHS[sym_idx].width;
+ syms.push(sym_idx);
+ }
+ self.text_stride = w;
+ if w > 0 {
+ self.text.resize(self.text_stride * 16, 0);
+ let mut pos = 0;
+ for &sym_idx in syms.iter() {
+ let glyph = &OSD_GLYPHS[sym_idx];
+ let mut mask = 1 << (glyph.width - 1);
+ while mask > 0 {
+ for (dline, (bits, mbits)) in self.text.chunks_exact_mut(w).zip(glyph.bits.iter().zip(glyph.mask.iter())) {
+ let wval = (bits & mask) != 0;
+ let bval = (mbits & mask) != 0;
+ dline[pos] = if wval { 2 } else if bval { 1 } else { 0 };
+ }
+ mask >>= 1;
+ pos += 1;
+ }
+ }
+ } else {
+ self.text.clear();
+ }
+ }
+ pub fn draw_yuv(&self, buffer: &mut [u8], pitch: usize) {
+ if !self.is_active() || self.text_stride == 0 {
+ return;
+ }
+ for (dline, sline) in buffer.chunks_exact_mut(pitch).zip(self.text.chunks_exact(self.text_stride)) {
+ for (dst, &src) in dline.iter_mut().zip(sline.iter()) {
+ match src {
+ 2 => *dst = 0xFF,
+ 1 => *dst = 0x00,
+ _ => {},
+ };
+ }
+ }
+ }
+ pub fn draw_rgb(&self, buffer: &mut [u8], pitch: usize) {
+ if !self.is_active() || self.text_stride == 0 {
+ return;
+ }
+ for (dline, sline) in buffer.chunks_exact_mut(pitch).zip(self.text.chunks_exact(self.text_stride)) {
+ for (dst, &src) in dline.chunks_exact_mut(3).zip(sline.iter()) {
+ match src {
+ 2 => dst.copy_from_slice(&[0xFF, 0xFF, 0xFF]),
+ 1 => dst.copy_from_slice(&[0x00, 0x00, 0x00]),
+ _ => {},
+ };
+ }
+ }
+ }
+}
+
+fn format_time(ms: u64) -> String {
+ let s = ms / 1000;
+ let (min, s) = (s / 60, s % 60);
+ let (h, min) = (min / 60, min % 60);
+ if h == 0 {
+ if min == 0 {
+ format!("{}", s)
+ } else {
+ format!("{}:{:02}", min, s)
+ }
+ } else {
+ format!("{}:{:02}:{:02}", h, min, s)
+ }
+}
+
+struct Glyph {
+ width: usize,
+ sym: char,
+ bits: [u16; 16],
+ mask: [u16; 16],
+}
+
+const OSD_GLYPHS: &[Glyph] = &[
+ Glyph {
+ width: 16,
+ sym: '?',
+ bits: [
+ 0b_0000000000000000,
+ 0b_0000111111100000,
+ 0b_0001100001110000,
+ 0b_0000000000110000,
+ 0b_0000000000110000,
+ 0b_0000000001100000,
+ 0b_0000000011000000,
+ 0b_0000000110000000,
+ 0b_0000000110000000,
+ 0b_0000000110000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000001111000000,
+ 0b_0000001111000000,
+ 0b_0000000000000000
+ ],
+ mask: [
+ 0b_0000111111100000,
+ 0b_0001111111110000,
+ 0b_0011111111111000,
+ 0b_0001100001111000,
+ 0b_0000000001111000,
+ 0b_0000000011110000,
+ 0b_0000000111100000,
+ 0b_0000001111000000,
+ 0b_0000001111000000,
+ 0b_0000001111000000,
+ 0b_0000000110000000,
+ 0b_0000000000000000,
+ 0b_0000001111000000,
+ 0b_0000011111100000,
+ 0b_0000011111100000,
+ 0b_0000001111000000
+ ],
+ },
+ Glyph {
+ width: 14,
+ sym: '0',
+ bits: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000111100000,
+ 0b_0000001000010000,
+ 0b_0000010000011000,
+ 0b_0000010000101000,
+ 0b_0000010001001000,
+ 0b_0000010010001000,
+ 0b_0000010100001000,
+ 0b_0000011000001000,
+ 0b_0000001000010000,
+ 0b_0000000111100000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ mask: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000001111110000,
+ 0b_0000011000011000,
+ 0b_0000110111101100,
+ 0b_0000101000100100,
+ 0b_0000101001010100,
+ 0b_0000101010110100,
+ 0b_0000101101010100,
+ 0b_0000101010010100,
+ 0b_0000100100110100,
+ 0b_0000110111101100,
+ 0b_0000011000011000,
+ 0b_0000001111110000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ },
+ Glyph {
+ width: 12,
+ sym: '1',
+ bits: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000001100000,
+ 0b_0000000011100000,
+ 0b_0000000110100000,
+ 0b_0000000000100000,
+ 0b_0000000000100000,
+ 0b_0000000000100000,
+ 0b_0000000000100000,
+ 0b_0000000000100000,
+ 0b_0000000000100000,
+ 0b_0000000011111000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ mask: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000001110000,
+ 0b_0000000010010000,
+ 0b_0000000100010000,
+ 0b_0000001001010000,
+ 0b_0000001111010000,
+ 0b_0000000001010000,
+ 0b_0000000001010000,
+ 0b_0000000001010000,
+ 0b_0000000001010000,
+ 0b_0000000111011100,
+ 0b_0000000100000100,
+ 0b_0000000111111100,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ },
+ Glyph {
+ width: 12,
+ sym: '2',
+ bits: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000011100000,
+ 0b_0000000100010000,
+ 0b_0000000000001000,
+ 0b_0000000000001000,
+ 0b_0000000000001000,
+ 0b_0000000000010000,
+ 0b_0000000000100000,
+ 0b_0000000001000000,
+ 0b_0000000010000000,
+ 0b_0000000100000000,
+ 0b_0000000111111000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ mask: [
+ 0b_0000000000000000,
+ 0b_0000000011100000,
+ 0b_0000000100010000,
+ 0b_0000001011101000,
+ 0b_0000001100010100,
+ 0b_0000000000010100,
+ 0b_0000000000010100,
+ 0b_0000000000101000,
+ 0b_0000000001010000,
+ 0b_0000000010100000,
+ 0b_0000000101000000,
+ 0b_0000001011111100,
+ 0b_0000001000000100,
+ 0b_0000001111111100,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ },
+ Glyph {
+ width: 12,
+ sym: '3',
+ bits: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000111111000,
+ 0b_0000000100001000,
+ 0b_0000000000010000,
+ 0b_0000000000100000,
+ 0b_0000000001000000,
+ 0b_0000000000100000,
+ 0b_0000000000010000,
+ 0b_0000000000001000,
+ 0b_0000000100001000,
+ 0b_0000000011110000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ mask: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000001111111100,
+ 0b_0000001000000100,
+ 0b_0000001011110100,
+ 0b_0000001110101000,
+ 0b_0000000001010000,
+ 0b_0000000010100000,
+ 0b_0000000001010000,
+ 0b_0000000000101000,
+ 0b_0000001100010100,
+ 0b_0000001011110100,
+ 0b_0000000100001000,
+ 0b_0000000011110000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ },
+ Glyph {
+ width: 12,
+ sym: '4',
+ bits: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000011000,
+ 0b_0000000000101000,
+ 0b_0000000001001000,
+ 0b_0000000010001000,
+ 0b_0000000100001000,
+ 0b_0000000111111000,
+ 0b_0000000000001000,
+ 0b_0000000000001000,
+ 0b_0000000000001000,
+ 0b_0000000000001000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ mask: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000011100,
+ 0b_0000000000100100,
+ 0b_0000000001010100,
+ 0b_0000000010110100,
+ 0b_0000000101010100,
+ 0b_0000001011110100,
+ 0b_0000001000000100,
+ 0b_0000001111110100,
+ 0b_0000000000010100,
+ 0b_0000000000010100,
+ 0b_0000000000010100,
+ 0b_0000000000011100,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ },
+ Glyph {
+ width: 12,
+ sym: '5',
+ bits: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000111111000,
+ 0b_0000000100001000,
+ 0b_0000000100000000,
+ 0b_0000000010000000,
+ 0b_0000000001000000,
+ 0b_0000000000110000,
+ 0b_0000000000001000,
+ 0b_0000000000001000,
+ 0b_0000000100001000,
+ 0b_0000000011110000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ mask: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000001111111100,
+ 0b_0000001000000100,
+ 0b_0000001011110100,
+ 0b_0000001010011100,
+ 0b_0000000101000000,
+ 0b_0000000010110000,
+ 0b_0000000001001000,
+ 0b_0000000000110100,
+ 0b_0000001100010100,
+ 0b_0000001011110100,
+ 0b_0000000100001000,
+ 0b_0000000011110000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ },
+ Glyph {
+ width: 12,
+ sym: '6',
+ bits: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000011110000,
+ 0b_0000000100001000,
+ 0b_0000000100000000,
+ 0b_0000000100000000,
+ 0b_0000000100000000,
+ 0b_0000000111110000,
+ 0b_0000000100001000,
+ 0b_0000000100001000,
+ 0b_0000000100001000,
+ 0b_0000000011110000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ mask: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000011110000,
+ 0b_0000000100001000,
+ 0b_0000001011110100,
+ 0b_0000001010011100,
+ 0b_0000001010000000,
+ 0b_0000001011110000,
+ 0b_0000001000001000,
+ 0b_0000001011110100,
+ 0b_0000001010010100,
+ 0b_0000001011110100,
+ 0b_0000000100001000,
+ 0b_0000000011110000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ },
+ Glyph {
+ width: 12,
+ sym: '7',
+ bits: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000001111111000,
+ 0b_0000001000001000,
+ 0b_0000000000001000,
+ 0b_0000000000010000,
+ 0b_0000000000010000,
+ 0b_0000000000010000,
+ 0b_0000000000100000,
+ 0b_0000000000100000,
+ 0b_0000000001100000,
+ 0b_0000000001000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ mask: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000011111111100,
+ 0b_0000010000000100,
+ 0b_0000010111110100,
+ 0b_0000011100010100,
+ 0b_0000000000101000,
+ 0b_0000000000101000,
+ 0b_0000000000101000,
+ 0b_0000000001010000,
+ 0b_0000000001010000,
+ 0b_0000000010010000,
+ 0b_0000000010100000,
+ 0b_0000000011100000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ },
+ Glyph {
+ width: 12,
+ sym: '8',
+ bits: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000011110000,
+ 0b_0000000100001000,
+ 0b_0000000100001000,
+ 0b_0000000100001000,
+ 0b_0000000011110000,
+ 0b_0000000010010000,
+ 0b_0000000100001000,
+ 0b_0000000100001000,
+ 0b_0000000100001000,
+ 0b_0000000011110000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ mask: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000011110000,
+ 0b_0000000100001000,
+ 0b_0000001011110100,
+ 0b_0000001010010100,
+ 0b_0000001011110100,
+ 0b_0000000100001000,
+ 0b_0000000101101000,
+ 0b_0000001010010100,
+ 0b_0000001010010100,
+ 0b_0000001011110100,
+ 0b_0000000100001000,
+ 0b_0000000011110000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ },
+ Glyph {
+ width: 12,
+ sym: '9',
+ bits: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000011110000,
+ 0b_0000000100001000,
+ 0b_0000000100001000,
+ 0b_0000000100001000,
+ 0b_0000000011111000,
+ 0b_0000000000001000,
+ 0b_0000000000001000,
+ 0b_0000000000001000,
+ 0b_0000000100001000,
+ 0b_0000000011110000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ mask: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000011110000,
+ 0b_0000000100001000,
+ 0b_0000001011110100,
+ 0b_0000001010010100,
+ 0b_0000001011110100,
+ 0b_0000000100000100,
+ 0b_0000000011110100,
+ 0b_0000000000010100,
+ 0b_0000001110010100,
+ 0b_0000001011110100,
+ 0b_0000000100001000,
+ 0b_0000000011110000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ },
+ Glyph {
+ width: 9,
+ sym: ':',
+ bits: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000111000,
+ 0b_0000000000111000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000111000,
+ 0b_0000000000111000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ mask: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000111000,
+ 0b_0000000001111100,
+ 0b_0000000001111100,
+ 0b_0000000000111000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000111000,
+ 0b_0000000001111100,
+ 0b_0000000001111100,
+ 0b_0000000000111000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ },
+ Glyph {
+ width: 12,
+ sym: ' ',
+ bits: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ mask: [
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000,
+ 0b_0000000000000000
+ ],
+ },
+];