Cogs.Core
RTP.cpp
1#include "RTP.h"
2
3#include "Context.h"
4#include "Resources/TextureManager.h"
5#include "Renderer/RenderTexture.h"
6
7#include "Foundation/Logging/Logger.h"
8#include "Foundation/Platform/Timer.h"
9
10#undef CurrentTime
11#include "jrtp/rtpsession.h"
12#include "jrtp/rtpsessionparams.h"
13#include "jrtp/rtpudpv4transmitter.h"
14#include "jrtp/rtptcptransmitter.h"
15#include "jrtp/rtppacket.h"
16#include "jrtp/rtpsourcedata.h"
17#include "jrtp/rtptcpaddress.h"
18
19#include <assert.h>
20#include <cinttypes>
21
22#define INITIAL_BUFFER 64*3*5*7
23
24using namespace Cogs::Core;
25using namespace Cogs::Network;
26
27namespace {
28 constexpr const uint8_t naluStartCode[] = { 0x00, 0x00, 0x00, 0x01 };
29
30 class CogsRTPMemoryManager : public jrtplib::RTPMemoryManager {
31 public:
32 static CogsRTPMemoryManager* instance() {
33 static CogsRTPMemoryManager i;
34
35 return &i;
36 }
37
38 void* AllocateBuffer(size_t numbytes, int /*memtype*/) {
39 void* mem = malloc(numbytes);
40
41 if (mem) {
42 OsoMP_Allocate(COGSMEM_LibRTP, mem, numbytes, nullptr, 0);
43 }
44 return mem;
45 }
46
47 void FreeBuffer(void* ptr) {
48 if (ptr) {
49 OsoMP_Free(COGSMEM_LibRTP, ptr, nullptr, 0);
50 }
51 free(ptr);
52 }
53 };
54
55int64_t timestamp_diff(uint32_t t1, uint32_t t0)
56{
57 // Computing timestamp difference:
58 // We have timestamp a=t0 and b=t1 and timeline (4 bit example):
59 // ---- ---- ---- ----
60
61 // Normal Difference:
62 // ---- -ab- ---- ----
63 // diff = b-a = 6-5 = 1
64
65 // Normal Negative Difference:
66 // ---- -ba- ---- ----
67 // diff = b-a = 6-5 = -1
68
69 // Wraparound:
70 // b--- ---- ---- ---a
71 // diff = (b-a)+2^bits = (0-15)+16 = 1
72
73 // Negative Wraparound:
74 // a--- ---- ---- ---b
75 // diff = (b-a)-2^bits = (15-0)-16 = -1
76
77 // Deciding wraparound
78 // abs(diff) >= 2^(bits-1) -> abs(diff) >= 2^3 = 8
79
80 // int64_t diff = (int64_t)t1 - (int64_t)t0;
81 // if(llabs(diff) > 0x7fffffffLL){
82 // if(diff > 0)
83 // diff -= (0xffffffffLL+1LL);
84 // else
85 // diff += (0xffffffffLL+1LL);
86 // }
87
88 int32_t diff = (int64_t)t1 - (int64_t)t0;
89 return diff;
90}
91
92void timestamp_diff_test()
93{
94 // Normal
95 assert(timestamp_diff(0, 0) == 0);
96 assert(timestamp_diff(0xffffffffu, 0xffffffffu) == 0);
97 assert(timestamp_diff(1, 1) == 0);
98 assert(timestamp_diff(2, 1) == 1);
99 assert(timestamp_diff(1, 2) == -1);
100
101 // Wraparound
102 assert(timestamp_diff(0, 0xffffffffu) == 1);
103 assert(timestamp_diff(1, 0xffffffffu) == 2);
104
105 // Negative Wraparound
106 assert(timestamp_diff(0xffffffffu, 0) == -1);
107 assert(timestamp_diff(0xffffffffu, 1) == -2);
108}
109} // namespace ...
110
111static Cogs::Logging::Log logger = Cogs::Logging::getLogger("RTP");
112
113Cogs::RTPStream::RTPStream(Cogs::Core::Context * context, uint32_t clock_rate, uint16_t port, Cogs::Network::AddrIn mc_adapter, bool udp):
114 context(context),
115 useUDP(udp),
116 clock_rate(clock_rate),
117 client_port(port)
118{
119 timestamp_diff_test();
120 LOG_INFO(logger, "jrtplib Version: %s", jrtplib::RTPLibraryVersion::GetVersion().GetVersionString().c_str());
121
122 tcpConnection.setDoNotProcess();
123
124 session = new jrtplib::RTPSession(nullptr, CogsRTPMemoryManager::instance());
125
126 jrtplib::RTPSessionParams sessionparams;
127 sessionparams.SetOwnTimestampUnit(1.0/clock_rate); // Local timestamp unit (MUST BE SET)
128 // sessionparams.SetAcceptOwnPackets(true);
129 assert(!sessionparams.IsUsingPollThread());
130
131 if (useUDP) {
132 jrtplib::RTPUDPv4TransmissionParams transparams;
133
134 transparams.SetPortbase(port);
135 transparams.SetRTPReceiveBuffer(1024*1024);
136 transparams.SetRTCPReceiveBuffer(1500*64);
137 if (!(mc_adapter[0] == 0 && mc_adapter[1] == 0 && mc_adapter[2] == 0 && mc_adapter[3] == 0)){
138 LOG_INFO(logger, "Multicast adapter: %s", mc_adapter.string().c_str());
139 uint8_t ip_arr[4] = {mc_adapter[0], mc_adapter[1], mc_adapter[2], mc_adapter[3]};
140 jrtplib::RTPIPv4Address rtp_ip;
141 rtp_ip.SetIP(ip_arr);
142 transparams.SetMulticastInterfaceIP(rtp_ip.GetIP());
143 }
144
145 int status = session->Create(sessionparams, &transparams, transparams.GetTransmissionProtocol());
146 if (status < 0) {
147 LOG_ERROR(logger, "session->Create Failed: %s", jrtplib::RTPGetErrorString(status).c_str());
148 return;
149 }
150 jrtplib::RTPUDPv4TransmissionInfo *info = reinterpret_cast<jrtplib::RTPUDPv4TransmissionInfo*>(session->GetTransmissionInfo());
151 rtp_port = info->GetRTPPort();
152 rtcp_port = info->GetRTCPPort();
153 }
154 else {
155 jrtplib::RTPTCPTransmissionParams transparams;
156 int status = session->Create(sessionparams, &transparams, transparams.GetTransmissionProtocol());
157
158 if (status < 0) {
159 LOG_ERROR(logger, "session->Create Failed: %s", jrtplib::RTPGetErrorString(status).c_str());
160 return;
161 }
162 rtp_port = port;
163 rtcp_port = port + 1;
164 }
165
166 // session.SetDefaultPayloadType(96);
167 // session.SetDefaultMark(false);
168 // session.SetDefaultTimestampIncrement(160);
169}
170
171Cogs::RTPStream::~RTPStream()
172{
173 LOG_INFO(logger, "Shutdown");
174 jrtplib::RTPTime delay(10.0);
175 session->BYEDestroy(delay, "BYE", 9);
176 for(auto &tmp : dest) {
177 if(tmp.second.fp) {
178 fclose(tmp.second.fp);
179 }
180 delete [] tmp.second.buffer;
181 }
182 delete session;
183}
184
185void Cogs::RTPStream::AddDestination(const uint8_t in_ip[4], uint16_t in_server_port)
186{
187 for (uint32_t i = 0; i < 4; i++) {
188 ip[i] = in_ip[i];
189 }
190 server_port = in_server_port;
191
192 LOG_INFO(logger, "Add destination %d.%d.%d.%d:%d-%d", ip[0], ip[1], ip[2], ip[3], server_port, server_port+1);
193
194 int status = 0;
195
196 if (useUDP) {
197 status = session->AddDestination(jrtplib::RTPIPv4Address(ip, server_port));
198 }
199 else {
201
202 if (tcpConnection.connect(addr)) {
203 LOG_INFO(logger, "RTPStream::AddDestination: Connected to %d.%d.%d.%d:%d-%d", ip[0], ip[1], ip[2], ip[3], server_port, server_port+1);
204
205 tcpConnection.enableAutoReconnect();
206 status = session->AddDestination(jrtplib::RTPTCPAddress(tcpConnection.getSocket()));
207 }
208 else {
209 LOG_ERROR(logger, "RTPStream::AddDestination failed to connect to : %d.%d.%d.%d:%d", ip[0], ip[1], ip[2], ip[3], server_port);
210 }
211 }
212 if(status < 0){
213 LOG_ERROR(logger, "RTPStream::AddDestination failed: %s", jrtplib::RTPGetErrorString(status).c_str());
214 }
215}
216
217void Cogs::RTPStream::JoinMulticastGroup(const uint8_t in_ip[4], uint16_t in_server_port)
218{
219 server_port = in_server_port;
220 for(uint32_t i=0; i<4; i++) ip[i] = in_ip[i];
221 LOG_INFO(logger, "Join multicast group %d.%d.%d.%d:%d-%d", ip[0], ip[1], ip[2], ip[3], server_port, server_port+1);
222 jrtplib::RTPIPv4Address addr(ip, server_port);
223 if(!session->SupportsMulticasting()){
224 LOG_ERROR(logger, "session->SupportsMulticasting failed. (Possibly duplicate connection)");
225 return;
226 }
227 int status = session->JoinMulticastGroup(addr);
228 if(status < 0){
229 LOG_ERROR(logger, "session->JoinMulticastGroup failed: %s",
230 jrtplib::RTPGetErrorString(status).c_str());
231 }
232}
233
234void Cogs::RTPStream::SendPacket(const uint8_t *buffer, size_t size)
235{
236 int status = session->SendPacket(buffer, size);
237 if(status < 0){
238 LOG_ERROR(logger, "session->SendPacket failed: %s",
239 jrtplib::RTPGetErrorString(status).c_str());
240 return;
241 }
242}
243
244static bool g_first = true;
245
246void Cogs::RTPStream::AddSSRC(uint32_t ssrc, Cogs::Core::Codec codec_in, ResourceId textureId)
247{
248 Dest d = {};
249 d.first = g_first;
250 g_first = false;
251 d.textureHandle = Cogs::Core::TextureHandle(context->textureManager->getHandle(textureId));
252 d.codec = codec_in;
253 // if(false){
254 // std::string file = "test_stream_" + std::to_string(stream_number++) + ".h264";
255 // LOG_INFO(logger, "Writing file %s", file.c_str());
256 // d.fp = fopen(file.c_str(), "wb");
257 // }
258 d.buffer_size = INITIAL_BUFFER;
259 d.buffer = new char[d.buffer_size];
260
261 LOG_INFO(logger, "Adding SSRC 0x%x to RTPStream %p", ssrc, this);
262
263 dest[ssrc] = std::move(d);
264}
265
266void Cogs::RTPStream::WriteData(Dest &dest_w)
267{
268 // Export to file...
269 if(dest_w.fp) {
270 fwrite(dest_w.nalu.data(), 1, dest_w.nalu.size(), dest_w.fp);
271 }
272
273 // Upload to decoder...
274 if(HandleIsValid(dest_w.textureHandle)){
275 IVideoDecoderContext* decoderContext = context->videoDecoderContext;
276
277 if (decoderContext) {
278 VideoDecoderPayload payload = {};
279
280 payload.size = dest_w.nalu.size();
281 payload.data = dest_w.nalu.data();
282 payload.timestamp = dest_w.timestamp;
283 payload.use_timestamp = true;
284
285 decoderContext->streamVideoData(dest_w.textureHandle, payload);
286 }
287 }
288 dest_w.nalu.clear();
289}
290
291Cogs::RTPStream::Dest *Cogs::RTPStream::GetLatestStream()
292{
293 uint64_t t = 0;
294 Dest *ret = nullptr;
295 for(auto &tmp : dest){
296 if(tmp.second.receive_time >= t){
297 t = tmp.second.receive_time;
298 ret = &tmp.second;
299 }
300 }
301 return ret;
302}
303
304void Cogs::RTPStream::Update()
305{
306 if(use_pool_thread) {
307 session->BeginDataAccess();
308 }
309 else {
310 session->Poll();
311 }
312
313 // Update TimestampUnit and handle BYE
314 if(session->GotoFirstSource()){
315 do{
316 jrtplib::RTPSourceData *source = session->GetCurrentSourceInfo();
317 source->SetTimestampUnit(1.0/clock_rate);
318 if(source->ReceivedBYE()){
319 uint32_t ssrc = source->GetSSRC();
320 auto iter = dest.find(ssrc);
321 if(iter != dest.end()){
322 size_t bye_len;
323 uint8_t *bye_reason = source->GetBYEReason(&bye_len);
324 jrtplib::RTPTime rtp_time = source->GetBYETime();
325 uint64_t bye_time = rtp_time.GetSeconds() * 1000000LL + rtp_time.GetMicroSeconds();
326 LOG_INFO(logger, "Removing SSRC 0x%x from RTPStream %p. BYE: %s (t=%" PRIu64 ")",
327 ssrc, this, bye_reason ? std::string((char*)bye_reason, bye_len).c_str() : "", bye_time);
328 if(iter->second.fp)
329 fclose(iter->second.fp);
330 delete [] iter->second.buffer;
331 dest.erase(iter);
332 }
333 }
334 } while(session->GotoNextSource());
335 }
336 else {
337 LOG_ERROR(logger, "GotoFirstSource() failed for RTPStream %p.", this);
338 }
339
340 // Handle Incoming Data
341 if(session->GotoFirstSourceWithData()){
342 std::unique_lock lock(dest_mu);
343 do {
344 jrtplib::RTPPacket *packet;
345
346 while ((packet = session->GetNextPacket()) != 0) {
347 uint32_t ssrc = packet->GetSSRC();
348 uint32_t eseq = packet->GetExtendedSequenceNumber();
349 uint8_t* data = packet->GetPayloadData();
350 size_t size = packet->GetPayloadLength();
351 jrtplib::RTPTime rtime = packet->GetReceiveTime();
352 uint64_t pkt_rtime = rtime.GetSeconds() * 1000000LL + rtime.GetMicroSeconds();
353 uint64_t pkt_time = 0xF000000000000000ULL;
354
355 if (packet->HasExtension()) {
356 uint16_t ext_id = packet->GetExtensionID();
357 size_t ext_size = packet->GetExtensionLength();
358 uint8_t *ext_data = packet->GetExtensionData();
359 // LOG_INFO(logger, "RTP Has extension id %u size %zu", ext_id, ext_size);
360
361 // One byte header extension rfc5285
362 if(rtp_one_byte_header_extension){
363 // LOG_INFO(logger, "RTP one byte header extension");
364 size_t idx = 0;
365 while(idx < ext_size) {
366 uint8_t ext_ext_header = ext_data[idx++];
367 if(ext_ext_header == 0) continue; // Padding byte
368 if(idx == ext_size) break;
369 uint16_t ext_ext_id = (ext_ext_header&0xf0)>>4;
370 size_t ext_ext_size = 1+ext_ext_header&0xf;
371 if(ext_ext_id == 15) break;
372 uint8_t *ext_ext_data = &ext_data[idx];
373 // Synchronisation metadata: 64-bit timestamp format
374 if(rfc6051_ext_id != 0 && ext_ext_id == rfc6051_ext_id){
375 uint64_t pkt_time_ext = 0;
376 uint64_t ntp =
377 ((uint64_t)ext_ext_data[7]<<0) |
378 ((uint64_t)ext_ext_data[6]<<8) |
379 ((uint64_t)ext_ext_data[5]<<16) |
380 ((uint64_t)ext_ext_data[4]<<24) |
381 ((uint64_t)ext_ext_data[3]<<32) |
382 ((uint64_t)ext_ext_data[2]<<40) |
383 ((uint64_t)ext_ext_data[1]<<48) |
384 ((uint64_t)ext_ext_data[0]<<56);
385 auto tconv = jrtplib::RTPTime(jrtplib::RTPNTPTime((ntp>>32)&0xffffffffu, ntp&0xffffffffu));
386 pkt_time_ext = tconv.GetSeconds() * 1000000LL + tconv.GetMicroSeconds();
387 static uint32_t testvar = 0;
388 if(testvar < 20){
389 LOG_INFO(logger, "NTP ts %" PRIu64 " ", ntp);
390 LOG_INFO(logger, "Using RTP 64 bit timestamp extension. (ext ts %" PRIu64 " old ts %" PRIu64 ")",
391 pkt_time_ext, pkt_time);
392 testvar++;
393 }
394 pkt_time = pkt_time_ext;
395 }
396 else{
397 LOG_WARNING(logger, "RTP has unused OBH extension id %u size %zu", ext_ext_id, ext_ext_size);
398 }
399 idx += ext_ext_size;
400 }
401 }
402
403 // Two byte header extension rfc5285
404 else if(rtp_two_byte_header_extension){
405 LOG_WARNING(logger, "RTP two byte header extension not supported."); // TODO add support for this?
406 }
407
408 // Unused extension
409 else{
410 LOG_WARNING(logger, "RTP has unused extension id %u size %zu.", ext_id, ext_size);
411 }
412 }
413 if (pkt_time == 0xF000000000000000ULL) {
414 jrtplib::RTPSourceData* source_data = session->GetCurrentSourceInfo();
415
416 if (source_data->SR_HasInfo()) {
417 uint32_t ref_ts = source_data->SR_GetRTPTimestamp();
418 double ts_unit = source_data->GetTimestampUnit();
419 uint32_t pkt_ts = packet->GetTimestamp();
420 int64_t ts_diff = timestamp_diff(pkt_ts, ref_ts);
421 int64_t ts_diff_us = (int64_t)((double)ts_diff * (ts_unit * 1000000.0));
422
423 // Flush packets if older then 5 seconds from senders report
424 if(ts_diff_us >= -1000000.0*5.0){
425 jrtplib::RTPTime ref_ntp_rtp = jrtplib::RTPTime(source_data->SR_GetNTPTimestamp());
426 uint64_t ref_time = ref_ntp_rtp.GetSeconds() * 1000000LL + ref_ntp_rtp.GetMicroSeconds();
427
428 pkt_time = ref_time + ts_diff_us;
429 }
430 else {
431 source_data->FlushPackets();
432 LOG_INFO(logger,"RTPStream %p: Flushed Packets SSRC 0x%x"
433 "(pkg age %" PRId64 " us pkt_ts %d ref_ts %d ts_unit %f)",
434 this, ssrc, ts_diff_us, pkt_ts, ref_ts, ts_unit);
435 }
436 }
437 else {
438 //LOG_ERROR(logger, "RTPStream %p has not received any SenderInfo.", this);
439 // No sender report, just use packet timestamp
440 pkt_time = packet->GetTimestamp();
441 }
442 }
443
444 if (pkt_time != 0xF000000000000000ULL) {
445 auto iter = dest.find(ssrc);
446 if(iter == dest.end()){
447 LOG_INFO(logger, "Adding SSRC 0x%x to RTPStream %p", ssrc, this);
448 Dest d = {};
449 d.first = g_first;
450 g_first = false;
451 d.textureHandle = Cogs::Core::TextureHandle::NoHandle;
452 d.codec = codec;
453 // if(false){
454 // std::string file = "test_stream_" + std::to_string(stream_number++) + ".h264";
455 // LOG_INFO(logger, "Writing file %s", file.c_str());
456 // d.fp = fopen(file.c_str(), "wb");
457 // }
458 d.buffer_size = INITIAL_BUFFER;
459 d.buffer = new char[d.buffer_size];
460 iter = dest.insert({ssrc, std::move(d)}).first;
461 }
462 Dest &d = iter->second;
463
464 if(d.first){
465 // uint32_t type = packet->GetPayloadType();
466 // printf("Got packet extended seq %d SSRC %x PayloadType %d MarkerBit %s Extension %s\n",
467 // eseq, ssrc, type, packet->HasMarker()?"true":"false", packet->HasExtension()?"true":"false");
468 }
469 if (d.pps.size() && pkt_time != d.timestamp) {
470 // int64_t ct = Cogs::Timer::currentTimeMicroseconds();
471 // int64_t diff = ct - pkt_time;
472 // int64_t rcv_diff = ct - pkt_rtime;
473 // printf("diff %f\tts_diff_us %f\tts_diff %lld\trcv_diff %f\n", diff/1000000.0, ts_diff_us/1000000.0, ts_diff, rcv_diff/1000000.0);
474 }
475
476 d.prev_receive_time = d.receive_time;
477 d.receive_time = pkt_rtime;
478 d.prev_timestamp = d.timestamp;
479 d.timestamp = pkt_time;
480 d.size = size;
481 d.prev_eseq = d.eseq;
482 d.eseq = eseq;
483
484 // for(size_t i=0; i<size && i<=1500; i++){
485 // printf("%2X ", data[i]);
486 // if(i%16 == 15) printf("\n");
487 // }
488
489 d.size_akk += (uint32_t)size;
490 if(d.receive_time-d.rate_time > 1ull<<27){
491 double rt_diff = (d.receive_time-d.rate_time)*(1.0/(1ull<<32));
492 double rate = (d.size_akk*8)/rt_diff;
493 double a = 1.0/8;
494 d.rate = (1.0-a)*d.rate + a*rate;
495 d.rate_time = d.receive_time;
496 d.size_akk = 0;
497 }
498
499
500 if (d.codec == Cogs::Core::Codec::None) {
501 }
502 else if (d.codec == Cogs::Core::Codec::HEVC) {
503 if((data[0] & 0x80) != 0){
504 LOG_ERROR(logger, "Corrupt RTP HEVC packet (f != 0). (RTPStream %p). Possible MPEG-TS stream not supported.", this);
505 session->DeletePacket(packet);
506 continue;
507 }
508 uint32_t type = (data[0]>>1)&0x3f;
509 // uint32_t layerId = (data[0]&0x1)<<8 | data[1]&0xf8;
510 uint32_t TID = data[1]&0x7;
511 if(TID == 0){
512 // A TID value of 0 is illegal to ensure that there is at least one bit in the NAL unit
513 // header equal to 1, so to enable independent considerations of start code emulations
514 // in the NAL unit header and in the NAL unit payload data.
515 LOG_ERROR(logger, "Corrupt RTP H265 packet (TID == 0).");
516 session->DeletePacket(packet);
517 continue;
518 }
519 // TODO DONL if(sprop-max-don-diff > 0)
520
521 if (type <= 40) {
522 processH265NALU(d, type, data, size);
523 }
524 else if (type == 48) { // Agregation Packets AP
525 LOG_ERROR(logger, "H265 aggregation packets are not supported.");
526 assert(false); // TODO
527 }
528 else if (type == 49) { // Fragment Unit FUs
529 uint32_t s = (data[2] >> 7) & 0x1; // Start of fragmented NAL unit
530 uint32_t e = (data[2] >> 6) & 0x1; // End of fragmented NAL unit
531 uint32_t fu_type = data[2] & 0x3f;
532
533 assert(fu_type >= 0 && fu_type <= 40);
534
535 // TODO DONL if(sprop-max-don-diff > 0)
536 if (s) {
537 d.nalu.write(naluStartCode, sizeof(naluStartCode));
538 d.nalu.write8(static_cast<uint8_t>(fu_type << 1));
539 d.nalu.write8(1);
540 }
541 size_t beg = 3; // TODO 5 DONL
542 size_t siz = size-beg;
543 d.nalu.write(&data[beg], siz);
544 if (e) {
545 WriteData(d);
546 }
547 }
548 else{
549 LOG_ERROR(logger, "Unsupported H265 packet of type %d encountered.", type);
550 //assert(false);
551 }
552 }
553 else if (d.codec == Cogs::Core::Codec::H264) {
554 if((data[0] & 0x80 ) != 0){
555 LOG_ERROR(logger, "Corrupt RTP H264 packet (f != 0). (RTPStream %p). Possible MPEG-TS stream not supported.", this);
556 session->DeletePacket(packet);
557 continue;
558 }
559 uint32_t nri = (data[0] >> 5) & 0x3f;
560 uint32_t rtp_type = data[0] & 0x1f;
561
562 if (rtp_type <= 23){ // Single NAL Unit Packet (NAL unit)
563 processH264NALU(d, rtp_type, data, size);
564 }
565 else if(rtp_type == 24) { // Single-time aggregation packet (STAP-A)
566 uint8_t* read = data + 1;
567
568 while (read < (data + size)) {
569 uint16_t naluSize = ntohs(*reinterpret_cast<uint16_t*>(read));
570 read += 2;
571
572 if ((read[0] & 0x80) != 0) {
573 LOG_ERROR(logger, "Corrupt RTP H264 packet: Non-zero 'f' field in STAP-A NALU. (RTPStream %p). Possible MPEG-TS stream not supported.", this);
574 }
575 else {
576 processH264NALU(d, read[0] & 0x1f, read, naluSize);
577 }
578 read += naluSize;
579 }
580 }
581 else if (rtp_type == 25) { // Single-time aggregation packet (STAP_B)
582 LOG_ERROR(logger, "STAP-B packets are not supported.");
583 assert(false);
584 }
585 else if ((rtp_type == 26) || (rtp_type == 27)) { // Multi-time aggregation packet (MTAP16, MTAP24)
586 LOG_ERROR(logger, "MTAP packets are not supported.");
587 assert(false);
588 }
589 else if ((rtp_type == 28) || (rtp_type == 29)) { // Fragmentation unit (FU-A, FU-B)
590 assert(rtp_type == 28);
591 uint32_t s = (data[1]>>7)&0x1; // Start of fragmented NAL unit
592 uint32_t e = (data[1]>>6)&0x1; // End of fragmented NAL unit
593 uint32_t r = (data[1]>>5)&0x1;
594 assert(r == 0);
595 uint32_t type = (data[1]>>0)&0x1f;
596 if(rtp_type == 29){
597 //uint16_t DON = (data[2]<<8) | (data[3]<<0);
598 }
599 if(type == 1){ // Coded slice of a non-IDR picture
600 if(s){
601 d.nalu.write(naluStartCode, sizeof(naluStartCode));
602 d.nalu.write8(static_cast<uint8_t>((nri<<5) | type));
603 }
604 size_t beg = (rtp_type == 29) ? 4 : 2;
605
606 d.nalu.write(&data[beg], size - beg);
607 if (e) {
608 WriteData(d);
609 }
610 }
611 else if(type == 5){ // Coded slice of an IDR picture
612 if(s){
613 d.nalu.write(naluStartCode, sizeof(naluStartCode));
614 d.nalu.write8(static_cast<uint8_t>((nri<<5) | type));
615 }
616 size_t beg = (rtp_type == 29) ? 4 : 2;
617
618 d.nalu.write(&data[beg], size - beg);
619 if (e) {
620 WriteData(d);
621 }
622 }
623 else if (type == 0) { // Unspecified type
624 if (s) {
625 d.nalu.write(naluStartCode, sizeof(naluStartCode));
626 d.nalu.write8(static_cast<uint8_t>((nri << 5) | type));
627 }
628 size_t beg = (rtp_type == 29) ? 4 : 2;
629
630 d.nalu.write(&data[beg], size - beg);
631 if (e) {
632 WriteData(d);
633 }
634 }
635 else{
636 assert(false);
637 }
638 }
639 else{
640 assert(false);
641 }
642 }
643 else{
644 assert(false); // Unsupported codec
645 }
646 }
647 session->DeletePacket(packet);
648 }
649 }
650 while(session->GotoNextSourceWithData());
651 }
652 if (use_pool_thread) {
653 session->EndDataAccess();
654 }
655}
656
657void Cogs::RTPStream::processH264NALU(Dest& dest, uint32_t rtpType, const void* data, size_t size) {
658 assert (rtpType <= 23);
659
660 if ((rtpType == 7) && !dest.sps.size()) {
661 dest.sps = std::string(static_cast<const char*>(data), size);
662 LOG_INFO(logger, "RTP received H264 SPS (RTPStream %p)", this);
663 }
664 else if ((rtpType == 8) && !dest.pps.size()){
665 dest.pps = std::string(static_cast<const char*>(data), size);
666 LOG_INFO(logger, "RTP received H264 PPS (RTPStream %p)", this);
667 }
668 dest.nalu.write(naluStartCode, sizeof(naluStartCode));
669 dest.nalu.write(data, size);
670 WriteData(dest);
671}
672
673void Cogs::RTPStream::processH265NALU(Dest& dest, uint32_t rtpType, const void* data, size_t size) {
674 assert (rtpType <= 40);
675
676 if ((rtpType == 32) && !dest.vps.size()) {
677 dest.vps = std::string(static_cast<const char*>(data), size);
678 LOG_INFO(logger, "RTP receive H265 VPS (RTPStream %p)", this);
679 }
680 else if((rtpType == 33) && !dest.sps.size()) {
681 dest.sps = std::string(static_cast<const char*>(data), size);
682 LOG_INFO(logger, "RTP receive H265 SPS (RTPStream %p)", this);
683 }
684 else if((rtpType == 34) && !dest.pps.size()) {
685 dest.pps = std::string(static_cast<const char*>(data), size);
686 LOG_INFO(logger, "RTP receive H265 PPS (RTPStream %p)", this);
687 }
688 dest.nalu.write(naluStartCode, sizeof(naluStartCode));
689 dest.nalu.write(data, size);
690 WriteData(dest);
691}
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
Log implementation class.
Definition: LogManager.h:140
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.