瀏覽代碼

Add a media handler to respond to intra frame requests

This introduces a PLIResponder class, which can be used for responding
back with an intra frame after the receiver requests one with an FIR
(Full Intra Request) or a PLI (Picture Loss Indicator) message.

This is useful when a video is being streamed live and we can control
the behavior of the video encoder. PLIResponder simply notifies its
caller when a new intra frame is requested, which passes this request
onto its video frame source.
Arda Cinar 1 年之前
父節點
當前提交
4467271af6
共有 4 個文件被更改,包括 83 次插入0 次删除
  1. 2 0
      CMakeLists.txt
  2. 35 0
      include/rtc/pliresponder.hpp
  3. 2 0
      include/rtc/rtc.hpp
  4. 44 0
      src/pliresponder.cpp

+ 2 - 0
CMakeLists.txt

@@ -92,6 +92,7 @@ set(LIBDATACHANNEL_SOURCES
 	${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpnackresponder.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/rtp.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/capi.cpp
+	${CMAKE_CURRENT_SOURCE_DIR}/src/pliresponder.cpp
 )
 
 set(LIBDATACHANNEL_HEADERS
@@ -132,6 +133,7 @@ set(LIBDATACHANNEL_HEADERS
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/mediahandlerrootelement.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtcpnackresponder.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/utils.hpp
+	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/pliresponder.hpp
 )
 
 set(LIBDATACHANNEL_IMPL_SOURCES

+ 35 - 0
include/rtc/pliresponder.hpp

@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2023 Arda Cinar
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef RTC_PLI_RESPONDER_H
+#define RTC_PLI_RESPONDER_H
+
+#if RTC_ENABLE_MEDIA
+
+#include "mediahandlerelement.hpp"
+#include <functional>
+
+namespace rtc {
+
+/// Responds to PLI and FIR messages sent by the receiver. The sender should respond to these
+/// messages by sending an intra. 
+class RTC_CPP_EXPORT PliResponder final : public MediaHandlerElement {
+    std::function<void(void)> onPli;
+
+public:
+	/// Constructs the PLIResponder object to notify whenever a new intra frame is requested
+	/// @param onPli The callback that gets called whenever an intra frame is requested by the receiver
+    PliResponder(std::function<void(void)> onPli);
+    ChainedIncomingControlProduct processIncomingControlMessage(message_ptr) override;
+};
+
+}
+
+#endif // RTC_ENABLE_MEDIA
+
+#endif // RTC_PLI_RESPONDER_H

+ 2 - 0
include/rtc/rtc.hpp

@@ -33,6 +33,8 @@
 #include "rtcpreceivingsession.hpp"
 #include "rtcpsrreporter.hpp"
 
+#include "pliresponder.hpp"
+
 // Opus/AAC/h264/h265/AV1 streaming
 #include "aacrtppacketizer.hpp"
 #include "av1packetizationhandler.hpp"

+ 44 - 0
src/pliresponder.cpp

@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2023 Arda Cinar
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+#include "pliresponder.hpp"
+
+#if RTC_ENABLE_MEDIA
+
+namespace rtc {
+
+ChainedIncomingControlProduct PliResponder::processIncomingControlMessage(message_ptr message) {
+	size_t offset = 0;
+
+	while ((sizeof(RtcpHeader) + offset) <= message->size()) {
+		auto header = reinterpret_cast<rtc::RtcpHeader*>(message->data() + offset);
+		uint8_t payload_type = header->payloadType();
+
+		if (payload_type == 196) { 
+			// FIR message, call pli handler anyway
+			onPli();
+			break;
+		} else if (payload_type == 206) {
+			// On a payload specific fb message, there is a "feedback message type" (FMT) in the
+			// header instead of a report count. PT = 206, FMT = 1 means a PLI message
+			uint8_t feedback_message_type = header->reportCount();
+			if (feedback_message_type == 1) {
+				onPli();
+				break;
+			}
+		}
+		offset += header->lengthInBytes();
+	}
+	return { message, std::nullopt };
+}
+
+PliResponder::PliResponder(std::function<void(void)> onPli) : onPli(onPli) { }
+
+}
+
+#endif // RTC_ENABLE_MEDIA