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> 35 void setup_video_sink_for_buffer_streaming(GstElement* pipeline)
39 IGBPWrapperHybris igbp = decoding_service_get_igraphicbufferproducer();
40 SurfaceTextureClientHybris stc = surface_texture_client_create_by_igbp(igbp);
43 surface_texture_client_set_hardware_rendering(stc, TRUE);
45 GstContext *context = gst_context_new(
"gst.mir.MirContext", TRUE);
46 GstStructure *structure = gst_context_writable_structure(context);
47 gst_structure_set(structure,
"gst_mir_context", G_TYPE_POINTER, stc, NULL);
50 gst_element_set_context(pipeline, context);
53 #else // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER 56 void setup_video_sink_for_buffer_streaming(GstElement*)
61 #endif // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER 65 bool is_mir_video_sink()
67 return g_strcmp0(::getenv(
"CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME"),
"mirsink") == 0;
81 static const std::string s{
"playbin"};
87 auto thiz =
static_cast<Playbin*
>(user_data);
95 if (user_data ==
nullptr)
112 std::placeholders::_1))),
128 throw std::runtime_error(
"Could not create pipeline for playbin.");
170 print_refs(*
this,
"gstreamer::Playbin::~Playbin pipeline");
180 print_refs(*
this,
"gstreamer::Playbin::~Playbin pipeline");
186 MH_INFO(
"Client died, resetting pipeline");
202 const auto ret = gst_element_set_state(
pipeline, GST_STATE_NULL);
205 case GST_STATE_CHANGE_FAILURE:
206 MH_WARNING(
"Failed to reset the pipeline state. Client reconnect may not function properly.");
208 case GST_STATE_CHANGE_NO_PREROLL:
209 case GST_STATE_CHANGE_SUCCESS:
210 case GST_STATE_CHANGE_ASYNC:
213 MH_WARNING(
"Failed to reset the pipeline state. Client reconnect may not function properly.");
224 if (!gst_is_missing_plugin_message(message))
227 gchar *desc = gst_missing_plugin_message_get_description(message);
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)) {
241 GstStructure *caps_data = gst_caps_get_structure(caps, 0);
247 const gchar *mime = gst_structure_get_name(caps_data);
248 if (strstr(mime,
"audio"))
250 else if (strstr(mime,
"video"))
253 MH_ERROR(
"Missing decoder for %s", mime);
258 switch (message.
type)
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:
303 case GST_MESSAGE_BUFFERING:
319 g_object_get (
pipeline,
"flags", &flags,
nullptr);
323 g_object_set (
pipeline,
"flags", flags,
nullptr);
325 if (::getenv(
"CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME") !=
nullptr)
328 ::getenv(
"CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME"),
331 MH_INFO(
"audio_sink: %s", ::getenv(
"CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME"));
340 if (::getenv(
"CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME") !=
nullptr)
343 ::getenv(
"CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME"),
346 MH_INFO(
"video_sink: %s", ::getenv(
"CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME"));
360 "No video sink configured for the current pipeline" 363 setup_video_sink_for_buffer_streaming(
pipeline);
368 g_object_set (
pipeline,
"volume", new_volume, NULL);
376 case media::Player::AudioStreamRole::alarm:
379 case media::Player::AudioStreamRole::alert:
382 case media::Player::AudioStreamRole::multimedia:
385 case media::Player::AudioStreamRole::phone:
396 if (g_strcmp0(orientation,
"rotate-0") == 0)
397 return media::Player::Orientation::rotate0;
398 else if (g_strcmp0(orientation,
"rotate-90") == 0)
399 return media::Player::Orientation::rotate90;
400 else if (g_strcmp0(orientation,
"rotate-180") == 0)
401 return media::Player::Orientation::rotate180;
402 else if (g_strcmp0(orientation,
"rotate-270") == 0)
403 return media::Player::Orientation::rotate270;
405 return media::Player::Orientation::rotate0;
412 MH_INFO(
"Audio stream role: %s", role_str);
414 GstStructure *props = gst_structure_from_string (role_str.c_str(), NULL);
415 if (
audio_sink !=
nullptr && props !=
nullptr)
417 g_object_set (
audio_sink,
"stream-properties", props, NULL);
421 MH_WARNING(
"Couldn't set audio stream role - couldn't get audio_sink from pipeline");
424 gst_structure_free (props);
435 gst_element_query_position (
pipeline, GST_FORMAT_TIME, &pos);
449 return static_cast<uint64_t
>(pos);
455 gst_element_query_duration (
pipeline, GST_FORMAT_TIME, &dur);
458 return static_cast<uint64_t
>(dur);
462 const std::string&
uri,
464 bool do_pipeline_reset)
466 gchar *current_uri =
nullptr;
467 g_object_get(
pipeline,
"current-uri", ¤t_uri, NULL);
472 if (current_uri and do_pipeline_reset)
475 std::string tmp_uri{uri};
477 if (uri_check->is_local_file())
479 if (uri_check->is_encoded())
483 MH_DEBUG(
"File URI was encoded, now decoded: %s", tmp_uri);
488 g_object_set(
pipeline,
"uri", tmp_uri.c_str(), NULL);
505 if (g_object_class_find_property(G_OBJECT_GET_CLASS(source),
506 "cookies") != NULL) {
507 gchar ** cookies = g_strsplit(
request_headers[
"Cookie"].c_str(),
";", 0);
508 g_object_set(source,
"cookies", cookies, NULL);
514 if (g_object_class_find_property(G_OBJECT_GET_CLASS(source),
515 "user-agent") != NULL) {
516 g_object_set(source,
"user-agent",
request_headers[
"User-Agent"].c_str(), NULL);
523 gchar* data =
nullptr;
524 g_object_get(
pipeline,
"current-uri", &data,
nullptr);
526 std::string result((data ==
nullptr ?
"" : data));
535 auto thiz =
static_cast<Playbin*
>(user_data);
536 if (thiz and thiz->pipeline)
537 gst_element_set_state(thiz->pipeline, thiz->current_new_state);
544 static const std::chrono::nanoseconds state_change_timeout
549 std::chrono::milliseconds{5000}
553 GstState current, pending;
560 MH_DEBUG(
"Requested state change in main thread context.");
562 GstState current, pending;
563 result = GST_STATE_CHANGE_SUCCESS == gst_element_get_state(
567 state_change_timeout.count());
571 const auto ret = gst_element_set_state(
pipeline, new_state);
573 MH_DEBUG(
"Requested state change not using main thread context.");
577 case GST_STATE_CHANGE_FAILURE:
578 result =
false;
break;
579 case GST_STATE_CHANGE_NO_PREROLL:
580 case GST_STATE_CHANGE_SUCCESS:
581 result =
true;
break;
582 case GST_STATE_CHANGE_ASYNC:
583 result = GST_STATE_CHANGE_SUCCESS == gst_element_get_state(
587 state_change_timeout.count());
594 if (result && new_state == GST_STATE_PLAYING)
603 catch (
const std::exception& e)
605 MH_WARNING(
"Problem querying video dimensions: %s", e.what());
609 MH_WARNING(
"Problem querying video dimensions.");
612 #ifdef DEBUG_GST_PIPELINE 613 MH_DEBUG(
"Dumping pipeline dot file");
614 GST_DEBUG_BIN_TO_DOT_FILE((GstBin*)
pipeline, GST_DEBUG_GRAPH_SHOW_ALL,
"pipeline");
624 return gst_element_seek_simple(
627 (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
633 if (not
video_sink || not is_mir_video_sink())
634 throw std::runtime_error
636 "Missing video sink or video sink does not support query of width and height." 640 uint32_t video_width = 0, video_height = 0;
641 g_object_get (
video_sink,
"height", &video_height,
nullptr);
642 g_object_get (
video_sink,
"width", &video_width,
nullptr);
657 signals.on_video_dimensions_changed(new_dimensions);
662 GError *error =
nullptr;
665 std::unique_ptr<GFile, void(*)(void *)> file(
666 g_file_new_for_uri(uri.c_str()), g_object_unref);
667 std::unique_ptr<GFileInfo, void(*)(void *)> info(
669 file.get(), G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE
"," 670 G_FILE_ATTRIBUTE_ETAG_VALUE, G_FILE_QUERY_INFO_NONE,
674 return std::string();
676 std::string content_type = g_file_info_get_attribute_string(
677 info.get(), G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE);
678 if (content_type.empty())
679 return std::string();
681 if (content_type ==
"application/octet-stream")
683 std::unique_ptr<GFileInfo, void(*)(void *)> full_info(
684 g_file_query_info(file.get(), G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
685 G_FILE_QUERY_INFO_NONE,
686 NULL, &error),g_object_unref);
689 return std::string();
691 content_type = g_file_info_get_attribute_string(
692 full_info.get(), G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
693 if (content_type.empty())
694 return std::string();
702 return std::string();
704 std::string encoded_uri;
706 gchar *uri_scheme = g_uri_parse_scheme(uri.c_str());
708 if (uri_scheme and strlen(uri_scheme) > 0 and uri_check->is_encoded())
710 MH_DEBUG(
"Is a URI and is already percent encoded");
714 else if (uri_scheme and strlen(uri_scheme) > 0 and !uri_check->is_encoded())
716 MH_DEBUG(
"Is a URI and is not already percent encoded");
717 gchar *encoded = g_uri_escape_string(uri.c_str(),
723 return std::string();
725 encoded_uri.assign(encoded);
730 GError *error =
nullptr;
731 MH_DEBUG(
"Is a path and is not already percent encoded");
732 gchar *str = g_filename_to_uri(uri.c_str(),
nullptr, &error);
736 return std::string();
738 encoded_uri.assign(str);
740 if (error !=
nullptr)
742 MH_WARNING(
"Failed to get actual track content type: %s", error->message);
746 return std::string(
"audio/video/");
748 gchar *escaped = g_uri_escape_string(encoded_uri.c_str(),
754 return std::string();
756 encoded_uri.assign(escaped);
768 return std::string();
770 gchar *decoded_gchar = g_uri_unescape_string(uri.c_str(),
nullptr);
772 return std::string();
774 const std::string decoded{decoded_gchar};
775 g_free(decoded_gchar);
782 return std::string();
784 const std::string encoded_uri{
encode_uri(uri)};
787 if (content_type.empty())
789 MH_WARNING(
"Failed to get actual track content type");
790 return std::string(
"audio/video/");
793 MH_INFO(
"Found content type: %s", content_type);
805 MH_INFO(
"Found audio content");
819 MH_INFO(
"Found video content");
static std::string get_audio_role_str(core::ubuntu::media::Player::AudioStreamRole audio_role)
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)
static gboolean set_state_in_main_thread(gpointer user_data)
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
GstState current_new_state
core::ubuntu::media::Player::Orientation orientation_lut(const gchar *orientation)
struct gstreamer::Bus::Message::Detail::@1 buffering
gstreamer::Bus & message_bus()
core::Signal< void > about_to_finish
void setup_pipeline_for_audio_video()
bool set_state_and_wait(GstState new_state, bool use_main_thread=false)
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