Thread FFmpeg::Stream::Video installieren
(20 answers)
Opened by cbxk1xg at 2010-10-05 18:16
So das ganze nochmal etwas anders:
Code (perl): (dl
)
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); } Aber ich hatte damit ganz ordentlich zu kämpfen. Das Problem war, dass GStremer intern durcheinander kam als ich "parsebin" als reinen Videodecoder einsetzte. Parsebin hat zwei ausgehenden "Pad"s und das habe ich nicht beachtet. Dadurch scheint GStreamer einige Daten und Referenzen zu früh zu löschen, sodass es bei mir immer wieder zu abstürzen kam. Da GStreamer intern über Threads arbeitet taten diese Fehler nur sporadisch und kaum wiederholbar und in einer breiten Variation an jeder Stelle des Codes auf. Wird die Pipeline über GStreamer::parse_launch gestartet, so werden die Plugins scheinbar ein ganz klein wenig anders behandelt und der Code war robuster. Leider gab es immer noch Probleme wenn man als Eventloop "Glib::MainLoop" nutzte. Das sollte kein Problem sein, wenn man die Plugins "korrekt" einsetzt. |