Ein Videomixer in Perl

Max Maischein

Frankfurt.pm

Vorgehen

  • Warum Videos bearbeiten?

  • Wie Videos bearbeiten?

  • Code

  • Hübsche Bilder

Ein Videomixer in Perl

Generative Videoinstallationen

  • Videoschleifen

  • Immer wiederholend

  • Aber nicht immer gleich

Videos zusammensetzen mit Perl

  • Offline mit ffmpeg

  • Die Videos können nicht verfremdet werden

  • Keine Live-Bilder von der Webcam

  • Keine Filme von YouTube etc.

OpenGL

  • Fester endlicher Automat

  • Darstellung von 3D Grafik

  • 3D Grafik ist etwas mehr als 2D Grafik

  • (wie Videos)

OpenGL (2)

Video

OpenGL (2)

Video

Webcam

OpenGL (2)

Video

Webcam

Logo

OpenGL (2)

Video

Webcam

Logo

OpenGL als Rechenmaschine

OpenGL (2)

Video

Webcam

Logo

OpenGL als Rechenmaschine

OpenGL (2)

Video

Webcam

Logo

OpenGL als Rechenmaschine

Hardwareunterstützung statt Perl

Demo1

Blumen mit Logo-Überlagerung, TV-Effekt

OpenGL

Pipeline ursprünglich fest

Objekt rastern

OpenGL

Pipeline ursprünglich fest

Objekt rastern

Objekt texturieren

OpenGL

Pipeline ursprünglich fest

Objekt rastern

Objekt texturieren

Objekt darstellen

OpenGL Pipeline

  • Es gab nur wenige, vorgegebene Funktionen zum Kombinieren von Pixeln bei der Texturierung:

  • Addition, Multiplikation, Subtraktion, OR, XOR, AND

  • Maskierung

OpenGL Shader

  • Pipeline komplett programmierbar (seit OpenGL 2.0)

  • Programme heissen "Shader"

  • Parallele Verarbeitung

  • Verfremdungs- und Effektfilter

OpenGL Shader

Schwarzweissfilter

OpenGL Shader

Schwarzweissfilter

Kantenerkennung

OpenGL Shader

Schwarzweissfilter

Kantenerkennung

  • Chromakey / Bluescreen / Greenscreen

  • Statischen Hintergrund vom Bild abziehen

  • Crossfades zwischen Filmen

  • Zwei Filme anhand einer Maske/eines dritten Films ineinander übergehen lassen

Das Programm

Das Programm

Das Programm

Das Programm

Das Programm

Das Programm

Perl Filter

  • (Ring)Puffer

  • Speichert Einzelbilder zwischen

  • Aus ffmpeg (schnell)

  • Von der Grafikkarte (langsam)

Anwendungen für den Puffer

Anwendungen für den Puffer

Anwendungen für den Puffer

  • Delay (1 s)

  • Vielleicht für Webcam

Filter "Nervös"

Filter "Nervös"

Filter "Nervös"

Filter "Nervös"

Filter "Nervös"

Filter "Nervös"

Demo Nervös

Filter "Feedback"

Feedback

Der Code

  • OpenGL - OpenGL Anbindung

  • OpenGL::Shader - OpenGL Shader/Filter

  • Source::FFmpeg - der Decoder für die Videostreams

  • Filter::Buffer - Ringpuffer für Feedback/Delay

Das Hauptprogramm

  1. Filme öffnen (Source::FFmpeg)

  2. Mainloop

     1:    my $curr_texture;
     2:    for my $movie (@movies) {
     3:        # Bild in Grafikkarte laden
     4:        $curr_texture = $movie->tick();
     5:        # Bild in Ringpuffer laden
     6:        ...
     7:        
     8:        # Textur-Ping-Pong
     9:        for my $filter (@active_filters) {
    10:            $curr_texture = $filter->render($curr_texture);
    11:        };
    12:    };

Source::FFmpeg

  • Startet ffmpeg mit ein paar Kommandozeilenparametern

  • ffmpeg gibt den Film nach STDOUT aus

  • Liefert ein Filehandle zurück, aus dem die einzelnen Bilder gelesen werden

Filminformationen lesen

 1:  sub stream_info {
 2:    my ($self,$filename) = @_;
 3:    my ($child_in, $stream, $info);
 4:    my $cmd = sprintf
 5:        qq{bin\\ffmpeg-old.exe -t 0 -i "%s-},
 6:        $filename;
 7:    my $pid = open3 $child_in, $stream, $stream, $cmd
 8:        or die "Couldn't spawn '$cmd': $!/$?";

Filminformationen lesen (2)

 1:    while (my $line = <$stream>) {
 2:        #print ">>$line";
 3:        if ($line =~ /Video: .*/) {
 4:            chomp $line;
 5:            print ">$line<\n";
 6:            my ($width,$height) = $line =~ /(\d+)x(\d+)/;
 7:            return ($width,$height);
 8:        };
 9:    };
10:  };

Film einlesen

Parameterüberprüfung

 1:  sub new {
 2:    my ($class,%args) = @_;
 3:    my $file = delete $args{filename};
 4:    die "No file: '$file'"
 5:        unless -f $file;
 6:    warn "$file seems valid.";

Film einlesen (2)

Die Informationen über den Film werden gleich beim Start eingelesen

 1:    my ($width,$height) = $class->stream_info($file);
 2:    
 3:    my $cmd = sprintf
 4:          qq{bin\\ffmpeg-old.exe -i "%s}
 5:        . qq{-f rawvideo -pix_fmt rgb24 - |},
 6:        $file;
 7:    my $pid = open my $stream, "$cmd"
 8:        or die "Couldn't spawn '$cmd': $!/$?";
 9:    binmode $stream;

...

Einzelbild lesen

tick() wird aufgerufen, wenn ein neues Bild eingelesen werden soll

 1:  sub tick {
 2:    my ($self) = @_;
 1:    # Textur anlegen
 2:    my $texture_id = $self->texture_id;
 3:    if (! $texture_id) {
 4:        ($texture_id) = glGenTextures_p(1);
 5:        $self->texture_id($texture_id);
 6:    };

Einzelbild lesen (2)

 1:    # Daten lesen
 2:    my $frame;
 3:    read $self->stream, $frame, $self->width * $self->height * $self->depth
 4:        or die "Read failure";
 5:    
 6:    # Übergeben an OpenGL
 7:    OpenGL::Tools::set_texture_pixels(
 8:        texture => $texture_id,
 9:        pixels => $frame,
10:        ...
11:    );

Aufräumen

ffmpeg stoppen, wenn das Objekt weggeworfen wird

 1:  sub DESTROY {
 2:    if (my $pid = $_[0]->pid) {
 3:        kill 9 => $pid
 4:    };
 5:  };

Nachteile von FFmpeg+OpenGL

  • Kein Sound

  • Keine Pause/Vorwärts/Zurückspulen

  • Nicht Server-fähig wegen OpenGL

Vorteile von FFmpeg+OpenGL

  • Einfache Installation

  • Funktioniert

Danke

Fragen?