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