Testing Gstmm Element seeking
- From: José Alburquerque <jaalburquerque cox net>
- To: Gtkmm Mailing List <gtkmm-list gnome org>
- Subject: Testing Gstmm Element seeking
- Date: Thu, 20 Dec 2007 16:36:01 -0500
Hi. I've been working on testing element seeking using gstmm and I've
made a few changes (attached) to gstmm. I also developed a mini gtkmm
application (included source files) that tests seeking and other things
the original ogg player uses, but I can't quite figure out how to
include it in the examples directory. Is it possible although it uses
gtkmm?
-Jose
Index: ChangeLog
===================================================================
--- ChangeLog (revision 109)
+++ ChangeLog (working copy)
@@ -1,3 +1,20 @@
+2007-12-20 José Alburquerque <jaalburquerque cox com>
+
+ * examples/ogg_player/main.cc: fixed time output formatting
+ * gst/gstmm.h: added <gstmm/query.h>
+ * gst/src/Makefile_list_of_hg.am_fragment: added query.hg to general
+ hg files
+ * gst/src/caps.hg: made some hidden methods public
+ * gst/src/clock.ccg: renamed get_millesconds() to more appropriate
+ name get_fractional_seconds(); added get_milliseconds(),
+ get_microseconds() and get_nanoseconds()
+ * gst/src/clock.hg: added declarations for get_microseconds(),
+ get_nanoseconds() and get_fractional_seconds()
+ * gst/src/element.hg: renamed seek_simple() method to seek()
+ (overloaded)
+ * gst/src/query.ccg: added new (empty) file
+ * gst/src/query.hg: added initial declaration for Gst::Query class
+
2007-12-13 José Alburquerque <jaalburquerque cox com>
* examples/ogg_player/main.cc: Changed pos and len to type gint64
Index: gst/src/element.hg
===================================================================
--- gst/src/element.hg (revision 109)
+++ gst/src/element.hg (working copy)
@@ -89,7 +89,7 @@
bool query_duration(Format& format) const;
_WRAP_METHOD(bool query_duration(Format& format, gint64& duration) const, gst_element_query_duration)
- _WRAP_METHOD(bool seek_simple(Format format, SeekFlags flags, const gint64& position), gst_element_seek_simple)
+ _WRAP_METHOD(bool seek(Format format, SeekFlags flags, const gint64& position), gst_element_seek_simple)
_WRAP_METHOD(bool seek(const double& rate, Format format, SeekFlags flags, SeekType current_type, const gint64& current_position, SeekType stop_type, const gint64& stop_position), gst_element_seek)
_IGNORE(gst_element_link, gst_element_get_compatible_pad, gst_element_link_many)
Index: gst/src/query.ccg
===================================================================
--- gst/src/query.ccg (revision 0)
+++ gst/src/query.ccg (revision 0)
@@ -0,0 +1,6 @@
+#include <gst/gstquery.h>
+
+namespace Gst
+{
+
+} //namesapce Gst
Index: gst/src/query.hg
===================================================================
--- gst/src/query.hg (revision 0)
+++ gst/src/query.hg (revision 0)
@@ -0,0 +1,15 @@
+#include <gstmm/miniobject.h>
+#include <gstmm/structure.h>
+#include <gstmm/wrap.h>
+_PINCLUDE(gstmm/private/miniobject_p.h)
+_DEFS(gstmm,gst)
+
+namespace Gst
+{
+class Query : public MiniObject
+{
+protected:
+ _CLASS_GSTMINIOBJECT(Query, GstQuery, GST_QUERY, Gst::MiniObject, GstMiniObject)
+};
+
+}//namespace Gst
Index: gst/src/caps.hg
===================================================================
--- gst/src/caps.hg (revision 109)
+++ gst/src/caps.hg (working copy)
@@ -8,12 +8,12 @@
class Caps
{
-public:
-
_CLASS_OPAQUE_REFCOUNTED(Caps, GstCaps, NONE, gst_caps_ref, gst_caps_unref)
_IGNORE(gst_caps_ref, gst_caps_unref)
+public:
//TODO: Why doesn't this use _WRAP_CREATE()?
+ //ANS: Could it be because there are two void methods that create a Caps? -Jose
static Glib::RefPtr<Caps> create_empty();
static Glib::RefPtr<Caps> create_any();
static Glib::RefPtr<Caps> create_full(Structure&);
Index: gst/src/clock.ccg
===================================================================
--- gst/src/clock.ccg (revision 109)
+++ gst/src/clock.ccg (working copy)
@@ -25,6 +25,24 @@
guint get_milliseconds(ClockTime time)
{
return GST_CLOCK_TIME_IS_VALID (time) ? \
+ (guint) ((((GstClockTime)(time)) / GST_MSECOND) % 1000) : 999;
+}
+
+guint get_microseconds(ClockTime time)
+{
+ return GST_CLOCK_TIME_IS_VALID (time) ? \
+ (guint) ((((GstClockTime)(time)) / GST_USECOND) % 1000) : 999;
+}
+
+guint get_nanoseconds(ClockTime time)
+{
+ return GST_CLOCK_TIME_IS_VALID (time) ? \
+ (guint) ((((GstClockTime)(time)) / GST_NSECOND) % 1000) : 999;
+}
+
+guint get_fractional_seconds(ClockTime time)
+{
+ return GST_CLOCK_TIME_IS_VALID (time) ? \
(guint) (((GstClockTime)(time)) % GST_SECOND) : 999999999;
}
Index: gst/src/clock.hg
===================================================================
--- gst/src/clock.hg (revision 109)
+++ gst/src/clock.hg (working copy)
@@ -26,6 +26,9 @@
guint get_minutes(ClockTime time);
guint get_seconds(ClockTime time);
guint get_milliseconds(ClockTime time);
+guint get_microseconds(ClockTime time);
+guint get_nanoseconds(ClockTime time);
+guint get_fractional_seconds(ClockTime time);
class Clock : public Object
{
Index: gst/src/Makefile_list_of_hg.am_fragment
===================================================================
--- gst/src/Makefile_list_of_hg.am_fragment (revision 109)
+++ gst/src/Makefile_list_of_hg.am_fragment (working copy)
@@ -4,8 +4,9 @@
files_posix_hg =
files_win32_hg =
-files_general_hg = enums.hg caps.hg clock.hg element.hg error.hg iterator.hg format.hg pad.hg \
- padtemplate.hg structure.hg systemclock.hg xml.hg bin.hg pipeline.hg bus.hg message.hg
+files_general_hg = enums.hg caps.hg clock.hg element.hg error.hg \
+ iterator.hg format.hg pad.hg padtemplate.hg query.hg structure.hg \
+ systemclock.hg xml.hg bin.hg pipeline.hg bus.hg message.hg
files_general_deprecated_hg =
Index: gst/gstmm.h
===================================================================
--- gst/gstmm.h (revision 109)
+++ gst/gstmm.h (working copy)
@@ -9,6 +9,7 @@
#include <gstmm/object.h>
#include <gstmm/pad.h>
#include <gstmm/pipeline.h>
+#include <gstmm/query.h>
#include <gstmm/structure.h>
#include <gstmm/systemclock.h>
Index: examples/ogg_player/main.cc
===================================================================
--- examples/ogg_player/main.cc (revision 109)
+++ examples/ogg_player/main.cc (working copy)
@@ -16,16 +16,18 @@
if (pipeline->query_position(fmt, pos)
&& pipeline->query_duration(fmt, len)) {
- std::cout << "Time: " << std::setfill('0') <<
+ std::cout << std::right << "Time: " << std::setfill('0') <<
std::setw(3) << Gst::get_hours(pos) << ":" <<
std::setw(2) << Gst::get_minutes(pos) << ":" <<
std::setw(2) << Gst::get_seconds(pos) << "." <<
- std::setw(9) << Gst::get_milliseconds(pos);
+ std::setw(9) << std::left << Gst::get_fractional_seconds(pos);
- std::cout << "/" << std::setw(3) << Gst::get_hours(len) << ":" <<
+ std::cout << std::right << "/" <<
+ std::setw(3) << Gst::get_hours(len) << ":" <<
std::setw(2) << Gst::get_minutes(len) << ":" <<
std::setw(2) << Gst::get_seconds(len) << "." <<
- std::setw(9) << Gst::get_milliseconds(len) << std::endl << std::flush;
+ std::setw(9) << std::left << Gst::get_fractional_seconds(len) <<
+ std::endl << std::flush;
}
return true;
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
* main.cc
* Copyright (C) José Alburquerque 2007 <jaalburquerque cox net>
*
* main.cc is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* main.cc is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gtkmm/main.h>
#include <gstmm/init.h>
#include <gstmm/element.h>
#include <gstmm/pipeline.h>
#include <iostream>
#include "PlayerWindow.h"
Glib::RefPtr<Gst::Pipeline> pipeline;
Glib::RefPtr<Gst::Element> decoder;
void on_parser_pad_added(const Glib::RefPtr<Gst::Pad>& newPad)
{
// We can now link this pad with the audio decoder
Glib::RefPtr<Gst::Pad> sinkPad = decoder->get_pad("sink");
newPad->link(sinkPad);
}
int
main (int argc, char *argv[])
{
Gtk::Main kit(argc, argv);
Gst::init(argc, argv);
// Create the pipeline
pipeline = Gst::Pipeline::create("audio-player");
// Create the elements
// Reads file from disk
Glib::RefPtr<Gst::Element> source = Gst::Element::create("filesrc", "file-source");
// Parses the ogg streams into elementary streams (note that an ogg file may contain a video stream too)
Glib::RefPtr<Gst::Element> parser = Gst::Element::create("oggdemux", "ogg-parser");
// Decodes a vorbis stream
decoder = Gst::Element::create("vorbisdec", "vorbis-decoder");
// Converts audio() to a format which can be used by the next element
Glib::RefPtr<Gst::Element> conv = Gst::Element::create("audioconvert", "converter");
// Outputs sound to an ALSA audio device
Glib::RefPtr<Gst::Element> sink = Gst::Element::create("alsasink", "alsa-output");
if (!pipeline || !source || !parser || !decoder || !conv || !sink)
{
std::cerr << "One element could not be created" << std::endl;
return -1;
}
// Put all elements in a pipeline:
try
{
pipeline->add(source)->add(parser)->add(decoder)->add(conv)->add(sink);
}
catch(const Glib::Error& ex)
{
std::cerr << "Error while adding elements to the pipeline: " << ex.what() << std::endl;
return -1;
}
// Link together:
source->link(parser);
// We cannot link the parser and decoder yet,
// because the parser uses dynamic pads. For that,
// we set a pad-added signal handler:
parser->signal_pad_added().connect( sigc::ptr_fun(&on_parser_pad_added) );
decoder->link(conv)->link(sink);
PlayerWindow mainWindow(source, pipeline);
kit.run(mainWindow);
// Clean up nicely:
pipeline->set_state(Gst::STATE_NULL);
return 0;
}
/***************************************************************************
* PlayerWindow.h
*
* Tue Dec 18 18:48:33 2007
* Copyright 2007 José Alburquerque
* <jaalburquerque cox net>
****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
*/
#ifndef _PLAYERWINDOW_H
#define _PLAYERWINDOW_H
#include <gtkmm/window.h>
#include <gtkmm/box.h>
#include <gtkmm/buttonbox.h>
#include <gtkmm/label.h>
#include <gtkmm/button.h>
#include <gtkmm/scale.h>
#include <gstmm/element.h>
#include <gstmm/pipeline.h>
class PlayerWindow : public Gtk::Window
{
public:
PlayerWindow(Glib::RefPtr<Gst::Element> sourceElement,
Glib::RefPtr<Gst::Pipeline> mainPipeline);
protected:
Gtk::VBox vBox;
Gtk::HButtonBox buttonBox;
Gtk::Label progressLabel;
Gtk::HScale progressScale;
Gtk::Button playButton;
Gtk::Button pauseButton;
Gtk::Button stopButton;
Gtk::Button rewindButton;
Gtk::Button forwardButton;
Gtk::Button openButton;
protected:
virtual bool on_bus_message(const Glib::RefPtr<Gst::Bus>& bus,
const Glib::RefPtr<Gst::Message>& message);
virtual void on_play(void);
virtual void on_pause(void);
virtual void on_stop(void);
virtual bool on_scale_value_changed(Gtk::ScrollType type, double value);
virtual void on_rewind(void);
virtual void on_forward(void);
virtual void on_open(void);
protected:
bool update_stream_progress(void);
void display_label_progress(gint64 pos, gint64 len);
private:
Glib::RefPtr<Gst::Element> sourceElement;
Glib::RefPtr<Gst::Pipeline> mainPipeline;
gint64 duration;
sigc::connection progressConnection;
};
#endif /* _PLAYERWINDOW_H */
// PlayerWindow.cc
// Tue Dec 18 18:47:47 2007
// Copyright 2007 José Alburquerque
// <jaalburquerque cox net>
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
#include <gtkmm/stock.h>
#include <gtkmm/filechooserdialog.h>
#include <gstmm/clock.h>
#include <iostream>
#include <sstream>
#include <iomanip>
#include "PlayerWindow.h"
PlayerWindow::PlayerWindow(Glib::RefPtr<Gst::Element> sourceElement,
Glib::RefPtr<Gst::Pipeline> mainPipeline) :
vBox(false, 5),
progressLabel("000:00:00.000000000 / 000:00:00.000000000"),
playButton(Gtk::Stock::MEDIA_PLAY),
pauseButton(Gtk::Stock::MEDIA_PAUSE),
stopButton(Gtk::Stock::MEDIA_STOP),
rewindButton(Gtk::Stock::MEDIA_REWIND),
forwardButton(Gtk::Stock::MEDIA_FORWARD),
openButton(Gtk::Stock::OPEN)
{
set_title("Gstmm Ogg Player Example");
add(vBox);
vBox.pack_start(progressLabel);
vBox.pack_start(progressScale);
vBox.pack_start(buttonBox);
progressLabel.set_alignment(Gtk::ALIGN_CENTER);
progressScale.set_range(0, 1);
progressScale.set_draw_value(false);
progressScale.signal_change_value().connect(
sigc::mem_fun(*this, &PlayerWindow::on_scale_value_changed));
buttonBox.pack_start(playButton);
buttonBox.pack_start(pauseButton);
buttonBox.pack_start(stopButton);
buttonBox.pack_start(rewindButton);
buttonBox.pack_start(forwardButton);
buttonBox.pack_start(openButton);
playButton.signal_clicked().connect(sigc::mem_fun(*this,
&PlayerWindow::on_play));
pauseButton.signal_clicked().connect(sigc::mem_fun(*this,
&PlayerWindow::on_pause));
stopButton.signal_clicked().connect(sigc::mem_fun(*this,
&PlayerWindow::on_stop));
rewindButton.signal_clicked().connect(sigc::mem_fun(*this,
&PlayerWindow::on_rewind));
forwardButton.signal_clicked().connect(sigc::mem_fun(*this,
&PlayerWindow::on_forward));
openButton.signal_clicked().connect(sigc::mem_fun(*this,
&PlayerWindow::on_open));
// get the bus from the pipeline
Glib::RefPtr<Gst::Bus> bus = mainPipeline->get_bus();
// Add a bus watch to receive messages from pipeline's bus
bus->add_watch( sigc::mem_fun( *this, &PlayerWindow::on_bus_message) );
progressScale.set_sensitive(false);
playButton.set_sensitive(false);
pauseButton.set_sensitive(false);
stopButton.set_sensitive(false);
rewindButton.set_sensitive(false);
forwardButton.set_sensitive(false);
this->sourceElement = sourceElement;
this->mainPipeline = mainPipeline;
show_all_children();
pauseButton.hide();
}
// This function is used to receive asynchronous messages from mainPipeline's bus
bool PlayerWindow::on_bus_message(const Glib::RefPtr<Gst::Bus>& bus,
const Glib::RefPtr<Gst::Message>& message)
{
switch (message->get_message_type())
{
case Gst::MESSAGE_EOS:
on_stop();
break;
case Gst::MESSAGE_ERROR:
{
Glib::RefPtr<Gst::MessageError> msgError =
Glib::RefPtr<Gst::MessageError>::cast_dynamic(message);
if(msgError)
{
Glib::Error err;
std::string debug; //TODO: Maybe this should be an optional parameter.
msgError->parse(err, debug);
std::cerr << "Error: " << err.what() << std::endl;
}
else
std::cerr << "Error." << std::endl;
on_stop();
break;
}
default:
{
//std::cout << "debug: on_bus_message: unhandled message=" << G_OBJECT_TYPE_NAME(message->gobj()) << std::endl;
}
break;
}
return true;
}
void PlayerWindow::on_play(void)
{
progressScale.set_sensitive(true);
playButton.set_sensitive(false);
pauseButton.set_sensitive(true);
stopButton.set_sensitive(true);
rewindButton.set_sensitive(true);
forwardButton.set_sensitive(true);
openButton.set_sensitive(false);
playButton.hide();
pauseButton.show();
// Call update_stream_progress function at a 200ms
// interval to regularly update the position of the stream
progressConnection = Glib::signal_timeout().connect(sigc::mem_fun(*this,
&PlayerWindow::update_stream_progress), 200);
// set Gstmm pipeline to play mode
mainPipeline->set_state(Gst::STATE_PLAYING);
}
void PlayerWindow::on_pause(void)
{
playButton.set_sensitive(true);
pauseButton.set_sensitive(false);
pauseButton.hide();
playButton.show();
// disconnect progress callback
progressConnection.disconnect();
// set Gstmm pipeline to pause mode
mainPipeline->set_state(Gst::STATE_PAUSED);
}
void PlayerWindow::on_stop(void)
{
progressScale.set_sensitive(false);
playButton.set_sensitive(true);
pauseButton.set_sensitive(false);
stopButton.set_sensitive(false);
rewindButton.set_sensitive(false);
forwardButton.set_sensitive(false);
openButton.set_sensitive(true);
pauseButton.hide();
playButton.show();
// disconnect progress callback
progressConnection.disconnect();
// set Gstmm pipeline to inactive mode
mainPipeline->set_state(Gst::STATE_NULL);
display_label_progress(0, duration);
progressScale.set_value(0);
}
bool PlayerWindow::on_scale_value_changed(Gtk::ScrollType type, double value)
{
gint64 newPos = gint64(value * duration);
if (mainPipeline->seek(Gst::FORMAT_TIME, Gst::SEEK_FLAG_FLUSH, newPos))
display_label_progress(newPos, duration);
else
std::cerr << "Could not seek!" << std::endl;
}
void PlayerWindow::on_rewind(void)
{
static const gint64 skipAmount = GST_SECOND * 2;
gint64 pos;
Gst::Format fmt = Gst::FORMAT_TIME;
if (mainPipeline->query_position(fmt, pos))
{
gint64 newPos = (pos > skipAmount) ? (pos - skipAmount) : 0;
if (mainPipeline->seek(Gst::FORMAT_TIME, Gst::SEEK_FLAG_FLUSH, newPos)) {
display_label_progress(newPos, duration);
progressScale.set_value(double(newPos) / duration);
}
else
std::cerr << "Could not seek!" << std::endl;
}
}
void PlayerWindow::on_forward(void)
{
static const gint64 skipAmount = GST_SECOND * 3;
gint64 pos;
Gst::Format fmt = Gst::FORMAT_TIME;
if (mainPipeline->query_position(fmt, pos))
{
gint64 newPos = ((pos + skipAmount) < duration) ? (pos + skipAmount) :
duration;
if (mainPipeline->seek(Gst::FORMAT_TIME, Gst::SEEK_FLAG_FLUSH, newPos))
{
progressScale.set_value(double(newPos) / duration);
display_label_progress(newPos, duration);
}
else
std::cerr << "Could not seek!" << std::endl;
}
}
void PlayerWindow::on_open(void)
{
static Glib::ustring workingDir = Glib::get_home_dir();
Gtk::FileChooserDialog chooser(*this,
"Select Ogg file", Gtk::FILE_CHOOSER_ACTION_OPEN);
Gtk::FileFilter filter;
filter.add_mime_type("application/ogg");
filter.set_name("Ogg files");
chooser.set_filter(filter);
chooser.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
chooser.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
chooser.set_current_folder(workingDir);
int response = chooser.run();
if (response == Gtk::RESPONSE_OK) {
workingDir = chooser.get_current_folder();
// Set filename property on the file source. Also add a message handler:
sourceElement->set_property("location", chooser.get_filename());
set_title(Glib::filename_display_basename(chooser.get_filename()));
playButton.set_sensitive(true);
display_label_progress(0, 0);
}
}
bool PlayerWindow::update_stream_progress(void)
{
Gst::Format fmt = Gst::FORMAT_TIME;
gint64 pos = 0;
if (mainPipeline->query_position(fmt, pos)
&& mainPipeline->query_duration(fmt, duration)) {
progressScale.set_value(double(pos) / duration);
display_label_progress(pos, duration);
}
return true;
}
void PlayerWindow::display_label_progress(gint64 pos, gint64 len) {
std::ostringstream locationStream (std::ostringstream::out);
std::ostringstream durationStream (std::ostringstream::out);
locationStream << std::right << std::setfill('0') <<
std::setw(3) << Gst::get_hours(pos) << ":" <<
std::setw(2) << Gst::get_minutes(pos) << ":" <<
std::setw(2) << Gst::get_seconds(pos) << "." <<
std::setw(9) << std::left << Gst::get_fractional_seconds(pos);
durationStream << std::right << std::setfill('0') <<
std::setw(3) << Gst::get_hours(len) << ":" <<
std::setw(2) << Gst::get_minutes(len) << ":" <<
std::setw(2) << Gst::get_seconds(len) << "." <<
std::setw(9) << std::left << Gst::get_fractional_seconds(len);
progressLabel.set_text(locationStream.str() + " / " + durationStream.str());
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]