Open Source im professionellen Einsatz

Newsletter abonnieren
Seite durchsuchen

HEFTARCHIV | NEWS | E-BIBLIOTHEK | VIDEO | BLOGS | WHITEPAPER | EVENTS | ACADEMY | ABO | SHOP

user friendly

  Home  »  Heft & Abo  »  Heftarchiv  »  2010  »  05  »  Episodenfilm  

RSS-Feed der aktuellen News von Linux-Magazin Online Folgen Sie Linux-Magazin Online auf Twitter
Diesen Artikel druckenDiesen Artikel weiterempfehlen Diesen Artikel kommentieren Newsletter abonnieren
Share/Bookmark

© Martin Wendring, Pixelio.de

Perl-Skript steuert Videowiedergabe

Episodenfilm

von Michael Schilli
Erschienen im Linux-Magazin 2010/05

Ein Perl-Skript mit GTK-2-Oberfläche merkt sich, wie weit sein Anwender gespeicherte Videos angesehen hat, und fährt auf Wunsch an der Stelle der letzten Unterbrechung wieder fort.

Wer wie ich im Bus auf dem Weg zur Arbeit mit dem Netbook Fernsehfilme ansieht, der muss mit an Sicherheit grenzender Wahrscheinlichkeit genau an der spannendsten Stelle umsteigen. Bleiben auf dem nächsten Teilstück nur 15 Minuten, dann lohnt es sich vielleicht nicht, nur eine weitere Szene des Films zu verfolgen. Stattdessen sehe ich mir dann auf der Kurzstrecke lieber die ebenfalls aufgezeichnete Tagesschau [2] an. Um den angefangenen Film aber später doch fertig zu sehen, genügt ein Klick (siehe Abbildung 1) und das Programm fährt genau dort fort, wo der User den Lauf vorher gestoppt hatte.

Das Durcheinander verhindern

Eine Zeitmaschine für gespeicherte Videos also, genau so, wie das mein Tivo [3] seit mehr als zehn Jahren zu Hause in San Francisco macht. Der digitale Videorekorder speichert eine Reihe von Fernsehsendungen und dazu jeweils den Zeitstempel der letzten Unterbrechung. Wählt man später wieder einen dieser Filme aus der Liste, nimmt der Recorder den Abspielvorgang genau dort wieder auf. I-Tunes oder Podcast-Software machen es ähnlich. Wie schwierig wäre es wohl, ein kurzes Skript mit derselben Funktion eigenhändig in Perl zu schreiben? Listing 1 zeigt mit weniger als 150 Zeilen das Ergebnis.


Abbildung 1: Die GTK-2-Oberfläche startet auf Mausdruck ausgewählte Videos an der Stelle der letzten Unterbrechung - beziehungsweise beim ersten Mal am Anfang.

Listing 1:

#!/usr/local/bin/perl -w
use strict;
use Gtk2 '-init';
use Gtk2::SimpleList;
use POE;
use POE::Wheel::Run;
use POE::Filter::Stream;
use YAML qw(LoadFile DumpFile);
 
my  ($home)    = glob "~";
my  $YAML_FILE = "$home/.ttv.dat";
my  $OFFSETS   = {};
my  $REWIND    = 10;

my @VIDEOS  = sort { -M $a <=> -M $b } 
              (<*.mp4>, <*.avi>);

if(-f $YAML_FILE) {
  $OFFSETS = LoadFile( $YAML_FILE );
}

POE::Session->create(
  inline_states => {
    _start     => \&ui_start,
    play_video => \&play_video,
    click      => \&click,
    output     => \&stdout_handler,
    play_ended => \&play_ended,
});

$poe_kernel->run();
exit 0;

###########################################
sub play_ended {
###########################################
  my($kernel, $heap) = @_[KERNEL, HEAP];

  DumpFile( $YAML_FILE, $OFFSETS );
  listbox_redraw($heap->{slist});
}

###########################################
sub click {
###########################################
  my($kernel, $session, $gtk_list_data) =
                 @_[KERNEL, SESSION, ARG1];

  my ($sl, $path) = @$gtk_list_data;
  my $row_ref = 
      $sl->get_row_data_from_path($path);

    $kernel->yield("play_video", 
                   $row_ref->[1]);
}

###########################################
sub ui_start {
###########################################
  my ($kernel, $session, $heap) = 
                 @_[KERNEL, SESSION, HEAP];

  $heap->{main_window} = 
            Gtk2::Window->new ('toplevel');

  $kernel->signal_ui_destroy(
                $heap->{main_window});

  $heap->{slist} = Gtk2::SimpleList->new (
    'Timer'    => 'text',
    'Video'    => 'text',
  );

  listbox_redraw( $heap->{slist} );

  $heap->{slist}->signal_connect(
      row_activated => 
          $session->callback("click"));

  $heap->{main_window}->add(
                         $heap->{slist});
  $heap->{main_window}->show_all;
}

###########################################
sub listbox_redraw {
###########################################
    my($slist) = @_;

    @{$slist->{data}} = (
       map { [ timer($_), $_ ] } @VIDEOS
    );
}

###########################################
sub timer {
###########################################
    my($video) = @_;

    my $sec = 0;
    $sec = $OFFSETS->{$video} if 
                exists  $OFFSETS->{$video};

    return sprintf("%02d:%02d:%02d", 
        int($sec/(60*60)), 
        ($sec/60)%60, $sec%60);
}

###########################################
sub play_video {
###########################################
  my ($kernel, $session, $heap, $video) =
           @_[KERNEL, SESSION, HEAP, ARG0];

  my $offset = 0;

  $offset = $OFFSETS->{ $video } - $REWIND 
    if exists $OFFSETS->{ $video } 
       and $OFFSETS->{ $video } > $REWIND;

  my $wheel =
    POE::Wheel::Run->new(
      Program     => "/usr/bin/mplayer",
      ProgramArgs => 
          ["-fs", "-ss", $offset, $video],
      StdoutFilter => 
               POE::Filter::Stream->new(),
      StdoutEvent => 'output',
      CloseEvent  => 'play_ended',
  );

  $heap->{video} = $video;
  $kernel->sig_child( $wheel->PID(), 
                      'sig_child' );

  $heap->{player} = $wheel;
}

###########################################
sub stdout_handler {
###########################################
    my ($heap, $input) = @_[HEAP, ARG0];

    if($input =~ /(?:^| )V:s*([d.]+)/m) {
        $OFFSETS->{$heap->{video}} = $1;
    }
}

Nun wäre es vermessen, ein Wunderwerk der Videotechnik wie Mplayer nachzubauen. Doch bringt der Tausendsassa ja glücklicherweise bereits alle Voraussetzungen für eine Zeitmaschinensteuerung mit: Wie Abbildung 2 zeigt, zählt der laufende Mplayer stetig die verstrichenen Videosekunden hoch, es ist also für ein Steuerprogramm relativ einfach festzustellen, wie weit der Player in einem Film fortgeschritten ist. Dabei darf der User sogar mit den [Page up]- und [Page down]-Tasten während der Vorführung wild im Video hin und her springen. Eine zweite Voraussetzung für die Fernsteuerung durch ein externes Programm wie das vorgestellte Perl-Skript ist die Option »-ss n«, die den Player mit einer angefügten Sekundenzahl anweist, das Video nicht von Anfang an abzuspielen, sondern die ersten n Sekunden zu überspringen. Damit ist auch schon klar, wie »ttv« funktioniert: Die GTK-2-getriebene Benutzeroberfläche wartet darauf, dass der User ein Video doppelklickt. Ist es das erste Mal, wirft das GUI den Mplayer an und lässt ihn das Video von Anfang an abspielen. Während der Player arbeitet und der User den laufenden Film genießt, greift das Skript über Mplayers Standardausgabe die verstreichenden Videosekunden ab und speichert diese laufend zwischen.


Abbildung 2: Mplayer zählt während des Laufs die Sekunden des Videos auf der Standardausgabe hoch. Das »ttv«-Skript greift die Daten von dort ab.

Bricht der User den Abspielvorgang ab (zum Beispiel indem er im Mplayer-Fenster die Taste [Q] drückt), taucht die grafische Oberfläche wieder auf und das Skript legt die Abspieldauer unter dem Namen des Videos in der YAML-Datei »~/.ttv.dat« im Homeverzeichnis ab (Abbildung 3).


Abbildung 3: In der YAML-Datei »~/ttv.dat« legt das Skript die Spieldauer angespielter Videos fest. Hier nicht gespeicherte Videos spielt es von Anfang an ab, falls der User sie auswählt.

Tanz auf fremden Hochzeiten

Erfahrene Snapshot-Leser ahnen schon, dass ich die Steuerung der GUI-Komponenten im ruckelfreien Zusammenspiel mit einem extern aufgerufenen Programm wie Mplayer wieder einmal mit dem Event-basierten Perl-Framework POE vom CPAN realisiere. Wie auch bei Terminalsteuerungen auf Curses-Basis hopst POE mit allen erdenklichen GUI-Eventschleifen im Takt und eignet sich hervorragend dazu, quasi-parallele Prozesse zu steuern. In diesem Fall startet das GUI-Skript den Videospieler hinter den Kulissen tatsächlich als separaten Prozess, aber im Hintergrund greift POE im robusten und eleganten Single-Process-/Single-Thread-Verfahren dessen Ausgabedaten ab, springt Callback-Handler an und kon- trolliert auch, ob der Player überhaupt noch läuft oder ob der User ihn nicht etwa schon abgeschaltet hat.

Da Zeile 3 von »ttv« das GTK-2-Modul vor den POE-Modulen anfordert, ist POE darüber informiert, dass nicht seine eigene Eventschleife den Prozess steuern wird, sondern GTK 2 mit dem CPAN-Modul POE::Loop::Glib als unsichtbarer Brücke. Zeile 11 legt den Pfad der YAML-Datei fest, in der das Skript später den Hash-Inhalt der Referenz »$OFFSETS« speichert. Die Datenstruktur weist Videodateinamen jeweils einer Fließkommazahl zu, die die bereits abgespielten Sekunden angibt.

Die globale Variable »$REWIND« gibt an, dass das Skript jeweils 10 Sekunden zurückspult, bevor es wieder mitten in ein früher unterbrochenes Videos hineinspringt. Das gibt dem Zuschauer die Ge- legenheit, im Ablauf des Filmgeschehens schnell wieder Fuß zu fassen. Verfügbare Videos sucht Zeile 15 im aktuellen Verzeichnis als MP4- und AVI-Dateien zusammen. Sie ist unter Umständen anzupassen, falls der User andere Formate bevorzugt.

Sie können diesen Artikel als PDF für 99 Cent kaufen. Klicken Sie dazu einfach auf eine der beiden Bezahloptionen Paypal oder ClickandBuy.


Diesen Artikel druckenDiesen Artikel weiterempfehlen Diesen Artikel kommentieren Newsletter abonnieren
Share/Bookmark
Ähnliche Artikel
Ich glotz' TV Digitaler Internet-Videorecorder in Perl
Netz-Journal Perl-Skript für periodische Kommandoaufrufe
Heilig nach Punkten Messenger-Plugin verschafft Vorteil durch Webseiten-Überwachung
Am Fließband Automatisiert Zeitschriftenartikel in PDF-Files konvertieren
Das Log als Ohrwurm Perl-Skript realisiert das singende, klingende Internet
Asyl für Django Webprogrammierung in Python/Django und PHP
Whitepaper
Open Source Datenintegration in der Praxis: Fallstudien und Anwendungsbeispiele

Über die letzten Jahre hinweg haben sich Open Source Lösungen als fester Bestandteil des gesamten Datenintegrationsmarktes etabliert. Viele Unternehmen haben bereits das Open Source Modell für Ihre Datenintegrationsprojekte aufgegriffen. Das vorliegende White Paper illustriert anhand ausgewählter Fallstudien und Anwendungsbeispiele die Implementierung von Open Source Datenintegration in der Praxis und benennt die daraus resultierenden Vorteile.

Download PDF (Registrierung erforderlich)
The Role of Open Source in Data Integration

Obwohl in den letzten Jahren viele technische Fortschritte erzielt werden konnten, verfügen die meisten Datenintegrationsprozesse nach wie vor nur über eine sehr begrenzte Automatisierung. Das vorliegende White Paper von dem Industry Analyst Mark Madson wird zunächst ein grundlegendes Verständnis von Daten Integration vermitteln, die Vorzüge von Open Source Lösungen für Daten Integration erläutern und Ihnen professionelle Empfehlungen geben, damit Sie Ihre Integrationsjobs noch einfacher und produktiver gestalten können.

Download PDF (Registrierung erforderlich)
Kommentare (0)