diff options
author | Kostya Shishkov <kostya.shishkov@gmail.com> | 2023-06-15 18:35:25 +0200 |
---|---|---|
committer | Kostya Shishkov <kostya.shishkov@gmail.com> | 2023-06-15 18:35:25 +0200 |
commit | 8686f9f650974a6065f93df178a76f8d24814ca7 (patch) | |
tree | c4d938f9808b7832726dd2ce1dc922403706fad7 | |
parent | 37f130a74415deaf920b04209e1c334a8876c381 (diff) | |
download | nihav-player-8686f9f650974a6065f93df178a76f8d24814ca7.tar.gz |
implement displaying time on screen
-rw-r--r-- | videoplayer/src/main.rs | 48 | ||||
-rw-r--r-- | videoplayer/src/osd.rs | 634 |
2 files changed, 675 insertions, 7 deletions
diff --git a/videoplayer/src/main.rs b/videoplayer/src/main.rs index dcd4d0a..3f15d94 100644 --- a/videoplayer/src/main.rs +++ b/videoplayer/src/main.rs @@ -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 index 0000000..74a8a95 --- /dev/null +++ b/videoplayer/src/osd.rs @@ -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 + ], + }, +]; |