diff --git a/README.md b/README.md index 85b61f0..32dea56 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Bino: A 3D video player with multi-display support Bino is a video player with two main features: + - Support for 3D videos, with a wide variety of input and output formats. - Support for distributed multi-display video, e.g. for powerwalls, Virtual Reality installations and other multi-projector setups. diff --git a/pkg/w32/notes.txt b/pkg/w32/notes.txt index f84be15..e3e1c20 100644 --- a/pkg/w32/notes.txt +++ b/pkg/w32/notes.txt @@ -17,4 +17,4 @@ The source code for Bino is available here: https://bino3d.org/download.html Instructions to build this package from source can be found here: -https://gitlab.marlam.de/marlam/bino/raw/master/README.Windows +https://git.marlam.de/gitweb/?p=bino.git;a=blob_plain;f=README.Windows;hb=HEAD diff --git a/src/base/dbg.cpp b/src/base/dbg.cpp index 6c6234f..044be67 100644 --- a/src/base/dbg.cpp +++ b/src/base/dbg.cpp @@ -74,8 +74,10 @@ namespace dbg (void)sigaction(SIGFPE, &signal_handler, NULL); (void)sigaction(SIGSEGV, &signal_handler, NULL); #endif +#if __cplusplus < 201700 std::set_unexpected(exception_crash); std::set_terminate(exception_crash); +#endif std::set_new_handler(oom_abort); } diff --git a/src/dispatch.cpp b/src/dispatch.cpp index d6f9327..703d865 100644 --- a/src/dispatch.cpp +++ b/src/dispatch.cpp @@ -1,7 +1,7 @@ /* * This file is part of bino, a 3D video player. * - * Copyright (C) 2010, 2011, 2012, 2013, 2015 + * Copyright (C) 2010, 2011, 2012, 2013, 2015, 2018 * Martin Lambers * Binocle (author: Olivier Letz ) * Frédéric Bour @@ -504,6 +504,12 @@ void dispatch::receive_cmd(const command& cmd) if (_input_data.params.subtitle_parallax_is_set()) _parameters.set_subtitle_parallax(_input_data.params.subtitle_parallax()); notify_all(notification::subtitle_parallax); + if (_input_data.params.vertical_pixel_shift_left_is_set()) + _parameters.set_vertical_pixel_shift_left(_input_data.params.vertical_pixel_shift_left()); + notify_all(notification::vertical_pixel_shift_left); + if (_input_data.params.vertical_pixel_shift_right_is_set()) + _parameters.set_vertical_pixel_shift_right(_input_data.params.vertical_pixel_shift_right()); + notify_all(notification::vertical_pixel_shift_right); if (!_parameters.stereo_mode_is_set()) { if (_media_input->video_frame_template().stereo_layout == parameters::layout_mono) _parameters.set_stereo_mode(parameters::mode_mono_left); @@ -833,6 +839,14 @@ void dispatch::receive_cmd(const command& cmd) _parameters.set_subtitle_parallax(clamp(s11n::load(p), -1.0f, +1.0f)); notify_all(notification::subtitle_parallax); break; + case command::set_vertical_pixel_shift_left: + _parameters.set_vertical_pixel_shift_left(s11n::load(p)); + notify_all(notification::vertical_pixel_shift_left); + break; + case command::set_vertical_pixel_shift_right: + _parameters.set_vertical_pixel_shift_right(s11n::load(p)); + notify_all(notification::vertical_pixel_shift_right); + break; // Volatile parameters case command::toggle_fullscreen: { @@ -1217,6 +1231,12 @@ bool dispatch::parse_command(const std::string& s, command* c) } else if (tokens.size() == 2 && tokens[0] == "adjust-subtitle-parallax" && str::to(tokens[1], &p.f)) { *c = command(command::adjust_subtitle_parallax, p.f); + } else if (tokens.size() == 2 && tokens[0] == "set-vertical-pixel-shift-left" + && str::to(tokens[1], &p.f)) { + *c = command(command::set_vertical_pixel_shift_left, p.f); + } else if (tokens.size() == 2 && tokens[0] == "set-vertical-pixel-shift-right" + && str::to(tokens[1], &p.f)) { + *c = command(command::set_vertical_pixel_shift_right, p.f); } else if (tokens.size() == 1 && tokens[0] == "toggle-fullscreen") { *c = command(command::toggle_fullscreen); } else if (tokens.size() == 1 && tokens[0] == "center") { diff --git a/src/dispatch.h b/src/dispatch.h index 2133f8d..23f8030 100644 --- a/src/dispatch.h +++ b/src/dispatch.h @@ -1,7 +1,7 @@ /* * This file is part of bino, a 3D video player. * - * Copyright (C) 2010, 2011, 2012, 2013, 2015 + * Copyright (C) 2010, 2011, 2012, 2013, 2015, 2018 * Martin Lambers * Joe * Binocle (author: Olivier Letz ) @@ -143,6 +143,8 @@ public: adjust_ghostbust, // float (relative adjustment) set_subtitle_parallax, // float (absolute value) adjust_subtitle_parallax, // float (relative adjustment) + set_vertical_pixel_shift_left, // float + set_vertical_pixel_shift_right, // float // Volatile parameters toggle_fullscreen, // no parameters center, // no parameters @@ -260,6 +262,8 @@ public: parallax, ghostbust, subtitle_parallax, + vertical_pixel_shift_left, + vertical_pixel_shift_right, // Volatile parameters fullscreen, center, diff --git a/src/main.cpp b/src/main.cpp index 474cdd0..aa232c7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -337,6 +337,10 @@ int main(int argc, char *argv[]) options.push_back(&subtitle_shadow); opt::val subtitle_parallax("subtitle-parallax", '\0', opt::optional, -1.0f, +1.0f); options.push_back(&subtitle_parallax); + opt::val vertical_pixel_shift_left("vertical-pixel-shift-left", '\0', opt::optional, -99999.9f, +99999.9f, 0.0f); + options.push_back(&vertical_pixel_shift_left); + opt::val vertical_pixel_shift_right("vertical-pixel-shift-right", '\0', opt::optional, -99999.9f, +99999.9f, 0.0f); + options.push_back(&vertical_pixel_shift_right); opt::val parallax("parallax", 'P', opt::optional, -1.0f, +1.0f); options.push_back(¶llax); opt::tuple crosstalk("crosstalk", '\0', opt::optional, 0.0f, 1.0f, std::vector(), 3); @@ -767,6 +771,10 @@ int main(int argc, char *argv[]) input_data.params.set_ghostbust(ghostbust.value()); if (subtitle_parallax.is_set()) input_data.params.set_subtitle_parallax(subtitle_parallax.value()); + if (vertical_pixel_shift_left.is_set()) + input_data.params.set_vertical_pixel_shift_left(vertical_pixel_shift_left.value()); + if (vertical_pixel_shift_right.is_set()) + input_data.params.set_vertical_pixel_shift_right(vertical_pixel_shift_right.value()); int retval = 0; std::vector command_files; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 988417a..1563eef 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -666,6 +666,10 @@ void main_window::open(QStringList filenames, input_data.params.set_source_aspect_ratio(initial_params.source_aspect_ratio()); if (initial_params.parallax_is_set()) input_data.params.set_parallax(initial_params.parallax()); + if (initial_params.vertical_pixel_shift_left_is_set()) + input_data.params.set_vertical_pixel_shift_left(initial_params.vertical_pixel_shift_left()); + if (initial_params.vertical_pixel_shift_right_is_set()) + input_data.params.set_vertical_pixel_shift_right(initial_params.vertical_pixel_shift_right()); if (initial_params.ghostbust_is_set()) input_data.params.set_ghostbust(initial_params.ghostbust()); if (initial_params.subtitle_parallax_is_set()) diff --git a/src/media_data.cpp b/src/media_data.cpp index b4acfb0..93b032d 100644 --- a/src/media_data.cpp +++ b/src/media_data.cpp @@ -1,7 +1,7 @@ /* * This file is part of bino, a 3D video player. * - * Copyright (C) 2010, 2011, 2012, 2013, 2015 + * Copyright (C) 2010, 2011, 2012, 2013, 2015, 2018 * Martin Lambers * Joe * D. Matz @@ -125,6 +125,8 @@ parameters::parameters() unset_parallax(); unset_ghostbust(); unset_subtitle_parallax(); + unset_vertical_pixel_shift_left(); + unset_vertical_pixel_shift_right(); // Volatile parameters unset_fullscreen(); unset_center(); @@ -180,6 +182,8 @@ const float parameters::_source_aspect_ratio_default = 0.0f; const float parameters::_parallax_default = 0.0f; const float parameters::_ghostbust_default = 0.0f; const float parameters::_subtitle_parallax_default = 0.0f; +const float parameters::_vertical_pixel_shift_left_default = 0.0f; +const float parameters::_vertical_pixel_shift_right_default = 0.0f; // Volatile parameter defaults const bool parameters::_fullscreen_default = false; const bool parameters::_center_default = false; @@ -575,6 +579,10 @@ void parameters::save(std::ostream &os) const s11n::save(os, _ghostbust_set); s11n::save(os, _subtitle_parallax); s11n::save(os, _subtitle_parallax_set); + s11n::save(os, _vertical_pixel_shift_left); + s11n::save(os, _vertical_pixel_shift_left_set); + s11n::save(os, _vertical_pixel_shift_right); + s11n::save(os, _vertical_pixel_shift_right_set); // Volatile parameters s11n::save(os, _fullscreen); s11n::save(os, _fullscreen_set); @@ -680,6 +688,10 @@ void parameters::load(std::istream &is) s11n::load(is, _ghostbust_set); s11n::load(is, _subtitle_parallax); s11n::load(is, _subtitle_parallax_set); + s11n::load(is, _vertical_pixel_shift_left); + s11n::load(is, _vertical_pixel_shift_left_set); + s11n::load(is, _vertical_pixel_shift_right); + s11n::load(is, _vertical_pixel_shift_right_set); // Volatile parameters s11n::load(is, _fullscreen); s11n::load(is, _fullscreen_set); @@ -879,6 +891,8 @@ void parameters::unset_video_parameters() unset_parallax(); unset_ghostbust(); unset_subtitle_parallax(); + unset_vertical_pixel_shift_left(); + unset_vertical_pixel_shift_right(); } std::string parameters::save_video_parameters() const @@ -902,6 +916,10 @@ std::string parameters::save_video_parameters() const s11n::save(oss, "ghostbust", _ghostbust); if (!subtitle_parallax_is_default()) s11n::save(oss, "subtitle_parallax", _subtitle_parallax); + if (!vertical_pixel_shift_left_is_default()) + s11n::save(oss, "vertical_pixel_shift_left", _vertical_pixel_shift_left); + if (!vertical_pixel_shift_right_is_default()) + s11n::save(oss, "vertical_pixel_shift_right", _vertical_pixel_shift_right); return oss.str(); } @@ -941,6 +959,12 @@ void parameters::load_video_parameters(const std::string &s) } else if (name == "subtitle_parallax") { s11n::load(value, _subtitle_parallax); _subtitle_parallax_set = true; + } else if (name == "vertical_pixel_shift_left") { + s11n::load(value, _vertical_pixel_shift_left); + _vertical_pixel_shift_left_set = true; + } else if (name == "vertical_pixel_shift_right") { + s11n::load(value, _vertical_pixel_shift_right); + _vertical_pixel_shift_right_set = true; } } } diff --git a/src/media_data.h b/src/media_data.h index 30c7bec..1214f91 100644 --- a/src/media_data.h +++ b/src/media_data.h @@ -1,7 +1,7 @@ /* * This file is part of bino, a 3D video player. * - * Copyright (C) 2010, 2011, 2012, 2013, 2015 + * Copyright (C) 2010, 2011, 2012, 2013, 2015, 2018 * Martin Lambers * Joe * D. Matz @@ -205,6 +205,8 @@ public: PARAMETER(float, parallax) // Parallax adjustment, -1 .. +1 PARAMETER(float, ghostbust) // Amount of crosstalk ghostbusting, 0 .. 1 PARAMETER(float, subtitle_parallax) // Subtitle parallax adjustment, -1 .. +1 + PARAMETER(float, vertical_pixel_shift_left) // Vertical shift in pixels for left view + PARAMETER(float, vertical_pixel_shift_right) // Vertical shift in pixels for right view // Volatile parameters PARAMETER(bool, fullscreen) // Fullscreen mode PARAMETER(bool, center) // Should the video be centered? diff --git a/src/media_input.cpp b/src/media_input.cpp index c1b8fcb..493708c 100644 --- a/src/media_input.cpp +++ b/src/media_input.cpp @@ -1,7 +1,7 @@ /* * This file is part of bino, a 3D video player. * - * Copyright (C) 2010, 2011, 2012, 2015 + * Copyright (C) 2010, 2011, 2012, 2015, 2018 * Martin Lambers * Frédéric Devernay * Joe @@ -38,7 +38,8 @@ media_input::media_input() : _active_video_stream(-1), _active_audio_stream(-1), _active_subtitle_stream(-1), _have_active_video_read(false), _have_active_audio_read(false), _have_active_subtitle_read(false), - _last_audio_data_size(0), _initial_skip(0), _duration(-1) + _last_audio_data_size(0), _initial_skip(0), _duration(-1), + _finished_first_frame_read(false) { } @@ -622,6 +623,26 @@ video_frame media_input::finish_video_frame_read() get_video_stream(1, o1, s1); video_frame f0 = _media_objects[o0].finish_video_frame_read(s0); video_frame f1 = _media_objects[o1].finish_video_frame_read(s1); + if (!_finished_first_frame_read && is_device()) + { + /* Try to keep both device streams in sync. This should only be + * relevant at the beginning of playback, i.e. the first frame read, + * when one device starts grabbing frames before the other does. */ + while (f0.is_valid() && f1.is_valid() + && f1.presentation_time > f0.presentation_time + video_frame_duration() / 2) + { + msg::dbg("skipping frame from device %d stream %d because device %d stream %d is ahead", o0, s0, o1, s1); + _media_objects[o0].start_video_frame_read(s0, 1); + f0 = _media_objects[o0].finish_video_frame_read(s0); + } + while (f0.is_valid() && f1.is_valid() + && f0.presentation_time > f1.presentation_time + video_frame_duration() / 2) + { + msg::dbg("skipping frame from device %d stream %d because device %d stream %d is ahead", o1, s1, o0, s0); + _media_objects[o1].start_video_frame_read(s1, 1); + f1 = _media_objects[o1].finish_video_frame_read(s1); + } + } if (f0.is_valid() && f1.is_valid()) { frame = _video_frame; @@ -655,6 +676,7 @@ video_frame media_input::finish_video_frame_read() } } _have_active_video_read = false; + _finished_first_frame_read = true; return frame; } diff --git a/src/media_input.h b/src/media_input.h index 8ff3778..880bfe1 100644 --- a/src/media_input.h +++ b/src/media_input.h @@ -1,7 +1,7 @@ /* * This file is part of bino, a 3D video player. * - * Copyright (C) 2010, 2011, 2012 + * Copyright (C) 2010, 2011, 2012, 2018 * Martin Lambers * Joe * @@ -53,6 +53,8 @@ private: int64_t _initial_skip; // Initial portion of input to skip, in microseconds. int64_t _duration; // Total combined duration of input. + bool _finished_first_frame_read; // Whether we have finished the first frame read from this input. + video_frame _video_frame; // Video frame template for currently active video stream. audio_blob _audio_blob; // Audio blob template for currently active audio stream. subtitle_box _subtitle_box; // Subtitle box template for currently active subtitle stream. diff --git a/src/video_output.cpp b/src/video_output.cpp index 10a5a25..b53d847 100644 --- a/src/video_output.cpp +++ b/src/video_output.cpp @@ -1,7 +1,7 @@ /* * This file is part of bino, a 3D video player. * - * Copyright (C) 2010, 2011, 2012, 2013, 2015 + * Copyright (C) 2010, 2011, 2012, 2013, 2015, 2018 * Martin Lambers * Frédéric Devernay * Joe @@ -1282,6 +1282,10 @@ void video_output::display_current_frame( glUniform1f(glGetUniformLocation(_render_prg, "parallax"), _render_params.parallax() * 0.05f * (_render_params.stereo_mode_swap() ? -1 : +1)); + glUniform1f(glGetUniformLocation(_render_prg, "vertical_shift_left"), + _render_params.vertical_pixel_shift_left() / frame.height); + glUniform1f(glGetUniformLocation(_render_prg, "vertical_shift_right"), + _render_params.vertical_pixel_shift_right() / frame.height); if (render_needs_subtitle(_render_params)) { glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, (_subtitle[_active_index].is_valid() diff --git a/src/video_output_qt.cpp b/src/video_output_qt.cpp index e9350d5..b8fb604 100644 --- a/src/video_output_qt.cpp +++ b/src/video_output_qt.cpp @@ -1121,6 +1121,8 @@ void video_output_qt::receive_notification(const notification& note) #endif // HAVE_LIBXNVCTRL || note.type == notification::crop_aspect_ratio || note.type == notification::parallax + || note.type == notification::vertical_pixel_shift_left + || note.type == notification::vertical_pixel_shift_right || note.type == notification::ghostbust)) { _widget->redisplay(); } diff --git a/src/video_output_render.fs.glsl b/src/video_output_render.fs.glsl index 39f3498..e853f57 100644 --- a/src/video_output_render.fs.glsl +++ b/src/video_output_render.fs.glsl @@ -1,7 +1,7 @@ /* * This file is part of bino, a 3D video player. * - * Copyright (C) 2010, 2011, 2012 + * Copyright (C) 2010, 2011, 2012, 2018 * Martin Lambers * Frédéric Devernay * @@ -59,6 +59,8 @@ uniform sampler2D rgb_l; uniform sampler2D rgb_r; uniform float parallax; +uniform float vertical_shift_left; +uniform float vertical_shift_right; #if defined(subtitle_enabled) uniform sampler2D subtitle; @@ -145,11 +147,11 @@ vec3 adjust_color(vec3 rgb) vec3 tex_l(vec2 texcoord) { - return adjust_color(texture2D(rgb_l, texcoord + vec2(parallax, 0.0)).rgb); + return adjust_color(texture2D(rgb_l, texcoord + vec2(parallax, vertical_shift_left)).rgb); } vec3 tex_r(vec2 texcoord) { - return adjust_color(texture2D(rgb_r, texcoord - vec2(parallax, 0.0)).rgb); + return adjust_color(texture2D(rgb_r, texcoord + vec2(-parallax, vertical_shift_right)).rgb); } #if defined(subtitle_enabled)