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