ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-MPV/MPV.pm
(Generate patch)

Comparing AnyEvent-MPV/MPV.pm (file contents):
Revision 1.10 by root, Mon Mar 20 12:31:03 2023 UTC vs.
Revision 1.13 by root, Mon Mar 20 14:42:40 2023 UTC

147 my $quit = AE::cv; 147 my $quit = AE::cv;
148 148
149 my $mpv = AnyEvent::MPV->new ( 149 my $mpv = AnyEvent::MPV->new (
150 trace => 1, 150 trace => 1,
151 args => ["--pause", "--idle=yes"], 151 args => ["--pause", "--idle=yes"],
152 on_event => sub {
153 my ($mpv, $event, $data) = @_;
154
155 if ($event eq "start-file") {
156 $mpv->cmd ("set", "pause", "no");
157 } elsif ($event eq "end-file") {
158 print "end-file<$data->{reason}>\n";
159 $quit->send;
160 }
161 },
162 ); 152 );
163 153
164 $mpv->start; 154 $mpv->start;
155
156 $mpv->register_event (start_file => sub {
157 $mpv->cmd ("set", "pause", "no");
158 });
159
160 $mpv->register_event (end_file => sub {
161 my ($mpv, $event, $data) = @_;
162
163 print "end-file<$data->{reason}>\n";
164 $quit->send;
165 });
166
165 $mpv->cmd (loadfile => $mpv->escape_binary ($videofile)); 167 $mpv->cmd (loadfile => $mpv->escape_binary ($videofile));
166 168
167 $quit->recv; 169 $quit->recv;
168 170
169This example uses a global condvar C<$quit> to wait for the file to finish 171This example uses a global condvar C<$quit> to wait for the file to finish
170playing. Also, most of the logic is now in an C<on_event> callback, which 172playing. Also, most of the logic is now implement in event handlers.
171receives an event name and the actual event object.
172 173
173The two events we handle are C<start-file>, which is emitted by F<mpv> 174The two events handlers we register are C<start-file>, which is emitted by
174once it has loaded a new file, and C<end-file>, which signals the end 175F<mpv> once it has loaded a new file, and C<end-file>, which signals the
175of a file. 176end of a file (underscores are internally replaced by minus signs, so you
177cna speicfy event names with either).
176 178
177In the former event, we again set the C<pause> property to C<no> so the 179In the C<start-file> event, we again set the C<pause> property to C<no>
178movie starts playing. For the latter event, we tell the main program to 180so the movie starts playing. For the C<end-file> event, we tell the main
179quit by invoking C<$quit>. 181program to quit by invoking C<$quit>.
180 182
181This should conclude the basics of operation. There are a few more 183This should conclude the basics of operation. There are a few more
182examples later in the documentation. 184examples later in the documentation.
183 185
184=head2 ENCODING CONVENTIONS 186=head2 ENCODING CONVENTIONS
216sub OBSID() { 0x10000000000000 } # 2**52 218sub OBSID() { 0x10000000000000 } # 2**52
217 219
218our $JSON = eval { require JSON::XS; JSON::XS:: } 220our $JSON = eval { require JSON::XS; JSON::XS:: }
219 || do { require JSON::PP; JSON::PP:: }; 221 || do { require JSON::PP; JSON::PP:: };
220 222
221our $JSON_CODER = 223our $JSON_ENCODER = $JSON->new->utf8;
224our $JSON_DECODER = $JSON->new->latin1;
222 225
223our $mpv_path; # last mpv path used 226our $mpv_path; # last mpv path used
224our $mpv_optionlist; # output of mpv --list-options 227our $mpv_optionlist; # output of mpv --list-options
225 228
226=item $mpv = AnyEvent::MPV->new (key => value...) 229=item $mpv = AnyEvent::MPV->new (key => value...)
352 355
353sub start { 356sub start {
354 my ($self, @extra_args) = @_; 357 my ($self, @extra_args) = @_;
355 358
356 return 0 if $self->{fh}; 359 return 0 if $self->{fh};
357
358 $self->{obscb} = {};
359 360
360 # cache optionlist for same "path" 361 # cache optionlist for same "path"
361 ($mpv_path, $mpv_optionlist) = ($self->{mpv}, scalar qx{\Q$self->{mpv}\E --list-options}) 362 ($mpv_path, $mpv_optionlist) = ($self->{mpv}, scalar qx{\Q$self->{mpv}\E --list-options})
362 if $self->{mpv} ne $mpv_path; 363 if $self->{mpv} ne $mpv_path;
363 364
400 while ($buf =~ s/^([^\n]+)\n//) { 401 while ($buf =~ s/^([^\n]+)\n//) {
401 $trace->("mpv>" => "$1"); 402 $trace->("mpv>" => "$1");
402 403
403 if ("{" eq substr $1, 0, 1) { 404 if ("{" eq substr $1, 0, 1) {
404 eval { 405 eval {
405 my $reply = $JSON->new->latin1->decode ($1); 406 my $reply = $JSON_DECODER->decode ($1);
406 407
407 if (exists $reply->{event}) { 408 if (defined (my $event = delete $reply->{event})) {
408 if ( 409 if (
409 $reply->{event} eq "client-message" 410 $event eq "client-message"
410 and $reply->{args}[0] eq "AnyEvent::MPV" 411 and $reply->{args}[0] eq "AnyEvent::MPV"
411 ) { 412 ) {
412 if ($reply->{args}[1] eq "key") { 413 if ($reply->{args}[1] eq "key") {
413 (my $key = $reply->{args}[2]) =~ s/\\x(..)/chr hex $1/ge; 414 (my $key = $reply->{args}[2]) =~ s/\\x(..)/chr hex $1/ge;
414 $self->on_key ($key); 415 $self->on_key ($key);
415 } 416 }
416 } elsif ( 417 } elsif (
417 $reply->{event} eq "property-change" 418 $event eq "property-change"
418 and OBSID <= $reply->{id} 419 and OBSID <= $reply->{id}
419 ) { 420 ) {
420 if (my $cb = $self->{obscb}{$reply->{id}}) { 421 if (my $cb = $self->{obscb}{$reply->{id}}) {
421 $cb->($self, $reply->{name}, $reply->{data}); 422 $cb->($self, $event, $reply->{data});
422 } 423 }
423 } else { 424 } else {
425 if (my $cbs = $self->{evtcb}{$event}) {
426 for my $evtid (keys %$cbs) {
427 my $cb = $cbs->{$evtid}
428 or next;
429 $cb->($self, $event, $reply);
430 }
431 }
432
424 $self->on_event (delete $reply->{event}, $reply); 433 $self->on_event ($event, $reply);
425 } 434 }
426 } elsif (exists $reply->{request_id}) { 435 } elsif (exists $reply->{request_id}) {
427 my $cv = delete $self->{cmdcv}{$reply->{request_id}}; 436 my $cv = delete $self->{cmdcv}{$reply->{request_id}};
428 437
429 unless ($cv) { 438 unless ($cv) {
460 $self->{_cmd} = sub { 469 $self->{_cmd} = sub {
461 my $cv = AE::cv; 470 my $cv = AE::cv;
462 471
463 $self->{cmdcv}{++$reqid} = $cv; 472 $self->{cmdcv}{++$reqid} = $cv;
464 473
465 my $cmd = $JSON->new->utf8->encode ({ command => ref $_[0] ? $_[0] : \@_, request_id => $reqid*1 }); 474 my $cmd = $JSON_ENCODER->encode ({ command => ref $_[0] ? $_[0] : \@_, request_id => $reqid*1 });
466 475
467 # (un-)apply escape_binary hack 476 # (un-)apply escape_binary hack
468 $cmd =~ s/\xf4\x8e\x97\x9f(..)/sprintf sprintf "\\x%02x", hex $1/ges; # f48e979f == 10e5df in utf-8 477 $cmd =~ s/\xf4\x8e\x97\x9f(..)/sprintf sprintf "\\x%02x", hex $1/ges; # f48e979f == 10e5df in utf-8
469 478
470 $trace->(">mpv" => $cmd); 479 $trace->(">mpv" => $cmd);
508 517
509 } 518 }
510 519
511 delete $self->{pid}; 520 delete $self->{pid};
512 delete $self->{cmdcv}; 521 delete $self->{cmdcv};
522 delete $self->{evtid};
523 delete $self->{evtcb};
513 delete $self->{obsid}; 524 delete $self->{obsid};
514 delete $self->{obscb}; 525 delete $self->{obscb};
515 delete $self->{wbuf}; 526 delete $self->{wbuf};
516} 527}
517 528
630 &cmd->recv 641 &cmd->recv
631} 642}
632 643
633=item $mpv->bind_key ($INPUT => $string) 644=item $mpv->bind_key ($INPUT => $string)
634 645
635This is an extension implement by this module to make it easy to get key events. The way this is implemented 646This is an extension implement by this module to make it easy to get key
636is to bind a C<client-message> witha first argument of C<AnyEvent::MPV> and the C<$string> you passed. This C<$string> is then 647events. The way this is implemented is to bind a C<client-message> witha
637passed to the C<on_key> handle when the key is proessed, e.g.: 648first argument of C<AnyEvent::MPV> and the C<$string> you passed. This
649C<$string> is then passed to the C<on_key> handle when the key is
650proessed, e.g.:
638 651
639 my $mpv = AnyEvent::MPV->new ( 652 my $mpv = AnyEvent::MPV->new (
640 on_key => sub { 653 on_key => sub {
641 my ($mpv, $key) = @_; 654 my ($mpv, $key) = @_;
642 655
646 }, 659 },
647 ); 660 );
648 661
649 $mpv_>bind_key (ESC => "letmeout"); 662 $mpv_>bind_key (ESC => "letmeout");
650 663
664You cna find a list of key names L<in the mpv
665documentation|https://mpv.io/manual/stable/#key-names>.
666
651The key configuration is lost when F<mpv> is stopped and must be (re-)done 667The key configuration is lost when F<mpv> is stopped and must be (re-)done
652after every C<start>. 668after every C<start>.
653 669
654=cut 670=cut
655 671
658 674
659 $event =~ s/([^A-Za-z0-9\-_])/sprintf "\\x%02x", ord $1/ge; 675 $event =~ s/([^A-Za-z0-9\-_])/sprintf "\\x%02x", ord $1/ge;
660 $self->cmd (keybind => $key => "no-osd script-message AnyEvent::MPV key $event"); 676 $self->cmd (keybind => $key => "no-osd script-message AnyEvent::MPV key $event");
661} 677}
662 678
679=item [$guard] = $mpv->register_event ($event => $coderef->($mpv, $event, $data))
680
681This method registers a callback to be invoked for a specific
682event. Whenever the event occurs, it calls the coderef with the C<$mpv>
683object, the C<$event> name and the event object, just like the C<on_event>
684method.
685
686For a lst of events, see L<the mpv
687documentation|https://mpv.io/manual/stable/#list-of-events>. Any
688underscore in the event name is replaced by a minus sign, so you can
689specify event names using underscores for easier quoting in Perl.
690
691In void context, the handler stays registered until C<stop> is called. In
692any other context, it returns a guard object that, when destroyed, will
693unregister the handler.
694
695You can register multiple handlers for the same event, and this method
696does not interfere with the C<on_event> mechanism. That is, you can
697completely ignore this method and handle events in a C<on_event> handler,
698or mix both approaches as you see fit.
699
700=cut
701
663sub AnyEvent::MPV::Unobserve::DESTROY { 702sub AnyEvent::MPV::Unevent::DESTROY {
664 my ($mpv, $obscb, $obsid) = @{$_[0]}; 703 my ($evtcb, $event, $evtid) = @{$_[0]};
704 delete $evtcb->{$event}{$evtid};
705}
665 706
666 delete $obscb->{$obsid}; 707sub register_event {
708 my ($self, $event, $cb) = @_;
667 709
668 if ($obscb == $mpv->{obscb}) { 710 $event =~ y/_/-/;
669 $mpv->cmd (unobserve_property => $obsid+0); 711
670 } 712 my $evtid = ++$self->{evtid};
713 $self->{evtcb}{$event}{$evtid} = $cb;
714
715 defined wantarray
716 and bless [$self->{evtcb}, $event, $evtid], AnyEvent::MPV::Unevent::
671} 717}
672 718
673=item [$guard] = $mpv->observe_property ($name => $coderef->($mpv, $name, $value)) 719=item [$guard] = $mpv->observe_property ($name => $coderef->($mpv, $name, $value))
674 720
675=item [$guard] = $mpv->observe_property_string ($name => $coderef->($mpv, $name, $value)) 721=item [$guard] = $mpv->observe_property_string ($name => $coderef->($mpv, $name, $value))
718 764
719 () # ensure the above method is called in void context 765 () # ensure the above method is called in void context
720 } 766 }
721 767
722=cut 768=cut
769
770sub AnyEvent::MPV::Unobserve::DESTROY {
771 my ($mpv, $obscb, $obsid) = @{$_[0]};
772
773 delete $obscb->{$obsid};
774
775 if ($obscb == $mpv->{obscb}) {
776 $mpv->cmd (unobserve_property => $obsid+0);
777 }
778}
723 779
724sub _observe_property { 780sub _observe_property {
725 my ($self, $type, $property, $cb) = @_; 781 my ($self, $type, $property, $cb) = @_;
726 782
727 my $obsid = OBSID + ++$self->{obsid}; 783 my $obsid = OBSID + ++$self->{obsid};

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines