AnyEvent-MPV

 view release on metacpan or  search on metacpan

MPV.pm  view on Meta::CPAN

}

=back

=head2 SUBCLASSING

Like most perl objects, C<AnyEvent::MPV> objects are implemented as
hashes, with the constructor simply storing all passed key-value pairs in
the object. If you want to subclass to provide your own C<on_*> methods,
be my guest and rummage around in the internals as much as you wish - the
only guarantee that this module dcoes is that it will not use keys with
double colons in the name, so youc an use those, or chose to simply not
care and deal with the breakage.

If you don't want to go to the effort of subclassing this module, you can
also specify all event handlers as constructor keys.

=head1 EXAMPLES

Here are some real-world code snippets, thrown in here mainly to give you
some example code to copy.

=head2 doomfrontend

At one point I replaced mythtv-frontend by my own terminal-based video
player (based on rxvt-unicode). I toyed with the diea of using F<mpv>'s
subtitle engine to create the user interface, but that is hard to use
since you don't know how big your letters are. It is also where most of
this modules code has originally been developed in.

It uses a unified input queue to handle various remote controls, so its
event handling needs are very simple - it simply feeds all events into the
input queue:

   my $mpv = AnyEvent::MPV->new (
      mpv   => $MPV,
      args  => \@MPV_ARGS,
      on_event => sub {
	 input_feed "mpv/$_[1]", $_[2];
      },
      on_key => sub {
	 input_feed $_[1];
      },
      on_eof => sub {
	 input_feed "mpv/quit";
      },
   );

   ...

   $mpv->start ("--idle=yes", "--pause", "--force-window=no");

It also doesn't use complicated command line arguments - the file search
options have the most impact, as they prevent F<mpv> from scanning
directories with tens of thousands of files for subtitles and more:

   --audio-client-name=doomfrontend
   --osd-on-seek=msg-bar --osd-bar-align-y=-0.85 --osd-bar-w=95
   --sub-auto=exact --audio-file-auto=exact

Since it runs on a TV without a desktop environemnt, it tries to keep complications such as dbus
away and the screensaver happy:

   # prevent xscreensaver from doing something stupid, such as starting dbus
   $ENV{DBUS_SESSION_BUS_ADDRESS} = "/"; # prevent dbus autostart for sure
   $ENV{XDG_CURRENT_DESKTOP} = "generic";

It does bind a number of keys to internal (to doomfrontend) commands:

   for (
      List::Util::pairs qw(
         ESC   return
         q     return
         ENTER enter
         SPACE pause
         [     steprev
         ]     stepfwd
         j     subtitle
         BS    red
         i     green
         o     yellow
         b     blue
         D     triangle
         UP    up
         DOWN  down
         RIGHT right
         LEFT  left
      ),
      (map { ("KP$_" => "num$_") } 0..9),
      KP_INS => 0, # KP0, but different
   ) {
      $mpv->bind_key ($_->[0] => $_->[1]);
   }

It also reacts to sponsorblock chapters, so it needs to know when vidoe
chapters change. Preadting C<AnyEvent::MPV>, it handles observers
manually:

   $mpv->cmd (observe_property => 1, "chapter-metadata");

It also tries to apply an F<mpv> profile, if it exists:

   eval {
      # the profile is optional
      $mpv->cmd ("apply-profile" => "doomfrontend");
   };

Most of the complicated parts deal with saving and restoring per-video
data, such as bookmarks, playing position, selected audio and subtitle
tracks and so on. However, since it uses L<Coro>, it can conveniently
block and wait for replies, which is n ot possible in purely event based
programs, as you are not allowed to block inside event callbacks in most
event loops. This simplifies the code quite a bit.

When the file to be played is a Tv recording done by mythtv, it uses the
C<appending> protocol and deinterlacing:

   if (is_myth $mpv_path) {
      $mpv_path = "appending://$mpv_path";
      $initial_deinterlace = 1;
   }



( run in 0.606 second using v1.01-cache-2.11-cpan-2398b32b56e )