Skip to content

Commit ee88ab7

Browse files
committed
Add H264RtpDepacketizer
Inverse of H264RtpPacketizer. Takes incoming H264 packets and emits H264 NALUs.
1 parent e87cbee commit ee88ab7

File tree

4 files changed

+183
-0
lines changed

4 files changed

+183
-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> rtp_buffer;
34+
35+
message_vector buildFrame(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/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

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
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 "track.hpp"
13+
14+
#include "impl/logcounter.hpp"
15+
16+
#include <cmath>
17+
#include <utility>
18+
19+
#ifdef _WIN32
20+
#include <winsock2.h>
21+
#else
22+
#include <arpa/inet.h>
23+
#endif
24+
25+
namespace rtc {
26+
27+
const unsigned long stapaHeaderSize = 1;
28+
const auto fuaHeaderSize = 2;
29+
const auto rtpHeaderSize = 12;
30+
31+
const auto naluTypeBitmask = std::byte(0x1F);
32+
const auto naluTypeSTAPA = std::byte(24);
33+
const auto naluTypeFUA = std::byte(28);
34+
const auto fuaEndBitmask = std::byte(0x40);
35+
const auto naluRefIdcBitmask = std::byte(0x60);
36+
37+
message_vector H264RtpDepacketizer::buildFrame(message_vector::iterator first,
38+
message_vector::iterator last) {
39+
message_vector out = {};
40+
auto fua_buffer = std::vector<std::byte>{};
41+
42+
for (auto it = first; (it - 1) != last; it++) {
43+
auto pkt = it->get();
44+
auto pktParsed = reinterpret_cast<const rtc::RtpHeader *>(pkt->data());
45+
auto headerSize =
46+
rtpHeaderSize + pktParsed->csrcCount() + pktParsed->getExtensionHeaderSize();
47+
auto naluType = pkt->at(headerSize) & naluTypeBitmask;
48+
49+
if (fua_buffer.size() != 0 || naluType == naluTypeFUA) {
50+
if (fua_buffer.size() == 0) {
51+
fua_buffer.push_back(std::byte(0));
52+
}
53+
54+
std::copy(pkt->begin() + headerSize + fuaHeaderSize, pkt->end(),
55+
std::back_inserter(fua_buffer));
56+
57+
if ((pkt->at(headerSize + 1) & fuaEndBitmask) != std::byte(0)) {
58+
auto naluRefIdc = pkt->at(headerSize) & naluRefIdcBitmask;
59+
auto fragmentedNaluType = pkt->at(headerSize + 1) & std::byte(naluTypeBitmask);
60+
fua_buffer.at(0) = naluRefIdc | fragmentedNaluType;
61+
62+
out.push_back(make_message(fua_buffer));
63+
fua_buffer.clear();
64+
}
65+
} else if (naluType > std::byte(0) && naluType < std::byte(24)) {
66+
out.push_back(make_message(pkt->begin() + headerSize, pkt->end()));
67+
} else if (naluType == naluTypeSTAPA) {
68+
auto currOffset = stapaHeaderSize + headerSize;
69+
70+
while (currOffset < pkt->size()) {
71+
auto naluSize =
72+
uint16_t(pkt->at(currOffset)) << 8 | uint8_t(pkt->at(currOffset + 1));
73+
74+
currOffset += 2;
75+
76+
if (pkt->size() < currOffset + naluSize) {
77+
throw std::runtime_error("STAP-A declared size is larger then buffer");
78+
}
79+
80+
out.push_back(
81+
make_message(pkt->begin() + currOffset, pkt->begin() + currOffset + naluSize));
82+
currOffset += naluSize;
83+
}
84+
85+
} else {
86+
throw std::runtime_error("Unknown H264 RTP Packetization");
87+
}
88+
}
89+
90+
return out;
91+
}
92+
93+
void H264RtpDepacketizer::incoming(message_vector &messages, const message_callback &) {
94+
for (auto message : messages) {
95+
if (message->type != Message::Binary) {
96+
continue;
97+
}
98+
99+
if (message->size() < sizeof(RtpHeader)) {
100+
PLOG_VERBOSE << "RTP packet is too small, size=" << message->size();
101+
continue;
102+
}
103+
104+
this->rtp_buffer.push_back(make_message(message->begin(), message->end()));
105+
}
106+
107+
while (this->rtp_buffer.size() != 0) {
108+
uint32_t current_timestamp = 0;
109+
size_t packets_in_timestamp = 0;
110+
111+
for (const auto &pkt : this->rtp_buffer) {
112+
auto p = reinterpret_cast<const rtc::RtpHeader *>(pkt->data());
113+
114+
if (current_timestamp == 0) {
115+
current_timestamp = p->timestamp();
116+
} else if (current_timestamp != p->timestamp()) {
117+
break;
118+
}
119+
120+
packets_in_timestamp++;
121+
}
122+
123+
if (packets_in_timestamp == this->rtp_buffer.size()) {
124+
break;
125+
}
126+
127+
auto first = this->rtp_buffer.begin();
128+
auto last = this->rtp_buffer.begin() + (packets_in_timestamp - 1);
129+
130+
messages = buildFrame(first, last);
131+
this->rtp_buffer.erase(this->rtp_buffer.begin(),
132+
this->rtp_buffer.begin() + packets_in_timestamp);
133+
}
134+
}
135+
136+
} // namespace rtc
137+
138+
#endif // RTC_ENABLE_MEDIA

0 commit comments

Comments
 (0)