use audiodec::*;
mod videodec;
use videodec::*;
+mod osd;
+use osd::*;
#[cfg(feature="debug")]
macro_rules! debug_log {
}
}
- 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
}
}
}
}
-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();
} 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();
tkeep: TimeKeep,
debug: bool,
+ osd: OSD,
#[cfg(feature="debug")]
logfile: File,
tkeep: TimeKeep::new(),
debug: false,
+ osd: OSD::new(),
#[cfg(feature="debug")]
logfile: File::create("debug.log").unwrap(),
}
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 {
Keycode::H => {
self.vcontrol.try_send_video(PktSendEvent::HurryUp);
},
+ Keycode::O => {
+ self.osd.toggle();
+ },
_ => {},
};
if !self.paused {
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();
}
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);
}
--- /dev/null
+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
+ ],
+ },
+];