]> git.nihav.org Git - nihav-player.git/blob - videoplayer/src/main.rs
videoplayer: set initial timestamp when available
[nihav-player.git] / videoplayer / src / main.rs
1 extern crate sdl2;
2 extern crate nihav_core;
3 extern crate nihav_registry;
4 extern crate nihav_allstuff;
5
6 use std::env;
7 use std::fs::File;
8 use std::io::Write;
9 use std::path::Path;
10 use std::time::{Duration, Instant};
11 use std::thread;
12
13 use sdl2::event::{Event, WindowEvent};
14 use sdl2::keyboard::Keycode;
15 use sdl2::mouse::MouseButton;
16 use sdl2::render::{Canvas, Texture, TextureCreator};
17 use sdl2::pixels::PixelFormatEnum;
18 use sdl2::video::{Window, WindowContext};
19
20 use nihav_registry::detect;
21 use nihav_core::frame::*;
22 use nihav_core::io::byteio::{FileReader, ByteReader};
23 use nihav_core::reorder::*;
24 use nihav_core::codecs::*;
25 use nihav_core::demuxers::*;
26 use nihav_registry::register::*;
27 use nihav_allstuff::*;
28
29 mod audiodec;
30 use audiodec::*;
31 mod videodec;
32 use videodec::*;
33 mod osd;
34 use osd::*;
35
36 #[cfg(feature="debug")]
37 macro_rules! debug_log {
38 ($log: expr; $blk: block) => {
39 $log.logfile.write($blk.as_bytes()).unwrap();
40 $log.logfile.write(b"\n").unwrap();
41 };
42 }
43 #[cfg(not(feature="debug"))]
44 macro_rules! debug_log {
45 ($log: expr; $blk: block) => {};
46 }
47
48 pub enum PktSendEvent {
49 Packet(NAPacket),
50 GetFrames,
51 Flush,
52 End,
53 ImmediateEnd,
54 HurryUp,
55 }
56
57 pub enum DecoderType {
58 Audio(Box<dyn NADecoder + Send>),
59 Video(Box<dyn NADecoder + Send>, Box<dyn FrameReorderer + Send>),
60 VideoMT(Box<dyn NADecoderMT + Send>, MTFrameReorderer),
61 }
62
63 pub struct DecoderStuff {
64 pub dsupp: Box<NADecoderSupport>,
65 pub dec: DecoderType,
66 }
67
68 fn format_time(ms: u64) -> String {
69 let s = ms / 1000;
70 let ds = (ms % 1000) / 100;
71 let (min, s) = (s / 60, s % 60);
72 let (h, min) = (min / 60, min % 60);
73 if h == 0 {
74 if min == 0 {
75 format!("{}.{}", s, ds)
76 } else {
77 format!("{}:{:02}.{}", min, s, ds)
78 }
79 } else {
80 format!("{}:{:02}:{:02}.{}", h, min, s, ds)
81 }
82 }
83
84 const FRAME_QUEUE_LEN: usize = 25;
85 const MAX_VOLUME: usize = 200;
86
87 pub type FrameRecord = (NABufferType, u64);
88
89 pub struct TimeKeep {
90 ref_time: Instant,
91 ref_ts: u64,
92 }
93
94 impl TimeKeep {
95 fn new() -> Self {
96 Self {
97 ref_time: Instant::now(),
98 ref_ts: 0,
99 }
100 }
101 pub fn get_cur_time(&self) -> u64 {
102 let add = self.ref_time.elapsed().as_millis() as u64;
103 self.ref_ts + add
104 }
105 fn reset_ts(&mut self) {
106 self.ref_ts = 0;
107 }
108 fn reset_all(&mut self, ts: u64) {
109 self.ref_time = Instant::now();
110 self.ref_ts = ts;
111 }
112 fn set_ts(&mut self) {
113 self.ref_ts = self.get_cur_time();
114 }
115 fn set_time(&mut self) {
116 self.ref_time = Instant::now();
117 }
118 }
119
120 pub struct DispFrame<'a> {
121 pub ts: u64,
122 pub is_yuv: bool,
123 pub valid: bool,
124 pub rgb_tex: Texture<'a>,
125 pub yuv_tex: Texture<'a>,
126 }
127
128 pub struct DispQueue<'a> {
129 pub pool: Vec<DispFrame<'a>>,
130 pub first_ts: u64,
131 pub last_ts: u64,
132 pub start: usize,
133 pub end: usize,
134 pub len: usize,
135 pub width: usize,
136 pub height: usize,
137 }
138
139 impl<'a> DispQueue<'a> {
140 fn new(texture_creator: &'a TextureCreator<WindowContext>, width: usize, height: usize, len: usize) -> Self {
141 let mut pool = Vec::with_capacity(len);
142 for _ in 0..len + 1 {
143 let rgb_tex = texture_creator.create_texture_streaming(PixelFormatEnum::RGB24, width as u32, height as u32).unwrap();
144 let yuv_tex = texture_creator.create_texture_streaming(PixelFormatEnum::IYUV, ((width + 1) & !1) as u32, ((height + 1) & !1) as u32).unwrap();
145 pool.push(DispFrame{ ts: 0, is_yuv: false, valid: false, rgb_tex, yuv_tex });
146 }
147 pool[len].is_yuv = false;
148 pool[len].rgb_tex.with_lock(None, |buffer: &mut [u8], _pitch: usize| {
149 for el in buffer.iter_mut() { *el = 0; }
150 }).unwrap();
151
152 Self { pool, first_ts: 0, last_ts: 0, start: 0, end: 0, len, width, height }
153 }
154
155 fn flush(&mut self) {
156 self.start = 0;
157 self.end = 0;
158 self.first_ts = 0;
159 self.last_ts = 0;
160 for frm in self.pool.iter_mut() {
161 frm.valid = false;
162 }
163 }
164
165 fn get_last_texture(&mut self, osd: &OSD) -> &Texture<'a> {
166 if self.pool[self.len].is_yuv {
167 if osd.is_active() {
168 self.pool[self.len].yuv_tex.with_lock(None, |buffer: &mut [u8], pitch: usize| {
169 osd.draw_yuv(buffer, pitch);
170 }).unwrap();
171 }
172 &self.pool[self.len].yuv_tex
173 } else {
174 if osd.is_active() {
175 self.pool[self.len].rgb_tex.with_lock(None, |buffer: &mut [u8], pitch: usize| {
176 osd.draw_rgb(buffer, pitch);
177 }).unwrap();
178 }
179 &self.pool[self.len].rgb_tex
180 }
181 }
182 pub fn is_empty(&self) -> bool { self.start == self.end }
183 pub fn is_full(&self) -> bool { self.len == 0 || self.start == (self.end + 1) % self.len }
184 pub fn move_end(&mut self) {
185 self.end += 1;
186 if self.end >= self.len {
187 self.end -= self.len;
188 }
189 }
190 pub fn move_start(&mut self) {
191 self.pool.swap(self.start, self.len);
192 self.start += 1;
193 if self.start >= self.len {
194 self.start -= self.len;
195 }
196 if !self.is_empty() {
197 self.first_ts = self.pool[self.start].ts;
198 }
199 }
200 }
201
202 fn try_display(disp_queue: &mut DispQueue, canvas: &mut Canvas<Window>, osd: &mut OSD, ctime: &TimeKeep) -> Option<u64> {
203 while !disp_queue.is_empty() {
204 let disp_time = disp_queue.first_ts;
205 let ctime = ctime.get_cur_time();
206 if disp_time > ctime + 10 {
207 return Some(disp_time - ctime);
208 } else if disp_time + 10 < ctime {
209 disp_queue.move_start();
210 } else {
211 if osd.is_active() {
212 osd.prepare(ctime);
213 }
214 let frm = &mut disp_queue.pool[disp_queue.start];
215 let texture = if frm.is_yuv {
216 if osd.is_active() {
217 frm.yuv_tex.with_lock(None, |buffer: &mut [u8], pitch: usize| {
218 osd.draw_yuv(buffer, pitch);
219 }).unwrap();
220 }
221 &frm.yuv_tex
222 } else {
223 if osd.is_active() {
224 frm.rgb_tex.with_lock(None, |buffer: &mut [u8], pitch: usize| {
225 osd.draw_rgb(buffer, pitch);
226 }).unwrap();
227 }
228 &frm.rgb_tex
229 };
230 canvas.clear();
231 canvas.copy(texture, None, None).unwrap();
232 canvas.present();
233
234 disp_queue.move_start();
235 if !disp_queue.is_empty() {
236 return Some((disp_queue.first_ts - ctime).saturating_sub(2));
237 } else {
238 return None;
239 }
240 }
241 }
242 None
243 }
244
245 struct Player {
246 sdl_context: sdl2::Sdl,
247 vsystem: sdl2::VideoSubsystem,
248 asystem: sdl2::AudioSubsystem,
249 xpos: Option<i32>,
250 ypos: Option<i32>,
251
252 acontrol: AudioControl,
253 vcontrol: VideoControl,
254
255 play_video: bool,
256 play_audio: bool,
257 has_video: bool,
258 has_audio: bool,
259 video_str: u32,
260 audio_str: u32,
261
262 vthreads: usize,
263 use_mt: bool,
264
265 paused: bool,
266 mute: bool,
267 volume: usize,
268 end: bool,
269
270 tkeep: TimeKeep,
271
272 debug: bool,
273 osd: OSD,
274
275 #[cfg(feature="debug")]
276 logfile: File,
277 }
278
279 impl Player {
280 fn new() -> Self {
281 let sdl_context = sdl2::init().unwrap();
282 let vsystem = sdl_context.video().unwrap();
283 let asystem = sdl_context.audio().unwrap();
284 vsystem.disable_screen_saver();
285 let acontrol = AudioControl::new(None, None, &asystem);
286 let vcontrol = VideoControl::new(None, 0, 0, 0, 0);
287 Self {
288 sdl_context, asystem, vsystem,
289 xpos: None,
290 ypos: None,
291
292 acontrol, vcontrol,
293
294 play_video: true,
295 play_audio: true,
296 has_video: false,
297 has_audio: false,
298 video_str: 0,
299 audio_str: 0,
300
301 vthreads: 3,
302 use_mt: true,
303
304 paused: false,
305 mute: false,
306 volume: 100,
307 end: false,
308
309 tkeep: TimeKeep::new(),
310
311 debug: false,
312 osd: OSD::new(),
313
314 #[cfg(feature="debug")]
315 logfile: File::create("debug.log").unwrap(),
316 }
317 }
318 fn seek(&mut self, off: u64, fwd: bool, dmx: &mut Demuxer, disp_queue: &mut DispQueue) {
319 let cur_time = self.tkeep.get_cur_time();
320 let seektime = if fwd { cur_time + off * 1000 } else {
321 cur_time.saturating_sub(off * 1000) };
322 debug_log!(self; {format!(" seek to {}", seektime)});
323
324 let ret = dmx.seek(NATimePoint::Milliseconds(seektime));
325 if ret.is_err() {
326 println!(" seek error");
327 return;
328 }
329
330 self.acontrol.flush();
331 self.vcontrol.flush();
332 disp_queue.flush();
333
334 self.tkeep.reset_ts();
335 self.prefill(dmx, disp_queue);
336 if !disp_queue.is_empty() {
337 self.tkeep.reset_all(disp_queue.first_ts);
338 } else {
339 let mut iterations = 0;
340 let mut time = self.acontrol.get_time();
341 while time.is_none() {
342 iterations += 1;
343 std::thread::yield_now();
344 if iterations > 1000000 { println!(" still no time set?!"); break; }
345 time = self.acontrol.get_time();
346 }
347 if let Some(time) = time {
348 self.tkeep.reset_all(time);
349 }
350 }
351 if !self.paused {
352 self.acontrol.resume();
353 }
354 }
355 fn prefill(&mut self, dmx: &mut Demuxer, disp_queue: &mut DispQueue) {
356 debug_log!(self; {" prefilling"});
357 while self.vcontrol.get_queue_size() < FRAME_QUEUE_LEN {
358 let mut try_send = self.acontrol.get_queue_size() < FRAME_QUEUE_LEN && (!self.has_video || (!self.vcontrol.is_filled(FRAME_QUEUE_LEN) && !disp_queue.is_full()));
359
360 if !self.vcontrol.try_send_queued() && self.vcontrol.get_queue_size() > FRAME_QUEUE_LEN / 2 {
361 try_send = false;
362 }
363 if !self.acontrol.try_send_queued() && self.acontrol.get_queue_size() > FRAME_QUEUE_LEN / 2 {
364 try_send = false;
365 }
366 if try_send {
367 match dmx.get_frame() {
368 Err(DemuxerError::EOF) => break,
369 Err(_) => break,
370 Ok(pkt) => {
371 let streamno = pkt.get_stream().get_id();
372 if self.has_video && streamno == self.video_str {
373 self.vcontrol.try_send_video(PktSendEvent::Packet(pkt));
374 } else if self.has_audio && streamno == self.audio_str {
375 self.acontrol.try_send_audio(PktSendEvent::Packet(pkt));
376 }
377 }
378 };
379 }
380 self.vcontrol.fill(disp_queue);
381
382 if !try_send {
383 break;
384 }
385 }
386 if self.has_video {
387 while self.vcontrol.get_queue_size() > 0 && !disp_queue.is_full() {
388 self.vcontrol.try_send_queued();
389 self.vcontrol.fill(disp_queue);
390 std::thread::sleep(Duration::from_millis(10));
391 }
392 self.vcontrol.wait_for_frames();
393 self.vcontrol.fill(disp_queue);
394 }
395 debug_log!(self; {format!(" prefilling done, frames {}-{} audio {}", disp_queue.start, disp_queue.end, self.acontrol.get_fill())});
396 }
397 fn toggle_pause(&mut self) {
398 self.paused = !self.paused;
399 if self.paused {
400 self.vsystem.enable_screen_saver();
401 self.tkeep.set_ts();
402 } else {
403 self.vsystem.disable_screen_saver();
404 self.tkeep.set_time();
405 }
406 if self.paused {
407 self.acontrol.pause();
408 } else {
409 self.acontrol.resume();
410 }
411 }
412 fn handle_events(&mut self, event_pump: &mut sdl2::EventPump, canvas: &mut Canvas<Window>, dmx: &mut Demuxer, disp_queue: &mut DispQueue) -> bool {
413 for event in event_pump.poll_iter() {
414 if let Event::Quit {..} = event {
415 self.end = true;
416 println!();
417 return true;
418 }
419 if let Event::Window {win_event: WindowEvent::Exposed, ..} = event {
420 canvas.clear();
421 canvas.copy(disp_queue.get_last_texture(&self.osd), None, None).unwrap();
422 canvas.present();
423 }
424 if let Event::MouseButtonDown {mouse_btn: MouseButton::Right, ..} = event {
425 self.toggle_pause();
426 }
427 if let Event::KeyDown {keycode: Some(keycode), ..} = event {
428 match keycode {
429 Keycode::Escape | Keycode::Q => {
430 self.end = true;
431 println!();
432 return true;
433 },
434 Keycode::Return => return true,
435 Keycode::Right => { self.seek(10, true, dmx, disp_queue); },
436 Keycode::Left => { self.seek(10, false, dmx, disp_queue); },
437 Keycode::Up => { self.seek(60, true, dmx, disp_queue); },
438 Keycode::Down => { self.seek(60, false, dmx, disp_queue); },
439 Keycode::PageUp => { self.seek(600, true, dmx, disp_queue); },
440 Keycode::PageDown => { self.seek(600, false, dmx, disp_queue); },
441 Keycode::Space => { self.toggle_pause(); },
442 Keycode::Plus | Keycode::KpPlus => {
443 self.volume = (self.volume + 10).min(MAX_VOLUME);
444 if !self.mute {
445 self.acontrol.set_volume(self.volume);
446 }
447 },
448 Keycode::Minus | Keycode::KpMinus => {
449 self.volume = self.volume.saturating_sub(10);
450 if !self.mute {
451 self.acontrol.set_volume(self.volume);
452 }
453 },
454 Keycode::D => {
455 self.debug = !self.debug;
456 },
457 Keycode::M => {
458 self.mute = !self.mute;
459 if self.mute {
460 self.acontrol.set_volume(0);
461 } else {
462 self.acontrol.set_volume(self.volume);
463 }
464 },
465 Keycode::H => {
466 self.vcontrol.try_send_video(PktSendEvent::HurryUp);
467 },
468 Keycode::O => {
469 self.osd.toggle();
470 },
471 _ => {},
472 };
473 if !self.paused {
474 print!("{:60}\r", ' ');
475 std::io::stdout().flush().unwrap();
476 }
477 }
478 }
479 false
480 }
481 fn play(&mut self, name: &str, start_time: NATimePoint) {
482 debug_log!(self; {format!("Playing {}", name)});
483
484 // prepare data source
485 let path = Path::new(name);
486 let mut file = File::open(path).unwrap();
487 let dmx_fact;
488 let mut fr = FileReader::new_read(&mut file);
489 let mut br = ByteReader::new(&mut fr);
490 let res = detect::detect_format(name, &mut br);
491 if res.is_none() {
492 println!("cannot detect format for {}", name);
493 return;
494 }
495 let (dmx_name, _score) = res.unwrap();
496 debug_log!(self; {format!(" found demuxer {} with score {:?}", dmx_name, _score)});
497 println!("trying demuxer {} on {}", dmx_name, name);
498
499 let mut dmx_reg = RegisteredDemuxers::new();
500 nihav_register_all_demuxers(&mut dmx_reg);
501 let mut dec_reg = RegisteredDecoders::new();
502 nihav_register_all_decoders(&mut dec_reg);
503 let mut mtdec_reg = RegisteredMTDecoders::new();
504 if self.use_mt {
505 nihav_register_all_mt_decoders(&mut mtdec_reg);
506 }
507
508 let ret = dmx_reg.find_demuxer(dmx_name);
509 if ret.is_none() {
510 println!("error finding {} demuxer", dmx_name);
511 return;
512 }
513 dmx_fact = ret.unwrap();
514 br.seek(SeekFrom::Start(0)).unwrap();
515 let ret = create_demuxer(dmx_fact, &mut br);
516 if ret.is_err() {
517 println!("error creating demuxer");
518 return;
519 }
520 let mut dmx = ret.unwrap();
521 if start_time != NATimePoint::None {
522 debug_log!(self; {format!(" start seek to {}", start_time)});
523 if dmx.seek(start_time).is_err() {
524 println!("initial seek failed");
525 }
526 }
527
528 let mut width = 640;
529 let mut height = 480;
530 let mut tb_num = 0;
531 let mut tb_den = 0;
532 let mut ainfo: Option<NAAudioInfo> = None;
533
534 let mut video_dec: Option<DecoderStuff> = None;
535 let mut audio_dec: Option<DecoderStuff> = None;
536
537 let duration = dmx.get_duration();
538 if duration != 0 {
539 println!(" total duration {}", format_time(duration));
540 }
541 self.has_video = false;
542 self.has_audio = false;
543 self.osd.reset();
544 self.osd.set_duration(duration);
545 for i in 0..dmx.get_num_streams() {
546 let s = dmx.get_stream(i).unwrap();
547 let info = s.get_info();
548 let decfunc = dec_reg.find_decoder(info.get_name());
549 let decfunc_mt = mtdec_reg.find_decoder(info.get_name());
550 println!("stream {} - {} {}", i, s, info.get_name());
551 debug_log!(self; {format!(" stream {} - {} {}", i, s, info.get_name())});
552 let str_id = s.get_id();
553 if info.is_video() {
554 if video_dec.is_none() && self.play_video {
555 if let Some(decfunc) = decfunc_mt {
556 let mut dec = (decfunc)();
557 let mut dsupp = Box::new(NADecoderSupport::new());
558 let props = info.get_properties().get_video_info().unwrap();
559 if props.get_width() != 0 {
560 width = props.get_width();
561 height = props.get_height();
562 }
563 if dec.init(&mut dsupp, info.clone(), self.vthreads).is_ok() {
564 video_dec = Some(DecoderStuff{ dsupp, dec: DecoderType::VideoMT(dec, MTFrameReorderer::new()) });
565 self.video_str = str_id;
566 let (tbn, tbd) = s.get_timebase();
567 tb_num = tbn;
568 tb_den = tbd;
569 self.has_video = true;
570 continue;
571 } else {
572 println!("failed to create multi-threaded decoder, falling back");
573 }
574 }
575 if let Some(decfunc) = decfunc {
576 let mut dec = (decfunc)();
577 let mut dsupp = Box::new(NADecoderSupport::new());
578 let props = info.get_properties().get_video_info().unwrap();
579 if props.get_width() != 0 {
580 width = props.get_width();
581 height = props.get_height();
582 }
583 let desc = get_codec_description(info.get_name());
584 let (reorder_depth, reord) = if desc.is_none() || (desc.unwrap().caps & CODEC_CAP_COMPLEX_REORDER) == 0 {
585 let reord: Box<dyn FrameReorderer + Send> = Box::new(IPBReorderer::new());
586 (3, reord)
587 } else {
588 let reord: Box<dyn FrameReorderer + Send> = Box::new(ComplexReorderer::new());
589 (16, reord)
590 };
591 dsupp.pool_u8 = NAVideoBufferPool::new(reorder_depth);
592 dsupp.pool_u16 = NAVideoBufferPool::new(reorder_depth);
593 dsupp.pool_u32 = NAVideoBufferPool::new(reorder_depth);
594 dec.init(&mut dsupp, info).unwrap();
595 video_dec = Some(DecoderStuff{ dsupp, dec: DecoderType::Video(dec, reord) });
596 self.video_str = str_id;
597 let (tbn, tbd) = s.get_timebase();
598 tb_num = tbn;
599 tb_den = tbd;
600 self.has_video = true;
601 } else {
602 println!("no video decoder for {} found!", info.get_name());
603 }
604 }
605 } else if info.is_audio() {
606 if audio_dec.is_none() && self.play_audio {
607 if let Some(decfunc) = decfunc {
608 let mut dec = (decfunc)();
609 let mut dsupp = Box::new(NADecoderSupport::new());
610 ainfo = info.get_properties().get_audio_info();
611 dec.init(&mut dsupp, info).unwrap();
612 audio_dec = Some(DecoderStuff{ dsupp, dec: DecoderType::Audio(dec) });
613 self.audio_str = str_id;
614 self.has_audio = true;
615 } else {
616 println!("no audio decoder for {} found!", info.get_name());
617 }
618 }
619 } else {
620 println!("decoder {} not found", info.get_name());
621 }
622 }
623 if !self.has_video && !self.has_audio {
624 println!("No playable streams found.");
625 return;
626 }
627
628 while (width <= 384) && (height <= 288) {
629 width <<= 1;
630 height <<= 1;
631 }
632
633 // prepare playback structure
634 let mut new_vcontrol = VideoControl::new(video_dec, width, height, tb_num, tb_den);
635 std::mem::swap(&mut self.vcontrol, &mut new_vcontrol);
636
637 let mut new_acontrol = AudioControl::new(audio_dec, ainfo, &self.asystem);
638 std::mem::swap(&mut self.acontrol, &mut new_acontrol);
639
640 if self.mute {
641 self.acontrol.set_volume(0);
642 } else {
643 self.acontrol.set_volume(self.volume);
644 }
645
646 let fname = path.file_name();
647 let wname = if let Some(fname) = fname {
648 "NihAV player - ".to_owned() + fname.to_str().unwrap()
649 } else {
650 "NihAV player".to_owned()
651 };
652 let mut builder = self.vsystem.window(&wname, width as u32, height as u32);
653 let window = if let (Some(xpos), Some(ypos)) = (self.xpos, self.ypos) {
654 builder.position(xpos, ypos).build().unwrap()
655 } else {
656 builder.position_centered().build().unwrap()
657 };
658 let mut canvas = window.into_canvas().build().unwrap();
659 let texture_creator = canvas.texture_creator();
660 let mut disp_q = DispQueue::new(&texture_creator, width, height, if self.has_video { FRAME_QUEUE_LEN } else { 0 });
661 if !self.has_video {
662 canvas.clear();
663 canvas.copy(disp_q.get_last_texture(&self.osd), None, None).unwrap();
664 canvas.present();
665 }
666
667 self.has_audio = self.acontrol.has_audio();
668 if !self.has_video && !self.has_audio {
669 println!("No playable streams.");
670 return;
671 }
672
673 // play
674 self.prefill(&mut dmx, &mut disp_q);
675 self.tkeep.reset_all(if !disp_q.is_empty() { disp_q.first_ts } else { 0 });
676 if !self.paused {
677 self.acontrol.resume();
678 }
679 let mut event_pump = self.sdl_context.event_pump().unwrap();
680 let mut last_disp = Instant::now();
681 let mut has_data = true;
682 'main: loop {
683 if self.handle_events(&mut event_pump, &mut canvas, &mut dmx, &mut disp_q) {
684 println!();
685 break 'main;
686 }
687 if !self.paused {
688 let mut try_send = self.acontrol.get_queue_size() < FRAME_QUEUE_LEN && self.vcontrol.get_queue_size() < FRAME_QUEUE_LEN;
689 if !self.vcontrol.try_send_queued() && self.vcontrol.is_filled(FRAME_QUEUE_LEN) {
690 try_send = false;
691 }
692 if !self.acontrol.try_send_queued() {
693 try_send = false;
694 }
695 while has_data && try_send {
696 match dmx.get_frame() {
697 Err(DemuxerError::EOF) => {
698 self.vcontrol.try_send_video(PktSendEvent::End);
699 self.acontrol.try_send_audio(PktSendEvent::End);
700 has_data = false;
701 },
702 Err(err) => {
703 println!("demuxer error {:?}", err);
704 if err == DemuxerError::IOError {
705 self.vcontrol.try_send_video(PktSendEvent::End);
706 self.acontrol.try_send_audio(PktSendEvent::End);
707 has_data = false;
708 }
709 },
710 Ok(pkt) => {
711 let streamno = pkt.get_stream().get_id();
712 if self.has_video && streamno == self.video_str {
713 debug_log!(self; {" sending video packet"});
714 self.vcontrol.try_send_video(PktSendEvent::Packet(pkt));
715 if self.vcontrol.is_filled(FRAME_QUEUE_LEN) {
716 try_send = false;
717 }
718 } else if self.has_audio && streamno == self.audio_str {
719 debug_log!(self; {" sending audio packet"});
720 self.acontrol.try_send_audio(PktSendEvent::Packet(pkt));
721 if self.acontrol.get_queue_size() >= FRAME_QUEUE_LEN {
722 try_send = false;
723 }
724 }
725 }
726 };
727 }
728 self.vcontrol.fill(&mut disp_q);
729 let mut sleep_time = 25;
730 debug_log!(self; {format!(" time {}", self.tkeep.get_cur_time())});
731 if self.has_video {
732 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())});
733 let ret = try_display(&mut disp_q, &mut canvas, &mut self.osd, &self.tkeep);
734 if let Some(next_time) = ret {
735 sleep_time = sleep_time.min(next_time);
736 }
737 }
738 if self.has_audio {
739 let time_left = self.acontrol.get_time_left();
740 debug_log!(self; {format!(" audio left {}", time_left)});
741 sleep_time = sleep_time.min(time_left);
742 }
743 debug_log!(self; {format!(" sleep {}ms", sleep_time)});
744 if last_disp.elapsed().as_millis() >= 10 {
745 let c_time = self.tkeep.get_cur_time();
746
747 if !self.debug {
748 print!(" {} {}% \r", format_time(c_time), self.acontrol.get_volume());
749 } else {
750 print!(" {} {} {}% {:3} {:6}\r", format_time(c_time), if self.vcontrol.is_yuv() { 'Y' } else { 'R' }, self.acontrol.get_volume(), (disp_q.end + disp_q.len - disp_q.start) % disp_q.len, self.acontrol.get_fill());
751 }
752 std::io::stdout().flush().unwrap();
753 last_disp = Instant::now();
754 }
755 let mut end = true;
756 if self.has_video && !self.vcontrol.is_video_end() {
757 end = false;
758 }
759 if self.has_audio && !self.acontrol.is_audio_end() {
760 end = false;
761 }
762 if end {
763 break;
764 }
765 thread::sleep(Duration::from_millis(sleep_time));
766 } else {
767 thread::sleep(Duration::from_millis(20));
768 }
769 }
770 let (xpos, ypos) = canvas.into_window().position();
771 self.xpos = Some(xpos);
772 self.ypos = Some(ypos);
773 println!();
774 std::mem::swap(&mut self.vcontrol, &mut new_vcontrol);
775 new_vcontrol.finish();
776 std::mem::swap(&mut self.acontrol, &mut new_acontrol);
777 new_acontrol.finish();
778 }
779 }
780
781 fn main() {
782 let args: Vec<String> = env::args().collect();
783
784 if args.len() == 1 {
785 println!("usage: nihav-player file1 file2 ...");
786 return;
787 }
788
789 let mut player = Player::new();
790
791 let mut aiter = args.iter().skip(1);
792 let mut seek_time = NATimePoint::None;
793 while let Some(arg) = aiter.next() {
794 match arg.as_str() {
795 "-an" => { player.play_audio = false; },
796 "-ae" => { player.play_audio = true; },
797 "-vn" => { player.play_video = false; },
798 "-ve" => { player.play_video = true; },
799 "-seek" => {
800 if let Some(arg) = aiter.next() {
801 if let Ok(time) = arg.parse::<NATimePoint>() {
802 seek_time = time;
803 } else {
804 println!("wrong seek time");
805 seek_time = NATimePoint::None;
806 }
807 }
808 },
809 "-vol" => {
810 if let Some(arg) = aiter.next() {
811 if let Ok(vol) = arg.parse::<usize>() {
812 player.volume = vol.min(MAX_VOLUME);
813 } else {
814 println!("wrong volume");
815 }
816 }
817 },
818 "-debug" => {
819 player.debug = true;
820 },
821 "-nodebug" => {
822 player.debug = false;
823 },
824 "-mt" => {
825 player.use_mt = true;
826 },
827 "-nomt" => {
828 player.use_mt = false;
829 },
830 "-threads" => {
831 if let Some(arg) = aiter.next() {
832 if let Ok(val) = arg.parse::<usize>() {
833 player.vthreads = val.max(1);
834 } else {
835 println!("wrong number of threads");
836 }
837 }
838 },
839 _ => {
840 player.play(arg, seek_time);
841 if player.end { break; }
842 seek_time = NATimePoint::None;
843 },
844 };
845 }
846 }