use sdl2::event::{Event, WindowEvent};
use sdl2::keyboard::{Keycode, Mod};
use sdl2::mouse::{MouseButton, MouseWheelDirection};
-use sdl2::render::{Canvas, Texture, TextureCreator};
+use sdl2::render::{BlendMode, Canvas, Texture, TextureCreator};
use sdl2::pixels::PixelFormatEnum;
use sdl2::video::{Window, WindowContext};
pub len: usize,
pub width: usize,
pub height: usize,
+ pub osd_tex: Texture<'a>,
}
impl<'a> DispQueue<'a> {
fn new(texture_creator: &'a TextureCreator<WindowContext>, width: usize, height: usize, len: usize) -> Self {
let mut pool = Vec::with_capacity(len);
for _ in 0..len + 1 {
- let rgb_tex = texture_creator.create_texture_streaming(PixelFormatEnum::RGB24, width as u32, height as u32).expect("failed to create RGB texture");
- let yuv_tex = texture_creator.create_texture_streaming(PixelFormatEnum::IYUV, ((width + 1) & !1) as u32, ((height + 1) & !1) as u32).expect("failed to create YUV texture");
+ let mut rgb_tex = texture_creator.create_texture_streaming(PixelFormatEnum::RGB24, width as u32, height as u32).expect("failed to create RGB texture");
+ let mut yuv_tex = texture_creator.create_texture_streaming(PixelFormatEnum::IYUV, ((width + 1) & !1) as u32, ((height + 1) & !1) as u32).expect("failed to create YUV texture");
+ rgb_tex.set_blend_mode(BlendMode::None);
+ yuv_tex.set_blend_mode(BlendMode::None);
pool.push(DispFrame{ ts: 0, is_yuv: false, valid: false, rgb_tex, yuv_tex });
}
pool[len].is_yuv = false;
for el in buffer.iter_mut() { *el = 0; }
}).expect("RGB texture could not be locked");
- Self { pool, first_ts: 0, last_ts: 0, start: 0, end: 0, len, width, height }
+ let mut osd_tex = texture_creator.create_texture_streaming(PixelFormatEnum::RGBA8888, width as u32, OSD_HEIGHT as u32).expect("failed to create RGBA texture");
+ osd_tex.set_blend_mode(BlendMode::Blend);
+
+ Self { pool, osd_tex, first_ts: 0, last_ts: 0, start: 0, end: 0, len, width, height }
}
fn flush(&mut self) {
}
}
- fn get_last_texture(&mut self, osd: &OSD) -> &Texture<'a> {
+ fn get_last_texture(&mut self) -> &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);
- }).expect("YUV texture locking failure");
- }
&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);
- }).expect("RGB texture locking failure");
- }
&self.pool[self.len].rgb_tex
}
}
}
}
+fn draw_osd(disp_queue: &mut DispQueue, canvas: &mut Canvas<Window>, osd: &mut OSD) {
+ disp_queue.osd_tex.with_lock(None, |buffer: &mut [u8], pitch: usize| {
+ osd.draw_tex(buffer, pitch);
+ }).expect("RGBA texture locking failure");
+ let (ow, oh) = osd.get_dimensions();
+ let srect = sdl2::rect::Rect::new(0, 0, ow as u32, oh as u32);
+ let drect = sdl2::rect::Rect::new(OSD_XOFF as i32, OSD_YOFF as i32, ow as u32, oh as u32);
+ canvas.copy(&disp_queue.osd_tex, srect, drect).expect("OSD blitting failure");
+}
+
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 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);
- }).expect("YUV texture locking failure");
- }
&frm.yuv_tex
} else {
- if osd.is_active() {
- frm.rgb_tex.with_lock(None, |buffer: &mut [u8], pitch: usize| {
- osd.draw_rgb(buffer, pitch);
- }).expect("RGB texture locking failure");
- }
&frm.rgb_tex
};
canvas.clear();
canvas.copy(texture, None, None).expect("canvas blit failure");
+ if osd.is_active() {
+ draw_osd(disp_queue, canvas, osd);
+ }
canvas.present();
disp_queue.move_start();
}
if let Event::Window {win_event: WindowEvent::Exposed, ..} = event {
canvas.clear();
- canvas.copy(disp_queue.get_last_texture(&self.osd), None, None).expect("blitting failure");
+ canvas.copy(disp_queue.get_last_texture(), None, None).expect("blitting failure");
+ if self.osd.is_active() {
+ draw_osd(disp_queue, canvas, &mut self.osd);
+ }
canvas.present();
}
if let Event::MouseButtonDown {mouse_btn, ..} = event {
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(&self.osd), None, None).expect("blit failure");
+ canvas.copy(disp_q.get_last_texture(), None, None).expect("blit failure");
canvas.present();
}
use std::time::Instant;
-const XOFF: usize = 10;
-const YOFF: usize = 4;
+pub const OSD_XOFF: usize = 10;
+pub const OSD_YOFF: usize = 4;
+pub const OSD_HEIGHT: usize = 16;
#[derive(Default)]
pub struct OSD {
}
self.text_stride = w;
if w > 0 {
- self.text.resize(self.text_stride * 16, 0);
+ self.text.resize(self.text_stride * OSD_HEIGHT, 0);
let mut pos = 0;
for &sym_idx in syms.iter() {
let glyph = &OSD_GLYPHS[sym_idx];
self.text.clear();
}
}
- pub fn draw_yuv(&self, buffer: &mut [u8], pitch: usize) {
+ pub fn draw_tex(&self, buffer: &mut [u8], pitch: usize) {
if !self.is_active() || self.text_stride == 0 {
return;
}
- for (dline, sline) in buffer.chunks_exact_mut(pitch).skip(YOFF).zip(self.text.chunks_exact(self.text_stride)) {
- for (dst, &src) in dline.iter_mut().skip(XOFF).zip(sline.iter()) {
+ 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(4).zip(sline.iter()) {
match src {
- 2 => *dst = 0xFF,
- 1 => *dst = 0x00,
- _ => {},
+ 2 => dst.copy_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF]),
+ 1 => dst.copy_from_slice(&[0xFF, 0x00, 0x00, 0x00]),
+ _ => dst.copy_from_slice(&[0x00, 0x00, 0x00, 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).skip(YOFF).zip(self.text.chunks_exact(self.text_stride)) {
- for (dst, &src) in dline.chunks_exact_mut(3).skip(XOFF).zip(sline.iter()) {
- match src {
- 2 => dst.copy_from_slice(&[0xFF, 0xFF, 0xFF]),
- 1 => dst.copy_from_slice(&[0x00, 0x00, 0x00]),
- _ => {},
- };
- }
- }
+ pub fn get_dimensions(&self) -> (usize, usize) {
+ (self.text_stride, OSD_HEIGHT)
}
}
struct Glyph {
width: usize,
sym: char,
- bits: [u16; 16],
- mask: [u16; 16],
+ bits: [u16; OSD_HEIGHT],
+ mask: [u16; OSD_HEIGHT],
}
const OSD_GLYPHS: &[Glyph] = &[