--- /dev/null
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TIZEN_MEDIA_TRANSPORTER_RECEIVER_RTSP_H__
+#define __TIZEN_MEDIA_TRANSPORTER_RECEIVER_RTSP_H__
+
+#ifdef __cplusplus
+
+#include <string>
+
+#include "MediaTransporter.h"
+#include "MediaTransporterBase.h"
+#include "MediaTransporterReceiver.h"
+#include "MediaTransporterGst.h"
+
+namespace tizen_media_transporter {
+
+typedef enum {
+ GST_AUTOPLUG_SELECT_TRY,
+ GST_AUTOPLUG_SELECT_EXPOSE,
+ GST_AUTOPLUG_SELECT_SKIP
+} GstAutoplugSelectResult;
+
+class MediaTransporterReceiverRtsp : public MediaTransporterReceiver
+{
+public:
+ MediaTransporterReceiverRtsp();
+ ~MediaTransporterReceiverRtsp();
+
+ void buildPipeline() override;
+ void startPipeline() override;
+ void stopPipeline() override;
+
+ void setSenderAddress(std::string address) override;
+ std::string getSenderAddress() override { return _senderAddress; }
+
+ mtprConnectionType type() override { return MTPR_CONNECTION_TYPE_RTSP_RECEIVER; }
+
+private:
+ static void _srcPadAddedCallback(GstElement* src, GstPad* pad, gpointer userData);
+ static void _srcNoMorePadsCallback(GstElement* src, gpointer userData);
+ static GstAutoplugSelectResult _decodebinAutoplugSelectCallback(GstElement* decodebin, GstPad* pad,
+ GstCaps* caps, GstElementFactory* factory, gpointer userData);
+ static void _decodebinElementAddedCallback(GstElement* decodebin, GstElement* element, gpointer userData);
+ static void _decodebinPadAddedCallback(GstElement* decodebin, GstPad* new_pad, gpointer userData);
+ static void _decodebinNoMorePadsCallback(GstElement* decodebin, gpointer userData);
+
+ std::string _senderAddress;
+};
+
+} // namespace
+
+#endif // __cplusplus
+#endif // __TIZEN_MEDIA_TRANSPORTER_RECEIVER_RTSP_H__
--- /dev/null
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cassert>
+#include <string>
+#include <algorithm>
+
+#include "MediaTransporterBase.h"
+#include "MediaTransporterException.h"
+#include "MediaTransporterReceiverRtsp.h"
+#include "MediaTransporterGst.h"
+#include "MediaTransporterLog.h"
+#include "MediaTransporterUtil.h"
+
+using namespace tizen_media_transporter;
+
+MediaTransporterReceiverRtsp::MediaTransporterReceiverRtsp()
+{
+ LOG_DEBUG("ctor: %p", this);
+}
+
+MediaTransporterReceiverRtsp::~MediaTransporterReceiverRtsp()
+{
+ LOG_DEBUG("dtor: %p", this);
+}
+
+void MediaTransporterReceiverRtsp::_srcPadAddedCallback(GstElement* src, GstPad *pad, gpointer userData)
+{
+ GstPad* sinkPad = NULL;
+ GstPadLinkReturn ret = GST_PAD_LINK_OK;
+
+ auto rtsp = static_cast<MediaTransporterReceiverRtsp*>(userData);
+ assert(rtsp);
+
+ LOG_INFO("src pad added in rtspsrc");
+
+ GstElement* decodebin = gst::_createElement(gst::DEFAULT_ELEMENT_DECODEBIN);
+ if (!decodebin) {
+ LOG_ERROR("failed to create decodebin");
+ return;
+ }
+
+ gst::_connectAndAppendSignal(&rtsp->_gst.signals, G_OBJECT(decodebin), "pad-added",
+ G_CALLBACK(_decodebinPadAddedCallback), userData);
+ gst::_connectAndAppendSignal(&rtsp->_gst.signals, G_OBJECT(decodebin), "no-more-pads",
+ G_CALLBACK(_decodebinNoMorePadsCallback), userData);
+
+ gst::_connectAndAppendSignal(&rtsp->_gst.signals, G_OBJECT(decodebin), "autoplug-select",
+ G_CALLBACK(_decodebinAutoplugSelectCallback), userData);
+ gst::_connectAndAppendSignal(&rtsp->_gst.signals, G_OBJECT(decodebin), "element-added",
+ G_CALLBACK(_decodebinElementAddedCallback), userData);
+
+ GstCaps* caps = gst_pad_query_caps(pad, NULL);
+ if (caps) {
+ g_object_set(decodebin, "sink-caps", caps, NULL);
+ gst_caps_unref(caps);
+ caps = NULL;
+ }
+
+ if (!gst_bin_add(GST_BIN(rtsp->_gst.pipeline), decodebin)) {
+ LOG_ERROR("failed to gst_bin_add");
+ goto ERROR;
+ }
+
+ sinkPad = gst_element_get_static_pad(decodebin, "sink");
+ ret = gst_pad_link(pad, sinkPad);
+ gst_object_unref(GST_OBJECT(sinkPad));
+
+ if (GST_PAD_LINK_FAILED(ret)) {
+ LOG_ERROR("failed to link pads, [%s:%s] - [%s:%s]",
+ GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkPad));
+ goto ERROR;
+ }
+
+ if (!gst_element_sync_state_with_parent(decodebin)) {
+ LOG_ERROR("failed to sync decodebin state with parent");
+ goto ERROR;
+ }
+
+ return;
+
+ERROR:
+ if (decodebin) {
+ gst_element_set_state(decodebin, GST_STATE_NULL);
+ if (!gst_bin_remove(GST_BIN(rtsp->_gst.pipeline), decodebin))
+ gst_object_unref(decodebin);
+ }
+}
+
+void MediaTransporterReceiverRtsp::_srcNoMorePadsCallback(GstElement* src, gpointer userData)
+{
+ LOG_INFO("no more src pad in rtspsrc");
+}
+
+GstAutoplugSelectResult MediaTransporterReceiverRtsp::_decodebinAutoplugSelectCallback(GstElement* decodebin, GstPad* pad,
+ GstCaps* caps, GstElementFactory* factory, gpointer userData)
+{
+ gchar* factory_name = GST_OBJECT_NAME(factory);
+
+ auto& excludedElements = MediaTransporterIni::get().general().gstExcludedElements;
+ auto it = std::find_if(excludedElements.begin(), excludedElements.end(),
+ [&factory_name](const std::string& element) {
+ return element.find(factory_name) != std::string::npos;
+ });
+ if (it != excludedElements.end()) {
+ LOG_WARNING("this element[%s] is an item of excluded element list in ini file, skip it", factory_name);
+ return GST_AUTOPLUG_SELECT_SKIP;
+ }
+
+ const gchar* factory_klass = gst_element_factory_get_klass(factory);
+ if (g_strrstr(factory_klass, "Codec/Decoder")) {
+ LOG_WARNING("expose without decoder %s", factory_name);
+ return GST_AUTOPLUG_SELECT_EXPOSE;
+ }
+
+ return GST_AUTOPLUG_SELECT_TRY;
+}
+
+void MediaTransporterReceiverRtsp::_decodebinElementAddedCallback(GstElement* decodebin, GstElement* element, gpointer userData)
+{
+ LOG_INFO("element is added %s", GST_ELEMENT_NAME(element));
+}
+
+void MediaTransporterReceiverRtsp::_decodebinNoMorePadsCallback(GstElement* decodebin, gpointer userData)
+{
+ auto rtsp = static_cast<MediaTransporterReceiverRtsp*>(userData);
+ std::string dotName = std::string { GST_ELEMENT_NAME(rtsp->_gst.pipeline) } + ".complete";
+ gst::_generateDot(rtsp->_gst.pipeline, dotName);
+
+ _noMoreStreamCallback(userData);
+}
+
+void MediaTransporterReceiverRtsp::_decodebinPadAddedCallback(GstElement* decodebin, GstPad* new_pad, gpointer userData)
+{
+ std::string mediaType = gst::_getMimeTypeFromPad(new_pad);
+
+ if (!_isSupportedMediaType(mediaType))
+ return;
+
+ LOG_INFO("new_pad[%s] media_type[%s]", GST_PAD_NAME(new_pad), mediaType.c_str());
+
+ auto rtsp = static_cast<MediaTransporterReceiverRtsp*>(userData);
+ assert(rtsp);
+
+ bool isAudio = _isAudioMediaType(mediaType);
+ if (rtsp->_audioCallback._callback && isAudio)
+ rtsp->_buildForwardingElements(decodebin, new_pad, G_CALLBACK(_encodedAudioStreamCallback));
+ else if (rtsp->_videoCallback._callback && !isAudio)
+ rtsp->_buildForwardingElements(decodebin, new_pad, G_CALLBACK(_encodedVideoStreamCallback));
+ else
+ rtsp->_buildRenderingElements(decodebin, new_pad, isAudio);
+
+ _streamAddedCallback(new_pad, userData);
+}
+
+void MediaTransporterReceiverRtsp::buildPipeline()
+{
+ GstElement* src = NULL;
+
+ MTPR_FENTER();
+
+ /* create mux to sink */
+ try {
+ if (_senderAddress.empty())
+ throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "address is empty");
+
+ src = gst::_createElement(gst::DEFAULT_ELEMENT_RTSPSRC);
+ g_object_set(G_OBJECT(src), "location", _senderAddress.c_str(), "latency", 10, NULL);
+
+ gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(src), "pad-added",
+ G_CALLBACK(_srcPadAddedCallback), this);
+ gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(src), "no-more-pads",
+ G_CALLBACK(_srcNoMorePadsCallback), this);
+ gst_bin_add(GST_BIN(_gst.pipeline), src);
+
+ } catch (const MediaTransporterException& e) {
+ LOG_ERROR("%s", e.what());
+ gst::_destroyElementFromParent(src);
+ throw;
+ }
+}
+
+void MediaTransporterReceiverRtsp::startPipeline()
+{
+ gst::_setPipelineState(_gst.pipeline, GST_STATE_PLAYING,
+ MediaTransporterIni::get().general().timeout);
+}
+
+void MediaTransporterReceiverRtsp::stopPipeline()
+{
+ gst::_setPipelineState(_gst.pipeline, GST_STATE_NULL,
+ MediaTransporterIni::get().general().timeout);
+}
+
+void MediaTransporterReceiverRtsp::setSenderAddress(std::string address)
+{
+ _senderAddress = address;
+}