From bba2483d4a53e1c0e9ab7648e25de296e2273c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 1 Aug 2018 19:04:39 +0200 Subject: [PATCH 1/4] Allow sharing Player's FrameRenderer --- backends/gstreamer/src/player.rs | 6 +++--- player/src/lib.rs | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/backends/gstreamer/src/player.rs b/backends/gstreamer/src/player.rs index 4557ea59..c95de358 100644 --- a/backends/gstreamer/src/player.rs +++ b/backends/gstreamer/src/player.rs @@ -82,7 +82,7 @@ struct PlayerInner { appsink: gst_app::AppSink, input_size: u64, subscribers: Vec>, - renderers: Vec>, + renderers: Vec>, last_metadata: Option, } @@ -91,7 +91,7 @@ impl PlayerInner { self.subscribers.push(sender); } - pub fn register_frame_renderer(&mut self, renderer: Box) { + pub fn register_frame_renderer(&mut self, renderer: Arc) { self.renderers.push(renderer); } @@ -187,7 +187,7 @@ impl Player for GStreamerPlayer { self.inner.lock().unwrap().register_event_handler(sender); } - fn register_frame_renderer(&self, renderer: Box) { + fn register_frame_renderer(&self, renderer: Arc) { self.inner.lock().unwrap().register_frame_renderer(renderer); } diff --git a/player/src/lib.rs b/player/src/lib.rs index cef15b70..ca54a35c 100644 --- a/player/src/lib.rs +++ b/player/src/lib.rs @@ -1,6 +1,7 @@ pub mod frame; pub mod metadata; +use std::sync::Arc; use std::sync::mpsc::Sender; #[derive(Clone, Debug)] @@ -22,7 +23,7 @@ pub enum PlayerEvent { pub trait Player: Send { fn register_event_handler(&self, sender: Sender); - fn register_frame_renderer(&self, renderer: Box); + fn register_frame_renderer(&self, renderer: Arc); fn setup(&self) -> Result<(), ()>; fn play(&self); @@ -37,9 +38,10 @@ pub struct DummyPlayer {} impl Player for DummyPlayer { fn register_event_handler(&self, _: Sender) {} - fn register_frame_renderer(&self, _: Box) {} + fn register_frame_renderer(&self, _: Arc) {} fn setup(&self) -> Result<(), ()> { + println!("You are using the DummyPlayer"); Err(()) } fn play(&self) {} From cd7bf4a06251c91b88fe87faeafd14dad0d21cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 1 Aug 2018 19:05:47 +0200 Subject: [PATCH 2/4] Test player --- examples/Cargo.toml | 10 ++ examples/test-player/main.rs | 196 ++++++++++++++++++++++ examples/test-player/ui.rs | 309 +++++++++++++++++++++++++++++++++++ 3 files changed, 515 insertions(+) create mode 100644 examples/test-player/main.rs create mode 100644 examples/test-player/ui.rs diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 41da6bda..1c055c51 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -4,8 +4,14 @@ version = "0.1.0" license = "MPL-2.0" [dependencies] +euclid = "0.19.0" +gleam = "0.6.0" +glutin = "0.17.0" rand = "0.5.0" +time = "0.1.40" servo-media = { path = "../servo-media" } +webrender = { git = "https://github.com/servo/webrender/" } +winit = "0.16.2" [[bin]] name = "audio_decoder" @@ -46,3 +52,7 @@ path = "play_noise.rs" [[bin]] name = "player" path = "player.rs" + +[[bin]] +name = "test-player" +path = "test-player/main.rs" diff --git a/examples/test-player/main.rs b/examples/test-player/main.rs new file mode 100644 index 00000000..c92462a4 --- /dev/null +++ b/examples/test-player/main.rs @@ -0,0 +1,196 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#![feature(rustc_private)] + +extern crate gleam; +extern crate glutin; +extern crate servo_media; +extern crate time; +extern crate webrender; +extern crate winit; + +use gleam::gl; +use servo_media::player::frame::{Frame, FrameRenderer}; +use servo_media::player::{Player, PlayerEvent}; +use servo_media::ServoMedia; +use std::env; +use std::fs::File; +use std::io::BufReader; +use std::io::Read; +use std::path::Path; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::mpsc; +use std::sync::{Arc, Mutex}; +use std::thread::Builder; +use webrender::api::*; + +#[path = "ui.rs"] +mod ui; + +struct PlayerWrapper { + player: Arc>>, + shutdown: Arc, +} + +impl PlayerWrapper { + pub fn new(path: &Path) -> Self { + let servo_media = ServoMedia::get().unwrap(); + let player = Arc::new(Mutex::new(servo_media.create_player().unwrap())); + let file = File::open(&path).unwrap(); + let metadata = file.metadata().unwrap(); + player.lock().unwrap().set_input_size(metadata.len()); + let (sender, receiver) = mpsc::channel(); + player.lock().unwrap().register_event_handler(sender); + player + .lock() + .unwrap() + .setup() + .expect("couldn't setup player"); + let player_ = player.clone(); + let player__ = player.clone(); + let shutdown = Arc::new(AtomicBool::new(false)); + let shutdown_ = shutdown.clone(); + let shutdown__ = shutdown.clone(); + Builder::new() + .name("File reader".to_owned()) + .spawn(move || { + let player = &player_; + let shutdown = &shutdown_; + let mut buf_reader = BufReader::new(file); + let mut buffer = [0; 8192]; + while !shutdown.load(Ordering::Relaxed) { + match buf_reader.read(&mut buffer[..]) { + Ok(0) => { + println!("finished pushing data"); + break; + } + Ok(size) => { + if let Err(_) = player + .lock() + .unwrap() + .push_data(Vec::from(&buffer[0..size])) + { + break; + } + } + Err(e) => { + eprintln!("Error: {}", e); + break; + } + } + } + }) + .unwrap(); + + Builder::new() + .name("Player event loop".to_owned()) + .spawn(move || { + let player = &player__; + let shutdown = &shutdown__; + while let Ok(event) = receiver.recv() { + match event { + PlayerEvent::EndOfStream => { + println!("EOF"); + break; + } + PlayerEvent::Error => { + println!("Error"); + break; + } + PlayerEvent::MetadataUpdated(ref m) => { + println!("Metadata updated! {:?}", m); + } + PlayerEvent::StateChanged(ref s) => { + println!("Player state changed to {:?}", s); + } + PlayerEvent::FrameUpdated => eprint!("."), + } + } + player.lock().unwrap().stop(); + shutdown.store(true, Ordering::Relaxed); + }) + .unwrap(); + + player.lock().unwrap().play(); + + PlayerWrapper { player, shutdown } + } + + fn shutdown(&self) { + self.player.lock().unwrap().stop(); + self.shutdown.store(true, Ordering::Relaxed); + } + + fn register_frame_renderer(&self, renderer: Arc) { + self.player + .lock() + .unwrap() + .register_frame_renderer(renderer); + } +} + +struct App { + frame_queue: Mutex>, +} + +impl App { + fn new() -> Self { + Self { + frame_queue: Mutex::new(Vec::new()), + } + } +} + +impl ui::Example for App { + fn render( + &self, + _api: &RenderApi, + _builder: &mut DisplayListBuilder, + _txn: &mut Transaction, + _framebuffer_size: DeviceUintSize, + _pipeline_id: PipelineId, + _document_id: DocumentId, + ) { + // XXX render frame queue + } + + fn on_event(&self, _: winit::WindowEvent, _: &RenderApi, _: DocumentId) -> bool { + false + } + + fn get_image_handlers( + &self, + _gl: &gl::Gl, + ) -> ( + Option>, + Option>, + ) { + (None, None) + } + + fn draw_custom(&self, _gl: &gl::Gl) {} +} + +impl FrameRenderer for App { + fn render(&self, frame: Frame) { + self.frame_queue.lock().unwrap().push(frame); + } +} + +fn main() { + let args: Vec<_> = env::args().collect(); + let filename: &str = if args.len() == 2 { + args[1].as_ref() + } else { + panic!("Usage: cargo run --bin test-player ") + }; + + let path = Path::new(filename); + let player_wrapper = PlayerWrapper::new(&path); + let app = Arc::new(App::new()); + player_wrapper.register_frame_renderer(app.clone()); + ui::main_wrapper(app, None); + player_wrapper.shutdown(); +} diff --git a/examples/test-player/ui.rs b/examples/test-player/ui.rs new file mode 100644 index 00000000..e4aac137 --- /dev/null +++ b/examples/test-player/ui.rs @@ -0,0 +1,309 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Copied from WebRender's boilerplate.rs. + +extern crate env_logger; +extern crate euclid; + +use gleam::gl; +use glutin::{self, GlContext}; +use std::env; +use std::path::PathBuf; +use std::sync::Arc; +use webrender; +use winit; +use webrender::api::*; + +struct Notifier { + events_proxy: winit::EventsLoopProxy, +} + +impl Notifier { + fn new(events_proxy: winit::EventsLoopProxy) -> Notifier { + Notifier { events_proxy } + } +} + +impl RenderNotifier for Notifier { + fn clone(&self) -> Box { + Box::new(Notifier { + events_proxy: self.events_proxy.clone(), + }) + } + + fn wake_up(&self) { + #[cfg(not(target_os = "android"))] + let _ = self.events_proxy.wakeup(); + } + + fn new_frame_ready(&self, + _: DocumentId, + _scrolled: bool, + _composite_needed: bool, + _render_time: Option) { + self.wake_up(); + } +} + +pub trait HandyDandyRectBuilder { + fn to(&self, x2: i32, y2: i32) -> LayoutRect; + fn by(&self, w: i32, h: i32) -> LayoutRect; +} +// Allows doing `(x, y).to(x2, y2)` or `(x, y).by(width, height)` with i32 +// values to build a f32 LayoutRect +impl HandyDandyRectBuilder for (i32, i32) { + fn to(&self, x2: i32, y2: i32) -> LayoutRect { + LayoutRect::new( + LayoutPoint::new(self.0 as f32, self.1 as f32), + LayoutSize::new((x2 - self.0) as f32, (y2 - self.1) as f32), + ) + } + + fn by(&self, w: i32, h: i32) -> LayoutRect { + LayoutRect::new( + LayoutPoint::new(self.0 as f32, self.1 as f32), + LayoutSize::new(w as f32, h as f32), + ) + } +} + +pub trait Example { + const TITLE: &'static str = "Servo Media Test Player"; + const PRECACHE_SHADERS: bool = false; + const WIDTH: u32 = 1920; + const HEIGHT: u32 = 1080; + + fn render( + &self, + api: &RenderApi, + builder: &mut DisplayListBuilder, + txn: &mut Transaction, + framebuffer_size: DeviceUintSize, + pipeline_id: PipelineId, + document_id: DocumentId, + ); + fn on_event( + &self, + winit::WindowEvent, + &RenderApi, + DocumentId, + ) -> bool { + false + } + fn get_image_handlers( + &self, + _gl: &gl::Gl, + ) -> (Option>, + Option>) { + (None, None) + } + fn draw_custom(&self, _gl: &gl::Gl) { + } +} + +pub fn main_wrapper( + example: Arc, + options: Option, +) { + env_logger::init(); + + let args: Vec = env::args().collect(); + let res_path = if args.len() > 1 { + Some(PathBuf::from(&args[1])) + } else { + None + }; + + let mut events_loop = winit::EventsLoop::new(); + let context_builder = glutin::ContextBuilder::new() + .with_gl(glutin::GlRequest::GlThenGles { + opengl_version: (3, 2), + opengles_version: (3, 0), + }); + let window_builder = winit::WindowBuilder::new() + .with_title(E::TITLE) + .with_multitouch() + .with_dimensions(winit::dpi::LogicalSize::new(E::WIDTH as f64, E::HEIGHT as f64)); + let window = glutin::GlWindow::new(window_builder, context_builder, &events_loop) + .unwrap(); + + unsafe { + window.make_current().ok(); + } + + let gl = match window.get_api() { + glutin::Api::OpenGl => unsafe { + gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) + }, + glutin::Api::OpenGlEs => unsafe { + gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) + }, + glutin::Api::WebGl => unimplemented!(), + }; + + println!("OpenGL version {}", gl.get_string(gl::VERSION)); + println!("Shader resource path: {:?}", res_path); + let device_pixel_ratio = window.get_hidpi_factor() as f32; + println!("Device pixel ratio: {}", device_pixel_ratio); + + println!("Loading shaders..."); + let opts = webrender::RendererOptions { + resource_override_path: res_path, + precache_shaders: E::PRECACHE_SHADERS, + device_pixel_ratio, + clear_color: Some(ColorF::new(0.3, 0.0, 0.0, 1.0)), + //scatter_gpu_cache_updates: false, + debug_flags: webrender::DebugFlags::ECHO_DRIVER_MESSAGES, + ..options.unwrap_or(webrender::RendererOptions::default()) + }; + + let framebuffer_size = { + let size = window + .get_inner_size() + .unwrap() + .to_physical(device_pixel_ratio as f64); + DeviceUintSize::new(size.width as u32, size.height as u32) + }; + let notifier = Box::new(Notifier::new(events_loop.create_proxy())); + let (mut renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts).unwrap(); + let api = sender.create_api(); + let document_id = api.add_document(framebuffer_size, 0); + + let (external, output) = example.get_image_handlers(&*gl); + + if let Some(output_image_handler) = output { + renderer.set_output_image_handler(output_image_handler); + } + + if let Some(external_image_handler) = external { + renderer.set_external_image_handler(external_image_handler); + } + + let epoch = Epoch(0); + let pipeline_id = PipelineId(0, 0); + let layout_size = framebuffer_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio); + let mut builder = DisplayListBuilder::new(pipeline_id, layout_size); + let mut txn = Transaction::new(); + + example.render( + &api, + &mut builder, + &mut txn, + framebuffer_size, + pipeline_id, + document_id, + ); + txn.set_display_list( + epoch, + None, + layout_size, + builder.finalize(), + true, + ); + txn.set_root_pipeline(pipeline_id); + txn.generate_frame(); + api.send_transaction(document_id, txn); + + println!("Entering event loop"); + events_loop.run_forever(|global_event| { + let mut txn = Transaction::new(); + let mut custom_event = true; + + match global_event { + winit::Event::WindowEvent { + event: winit::WindowEvent::CloseRequested, + .. + } => return winit::ControlFlow::Break, + winit::Event::WindowEvent { + event: winit::WindowEvent::KeyboardInput { + input: winit::KeyboardInput { + state: winit::ElementState::Pressed, + virtual_keycode: Some(key), + .. + }, + .. + }, + .. + } => match key { + winit::VirtualKeyCode::Escape => return winit::ControlFlow::Break, + winit::VirtualKeyCode::P => renderer.toggle_debug_flags(webrender::DebugFlags::PROFILER_DBG), + winit::VirtualKeyCode::O => renderer.toggle_debug_flags(webrender::DebugFlags::RENDER_TARGET_DBG), + winit::VirtualKeyCode::I => renderer.toggle_debug_flags(webrender::DebugFlags::TEXTURE_CACHE_DBG), + winit::VirtualKeyCode::S => renderer.toggle_debug_flags(webrender::DebugFlags::COMPACT_PROFILER), + winit::VirtualKeyCode::Q => renderer.toggle_debug_flags( + webrender::DebugFlags::GPU_TIME_QUERIES | webrender::DebugFlags::GPU_SAMPLE_QUERIES + ), + winit::VirtualKeyCode::Key1 => txn.set_window_parameters( + framebuffer_size, + DeviceUintRect::new(DeviceUintPoint::zero(), framebuffer_size), + 1.0 + ), + winit::VirtualKeyCode::Key2 => txn.set_window_parameters( + framebuffer_size, + DeviceUintRect::new(DeviceUintPoint::zero(), framebuffer_size), + 2.0 + ), + winit::VirtualKeyCode::M => api.notify_memory_pressure(), + #[cfg(feature = "capture")] + winit::VirtualKeyCode::C => { + let path: PathBuf = "../captures/example".into(); + //TODO: switch between SCENE/FRAME capture types + // based on "shift" modifier, when `glutin` is updated. + let bits = CaptureBits::all(); + api.save_capture(path, bits); + }, + _ => { + let win_event = match global_event { + winit::Event::WindowEvent { event, .. } => event, + _ => unreachable!() + }; + custom_event = example.on_event( + win_event, + &api, + document_id, + ) + }, + }, + winit::Event::WindowEvent { event, .. } => custom_event = example.on_event( + event, + &api, + document_id, + ), + _ => return winit::ControlFlow::Continue, + }; + + if custom_event { + let mut builder = DisplayListBuilder::new(pipeline_id, layout_size); + + example.render( + &api, + &mut builder, + &mut txn, + framebuffer_size, + pipeline_id, + document_id, + ); + txn.set_display_list( + epoch, + None, + layout_size, + builder.finalize(), + true, + ); + txn.generate_frame(); + } + api.send_transaction(document_id, txn); + + renderer.update(); + renderer.render(framebuffer_size).unwrap(); + let _ = renderer.flush_pipeline_info(); + example.draw_custom(&*gl); + window.swap_buffers().ok(); + + winit::ControlFlow::Continue + }); + + renderer.deinit(); +} From e745860828d56f0d5c3c2f518680d3d66d702bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 2 Aug 2018 16:55:56 +0200 Subject: [PATCH 3/4] Render video --- examples/test-player/main.rs | 52 +++++++++++++++++++++++++++++++++--- examples/test-player/ui.rs | 7 +++-- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/examples/test-player/main.rs b/examples/test-player/main.rs index c92462a4..4b65296c 100644 --- a/examples/test-player/main.rs +++ b/examples/test-player/main.rs @@ -24,6 +24,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc; use std::sync::{Arc, Mutex}; use std::thread::Builder; +use ui::HandyDandyRectBuilder; use webrender::api::*; #[path = "ui.rs"] @@ -133,12 +134,14 @@ impl PlayerWrapper { struct App { frame_queue: Mutex>, + current_frame: Mutex>, } impl App { fn new() -> Self { Self { frame_queue: Mutex::new(Vec::new()), + current_frame: Mutex::new(None), } } } @@ -146,20 +149,61 @@ impl App { impl ui::Example for App { fn render( &self, - _api: &RenderApi, - _builder: &mut DisplayListBuilder, - _txn: &mut Transaction, + api: &RenderApi, + builder: &mut DisplayListBuilder, + txn: &mut Transaction, _framebuffer_size: DeviceUintSize, _pipeline_id: PipelineId, _document_id: DocumentId, ) { - // XXX render frame queue + let frame = if self.frame_queue.lock().unwrap().is_empty() { + let mut frame = self.current_frame.lock().unwrap(); + if frame.is_none() { + return; + } + frame.take().unwrap() + } else { + self.frame_queue.lock().unwrap().pop().unwrap() + }; + let width = frame.get_width() as u32; + let height = frame.get_height() as u32; + let image_descriptor = + ImageDescriptor::new(width, height, ImageFormat::BGRA8, false, false); + let image_data = ImageData::new_shared(frame.get_data().clone()); + *self.current_frame.lock().unwrap() = Some(frame); + let image_key = api.generate_image_key(); + txn.add_image(image_key, image_descriptor, image_data, None); + let bounds = (0, 0).to(width as i32, height as i32); + let info = LayoutPrimitiveInfo::new(bounds); + builder.push_stacking_context( + &info, + None, + TransformStyle::Flat, + MixBlendMode::Normal, + Vec::new(), + GlyphRasterSpace::Screen, + ); + let image_size = LayoutSize::new(width as f32, height as f32); + let info = LayoutPrimitiveInfo::new(bounds); + builder.push_image( + &info, + image_size, + LayoutSize::zero(), + ImageRendering::Auto, + AlphaType::PremultipliedAlpha, + image_key, + ); + builder.pop_stacking_context(); } fn on_event(&self, _: winit::WindowEvent, _: &RenderApi, _: DocumentId) -> bool { false } + fn needs_repaint(&self) -> bool { + !self.frame_queue.lock().unwrap().is_empty() + } + fn get_image_handlers( &self, _gl: &gl::Gl, diff --git a/examples/test-player/ui.rs b/examples/test-player/ui.rs index e4aac137..d9265800 100644 --- a/examples/test-player/ui.rs +++ b/examples/test-player/ui.rs @@ -92,6 +92,9 @@ pub trait Example { ) -> bool { false } + fn needs_repaint(&self) -> bool { + false + } fn get_image_handlers( &self, _gl: &gl::Gl, @@ -271,10 +274,10 @@ pub fn main_wrapper( &api, document_id, ), - _ => return winit::ControlFlow::Continue, + _ => (), }; - if custom_event { + if custom_event || example.needs_repaint() { let mut builder = DisplayListBuilder::new(pipeline_id, layout_size); example.render( From fbe830b8068ff6c285e3a2cca67c6cd86e99b6fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 2 Aug 2018 18:13:38 +0200 Subject: [PATCH 4/4] Remove old player test --- examples/Cargo.toml | 6 +- examples/player.rs | 108 ----------------------- examples/{test-player => player}/main.rs | 0 examples/{test-player => player}/ui.rs | 0 4 files changed, 1 insertion(+), 113 deletions(-) delete mode 100644 examples/player.rs rename examples/{test-player => player}/main.rs (100%) rename examples/{test-player => player}/ui.rs (100%) diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 1c055c51..42a355f0 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -51,8 +51,4 @@ path = "play_noise.rs" [[bin]] name = "player" -path = "player.rs" - -[[bin]] -name = "test-player" -path = "test-player/main.rs" +path = "player/main.rs" diff --git a/examples/player.rs b/examples/player.rs deleted file mode 100644 index f0b2bfdd..00000000 --- a/examples/player.rs +++ /dev/null @@ -1,108 +0,0 @@ -extern crate servo_media; - -use servo_media::player::PlayerEvent; -use servo_media::ServoMedia; -use std::env; -use std::error::Error; -use std::fs::File; -use std::io::BufReader; -use std::io::Read; -use std::path::Path; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::mpsc; -use std::sync::{Arc, Mutex}; -use std::thread; - -fn run_example(servo_media: Arc) { - let player = Arc::new(Mutex::new(servo_media.create_player().unwrap())); - let args: Vec<_> = env::args().collect(); - let filename: &str = if args.len() == 2 { - args[1].as_ref() - } else { - panic!("Usage: cargo run --bin player ") - }; - - let (sender, receiver) = mpsc::channel(); - player.lock().unwrap().register_event_handler(sender); - - let path = Path::new(filename); - let display = path.display(); - - let file = match File::open(&path) { - Err(why) => panic!("couldn't open {}: {}", display, why.description()), - Ok(file) => file, - }; - - if let Ok(metadata) = file.metadata() { - player.lock().unwrap().set_input_size(metadata.len()); - } - - player - .lock() - .unwrap() - .setup() - .expect("couldn't setup player"); - - let player_clone = Arc::clone(&player); - let shutdown = Arc::new(AtomicBool::new(false)); - let shutdown_clone = shutdown.clone(); - let t = thread::spawn(move || { - let player = &player_clone; - let mut buf_reader = BufReader::new(file); - let mut buffer = [0; 8192]; - while !shutdown_clone.load(Ordering::Relaxed) { - match buf_reader.read(&mut buffer[..]) { - Ok(0) => { - println!("finished pushing data"); - break; - } - Ok(size) => { - if let Err(_) = player - .lock() - .unwrap() - .push_data(Vec::from(&buffer[0..size])) - { - break; - } - } - Err(e) => { - eprintln!("Error: {}", e); - break; - } - } - } - }); - - player.lock().unwrap().play(); - - while let Ok(event) = receiver.recv() { - match event { - PlayerEvent::EndOfStream => { - println!("EOF"); - break; - } - PlayerEvent::Error => { - println!("Error"); - break; - } - PlayerEvent::MetadataUpdated(ref m) => { - println!("Metadata updated! {:?}", m); - } - PlayerEvent::StateChanged(ref s) => { - println!("Player state changed to {:?}", s); - } - PlayerEvent::FrameUpdated => eprint!("."), - } - } - - shutdown.store(true, Ordering::Relaxed); - let _ = t.join(); - - player.lock().unwrap().stop(); -} - -fn main() { - if let Ok(servo_media) = ServoMedia::get() { - run_example(servo_media); - } -} diff --git a/examples/test-player/main.rs b/examples/player/main.rs similarity index 100% rename from examples/test-player/main.rs rename to examples/player/main.rs diff --git a/examples/test-player/ui.rs b/examples/player/ui.rs similarity index 100% rename from examples/test-player/ui.rs rename to examples/player/ui.rs