[1.0.9] add rtsp receiver 96/284596/2
authorEunhye Choi <eunhae1.choi@samsung.com>
Mon, 21 Nov 2022 11:41:54 +0000 (20:41 +0900)
committerEunhye Choi <eunhae1.choi@samsung.com>
Tue, 22 Nov 2022 07:34:13 +0000 (16:34 +0900)
- rtsp receiver which export demuxed
  audio and video data to application

Change-Id: I70f9aee530a14a338a192f831591cedb8f28a34f

include/MediaTransporterGst.h
include/MediaTransporterReceiverRtsp.h [new file with mode: 0644]
include/mtpr.h
packaging/capi-media-transporter.spec
src/MediaTransporterFactory.cpp
src/MediaTransporterReceiverRtsp.cpp [new file with mode: 0644]
test/mtpr_test.c

index b001fc4e7c165e134bf22691db72d1b61b3ef365..005cafdde120cd8b2b6259de308d3da25bd882a4 100644 (file)
@@ -47,6 +47,8 @@ const std::string DEFAULT_ELEMENT_RISTSINK   = "ristsink";
 const std::string DEFAULT_ELEMENT_SRTSRC     = "srtsrc";
 const std::string DEFAULT_ELEMENT_SRTSINK    = "srtsink";
 const std::string DEFAULT_ELEMENT_RTSPSINK   = "rtspclientsink";
+const std::string DEFAULT_ELEMENT_RTSPSRC    = "rtspsrc";
+const std::string DEFAULT_ELEMENT_DECODEBIN  = "decodebin";
 
 const std::string DEFAULT_VIDEO_SINK_ELEMENT = "tizenwlsink";
 const std::string DEFAULT_AUDIO_SINK_ELEMENT = "pulsesink";
diff --git a/include/MediaTransporterReceiverRtsp.h b/include/MediaTransporterReceiverRtsp.h
new file mode 100644 (file)
index 0000000..17e477c
--- /dev/null
@@ -0,0 +1,67 @@
+/**
+ * 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__
index f404e7561a25ac48774dafa55822730c69460d23..12679e78ee50e139573ebb80f6dee6b555cf9ea7 100644 (file)
@@ -61,6 +61,7 @@ typedef enum {
        MTPR_CONNECTION_TYPE_SRT_SENDER,
        MTPR_CONNECTION_TYPE_SRT_RECEIVER,
        MTPR_CONNECTION_TYPE_RTSP_SENDER,
+       MTPR_CONNECTION_TYPE_RTSP_RECEIVER,
        MTPR_CONNECTION_TYPE_RTSP_SENDER_TO_SERVER
 } mtpr_connection_type_e;
 
index 262d77aa83dd742ad0bb3109e34c7bb4cc8865d8..ec7b5f3e31d0f3eab2e5eaeb22a8626e0e295268 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-transporter
 Summary:    A Media Transporter library in Tizen Native API
-Version:    1.0.8
+Version:    1.0.9
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index 3dc6dc5e4a419310b9db78982b263c490f46d173..485341e8bfc64b13ca0be8bef954b5a47202b173 100644 (file)
@@ -21,6 +21,7 @@
 #include "MediaTransporterSenderRtsp.h"
 #include "MediaTransporterSenderToServerRtsp.h"
 #include "MediaTransporterReceiverRist.h"
+#include "MediaTransporterReceiverRtsp.h"
 #include "MediaTransporterReceiverSrt.h"
 
 using namespace tizen_media_transporter;
@@ -39,6 +40,8 @@ MediaTransporterBase* MediaTransporterFactory::create(mtprConnectionType type)
                return static_cast<MediaTransporterBase*>(new MediaTransporterReceiverSrt());
        case MTPR_CONNECTION_TYPE_RTSP_SENDER:
                return static_cast<MediaTransporterBase*>(new MediaTransporterSenderRtsp());
+       case MTPR_CONNECTION_TYPE_RTSP_RECEIVER:
+               return static_cast<MediaTransporterBase*>(new MediaTransporterReceiverRtsp());
        case MTPR_CONNECTION_TYPE_RTSP_SENDER_TO_SERVER:
                return static_cast<MediaTransporterBase*>(new MediaTransporterSenderToServerRtsp());
        default:
diff --git a/src/MediaTransporterReceiverRtsp.cpp b/src/MediaTransporterReceiverRtsp.cpp
new file mode 100644 (file)
index 0000000..fef01c9
--- /dev/null
@@ -0,0 +1,211 @@
+/**
+ * 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;
+}
index 2706d6433d0aa95a0518b30ccc6aa4323d60eac2..2545695373c172dbe4ace43a412e922cf7e300d7 100644 (file)
@@ -1152,7 +1152,7 @@ static void displaymenu()
                display_sub_basic();
        } else if (g_menu_state == CURRENT_STATUS_CONNECTION_TYPE) {
                g_print("*** Input connection type.\n\
-    (0:RIST_SENDER, 1:RIST_RECEIVER, 2:SRT_SENDER, 3:SRT_RECEIVER, 4:RTSP_SENDER, 5:RTSP_SENDER_TO_SERVER)\n");
+    (0:RIST_SENDER, 1:RIST_RECEIVER, 2:SRT_SENDER, 3:SRT_RECEIVER, 4:RTSP_SENDER, 5:RTS_RECEIVER, 6:RTSP_SENDER_TO_SERVER)\n");
        } else if (g_menu_state == CURRENT_STATUS_SENDER_ADDRESS) {
                g_print("*** Input sender address:\n");
        } else if (g_menu_state == CURRENT_STATUS_RECEIVER_ADDRESS) {