ERLEDIGT
JA
JA
ANTWORTEN
2
2
ZUGRIFFE
1599
1599
EMPFEHLEN
-
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:
über gst-launch funktioniert das und das video wird angezeigt.Code :1
gst-launch filesrc location=test.avi ! avidemux name=demux demux.audio_00 ! queue ! fakesink demux.video_00 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! xvimagesin
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
-
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); }
-
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
-
GStreamer Pipeline startet nicht
Von Der Wolf im Forum C/C++Antworten: 3Letzter Beitrag: 13.09.10, 13:50 -
GStreamer und FFT
Von Der Wolf im Forum C/C++Antworten: 8Letzter Beitrag: 30.08.10, 16:16 -
[perl] *.sql in Perl-skript einbinden
Von RedDevilGT im Forum CGI, Perl, Python, Ruby, Power ShellAntworten: 1Letzter Beitrag: 08.05.09, 10:11 -
GStreamer und GTK
Von MS47475 im Forum C/C++Antworten: 0Letzter Beitrag: 13.01.08, 20:03 -
Anfänger.. was kann perl? - was ist perl?
Von cameeel im Forum CGI, Perl, Python, Ruby, Power ShellAntworten: 12Letzter Beitrag: 09.02.05, 20:35





Zitieren
Login





