tutorials.de Buch-Aktion 05/2012
ERLEDIGT
JA
ANTWORTEN
2
ZUGRIFFE
1599
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    ToPeG ToPeG ist offline Grünschnabel
    Registriert seit
    Aug 2005
    Beiträge
    4
    Seit zweit Tagen versuche ich tiefer in die Programmierung von GStreamer ein zu steigen. Einfaches mit "Playbin" oder kurze Pipelines funktionieren. Doch nun habe ich versucht dieses in perl um zu setzten:
    Code :
    1
    
    gst-launch filesrc location=test.avi ! avidemux name=demux  demux.audio_00 ! queue ! fakesink   demux.video_00 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! xvimagesin
    über gst-launch funktioniert das und das video wird angezeigt.
    Die Ausgabe:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    Setting pipeline to PAUSED ...
    Pipeline is PREROLLING ...
    Pipeline is PREROLLED ...
    Setting pipeline to PLAYING ...
    New clock: GstSystemClock
    Got EOS from element "pipeline0".
    Execution ended after 19959987232 ns.
    Setting pipeline to PAUSED ...
    Setting pipeline to READY ...
    Setting pipeline to NULL ...
    Freeing pipeline ...

    Doch das selbe in perl funktioniert nicht. Das heißt ich bekomme kein Bild angezeigt und das Script beendet sich nicht wenn das Video abgelaufen sein sollte.

    Der Code:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    
    #!/usr/bin/perl
    use strict;
    use warnings;
    use utf8;
    use Glib qw(TRUE FALSE);
    use GStreamer;
     
    my $file='test.avi';
     
    my $loop = Glib::MainLoop -> new(undef, FALSE);
    GStreamer->init();
    my $pipeline = GStreamer::Pipeline -> new("mypipeline");
    $pipeline->get_bus()->add_watch( \&my_bus_callback, [$loop, $pipeline]);
     
    my (
        $src,$demux,
        $vqueue,$vdecode,$vfilter1,$vfilter2,$vsink,
        $aqueue,$asink,
      ) = GStreamer::ElementFactory -> make(
        filesrc          => "data_src",
        avidemux         => "data_dmux",
        queue            => "video_queue",
        decodebin        => "video_decoder",
        ffmpegcolorspace => "video_collorspace",
        videoscale       => "video_scale",
        xvimagesink      => "video_sink",
        queue            => "audio_queue",
        fakesink         => "audio_sink",
      );
     
    $pipeline->add($src,$demux);
    $src->link($demux);
     
    $pipeline->add($vqueue,$vdecode,$vfilter1,$vfilter2,$vsink);
    $vqueue->link($vdecode,$vfilter1,$vfilter2,$vsink);
     
    $pipeline->add($aqueue,$asink);
    $aqueue->link($asink);
     
    $demux->signal_connect(pad_added => \&new_pad, [$vqueue,$aqueue]);
     
     
    $src->set(location => $file);
    $pipeline->set_state("playing");
    $loop->run();
    $pipeline->set_state("null");
     
    ########################################################################
     
    sub new_pad
    {
      my $element=shift;
      my $pad=shift;
      my ($video_link_to, $audio_link_to)=@{shift()};
     
      if($pad->get_name() eq 'video_00')
      {
        $pad->link($video_link_to->get_pad('sink'));
        print "link ".$element->get_name()." video-pad to ".$video_link_to->get_name()."\n";
      }
      elsif($pad->get_name() eq 'audio_00')
      {
        $pad->link($audio_link_to->get_pad('sink'));
        print "link ".$element->get_name()." audio-pad to ".$audio_link_to->get_name()."\n";
      }
    }
     
    sub my_bus_callback
    {
      my $bus=shift;
      my $message=shift;
      my ($loop, $pipe)=@{shift()};
     
      if ($message -> type eq "warning")
      {
        print STDERR $message->error()."\n";
        print STDERR $message->debug()."\n";
      }
     
      elsif ($message->type eq "error")
      {
        print STDERR $message->error()."\n";
        print STDERR $message->debug()."\n";
        $loop -> quit();
      }
     
      elsif ($message->type eq "eos")
      { $loop -> quit(); }
     
      elsif($message->type eq "state-changed")
      {
        my $src=$message->src()->get_name() || '[UNKNOWN]';
        print qq(Object "$src" ).$message->new_state()."\n";
      }
     
      # remove message from the queue
      return TRUE;
    }

    Die Ausgabe:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    Object "audio_sink" ready
    Object "video_sink" ready
    Object "audio_queue" ready
    Object "video_scale" ready
    Object "video_collorspace" ready
    Object "fakesink" ready
    Object "typefind" ready
    Object "video_decoder" ready
    Object "video_queue" ready
    Object "data_dmux" ready
    Object "data_src" ready
    Object "mypipeline" ready
    Object "audio_queue" paused
    Object "video_scale" paused
    Object "video_collorspace" paused
    Object "typefind" paused
    Object "video_queue" paused
    Object "data_dmux" paused
    Object "data_src" paused
    link data_dmux video-pad to video_queue
    link data_dmux audio-pad to audio_queue
    Object "audio_sink" paused
    Object "ffdec_h2630" ready
    Object "ffdec_h2630" paused
    Object "fakesink" paused
    Object "video_decoder" paused
    Object "fakesink" ready
    Object "fakesink" null

    Ich hoffe jemand kann mir weiter helfen.
    Danke
     

  2. #2
    ToPeG ToPeG ist offline Grünschnabel
    Registriert seit
    Aug 2005
    Beiträge
    4
    Nach einigen versuchen kann ich sagen, dass sich "Glib::MainLoop" und GStreamer nicht vertragen. Aus irgend einem Grund scheint GStreamer oder MainLoop nicht Threadsave oder inkompatibel zu sein. Nicht nur das sich einiges nicht starten lässt, auch kommt es immer immer wieder zu Kopierfehlern zwischen den Threads und damit sporadisch Fehlermeldung . Nach viel probieren bin ich nun zu so einer Lösung gekommen:

    Das Script kopiert ein Frame aus einem Video und speichert es als jpg.
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    
    #!/usr/bin/perl
    use strict;
    use warnings;
    use utf8;
    use Glib qw(TRUE FALSE);
    use GStreamer -init;
     
    # eingabe datei
    my $file='test.avi';
    # ausgabe datei
    my $ofile='test.jpg';
    # position im video
    my $pos=3_000_000_000; # ns
    # höhe /breite
    my $scale_w=720;
    my $scale_h=510;
     
    my @scales;
    push(@scales,"width=$scale_w") if($scale_w);
    push(@scales,"height=$scale_h") if($scale_h);
     
    #pipeline erzeugen
    my $pipeline = GStreamer::parse_launch(sprintf(
            'filesrc location=%s ! avidemux name=data_demux '.
            'data_demux.audio_00 ! queue ! fakesink '.
            'data_demux.video_00 ! decodebin name=video_decode ! ffmpegcolorspace '.
            '! videoscale ! video/x-raw-yuv,%s ! jpegenc ! fakesink name=video_sink signal-handoffs=TRUE ',
          $file,join(',',@scales)));
     
    # der pipeline einen Namen geben
    $pipeline->set_name('my_pipeline');
     
    # Puffer für die Ausgabe
    my $buffer=undef;
     
    # Listener für Frame einrichten
    my $video_sink=$pipeline->get_by_name('video_sink');
    $video_sink->signal_connect(handoff => sub{
        return TRUE if($buffer);
     
        my $query=GStreamer::Query::Position->new('time');
        $video_sink->query($query);
        my (undef, $pos_now)=$query->position;
     
        return TRUE if($pos_now<$pos);
     
        $buffer=$_[1];
     
        return TRUE;
      });
     
    # video abspielen
    $pipeline->set_state("playing");
    my $seek=1;
    my $bus=$pipeline->get_bus();
    while (1)
    {
      # alle nahrichten vom bus holen
      my $message = $bus -> poll("any", 0);
     
      # Schleife beenden wenn wir ein Bild haben
      last if($buffer);
     
      # wenn keine Nachrichten warten
      unless (defined $message)
      {
        select(undef,undef,undef,0.25);
        next;
      }
     
     
      # beenden wenn das Video am Ende ist,
      # oder ein Fehler auftrat
      last if (
                $message->type & "eos"     ||
                $message->type & "error"   ||
                $message->type & "warning"
              );
     
     
      # wenn sich det Zusand eines pileelemts geändert hat
      if($message->type & "state-changed")
      {
        # Name des Elementes ermitteln
        my $name=$message->src()->get_name() || 'UNDEF';
        #print "$name => ".$message->new_state()."\n";
     
        # es wurde noch nicht zu der stelle gespringen,
        # der Name stimmt und die pipeline ist "playing"
        if($seek && $name eq 'my_pipeline' && $message->new_state() eq 'playing')
        {
          # zur gewünschten Stelle springen
          $pipeline->seek(1,'time','flush','set',$pos,'none',0) || last;
          $seek--;
        }
      }
    }
    # pipeline stoppen
    $pipeline->set_state("null");
     
    # wenn ein bild da ist
    if($buffer)
    {
      # bild in Datei schreiben.
      open(my $fh, '>', $ofile) or die("Error open $ofile! ($!)");
      binmode($fh);
      print $fh $buffer->data();
      close($fh);
    }
     

  3. #3
    ToPeG ToPeG ist offline Grünschnabel
    Registriert seit
    Aug 2005
    Beiträge
    4
    Ich konnte mich nicht damit zufrieden geben.
    Nach einigem Herumprobieren habe ich auch eine Lösung ohne "parse_launch" gefunden. Das Problem scheint zu sein, dass das Plugin "parsebin" es nicht mag als reiner Videodecoder eingesetzt zu werden. Ich vermute mal das "parse_launch" erkennt wenn ein Plugin mehr als einen "pad" anbietet und das anders behandelt. Die von "Hand" erzeugte Pipeline beachtete das gar nicht. Wenn Ich "parsebin" auch als Demuxer einsetze funktioniert alles wie es soll.

    Ein Hinweis in der Richtung wäre sicherlich sinnvoll.

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    
    #!/usr/bin/perl
    use strict;
    use warnings;
    use utf8;
    use Glib qw(TRUE FALSE);
    use GStreamer -init;
     
    # eingabe datei
    my $file='test.avi';
    # ausgabe datei
    my $ofile='test.jpg';
    # position im video
    my $pos=3_000_000_000; # ns
    my $scale_w=720;
    my $scale_h=210;
     
    my @scales=('video/x-raw-yuv');
    push(@scales,"width=$scale_w") if($scale_w);
    push(@scales,"height=$scale_h") if($scale_h);
     
    #pipeline erzeugen
    my $pipeline = GStreamer::Pipeline->new("my_pipeline");
    my( $src, $decoder,
        $vcolor, $vscale, $vcaps, $vjpeg, $vsink,
        $aqueue, $asink ) =
      GStreamer::ElementFactory -> make(
        filesrc          => "data_src",
        decodebin        => "data_decoder",
     
        ffmpegcolorspace => "video_colorspace",
        videoscale       => "video_scale",
        capsfilter       => "video_caps",
        jpegenc          => "video_jpeg",
        fakesink         => "video_sink",
     
        queue            => "audio_queue",
        fakesink         => "audio_sink",
      );
     
    $pipeline->add($src, $decoder, $vcolor, $vscale, $vcaps, $vjpeg, $vsink, $aqueue, $asink);
     
    $src   ->link($decoder);
    $vcolor->link($vscale, $vcaps, $vjpeg, $vsink);
    $aqueue->link($asink);
     
    $vcaps->set('caps', GStreamer::Caps->from_string(join(', ',@scales)));
     
    $pipeline->get_by_name('data_decoder')->signal_connect(pad_added => sub{
        my $element=shift;
        my $pad=shift;
     
        my $type='unknown';
        $type=lc($1) if($pad->get_caps()->to_string()=~m!^([^/]+)!);
     
        if($type eq 'video' || $type eq 'image')
        {
          $pad->link($vcolor->get_pad('sink'));
          #print "link ".$element->get_name()." video (".$pad->get_name().") to ".$vcolor->get_name()."\n";
        }
        elsif($type eq 'audio')
        {
          $pad->link($aqueue->get_pad('sink'));
          #print "link ".$element->get_name()." audio (".$pad->get_name().") to ".$aqueue->get_name()."\n";
        }
        else
        { print "not link $type from ".$pad->get_name()."\n"; }
      });
    $src->set('location' => $file);
     
    # Puffer für die Ausgabe
    my $buffer=undef;
     
    # Listener für Frame einrichten
    $vsink->set('signal-handoffs' => TRUE);
    $vsink->signal_connect(handoff => sub{
        return TRUE if($buffer);
     
        my $query=GStreamer::Query::Position->new('time');
        $vsink->query($query);
        my (undef, $pos_now)=$query->position;
     
        return TRUE if($pos_now<$pos);
     
        $buffer=$_[1];
     
        return TRUE;
      });
     
    # video abspielen
    $pipeline->set_state("playing");
    my $seek=1;
    my $bus=$pipeline->get_bus();
    while (1)
    {
      # alle nahrichten vom bus holen
      my $message = $bus -> poll("any", 0);
     
     
      # wenn keine Nachrichten warten
      unless (defined $message)
      {
        # Schleife beenden wenn wir ein Bild haben
        last if($buffer);
     
        select(undef,undef,undef,0.25);
        #print "WAIT ".time()."\n";
        next;
      }
     
     
      # beenden wenn das Video am Ende ist,
      # oder ein Fehler auftrat
      last if ( $message->type & "eos");
      if ( $message->type & "error"   || $message->type & "warning" )
      {
        print "ERROR:\n";
        print $message->error()."\n";
        print $message->debug()."\n";
        last;
      }
     
     
      # wenn sich det Zusand eines pileelemts geändert hat
      if($message->type & "state-changed")
      {
        # Name des Elementes ermitteln
        my $name=$message->src()->get_name() || 'UNDEF';
        #print "$name => ".$message->new_state()."\n";
     
        # es wurde noch nicht zu der stelle gespringen,
        # der Name stimmt und die pipeline ist "playing"
        if($seek && $name eq 'my_pipeline' && $message->new_state() eq 'playing')
        {
          # zur gewünschten Stelle springen
          $pipeline->seek(1,'time','flush','set',$pos,'none',0) || last;
          $seek--;
        }
      }
    }
    # pipeline stoppen
    $pipeline->set_state("null");
     
    # wenn ein bild da ist
    if($buffer)
    {
      # bild in Datei schreiben.
      #open(my $fh, '>', $ofile) or die("Error open $ofile! ($!)");
      open(my $fh, '| display -') or die("Error open $ofile! ($!)");
      binmode($fh);
      print $fh $buffer->data();
      close($fh);
    }


    EDIT:
    Ich denke so würde das auch über "Glib::MainLoop" funktionieren.
    Geändert von ToPeG (10.10.10 um 16:43 Uhr)
     

Ähnliche Themen

  1. GStreamer Pipeline startet nicht
    Von Der Wolf im Forum C/C++
    Antworten: 3
    Letzter Beitrag: 13.09.10, 13:50
  2. GStreamer und FFT
    Von Der Wolf im Forum C/C++
    Antworten: 8
    Letzter Beitrag: 30.08.10, 16:16
  3. [perl] *.sql in Perl-skript einbinden
    Von RedDevilGT im Forum CGI, Perl, Python, Ruby, Power Shell
    Antworten: 1
    Letzter Beitrag: 08.05.09, 10:11
  4. GStreamer und GTK
    Von MS47475 im Forum C/C++
    Antworten: 0
    Letzter Beitrag: 13.01.08, 20:03
  5. Anfänger.. was kann perl? - was ist perl?
    Von cameeel im Forum CGI, Perl, Python, Ruby, Power Shell
    Antworten: 12
    Letzter Beitrag: 09.02.05, 20:35

Stichworte