Skip to content

Commit b7f1f03

Browse files
Merge pull request #1082 from Sean-Der/h264-rtp-depacketizer
Add H264RtpDepacketizer
2 parents d498c84 + 70a1fc3 commit b7f1f03

File tree

5 files changed

+185
-0
lines changed

5 files changed

+185
-0
lines changed

CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ set(LIBDATACHANNEL_SOURCES
7676
${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpsrreporter.cpp
7777
${CMAKE_CURRENT_SOURCE_DIR}/src/rtppacketizer.cpp
7878
${CMAKE_CURRENT_SOURCE_DIR}/src/h264rtppacketizer.cpp
79+
${CMAKE_CURRENT_SOURCE_DIR}/src/h264rtpdepacketizer.cpp
7980
${CMAKE_CURRENT_SOURCE_DIR}/src/nalunit.cpp
8081
${CMAKE_CURRENT_SOURCE_DIR}/src/h265rtppacketizer.cpp
8182
${CMAKE_CURRENT_SOURCE_DIR}/src/h265nalunit.cpp
@@ -110,6 +111,7 @@ set(LIBDATACHANNEL_HEADERS
110111
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtcpsrreporter.hpp
111112
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtppacketizer.hpp
112113
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h264rtppacketizer.hpp
114+
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h264rtpdepacketizer.hpp
113115
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/nalunit.hpp
114116
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h265rtppacketizer.hpp
115117
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h265nalunit.hpp

include/rtc/h264rtpdepacketizer.hpp

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* Copyright (c) 2020 Staz Modrzynski
3+
* Copyright (c) 2020 Paul-Louis Ageneau
4+
*
5+
* This Source Code Form is subject to the terms of the Mozilla Public
6+
* License, v. 2.0. If a copy of the MPL was not distributed with this
7+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
8+
*/
9+
10+
#ifndef RTC_H264_RTP_DEPACKETIZER_H
11+
#define RTC_H264_RTP_DEPACKETIZER_H
12+
13+
#if RTC_ENABLE_MEDIA
14+
15+
#include "common.hpp"
16+
#include "mediahandler.hpp"
17+
#include "message.hpp"
18+
#include "rtp.hpp"
19+
20+
#include <iterator>
21+
22+
namespace rtc {
23+
24+
/// RTP depacketization for H264
25+
class RTC_CPP_EXPORT H264RtpDepacketizer : public MediaHandler {
26+
public:
27+
H264RtpDepacketizer() = default;
28+
virtual ~H264RtpDepacketizer() = default;
29+
30+
void incoming(message_vector &messages, const message_callback &send) override;
31+
32+
private:
33+
std::vector<message_ptr> mRtpBuffer;
34+
35+
message_vector buildFrames(message_vector::iterator firstPkt, message_vector::iterator lastPkt);
36+
};
37+
38+
} // namespace rtc
39+
40+
#endif // RTC_ENABLE_MEDIA
41+
42+
#endif /* RTC_H264_RTP_DEPACKETIZER_H */

include/rtc/nalunit.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ struct RTC_CPP_EXPORT NalUnitHeader {
2525

2626
bool forbiddenBit() const { return _first >> 7; }
2727
uint8_t nri() const { return _first >> 5 & 0x03; }
28+
uint8_t idc() const { return _first & 0x60; }
2829
uint8_t unitType() const { return _first & 0x1F; }
2930

3031
void setForbiddenBit(bool isSet) { _first = (_first & 0x7F) | (isSet << 7); }

include/rtc/rtc.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
// Media
3131
#include "av1rtppacketizer.hpp"
3232
#include "h264rtppacketizer.hpp"
33+
#include "h264rtpdepacketizer.hpp"
3334
#include "h265rtppacketizer.hpp"
3435
#include "mediahandler.hpp"
3536
#include "plihandler.hpp"

src/h264rtpdepacketizer.cpp

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/**
2+
* Copyright (c) 2023 Paul-Louis Ageneau
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*/
8+
9+
#if RTC_ENABLE_MEDIA
10+
11+
#include "h264rtpdepacketizer.hpp"
12+
#include "nalunit.hpp"
13+
#include "track.hpp"
14+
15+
#include "impl/logcounter.hpp"
16+
17+
#include <cmath>
18+
#include <utility>
19+
20+
#ifdef _WIN32
21+
#include <winsock2.h>
22+
#else
23+
#include <arpa/inet.h>
24+
#endif
25+
26+
namespace rtc {
27+
28+
const unsigned long stapaHeaderSize = 1;
29+
const auto fuaHeaderSize = 2;
30+
31+
const uint8_t naluTypeSTAPA = 24;
32+
const uint8_t naluTypeFUA = 28;
33+
34+
message_vector H264RtpDepacketizer::buildFrames(message_vector::iterator begin,
35+
message_vector::iterator end) {
36+
message_vector out = {};
37+
auto fua_buffer = std::vector<std::byte>{};
38+
39+
for (auto it = begin; it != end; it++) {
40+
auto pkt = it->get();
41+
auto pktParsed = reinterpret_cast<const rtc::RtpHeader *>(pkt->data());
42+
auto headerSize =
43+
sizeof(rtc::RtpHeader) + pktParsed->csrcCount() + pktParsed->getExtensionHeaderSize();
44+
auto nalUnitHeader = NalUnitHeader{std::to_integer<uint8_t>(pkt->at(headerSize))};
45+
46+
if (fua_buffer.size() != 0 || nalUnitHeader.unitType() == naluTypeFUA) {
47+
if (fua_buffer.size() == 0) {
48+
fua_buffer.push_back(std::byte(0));
49+
}
50+
51+
auto nalUnitFragmentHeader =
52+
NalUnitFragmentHeader{std::to_integer<uint8_t>(pkt->at(headerSize + 1))};
53+
54+
std::copy(pkt->begin() + headerSize + fuaHeaderSize, pkt->end(),
55+
std::back_inserter(fua_buffer));
56+
57+
if (nalUnitFragmentHeader.isEnd()) {
58+
fua_buffer.at(0) =
59+
std::byte(nalUnitHeader.idc() | nalUnitFragmentHeader.unitType());
60+
61+
out.push_back(make_message(std::move(fua_buffer)));
62+
fua_buffer.clear();
63+
}
64+
} else if (nalUnitHeader.unitType() > 0 && nalUnitHeader.unitType() < 24) {
65+
out.push_back(make_message(pkt->begin() + headerSize, pkt->end()));
66+
} else if (nalUnitHeader.unitType() == naluTypeSTAPA) {
67+
auto currOffset = stapaHeaderSize + headerSize;
68+
69+
while (currOffset < pkt->size()) {
70+
auto naluSize =
71+
uint16_t(pkt->at(currOffset)) << 8 | uint8_t(pkt->at(currOffset + 1));
72+
73+
currOffset += 2;
74+
75+
if (pkt->size() < currOffset + naluSize) {
76+
throw std::runtime_error("STAP-A declared size is larger then buffer");
77+
}
78+
79+
out.push_back(
80+
make_message(pkt->begin() + currOffset, pkt->begin() + currOffset + naluSize));
81+
currOffset += naluSize;
82+
}
83+
84+
} else {
85+
throw std::runtime_error("Unknown H264 RTP Packetization");
86+
}
87+
}
88+
89+
return out;
90+
}
91+
92+
void H264RtpDepacketizer::incoming(message_vector &messages, const message_callback &) {
93+
for (auto message : messages) {
94+
if (message->type == Message::Control) {
95+
continue; // RTCP
96+
}
97+
98+
if (message->size() < sizeof(RtpHeader)) {
99+
PLOG_VERBOSE << "RTP packet is too small, size=" << message->size();
100+
continue;
101+
}
102+
103+
mRtpBuffer.push_back(message);
104+
}
105+
106+
messages.clear();
107+
108+
while (mRtpBuffer.size() != 0) {
109+
uint32_t current_timestamp = 0;
110+
size_t packets_in_timestamp = 0;
111+
112+
for (const auto &pkt : mRtpBuffer) {
113+
auto p = reinterpret_cast<const rtc::RtpHeader *>(pkt->data());
114+
115+
if (current_timestamp == 0) {
116+
current_timestamp = p->timestamp();
117+
} else if (current_timestamp != p->timestamp()) {
118+
break;
119+
}
120+
121+
packets_in_timestamp++;
122+
}
123+
124+
if (packets_in_timestamp == mRtpBuffer.size()) {
125+
break;
126+
}
127+
128+
auto begin = mRtpBuffer.begin();
129+
auto end = mRtpBuffer.begin() + (packets_in_timestamp - 1);
130+
131+
auto frames = buildFrames(begin, end + 1);
132+
messages.insert(messages.end(), frames.begin(), frames.end());
133+
mRtpBuffer.erase(mRtpBuffer.begin(), mRtpBuffer.begin() + packets_in_timestamp);
134+
}
135+
}
136+
137+
} // namespace rtc
138+
139+
#endif // RTC_ENABLE_MEDIA

0 commit comments

Comments
 (0)