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