22 #include <gst/pbutils/missing-plugins.h> 24 #if defined(MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER) 25 #include <hybris/media/surface_texture_client_hybris.h> 26 #include <hybris/media/media_codec_layer.h> 28 #include "../util/uri_check.h" 36 void setup_video_sink_for_buffer_streaming(GstElement* pipeline)
40 IGBPWrapperHybris igbp = decoding_service_get_igraphicbufferproducer();
41 SurfaceTextureClientHybris stc = surface_texture_client_create_by_igbp(igbp);
44 surface_texture_client_set_hardware_rendering(stc, TRUE);
46 GstContext *context = gst_context_new(
"gst.mir.MirContext", TRUE);
47 GstStructure *structure = gst_context_writable_structure(context);
48 gst_structure_set(structure,
"gst_mir_context", G_TYPE_POINTER, stc, NULL);
51 gst_element_set_context(pipeline, context);
54 #else // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER 57 void setup_video_sink_for_buffer_streaming(GstElement*)
62 #endif // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER 66 bool is_mir_video_sink()
68 return g_strcmp0(::getenv(
"CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME"),
"mirsink") == 0;
82 static const std::string s{
"playbin"};
88 auto thiz =
static_cast<Playbin*
>(user_data);
96 if (user_data ==
nullptr)
113 std::placeholders::_1))),
128 throw std::runtime_error(
"Could not create pipeline for playbin.");
157 cout << func << endl;
159 cout <<
"pipeline: " << GST_OBJECT_REFCOUNT(pb.
pipeline) << endl;
161 cout <<
"video_sink: " << GST_OBJECT_REFCOUNT(pb.
video_sink) << endl;
163 cout <<
"audio_sink: " << GST_OBJECT_REFCOUNT(pb.
audio_sink) << endl;
170 print_refs(*
this,
"gstreamer::Playbin::~Playbin pipeline");
180 print_refs(*
this,
"gstreamer::Playbin::~Playbin pipeline");
186 std::cout <<
"Client died, resetting pipeline" << std::endl;
201 std::cout << __PRETTY_FUNCTION__ << std::endl;
202 auto ret = gst_element_set_state(
pipeline, GST_STATE_NULL);
205 case GST_STATE_CHANGE_FAILURE:
206 std::cout <<
"Failed to reset the pipeline state. Client reconnect may not function properly." << std::endl;
208 case GST_STATE_CHANGE_NO_PREROLL:
209 case GST_STATE_CHANGE_SUCCESS:
210 case GST_STATE_CHANGE_ASYNC:
213 std::cout <<
"Failed to reset the pipeline state. Client reconnect may not function properly." << std::endl;
224 if (!gst_is_missing_plugin_message(message))
227 gchar *desc = gst_missing_plugin_message_get_description(message);
228 std::cerr <<
"Missing plugin: " << desc << std::endl;
231 const GstStructure *msg_data = gst_message_get_structure(message);
232 if (g_strcmp0(
"decoder", gst_structure_get_string(msg_data,
"type")) != 0)
236 if (!gst_structure_get(msg_data,
"detail", GST_TYPE_CAPS, &caps, NULL)) {
237 std::cerr << __PRETTY_FUNCTION__ <<
": No detail" << std::endl;
241 GstStructure *caps_data = gst_caps_get_structure(caps, 0);
243 std::cerr << __PRETTY_FUNCTION__ <<
": No caps data" << std::endl;
247 const gchar *mime = gst_structure_get_name(caps_data);
248 if (strstr(mime,
"audio"))
250 else if (strstr(mime,
"video"))
253 std::cerr <<
"Missing decoder for " << mime << std::endl;
260 case GST_MESSAGE_ERROR:
263 case GST_MESSAGE_WARNING:
266 case GST_MESSAGE_INFO:
269 case GST_MESSAGE_STATE_CHANGED:
270 if (message.
source ==
"playbin") {
276 case GST_MESSAGE_ELEMENT:
279 case GST_MESSAGE_TAG:
282 if (gst_tag_list_get_string(message.
detail.
tag.
tag_list,
"image-orientation", &orientation))
286 g_free (orientation);
292 case GST_MESSAGE_ASYNC_DONE:
300 case GST_MESSAGE_EOS:
315 g_object_get (
pipeline,
"flags", &flags,
nullptr);
319 g_object_set (
pipeline,
"flags", flags,
nullptr);
321 if (::getenv(
"CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME") !=
nullptr)
324 ::getenv(
"CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME"),
327 std::cout <<
"audio_sink: " << ::getenv(
"CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME") << std::endl;
336 if (::getenv(
"CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME") !=
nullptr)
339 ::getenv(
"CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME"),
342 std::cout <<
"video_sink: " << ::getenv(
"CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME") << std::endl;
356 "No video sink configured for the current pipeline" 359 setup_video_sink_for_buffer_streaming(
pipeline);
364 g_object_set (
pipeline,
"volume", new_volume, NULL);
372 case media::Player::AudioStreamRole::alarm:
375 case media::Player::AudioStreamRole::alert:
378 case media::Player::AudioStreamRole::multimedia:
381 case media::Player::AudioStreamRole::phone:
392 if (g_strcmp0(orientation,
"rotate-0") == 0)
393 return media::Player::Orientation::rotate0;
394 else if (g_strcmp0(orientation,
"rotate-90") == 0)
395 return media::Player::Orientation::rotate90;
396 else if (g_strcmp0(orientation,
"rotate-180") == 0)
397 return media::Player::Orientation::rotate180;
398 else if (g_strcmp0(orientation,
"rotate-270") == 0)
399 return media::Player::Orientation::rotate270;
401 return media::Player::Orientation::rotate0;
408 std::cout <<
"Audio stream role: " << role_str << std::endl;
410 GstStructure *props = gst_structure_from_string (role_str.c_str(), NULL);
411 if (
audio_sink !=
nullptr && props !=
nullptr) {
412 g_object_set (
audio_sink,
"stream-properties", props, NULL);
415 "Warning: couldn't set audio stream role - couldn't get audio_sink from pipeline" <<
419 gst_structure_free (props);
430 gst_element_query_position (
pipeline, GST_FORMAT_TIME, &pos);
444 return static_cast<uint64_t
>(pos);
450 gst_element_query_duration (
pipeline, GST_FORMAT_TIME, &dur);
453 return static_cast<uint64_t
>(dur);
457 const std::string&
uri,
459 bool do_pipeline_reset)
461 gchar *current_uri =
nullptr;
462 g_object_get(
pipeline,
"current-uri", ¤t_uri, NULL);
467 if (current_uri and do_pipeline_reset)
470 std::string tmp_uri{uri};
472 if (uri_check->is_local_file())
474 if (uri_check->is_encoded())
479 std::cout <<
"File URI was encoded, now decoded: " << tmp_uri << std::endl;
485 g_object_set(
pipeline,
"uri", tmp_uri.c_str(), NULL);
502 if (g_object_class_find_property(G_OBJECT_GET_CLASS(source),
503 "cookies") != NULL) {
504 gchar ** cookies = g_strsplit(
request_headers[
"Cookie"].c_str(),
";", 0);
505 g_object_set(source,
"cookies", cookies, NULL);
511 if (g_object_class_find_property(G_OBJECT_GET_CLASS(source),
512 "user-agent") != NULL) {
513 g_object_set(source,
"user-agent",
request_headers[
"User-Agent"].c_str(), NULL);
520 gchar* data =
nullptr;
521 g_object_get(
pipeline,
"current-uri", &data,
nullptr);
523 std::string result((data ==
nullptr ?
"" : data));
531 static const std::chrono::nanoseconds state_change_timeout
536 std::chrono::milliseconds{5000}
539 auto ret = gst_element_set_state(
pipeline, new_state);
541 std::cout << __PRETTY_FUNCTION__ <<
": requested state change." << std::endl;
543 bool result =
false; GstState current, pending;
546 case GST_STATE_CHANGE_FAILURE:
547 result =
false;
break;
548 case GST_STATE_CHANGE_NO_PREROLL:
549 case GST_STATE_CHANGE_SUCCESS:
550 result =
true;
break;
551 case GST_STATE_CHANGE_ASYNC:
552 result = GST_STATE_CHANGE_SUCCESS == gst_element_get_state(
556 state_change_timeout.count());
562 if (result && new_state == GST_STATE_PLAYING)
571 catch (
const std::exception& e)
573 std::cerr <<
"Problem querying video dimensions: " << e.what() << std::endl;
577 std::cerr <<
"Problem querying video dimensions." << std::endl;
580 #ifdef DEBUG_GST_PIPELINE 581 std::cout <<
"Dumping pipeline dot file" << std::endl;
582 GST_DEBUG_BIN_TO_DOT_FILE((GstBin*)
pipeline, GST_DEBUG_GRAPH_SHOW_ALL,
"pipeline");
592 return gst_element_seek_simple(
595 (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
601 if (not
video_sink || not is_mir_video_sink())
602 throw std::runtime_error
604 "Missing video sink or video sink does not support query of width and height." 608 uint32_t video_width = 0, video_height = 0;
609 g_object_get (
video_sink,
"height", &video_height,
nullptr);
610 g_object_get (
video_sink,
"width", &video_width,
nullptr);
625 signals.on_video_dimensions_changed(new_dimensions);
630 GError *error =
nullptr;
633 std::unique_ptr<GFile, void(*)(void *)> file(
634 g_file_new_for_uri(uri.c_str()), g_object_unref);
635 std::unique_ptr<GFileInfo, void(*)(void *)> info(
637 file.get(), G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE
"," 638 G_FILE_ATTRIBUTE_ETAG_VALUE, G_FILE_QUERY_INFO_NONE,
642 return std::string();
644 return std::string(g_file_info_get_attribute_string(
645 info.get(), G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE));
651 return std::string();
653 std::string encoded_uri;
655 gchar *uri_scheme = g_uri_parse_scheme(uri.c_str());
657 if (uri_scheme and strlen(uri_scheme) > 0 and uri_check->is_encoded())
660 std::cout <<
"Is a URI and is already percent encoded" << std::endl;
665 else if (uri_scheme and strlen(uri_scheme) > 0 and !uri_check->is_encoded())
668 std::cout <<
"Is a URI and is not already percent encoded" << std::endl;
670 gchar *encoded = g_uri_escape_string(uri.c_str(),
676 return std::string();
678 encoded_uri.assign(encoded);
683 GError *error =
nullptr;
685 std::cout <<
"Is a path and is not already percent encoded" << std::endl;
687 gchar *str = g_filename_to_uri(uri.c_str(),
nullptr, &error);
691 return std::string();
693 encoded_uri.assign(str);
695 if (error !=
nullptr)
697 std::cerr <<
"Warning: failed to get actual track content type: " << error->message
702 return std::string(
"audio/video/");
704 gchar *escaped = g_uri_escape_string(encoded_uri.c_str(),
710 return std::string();
712 encoded_uri.assign(escaped);
724 return std::string();
726 gchar *decoded_gchar = g_uri_unescape_string(uri.c_str(),
nullptr);
728 return std::string();
730 const std::string decoded{decoded_gchar};
731 g_free(decoded_gchar);
738 return std::string();
740 const std::string encoded_uri{
encode_uri(uri)};
743 if (content_type.empty())
745 std::cerr <<
"Warning: failed to get actual track content type" << std::endl;
746 return std::string(
"audio/video/");
749 std::cout <<
"Found content type: " << content_type << std::endl;
761 std::cout <<
"Found audio content" << std::endl;
775 std::cout <<
"Found video content" << std::endl;
static std::string get_audio_role_str(core::ubuntu::media::Player::AudioStreamRole audio_role)
bool set_state_and_wait(GstState new_state)
static void source_setup(GstElement *, GstElement *source, gpointer user_data)
void setup_source(GstElement *source)
void set_uri(const std::string &uri, const core::ubuntu::media::Player::HeadersType &headers, bool do_pipeline_reset=true)
core::ubuntu::media::video::Dimensions get_video_dimensions() const
void process_message_element(GstMessage *message)
bool seek(const std::chrono::microseconds &ms)
uint64_t duration() const
core::Connection on_new_message_connection_async
static const std::string & pipeline_name()
void emit_video_dimensions_changed_if_changed(const core::ubuntu::media::video::Dimensions &new_dimensions)
bool can_play_streams() const
void set_lifetime(core::ubuntu::media::Player::Lifetime)
struct gstreamer::Playbin::@12 signals
void set_audio_stream_role(core::ubuntu::media::Player::AudioStreamRole new_audio_role)
bool is_missing_audio_codec
core::ubuntu::media::Player::Orientation orientation_lut(const gchar *orientation)
gstreamer::Bus & message_bus()
core::Signal< void > about_to_finish
void setup_pipeline_for_audio_video()
union gstreamer::Bus::Message::Detail detail
std::string get_file_content_type(const std::string &uri) const
std::string encode_uri(const std::string &uri) const
gulong source_setup_handler_id
core::ubuntu::media::video::Dimensions cached_video_dimensions
struct gstreamer::Bus::Message::Detail::Tag tag
boost::flyweight< std::string > source
bool is_audio_file(const std::string &uri) const
bool is_video_file(const std::string &uri) const
struct gstreamer::Bus::Message::Detail::ErrorWarningInfo error_warning_info
void set_volume(double new_volume)
void on_new_message_async(const Bus::Message &message)
void create_video_sink(uint32_t texture_id)
gulong about_to_finish_handler_id
bool is_missing_video_codec
core::Signal< Message > on_new_message_async
core::ubuntu::media::Player::HeadersType request_headers
uint64_t position() const
std::string decode_uri(const std::string &uri) const
MediaFileType media_file_type() const
struct gstreamer::Bus::Message::Detail::StateChanged state_changed
uint64_t previous_position
core::ubuntu::media::Player::Lifetime player_lifetime
std::string file_info_from_uri(const std::string &uri) const