#!/usr/bin/perl use strict; use warnings; use Glib qw(TRUE FALSE filename_to_unicode); use GStreamer qw(-init GST_RANK_MARGINAL); # $Id$ my ($pipeline, @factories); # This function is called by the registry loader. Its return value # (TRUE or FALSE) decides whether the given feature will be included # in the list that we're generating further down. sub cb_feature_filter { my ($feature, $data) = @_; # we only care about element factories return FALSE unless ($feature -> isa("GStreamer::ElementFactory")); # only parsers, demuxers and decoders my $klass = $feature -> get_klass(); return FALSE if (index($klass, "Demux") == -1 && index($klass, "Decoder") == -1 && index($klass, "Parse") == -1); # only select elements with autoplugging rank my $rank = $feature -> get_rank(); return FALSE if ($rank < GST_RANK_MARGINAL); return TRUE; } # This function is called to sort features by rank. sub cb_compare_ranks { return $b -> get_rank() - $a -> get_rank(); } sub init_factories { # first filter out the interesting element factories @factories = GStreamer::RegistryPool -> feature_filter( \&cb_feature_filter, FALSE); # sort them according to their ranks @factories = sort cb_compare_ranks @factories; } my ($converter, $scale, $audiosink); sub cb_newpad { my ($element, $pad, $data) = @_; try_to_plug($pad, $pad -> get_caps()); } sub close_link { my ($srcpad, $sinkelement, $padname, @templlist) = @_; my $has_dynamic_pads = FALSE; printf "Plugging pad %s:%s to newly created %s:%s\n", $srcpad -> get_parent() -> get_name(), $srcpad -> get_name(), $sinkelement -> get_name(), $padname; # add the element to the pipeline and set correct state $sinkelement -> set_state("paused"); $pipeline -> add($sinkelement); $srcpad -> link($sinkelement -> get_pad($padname)); $pipeline -> sync_children_state(); # if we have static source pads, link those. If we have dynamic # source pads, listen for new-pad signals on the element foreach my $templ (@templlist) { my $direction = $templ -> get_direction(); my $presence = $templ -> get_presence(); # only sourcepads, no request pads next if ($direction ne "src" || $presence eq "request"); if ($presence eq "always") { my $pad = $sinkelement -> get_pad($templ -> get_name_template()); my $caps = $pad -> get_caps(); # link try_to_plug($pad, $caps); } elsif ($presence eq "sometimes") { $has_dynamic_pads = TRUE; } } # listen for newly created pads if this element supports that if ($has_dynamic_pads) { $sinkelement -> signal_connect(new_pad => \&cb_newpad); } } sub try_to_plug { my ($pad, $caps) = @_; my $parent = $pad -> get_parent(); # don't plug if we're already plugged if ($audiosink -> get_pad("sink") -> is_linked()) { printf "Omitting link for pad %s:%s because we're already linked\n", $parent -> get_name(), $pad -> get_name(); return; } # as said above, we only try to plug audio... Omit video my $mime = $caps -> get_structure(0) -> { name }; if (index($mime, "video") > -1) { printf "Omitting link for pad %s:%s because mimetype %s is non-audio\n", $parent -> get_name(), $pad -> get_name(), $mime; return; } # can it link to the audiopad? my $audiocaps = $audiosink -> get_pad("sink") -> get_caps(); my $res = $caps -> intersect($audiocaps); if ($res && !$res -> is_empty()) { print "Found pad to link to audiosink - plugging is now done\n"; close_link($pad, $converter, "sink", ()); close_link($converter -> get_pad("src"), $scale, "sink", ()); close_link($scale -> get_pad("src"), $audiosink, "sink", ()); return; } # try to plug from our list foreach my $factory (@factories) { foreach my $templ ($factory -> get_pad_templates()) { # find the sink template - need an always pad next if ($templ -> get_direction() ne "sink" || $templ -> get_presence() ne "always"); # can it link? my $res = $caps -> intersect($templ -> get_caps()); if ($res && !$res -> is_empty()) { # close link and return my $element = $factory -> create(undef); close_link($pad, $element, $templ -> get_name_template(), $factory -> get_pad_templates()); return; } # we only check one sink template per factory, so move on to the # next factory now last; } } # if we get here, no item was found printf "No compatible pad found to decode %s on %s:%s\n", $mime, $parent -> get_name(), $pad -> get_name(); } sub cb_typefound { my ($typefind, $probability, $caps, $data) = @_; printf "Detected media type %s\n", $caps -> to_string(); # actually plug now try_to_plug($typefind -> get_pad("src"), $caps); } sub cb_error { my ($pipeline, $source, $error, $debug, $data) = @_; printf "Error: %s\n", $error -> message(); } # init ourselves init_factories(); # args unless ($#ARGV == 0) { print "Usage: $0 \n"; exit -1; } # pipeline $pipeline = GStreamer::parse_launch( sprintf qq(filesrc location="%s" ! typefind name=tf), filename_to_unicode $ARGV[0]); $pipeline -> signal_connect(error => \&cb_error); my $typefind = $pipeline -> get_by_name("tf"); $typefind -> signal_connect(have_type => \&cb_typefound); ($converter, $scale, $audiosink) = GStreamer::ElementFactory -> make(audioconvert => "audio-converter", audioscale => "audio-scale", alsasink => "audiosink"); $audiosink -> set_state("paused"); $pipeline -> set_state("playing"); # run while ($pipeline -> iterate()) { } # exit $pipeline -> set_state("null");