>From 0c2e96e2105e08bc8f1eef652f830972f71fd39d Mon Sep 17 00:00:00 2001 From: Martin Lambers Date: Sun, 24 Apr 2011 16:00:34 +0200 Subject: [PATCH] Add a loop mode. This allows to loop the current file. This can be extended in the future. --- doc/bino.1 | 4 ++- doc/bino.texi | 5 +++- src/Makefile.am | 1 + src/controller.h | 6 +++- src/icons/media-playlist-repeat.png | Bin 0 -> 2872 bytes src/main.cpp | 8 ++++- src/media_data.cpp | 6 +++- src/media_data.h | 7 +++++ src/player.cpp | 30 ++++++++++++++++++++- src/player_qt.cpp | 48 +++++++++++++++++++++++++++-------- src/player_qt.h | 2 + 11 files changed, 97 insertions(+), 20 deletions(-) create mode 100644 src/icons/media-playlist-repeat.png diff --git a/doc/bino.1 b/doc/bino.1 index 233333a..e7e2d47 100644 --- a/doc/bino.1 +++ b/doc/bino.1 @@ -29,7 +29,7 @@ Print version. .IP "\-n|\-\-no\-gui" Do not use the GUI, just play the given input in a plain window using the parameters given on the command line. -.IP "\-l|\-\-log\-level=\fILEVEL\fP" +.IP "\-L|\-\-log\-level=\fILEVEL\fP" Select log level: \fIdebug\fP, \fIinfo\fP, \fIwarning\fP, \fIerror\fP, or \fIquiet\fP. .IP "\-v|\-\-video=\fISTREAM\fP" @@ -188,6 +188,8 @@ Amount of crosstalk ghostbusting to apply (0 to 1). .IP "\-b|\-\-benchmark" Benchmark mode: no audio, no time synchronization, output of frames-per-second measurements. +.IP "\-l|\-\-loop" +Loop the input media. .SH INTERACTIVE CONTROL .IP "ESC" Leave fullscreen mode, or quit when in window mode. diff --git a/doc/bino.texi b/doc/bino.texi index f503732..47bf61a 100644 --- a/doc/bino.texi +++ b/doc/bino.texi @@ -95,7 +95,7 @@ Print version. @itemx --no-gui Do not use the GUI, just play the given input in a plain window using the parameters given on the command line. address@hidden -l address@hidden -L @itemx address@hidden Select log level: @var{debug}, @var{info}, @var{warning}, @var{error}, or @var{quiet}. @@ -148,6 +148,9 @@ Amount of crosstalk ghostbusting to apply (0 to 1). @itemx --benchmark Benchmark mode: no audio, no time synchronization, output of frames-per-second measurements. address@hidden -l address@hidden --loop +Loop the input media. @end table @node Input Layouts diff --git a/src/Makefile.am b/src/Makefile.am index 8df35d3..4452882 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -34,6 +34,7 @@ ICONS = \ icons/media-playback-pause.png \ icons/media-playback-start.png \ icons/media-playback-stop.png \ + icons/media-playlist-repeat.png \ icons/media-seek-backward.png \ icons/media-seek-forward.png \ icons/preferences-desktop-keyboard.png \ diff --git a/src/controller.h b/src/controller.h index 93021dd..96ae0be 100644 --- a/src/controller.h +++ b/src/controller.h @@ -83,7 +83,8 @@ public: adjust_subtitle_parallax, // float (relative adjustment) set_subtitle_parallax, // float (absolute value) seek, // float (relative adjustment) - set_pos // float (absolute position) + set_pos, // float (absolute position) + set_loop_mode, // parameters::loop_mode_t }; type type; @@ -146,7 +147,8 @@ public: subtitle_scale, // float subtitle_color, // uint64_t subtitle_parallax, // float - pos // float + pos, // float + loop_mode, // parameters::loop_mode_t }; type type; diff --git a/src/icons/media-playlist-repeat.png b/src/icons/media-playlist-repeat.png new file mode 100644 index 0000000000000000000000000000000000000000..60f46047ea1754c1b2aaab99c94cf50c20950c4b GIT binary patch literal 2872 zcmV-83&-?{P)address@hidden zkO#)yW{YoR(TKjt!IYmj*+r9?z%%8+uQ`~d79?C1G>@fb8f zx3fF>?VCUS`8S)address@hidden@^iPVgm$xG#WuuXwyU)Yp}FJd0kV+ z3Po)sAPK{Q(}4)QD=Wq%5drK;#Fr)address@hidden(7cTFMj;= zS5BRLp(6`i0)S8GKCV4Pq69{OplO-=G_P|8*84K2R?)address@hidden;yTsdGq-k-v8Sb zxOejkeCdl{fVbZMJ?u<&;address@hidden;JXKyc>`033nZ&SHf^MO)z7Dq|tLCfV}j zWx_%r?S-KIvd$*8pEC)NO-*)=thGJ>@3FnT4O?5+*`3x_SK;Eti!f_5#Mr>KYuDht address@hidden)1UZhruR2kkkA;6R~Sl1Q6H?H3(0z7yOp;>`u zX#}Go;zKUshjaddress@hidden<{ZWn;8lz&w2P2zGb(K78zt5mwhWU_2VJ z0EKDb8*h9aE?hWoAyY3EQN37$h7}K$hNxM;KGv)O&~+VLy7X6g=iPV2l43VAf8P^= address@hidden)Fi`#W&^?mZFU^qJG}`s=TWbOx+$s1y|JkT;address@hidden>dafU~PRJ address@hidden(W5Kyu~R4E$8Y`ue)h{>i2$QG;ujIo53id$Hxf~Iso-VD+n2(a zwrgQFo5TJ4+px2<3*uT)^9x address@hidden(W((^Pm7m4&O-uXPRKgTW%se z`_vMA`NW!9D09Sf0X$?Ti7bwIG>Pz&>uyyFX7bUvw%s zvcIG0RfthhR1P|ZEX2|{mMpvk`)z=>&5)Z+7)9Y(1t7jl$+KYVj%XGT&7kPU!z5ym zl&`|Kyoaoq7a^wej%08v25zOVd7KUFG)?J zPS1$W>yq#Mjk# zpzB(address@hidden<2q8)$Yslo00J1;~w1W(bStr6rWY>tnBZ_2n3egtt6WGP~ zNP`-?ng(HcM7;&iEsZs+q2%zcuqQT)RrnYU`}HMWw4GiTyeqPj_;4Q7cb z;address@hidden)address@hiddenn$XPIaFw#zck{x3-_CE|JKo(stV zG5UrfT1paE>address@hidden>address@hidden>Q^7vwe1^ zJhVViH6B|@@a%de5OLYGsAVt`6;LT>7c|lqi1jyuem1I$iG4hg#VGq?l38Ssolp(Y znU_askOk0al$g2z^*8Lf6Ahey9;{?Ow4n$rv|pjRMSOo}s?W#4N0fJZk;nTPl=^P9 z1)>70frEY*)E_1;s99`SYKvbvwWkl-N&_2r;C;X$o4`V8j62d?07O1r0DJLP|3cx- address@hidden(82!k`T~A;WyXiAb4wDlOv(-UGNPiv z$nX2+7(address@hidden|qKm7sB=4$qWNWZzdmwGOLe6)5ywsP|jY-aNtXRFjPs zVqQWpXad`oR>address@hidden&address@hidden>?}08>1qKCyt{~pM*l;P zYu;-hU#IC`hJs}5D7;%)-m!>address@hidden;i>@address@hidden zkWC$wnmvNf1(btb(address@hidden<1&$)N?D z9$gBsx-6j3EJJ)1M#arQ*Qo0Zc#l*T(;28&nF7}N#EkPQNK^5;7N8Q~|NMCR?I$Pi zfAC`fy$C#HO+H+J?Y$0eJ!&ChL#`kimm8_2LWDrPScSt{^u$Ntbv`2am6SuR&#n?Q zOiEoTMVka51R4z>address@hidden>_oo`}stcZ_9|>e4-s&address@hidden z>sZ9n$R?l>lt%)WZC=B^hEWhcs-C0P<*%Mwhn41V3#c!887%$`3Y>*eUFLoq$4IM^ zhhhH?K#o|V*<`s!1~PV;lv9 zx`r7HlEws(MW+lLHnGmISY=(a778d-%c5BxG!uIwv~Od5hAssBYs307me02+8^z!W zC)address@hiddenD^uke^TE^wcyRO9?Ni_W&iA1FtDgg?m8TFT zEC%G?YyuVuVXP1jZB+HX(Sre*Q4GOzIa9*EcoxLnfWdy&(^6c zJV?JIUR=VfgUQ|={Z#)address@hidden;NwAQ&z<^H(y!LZ$l%`a zXn$@t*ZQE<;D?rio|cELJ!E`f8M&H$!2blq WeVahbBr literal 0 HcmV?d00001 diff --git a/src/main.cpp b/src/main.cpp index 7d01acd..50e7c0a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -147,7 +147,7 @@ int main(int argc, char *argv[]) log_levels.push_back("warning"); log_levels.push_back("error"); log_levels.push_back("quiet"); - opt::val log_level("log-level", 'l', opt::optional, log_levels, ""); + opt::val log_level("log-level", 'L', opt::optional, log_levels, ""); options.push_back(&log_level); std::vector input_modes; input_modes.push_back("mono"); @@ -228,6 +228,8 @@ int main(int argc, char *argv[]) options.push_back(&ghostbust); opt::flag benchmark("benchmark", 'b', opt::optional); options.push_back(&benchmark); + opt::flag loop("loop", 'l', opt::optional); + options.push_back(&loop); // Accept some Equalizer options. These are passed to Equalizer for interpretation. opt::val eq_server("eq-server", '\0', opt::optional); options.push_back(&eq_server); @@ -282,7 +284,7 @@ int main(int argc, char *argv[]) " --help Print help.\n" " --version Print version.\n" " -n|--no-gui Do not use the GUI, just show a plain window.\n" - " -l|--log-level=LEVEL Set log level (debug/info/warning/error/quiet).\n" + " -L|--log-level=LEVEL Set log level (debug/info/warning/error/quiet).\n" " -v|--video=STREAM Select video stream (1-n, depending on input).\n" " -a|--audio=STREAM Select audio stream (1-n, depending on input).\n" " -s|--subtitle=STREAM Select subtitle stream (0-n, depending on input).\n" @@ -342,6 +344,7 @@ int main(int argc, char *argv[]) " values for the R,G,B channels.\n" " -G|--ghostbust=VAL Amount of ghostbusting to apply (0 to 1).\n" " -b|--benchmark Benchmark mode (no audio, show fps).\n" + " -l|--loop Loop the input media.\n" "\n" "Interactive control:\n" " ESC Leave fullscreen mode, or quit.\n" @@ -476,6 +479,7 @@ int main(int argc, char *argv[]) { msg::inf(_("Benchmark mode: audio and time synchronization disabled.")); } + init_data.params.loop_mode = (loop.value() ? parameters::loop_current : parameters::no_loop); int retval = 0; player *player = NULL; diff --git a/src/media_data.cpp b/src/media_data.cpp index 4db6781..f6e1904 100644 --- a/src/media_data.cpp +++ b/src/media_data.cpp @@ -540,7 +540,8 @@ parameters::parameters() : subtitle_size(std::numeric_limits::min()), subtitle_scale(-1.0f), subtitle_color(std::numeric_limits::max()), - subtitle_parallax(std::numeric_limits::quiet_NaN()) + subtitle_parallax(std::numeric_limits::quiet_NaN()), + loop_mode(no_loop) { } @@ -836,6 +837,7 @@ void parameters::save(std::ostream &os) const s11n::save(os, subtitle_scale); s11n::save(os, subtitle_color); s11n::save(os, subtitle_parallax); + s11n::save(os, static_cast(loop_mode)); } void parameters::load(std::istream &is) @@ -859,4 +861,6 @@ void parameters::load(std::istream &is) s11n::load(is, subtitle_scale); s11n::load(is, subtitle_color); s11n::load(is, subtitle_parallax); + s11n::load(is, x); + loop_mode = static_cast(x); } diff --git a/src/media_data.h b/src/media_data.h index 29fc8f3..3489ed9 100644 --- a/src/media_data.h +++ b/src/media_data.h @@ -270,6 +270,12 @@ public: red_blue_monochrome, // Red/blue anaglyph, monochrome method } stereo_mode_t; + typedef enum + { + no_loop, // Do not loop. + loop_current, // Loop the current media input. + } loop_mode_t; + stereo_mode_t stereo_mode; // Stereo mode bool stereo_mode_swap; // Swap left and right view float parallax; // Parallax adjustment, -1 .. +1 @@ -287,6 +293,7 @@ public: float subtitle_scale; // Scale factor uint64_t subtitle_color; // Subtitle color in uint32_t bgra32 format, > UINT32_MAX means keep default float subtitle_parallax; // Subtitle parallax adjustment, -1 .. +1 + loop_mode_t loop_mode; // Current loop behaviour. // Constructor parameters(); diff --git a/src/player.cpp b/src/player.cpp index 05b31e4..4dfcd3d 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -516,7 +516,15 @@ int64_t player::step(bool *more_steps, int64_t *seek_to, bool *prep_frame, bool else { msg::dbg("End of video stream."); - stop_playback(); + if (_params.loop_mode == parameters::loop_current) + { + _set_pos_request = 0.0f; + *more_steps = true; + } + else + { + stop_playback(); + } return 0; } } @@ -592,7 +600,15 @@ int64_t player::step(bool *more_steps, int64_t *seek_to, bool *prep_frame, bool if (!blob.is_valid()) { msg::dbg("End of audio stream."); - stop_playback(); + if (_params.loop_mode == parameters::loop_current) + { + _set_pos_request = 0.0f; + *more_steps = true; + } + else + { + stop_playback(); + } return 0; } _audio_pos = blob.presentation_time; @@ -1050,6 +1066,16 @@ void player::receive_cmd(const command &cmd) _set_pos_request = param; /* notify when request is fulfilled */ break; + case command::set_loop_mode: + { + int old_loop_mode = static_cast(_params.loop_mode); + int loop_mode; + s11n::load(p, loop_mode); + _params.loop_mode = static_cast(loop_mode); + parameters_changed = true; + notify(notification::loop_mode, old_loop_mode, loop_mode); + } + break; } if (parameters_changed && _video_output) diff --git a/src/player_qt.cpp b/src/player_qt.cpp index 20c068f..d2e4fae 100644 --- a/src/player_qt.cpp +++ b/src/player_qt.cpp @@ -730,7 +730,7 @@ controls_widget::controls_widget(QSettings *settings, QWidget *parent) _seek_slider->setRange(0, 2000); _seek_slider->setTracking(false); connect(_seek_slider, SIGNAL(valueChanged(int)), this, SLOT(seek_slider_changed())); - layout->addWidget(_seek_slider, 0, 0, 1, 13); + layout->addWidget(_seek_slider, 0, 0, 1, 15); _play_button = new QPushButton(get_icon("media-playback-start"), ""); _play_button->setToolTip(_("

Play.

")); connect(_play_button, SIGNAL(pressed()), this, SLOT(play_pressed())); @@ -744,58 +744,67 @@ controls_widget::controls_widget(QSettings *settings, QWidget *parent) connect(_stop_button, SIGNAL(pressed()), this, SLOT(stop_pressed())); layout->addWidget(_stop_button, 1, 2); layout->addWidget(new QWidget, 1, 3); + _loop_button = new QPushButton(get_icon("media-playlist-repeat"), ""); + _loop_button->setToolTip(_("

Toggle loop mode.

")); + _loop_button->setCheckable(true); + _loop_button->setChecked(false); + connect(_loop_button, SIGNAL(toggled(bool)), this, SLOT(loop_pressed())); + layout->addWidget(_loop_button, 1, 4); + layout->addWidget(new QWidget, 1, 5); _fullscreen_button = new QPushButton(get_icon("view-fullscreen"), ""); _fullscreen_button->setToolTip(_("

Switch to fullscreen mode. " "You can leave fullscreen mode by pressing the f key.

")); connect(_fullscreen_button, SIGNAL(pressed()), this, SLOT(fullscreen_pressed())); - layout->addWidget(_fullscreen_button, 1, 4); + layout->addWidget(_fullscreen_button, 1, 6); _center_button = new QPushButton(get_icon("view-restore"), ""); _center_button->setToolTip(_("

Center the video area on your screen.

")); connect(_center_button, SIGNAL(pressed()), this, SLOT(center_pressed())); - layout->addWidget(_center_button, 1, 5); - layout->addWidget(new QWidget, 1, 6); + layout->addWidget(_center_button, 1, 7); + layout->addWidget(new QWidget, 1, 8); _bbb_button = new QPushButton(get_icon("media-seek-backward"), ""); _bbb_button->setFixedSize(_bbb_button->minimumSizeHint()); _bbb_button->setIconSize(_bbb_button->iconSize() * 12 / 10); _bbb_button->setToolTip(_("

Seek backward 10 minutes.

")); connect(_bbb_button, SIGNAL(pressed()), this, SLOT(bbb_pressed())); - layout->addWidget(_bbb_button, 1, 7); + layout->addWidget(_bbb_button, 1, 9); _bb_button = new QPushButton(get_icon("media-seek-backward"), ""); _bb_button->setFixedSize(_bb_button->minimumSizeHint()); _bb_button->setToolTip(_("

Seek backward 1 minute.

")); connect(_bb_button, SIGNAL(pressed()), this, SLOT(bb_pressed())); - layout->addWidget(_bb_button, 1, 8); + layout->addWidget(_bb_button, 1, 10); _b_button = new QPushButton(get_icon("media-seek-backward"), ""); _b_button->setFixedSize(_b_button->minimumSizeHint()); _b_button->setIconSize(_b_button->iconSize() * 8 / 10); _b_button->setToolTip(_("

Seek backward 10 seconds.

")); connect(_b_button, SIGNAL(pressed()), this, SLOT(b_pressed())); - layout->addWidget(_b_button, 1, 9); + layout->addWidget(_b_button, 1, 11); _f_button = new QPushButton(get_icon("media-seek-forward"), ""); _f_button->setFixedSize(_f_button->minimumSizeHint()); _f_button->setIconSize(_f_button->iconSize() * 8 / 10); _f_button->setToolTip(_("

Seek forward 10 seconds.

")); connect(_f_button, SIGNAL(pressed()), this, SLOT(f_pressed())); - layout->addWidget(_f_button, 1, 10); + layout->addWidget(_f_button, 1, 12); _ff_button = new QPushButton(get_icon("media-seek-forward"), ""); _ff_button->setFixedSize(_ff_button->minimumSizeHint()); _ff_button->setToolTip(_("

Seek forward 1 minute.

")); connect(_ff_button, SIGNAL(pressed()), this, SLOT(ff_pressed())); - layout->addWidget(_ff_button, 1, 11); + layout->addWidget(_ff_button, 1, 13); _fff_button = new QPushButton(get_icon("media-seek-forward"), ""); _fff_button->setFixedSize(_fff_button->minimumSizeHint()); _fff_button->setIconSize(_fff_button->iconSize() * 12 / 10); _fff_button->setToolTip(_("

Seek forward 10 minutes.

")); connect(_fff_button, SIGNAL(pressed()), this, SLOT(fff_pressed())); - layout->addWidget(_fff_button, 1, 12); + layout->addWidget(_fff_button, 1, 14); layout->setRowStretch(0, 0); layout->setColumnStretch(3, 1); - layout->setColumnStretch(6, 1); + layout->setColumnStretch(5, 1); + layout->setColumnStretch(8, 1); setLayout(layout); _play_button->setEnabled(false); _pause_button->setEnabled(false); _stop_button->setEnabled(false); + _loop_button->setEnabled(false); _fullscreen_button->setEnabled(false); _center_button->setEnabled(false); _bbb_button->setEnabled(false); @@ -833,6 +842,13 @@ void controls_widget::stop_pressed() send_cmd(command::toggle_play); } +void controls_widget::loop_pressed() +{ + int loop_mode = static_cast(_loop_button->isChecked() + ? parameters::loop_current : parameters::no_loop); + send_cmd(command::set_loop_mode, loop_mode); +} + void controls_widget::fullscreen_pressed() { send_cmd(command::toggle_fullscreen); @@ -893,6 +909,7 @@ void controls_widget::update(const player_init_data &, bool have_valid_input, bo _play_button->setEnabled(false); _pause_button->setEnabled(false); _stop_button->setEnabled(false); + _loop_button->setEnabled(false); _fullscreen_button->setEnabled(false); _center_button->setEnabled(false); _bbb_button->setEnabled(false); @@ -920,6 +937,7 @@ void controls_widget::receive_notification(const notification ¬e) _play_button->setEnabled(!flag); _pause_button->setEnabled(flag); _stop_button->setEnabled(flag); + _loop_button->setEnabled(flag); _fullscreen_button->setEnabled(flag); _center_button->setEnabled(flag); _bbb_button->setEnabled(flag); @@ -2022,6 +2040,14 @@ void main_window::receive_notification(const notification ¬e) _settings->endGroup(); break; + case notification::loop_mode: + { + int loop_mode; + s11n::load(current, loop_mode); + _init_data.params.loop_mode = static_cast(loop_mode); + } + break; + case notification::pause: case notification::stereo_layout: case notification::stereo_mode: diff --git a/src/player_qt.h b/src/player_qt.h index f0e0cc6..b41db10 100644 --- a/src/player_qt.h +++ b/src/player_qt.h @@ -117,6 +117,7 @@ private: QPushButton *_play_button; QPushButton *_pause_button; QPushButton *_stop_button; + QPushButton *_loop_button; QPushButton *_fullscreen_button; QPushButton *_center_button; QPushButton *_bbb_button; @@ -132,6 +133,7 @@ private slots: void play_pressed(); void pause_pressed(); void stop_pressed(); + void loop_pressed(); void fullscreen_pressed(); void center_pressed(); void bbb_pressed(); -- 1.7.1