Skip to content

Commit 6414b44

Browse files
committed
update tutorial 4 and add CPP example
1 parent 6e77847 commit 6414b44

File tree

7 files changed

+265
-56
lines changed

7 files changed

+265
-56
lines changed

subprojects/basic01/helloworld.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Glib::RefPtr<Glib::MainLoop> mainloop;
3232
bool on_bus_message(const Glib::RefPtr<Gst::Bus>& /* bus */,
3333
const Glib::RefPtr<Gst::Message>& message)
3434
{
35-
switch(message->get_message_type()) {
35+
switch (message->get_message_type()) {
3636
case Gst::MESSAGE_EOS:
3737
std::cout << std::endl << "End of stream" << std::endl;
3838
mainloop->quit();
@@ -42,7 +42,7 @@ bool on_bus_message(const Glib::RefPtr<Gst::Bus>& /* bus */,
4242
Glib::RefPtr<Gst::MessageError> msgError =
4343
Glib::RefPtr<Gst::MessageError>::cast_static(message);
4444

45-
if(msgError)
45+
if (msgError)
4646
{
4747
Glib::Error err;
4848
err = msgError->parse_error();
@@ -66,7 +66,7 @@ bool on_bus_message(const Glib::RefPtr<Gst::Bus>& /* bus */,
6666
int main(int argc, char** argv)
6767
{
6868
// Check input arguments:
69-
if(argc < 2)
69+
if (argc < 2)
7070
{
7171
std::cout << "Usage: " << argv[0] << " <media file or uri>" << std::endl;
7272
std::cout << "example uri https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm" << std::endl;
@@ -83,21 +83,21 @@ int main(int argc, char** argv)
8383
Glib::RefPtr<Gst::Element> playbin = Gst::ElementFactory::create_element("playbin");
8484
#endif
8585

86-
if(!playbin)
86+
if (!playbin)
8787
{
88-
std::cerr << "The playbin2 element could not be created." << std::endl;
88+
std::cerr << "The playbin element could not be created." << std::endl;
8989
return EXIT_FAILURE;
9090
}
9191

9292
// Take the commandline argument and ensure that it is a uri:
9393
Glib::ustring uri;
9494

95-
if(gst_uri_is_valid(argv[1]))
95+
if (gst_uri_is_valid(argv[1]))
9696
uri = argv[1];
9797
else
9898
uri = Glib::filename_to_uri(argv[1]);
9999

100-
// Set the playbyin2's uri property.
100+
// Set the playbin's uri property.
101101
playbin->set_property("uri", uri);
102102

103103
// Create the main loop.

subprojects/basic02/basic-tutorial-2.cpp

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,31 +24,30 @@ bool bus_message_watch(const Glib::RefPtr<Gst::Bus>& /* bus */,
2424
std::cout << "Source object: " << message->get_source()->get_name() << std::endl;
2525
}
2626

27-
switch (message->get_message_type())
28-
{
29-
// Handle ERROR message - print error and debug information
30-
case Gst::MESSAGE_ERROR:
31-
{
32-
auto error_msg = Glib::RefPtr<Gst::MessageError>::cast_static(message);
33-
std::cout << "Error: " << error_msg->parse_error().what() << std::endl;
34-
std::cout << "Debug: " << error_msg->parse_debug() << std::endl;
35-
break;
36-
}
37-
// Handle EOS message - quit the loop
38-
case Gst::MESSAGE_EOS:
39-
main_loop->quit();
40-
break;
41-
// Handle state changed message - print details
42-
case Gst::MESSAGE_STATE_CHANGED:
43-
{
44-
auto state_changed_msg = Glib::RefPtr<Gst::MessageStateChanged>::cast_static(message);
45-
std::cout << "Old state: " << Gst::Enums::get_name(state_changed_msg->parse_old_state()) << std::endl;
46-
std::cout << "New state: " << Gst::Enums::get_name(state_changed_msg->parse_new_state()) << std::endl;
47-
break;
48-
}
49-
// Unhanlded messages
50-
default:
51-
break;
27+
switch (message->get_message_type()) {
28+
// Handle ERROR message - print error and debug information
29+
case Gst::MESSAGE_ERROR:
30+
{
31+
auto error_msg = Glib::RefPtr<Gst::MessageError>::cast_static(message);
32+
std::cout << "Error: " << error_msg->parse_error().what() << std::endl;
33+
std::cout << "Debug: " << error_msg->parse_debug() << std::endl;
34+
break;
35+
}
36+
// Handle EOS message - quit the loop
37+
case Gst::MESSAGE_EOS:
38+
main_loop->quit();
39+
break;
40+
// Handle state changed message - print details
41+
case Gst::MESSAGE_STATE_CHANGED:
42+
{
43+
auto state_changed_msg = Glib::RefPtr<Gst::MessageStateChanged>::cast_static(message);
44+
std::cout << "Old state: " << Gst::Enums::get_name(state_changed_msg->parse_old_state()) << std::endl;
45+
std::cout << "New state: " << Gst::Enums::get_name(state_changed_msg->parse_new_state()) << std::endl;
46+
break;
47+
}
48+
// Unhanlded messages
49+
default:
50+
break;
5251
}
5352

5453
return true;

subprojects/basic03/basic-tutorial-3.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ Glib::RefPtr<Glib::MainLoop> mainloop;
1515
bool on_bus_message(const Glib::RefPtr<Gst::Bus>& /* bus */,
1616
const Glib::RefPtr<Gst::Message>& message)
1717
{
18-
switch(message->get_message_type())
19-
{
18+
switch (message->get_message_type()) {
2019
case Gst::MESSAGE_EOS:
2120
std::cout << std::endl << "End of stream" << std::endl;
2221
mainloop->quit();
@@ -124,7 +123,7 @@ int main(int argc, char** argv)
124123
std::cout << "Exception while linking elements: " << ex.what() << std::endl;
125124
}
126125

127-
// Set the playbyin2's uri property.
126+
// Set the uri property.
128127
source->set_property("uri", uri);
129128
// Signal handler for on-pad-added signal of source element
130129
// Here we use lambda to expose local variables that are needed

subprojects/basic03/dynamic_src.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,14 @@ int main(int argc, char** argv)
125125
return EXIT_FAILURE;
126126
}
127127

128-
// Set the playbyin2's uri property.
128+
// Set the URI to play
129129
source->set_property("pattern", 0);
130130

131131
// Create the main loop.
132132
mainloop = Glib::MainLoop::create();
133133

134134
// Get the bus and watch the messages
135-
Glib::RefPtr<Gst::Bus> bus {pipeline->get_bus()};
135+
RefPtr<Gst::Bus> bus {pipeline->get_bus()};
136136
bus->add_watch(sigc::ptr_fun(&on_bus_message));
137137

138138
// start play back and listen to events
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/* gstreamermm - a C++ wrapper for gstreamer
2+
*
3+
* Basic Tutorial 4: Time management
4+
*
5+
* This tutorial shows how to use GStreamer time-related facilities. In particular:
6+
* - How to query the pipeline for information like stream position or duration.
7+
* - How to seek (jump) to a different position (time) inside the stream.
8+
*/
9+
10+
#include <gstreamermm.h>
11+
#include <glibmm/main.h>
12+
#include <iostream>
13+
#include <iomanip>
14+
#include <cstdlib>
15+
16+
using Glib::RefPtr;
17+
18+
// Expose objects to be used in callbacks
19+
RefPtr<Glib::MainLoop> mainloop;
20+
RefPtr<Gst::Element> playbin;
21+
static bool playing {false};
22+
static bool seekable {false};
23+
static bool seek_done {false};
24+
static gint64 duration {(gint64)Gst::CLOCK_TIME_NONE};
25+
26+
static std::ostringstream format_gst_time(gint64 gst_time)
27+
{
28+
std::ostringstream oss_gst_time (std::ostringstream::out);
29+
30+
oss_gst_time << std::right << std::setfill('0') <<
31+
std::setw(3) << Gst::get_hours(gst_time) << ":" <<
32+
std::setw(2) << Gst::get_minutes(gst_time) << ":" <<
33+
std::setw(2) << Gst::get_seconds(gst_time) << "." <<
34+
std::setw(9) << std::left << Gst::get_fractional_seconds(gst_time);
35+
return oss_gst_time;
36+
}
37+
38+
// This function is used to receive asynchronous messages in the main loop.
39+
bool on_bus_message(const RefPtr<Gst::Bus>&,
40+
const RefPtr<Gst::Message>& message)
41+
{
42+
switch (message->get_message_type()) {
43+
case Gst::MESSAGE_EOS:
44+
std::cout << std::endl << "End of stream" << std::endl;
45+
mainloop->quit();
46+
return false;
47+
case Gst::MESSAGE_ERROR:
48+
{
49+
RefPtr<Gst::MessageError> msgError {RefPtr<Gst::MessageError>::cast_static(message)};
50+
if (msgError)
51+
{
52+
Glib::Error err {msgError->parse_error()};
53+
std::string debug_info {msgError->parse_debug()};
54+
std::cerr << "Error received from element " << message->get_source()->get_name() << ": " <<
55+
err.what() << std::endl;
56+
if (!debug_info.empty())
57+
std::cout << "Debugging information: " << debug_info << std::endl;
58+
}
59+
else
60+
{
61+
std::cerr << "Error." << std::endl;
62+
}
63+
mainloop->quit();
64+
return false;
65+
}
66+
case Gst::MESSAGE_DURATION_CHANGED:
67+
/* The duration has changed, mark the current one as invalid */
68+
duration = Gst::CLOCK_TIME_NONE;
69+
break;
70+
case Gst::MESSAGE_STATE_CHANGED:
71+
{
72+
// We are only interested in state-changed messages from the playbin
73+
if (RefPtr<Gst::Element>::cast_dynamic(message->get_source()) == playbin)
74+
{
75+
auto state_get_name = [] (Gst::State state) -> std::string {
76+
return gst_element_state_get_name(static_cast<GstState>(state));
77+
};
78+
RefPtr<Gst::MessageStateChanged> msgSC {RefPtr<Gst::MessageStateChanged>::cast_static(message)};
79+
Gst::State old_state {msgSC->parse_old_state()};
80+
Gst::State new_state {msgSC->parse_new_state()};
81+
std::cout << "Pipeline state changed: " <<
82+
state_get_name(old_state) << " -> " <<
83+
state_get_name(new_state) << std::endl;
84+
/* Remember whether we are in the PLAYING state or not */
85+
playing = (new_state == Gst::STATE_PLAYING);
86+
if (playing)
87+
{
88+
/* We just moved to PLAYING. Check if seeking is possible */
89+
Gst::Format format {Gst::FORMAT_TIME};
90+
RefPtr<Gst::Query> query {Gst::Query::create_seeking(format)};
91+
if (playbin->query(query))
92+
{
93+
gint64 segment_start {0}, segment_end {0};
94+
RefPtr<Gst::QuerySeeking> seek_query = RefPtr<Gst::QuerySeeking>::cast_static(query);
95+
seek_query->parse(format, seekable, segment_start, segment_end);
96+
if (seekable)
97+
std::cout << "Seeking is ENABLED from " << format_gst_time(segment_start).str() <<
98+
" to " << format_gst_time(segment_end).str() << std::endl;
99+
else
100+
std::cout << "Seeking is DISABLED for this stream." << std::endl;
101+
}
102+
}
103+
}
104+
break;
105+
}
106+
default:
107+
//std::cout << "Unhandled message type: " << message->get_message_type() << std::endl;
108+
break;
109+
}
110+
111+
return true;
112+
}
113+
114+
bool on_timeout()
115+
{
116+
// only if playing
117+
if (playing)
118+
{
119+
/* Query the current position of the stream */
120+
gint64 position {0};
121+
if (!playbin->query_position(Gst::FORMAT_TIME, position))
122+
std::cerr << "Could not query current position." << std::endl;
123+
124+
/* If we didn't know it yet, query the stream duration */
125+
if (duration == (gint64)Gst::CLOCK_TIME_NONE)
126+
{
127+
if (!playbin->query_duration(Gst::FORMAT_TIME, duration))
128+
std::cerr << "Could not query current duration." << std::endl;
129+
}
130+
131+
/* Print current position and total duration */
132+
std::cout << format_gst_time(position).str() << "/" <<
133+
format_gst_time(duration).str() << "\r" << std::flush;
134+
135+
// If seeking is enabled, we have not done it yet, and the time is right, seek
136+
if (seekable && !seek_done && position > 10 * (gint64)Gst::SECOND)
137+
{
138+
std::cout << "Reached 10s, performing seek..." << std::endl;
139+
playbin->seek(Gst::FORMAT_TIME, Gst::SEEK_FLAG_FLUSH | Gst::SEEK_FLAG_KEY_UNIT, 30 * Gst::SECOND);
140+
seek_done = true;
141+
}
142+
}
143+
144+
return true;
145+
}
146+
147+
int main(int argc, char** argv)
148+
{
149+
// Initialize gstreamermm:
150+
Gst::init(argc, argv);
151+
152+
// default uri
153+
Glib::ustring uri {"https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm"};
154+
155+
// Take the commandline argument and ensure that it is a uri:
156+
if (argc < 2)
157+
{
158+
std::cout << "Usage: " << argv[0] << " <uri>" << std::endl;
159+
std::cout << "missing uri argument, use default uri instead." << std::endl;
160+
}
161+
else if (Gst::URIHandler::uri_is_valid(argv[1]))
162+
{
163+
uri = argv[1];
164+
}
165+
166+
playbin = Gst::ElementFactory::create_element("playbin");
167+
168+
if (!playbin)
169+
{
170+
std::cerr << "The playbin element could not be created." << std::endl;
171+
return EXIT_FAILURE;
172+
}
173+
174+
// Set the URI to play
175+
playbin->set_property("uri", uri);
176+
177+
// Create the main loop.
178+
mainloop = Glib::MainLoop::create();
179+
180+
// Get the bus and watch the messages
181+
RefPtr<Gst::Bus> bus {playbin->get_bus()};
182+
bus->add_watch(sigc::ptr_fun(&on_bus_message));
183+
184+
// start play back and listen to events
185+
if (playbin->set_state(Gst::STATE_PLAYING) == Gst::STATE_CHANGE_FAILURE)
186+
{
187+
std::cerr << "Unable to set the pipeline to the playing state." << std::endl;
188+
return EXIT_FAILURE;
189+
}
190+
191+
// timeout of 100 milliseconds
192+
Glib::signal_timeout().connect(sigc::ptr_fun(&on_timeout), 100);
193+
194+
// Now set the playbin to the PLAYING state and start the main loop:
195+
std::cout << "Running." << std::endl;
196+
mainloop->run();
197+
198+
// Clean up nicely:
199+
std::cout << "Returned. Stopping pipeline." << std::endl;
200+
playbin->set_state(Gst::STATE_NULL);
201+
202+
return EXIT_SUCCESS;
203+
}

0 commit comments

Comments
 (0)