]> git.nihav.org Git - nihav-player.git/commitdiff
implement displaying time on screen
authorKostya Shishkov <kostya.shishkov@gmail.com>
Thu, 15 Jun 2023 16:35:25 +0000 (18:35 +0200)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Thu, 15 Jun 2023 16:35:25 +0000 (18:35 +0200)
videoplayer/src/main.rs
videoplayer/src/osd.rs [new file with mode: 0644]

index dcd4d0a3538fa51e2a15372f506c11cfbf032137..3f15d9462ec1cc64bc534d63d802817a5d5de399 100644 (file)
@@ -29,6 +29,8 @@ mod audiodec;
 use audiodec::*;
 mod videodec;
 use videodec::*;
+mod osd;
+use osd::*;
 
 #[cfg(feature="debug")]
 macro_rules! debug_log {
@@ -159,10 +161,20 @@ impl<'a> DispQueue<'a> {
         }
     }
 
-    fn get_last_texture(&self) -> &Texture<'a> {
+    fn get_last_texture(&mut self, osd: &OSD) -> &Texture<'a> {
         if self.pool[self.len].is_yuv {
+            if osd.is_active() {
+                self.pool[self.len].yuv_tex.with_lock(None, |buffer: &mut [u8], pitch: usize| {
+                        osd.draw_yuv(buffer, pitch);
+                    }).unwrap();
+            }
             &self.pool[self.len].yuv_tex
         } else {
+            if osd.is_active() {
+                self.pool[self.len].rgb_tex.with_lock(None, |buffer: &mut [u8], pitch: usize| {
+                        osd.draw_rgb(buffer, pitch);
+                    }).unwrap();
+            }
             &self.pool[self.len].rgb_tex
         }
     }
@@ -186,7 +198,7 @@ impl<'a> DispQueue<'a> {
     }
 }
 
-fn try_display(disp_queue: &mut DispQueue, canvas: &mut Canvas<Window>, ctime: &TimeKeep) -> Option<u64> {
+fn try_display(disp_queue: &mut DispQueue, canvas: &mut Canvas<Window>, osd: &mut OSD, ctime: &TimeKeep) -> Option<u64> {
     while !disp_queue.is_empty() {
         let disp_time = disp_queue.first_ts;
         let ctime = ctime.get_cur_time();
@@ -195,8 +207,25 @@ fn try_display(disp_queue: &mut DispQueue, canvas: &mut Canvas<Window>, ctime: &
         } else if disp_time + 10 < ctime {
             disp_queue.move_start();
         } else {
-            let frm = &disp_queue.pool[disp_queue.start];
-            let texture = if frm.is_yuv { &frm.yuv_tex } else { &frm.rgb_tex };
+            if osd.is_active() {
+                osd.prepare(ctime);
+            }
+            let frm = &mut disp_queue.pool[disp_queue.start];
+            let texture = if frm.is_yuv {
+                    if osd.is_active() {
+                        frm.yuv_tex.with_lock(None, |buffer: &mut [u8], pitch: usize| {
+                                osd.draw_yuv(buffer, pitch);
+                            }).unwrap();
+                    }
+                    &frm.yuv_tex
+                } else {
+                    if osd.is_active() {
+                        frm.rgb_tex.with_lock(None, |buffer: &mut [u8], pitch: usize| {
+                                osd.draw_rgb(buffer, pitch);
+                            }).unwrap();
+                    }
+                    &frm.rgb_tex
+                };
             canvas.clear();
             canvas.copy(texture, None, None).unwrap();
             canvas.present();
@@ -238,6 +267,7 @@ struct Player {
     tkeep:          TimeKeep,
 
     debug:          bool,
+    osd:            OSD,
 
     #[cfg(feature="debug")]
     logfile:        File,
@@ -274,6 +304,7 @@ impl Player {
             tkeep:          TimeKeep::new(),
 
             debug:          false,
+            osd:            OSD::new(),
 
             #[cfg(feature="debug")]
             logfile:        File::create("debug.log").unwrap(),
@@ -367,7 +398,7 @@ impl Player {
             }
             if let Event::Window {win_event: WindowEvent::Exposed, ..} = event {
                 canvas.clear();
-                canvas.copy(disp_queue.get_last_texture(), None, None).unwrap();
+                canvas.copy(disp_queue.get_last_texture(&self.osd), None, None).unwrap();
                 canvas.present();
             }
             if let Event::KeyDown {keycode: Some(keycode), ..} = event {
@@ -425,6 +456,9 @@ impl Player {
                     Keycode::H => {
                         self.vcontrol.try_send_video(PktSendEvent::HurryUp);
                     },
+                    Keycode::O => {
+                        self.osd.toggle();
+                    },
                     _ => {},
                 };
                 if !self.paused {
@@ -611,7 +645,7 @@ impl Player {
         let mut disp_q = DispQueue::new(&texture_creator, width, height, if self.has_video { FRAME_QUEUE_LEN } else { 0 });
         if !self.has_video {
             canvas.clear();
-            canvas.copy(disp_q.get_last_texture(), None, None).unwrap();
+            canvas.copy(disp_q.get_last_texture(&self.osd), None, None).unwrap();
             canvas.present();
         }
 
@@ -674,7 +708,7 @@ impl Player {
                 debug_log!(self; {format!(" time {}", self.tkeep.get_cur_time())});
                 if self.has_video {
                     debug_log!(self; {format!("  disp queue {}-{}, {}-{} vqueue fill {}", disp_q.first_ts, disp_q.last_ts, disp_q.start, disp_q.end, self.vcontrol.get_queue_size())});
-                    let ret = try_display(&mut disp_q, &mut canvas, &self.tkeep);
+                    let ret = try_display(&mut disp_q, &mut canvas, &mut self.osd, &self.tkeep);
                     if let Some(next_time) = ret {
                         sleep_time = sleep_time.min(next_time);
                     }
diff --git a/videoplayer/src/osd.rs b/videoplayer/src/osd.rs
new file mode 100644 (file)
index 0000000..74a8a95
--- /dev/null
@@ -0,0 +1,634 @@
+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
+        ],
+    },
+];