Skip to content

Commit 7425e0c

Browse files
committed
VP8 depacketizer and VP8naluit
1 parent d4c25bf commit 7425e0c

7 files changed

+559
-8
lines changed

CMakeLists.txt

+6-3
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,10 @@ set(LIBDATACHANNEL_SOURCES
8181
${CMAKE_CURRENT_SOURCE_DIR}/src/h264rtppacketizer.cpp
8282
${CMAKE_CURRENT_SOURCE_DIR}/src/h264rtpdepacketizer.cpp
8383
${CMAKE_CURRENT_SOURCE_DIR}/src/nalunit.cpp
84+
${CMAKE_CURRENT_SOURCE_DIR}/src/vp8nalunit.cpp
8485
${CMAKE_CURRENT_SOURCE_DIR}/src/h265rtppacketizer.cpp
8586
${CMAKE_CURRENT_SOURCE_DIR}/src/h265rtpdepacketizer.cpp
87+
${CMAKE_CURRENT_SOURCE_DIR}/src/vp8rtpdepacketizer.cpp
8688
${CMAKE_CURRENT_SOURCE_DIR}/src/h265nalunit.cpp
8789
${CMAKE_CURRENT_SOURCE_DIR}/src/av1rtppacketizer.cpp
8890
${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpnackresponder.cpp
@@ -119,7 +121,9 @@ set(LIBDATACHANNEL_HEADERS
119121
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtpdepacketizer.hpp
120122
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h264rtppacketizer.hpp
121123
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h264rtpdepacketizer.hpp
124+
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/vp8rtpdepacketizer.hpp
122125
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/nalunit.hpp
126+
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/vp8nalunit.hpp
123127
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h265rtppacketizer.hpp
124128
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h265rtpdepacketizer.hpp
125129
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h265nalunit.hpp
@@ -435,8 +439,8 @@ else()
435439
find_package(OpenSSL REQUIRED)
436440
target_compile_definitions(datachannel PRIVATE USE_GNUTLS=0)
437441
target_compile_definitions(datachannel-static PRIVATE USE_GNUTLS=0)
438-
target_link_libraries(datachannel PRIVATE OpenSSL::SSL)
439-
target_link_libraries(datachannel-static PRIVATE OpenSSL::SSL)
442+
target_link_libraries(datachannel PRIVATE ${OPENSSL_SSL_LIBRARY})
443+
target_link_libraries(datachannel-static PRIVATE ${OPENSSL_SSL_LIBRARY})
440444
endif()
441445

442446
if (USE_NICE)
@@ -594,4 +598,3 @@ if(NOT NO_EXAMPLES)
594598
add_subdirectory(examples/copy-paste)
595599
add_subdirectory(examples/copy-paste-capi)
596600
endif()
597-

include/rtc/nalunit.hpp

+13-5
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ enum NalUnitStartSequenceMatch {
6262

6363
static const size_t H264_NAL_HEADER_SIZE = 1;
6464
static const size_t H265_NAL_HEADER_SIZE = 2;
65+
static const size_t VP8_NAL_HEADER_SIZE = 0;
6566

6667
struct NalUnitFragmentA;
6768

@@ -80,16 +81,23 @@ struct RTC_CPP_EXPORT NalUnit : binary {
8081
static NalUnitStartSequenceMatch StartSequenceMatchSucc(NalUnitStartSequenceMatch match,
8182
std::byte _byte, Separator separator);
8283

83-
enum class Type { H264, H265 };
84+
enum class Type { H264, H265, VP8 };
8485

8586
NalUnit(const NalUnit &unit) = default;
8687
NalUnit(size_t size, bool includingHeader = true, Type type = Type::H264)
87-
: binary(size + (includingHeader ? 0
88-
: (type == Type::H264 ? H264_NAL_HEADER_SIZE
89-
: H265_NAL_HEADER_SIZE))) {}
88+
: binary( size + (includingHeader
89+
? 0
90+
: (type == Type::H264
91+
? H264_NAL_HEADER_SIZE
92+
: (type == Type::H265
93+
? H265_NAL_HEADER_SIZE
94+
: VP8_NAL_HEADER_SIZE))) )
95+
{}
9096
NalUnit(binary &&data) : binary(std::move(data)) {}
9197
NalUnit(Type type = Type::H264)
92-
: binary(type == Type::H264 ? H264_NAL_HEADER_SIZE : H265_NAL_HEADER_SIZE) {}
98+
: binary(type == Type::H264 ? H264_NAL_HEADER_SIZE
99+
: (type == Type::H265 ? H265_NAL_HEADER_SIZE
100+
: VP8_NAL_HEADER_SIZE)) {}
93101
template <typename Iterator> NalUnit(Iterator begin_, Iterator end_) : binary(begin_, end_) {}
94102

95103
bool forbiddenBit() const { return header()->forbiddenBit(); }

include/rtc/rtc.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "h264rtpdepacketizer.hpp"
3434
#include "h265rtppacketizer.hpp"
3535
#include "h265rtpdepacketizer.hpp"
36+
#include "vp8rtpdepacketizer.hpp"
3637
#include "mediahandler.hpp"
3738
#include "plihandler.hpp"
3839
#include "rembhandler.hpp"

include/rtc/vp8naluit.hpp

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#ifndef RTC_VP8_NAL_UNIT_H
2+
#define RTC_VP8_NAL_UNIT_H
3+
4+
#if RTC_ENABLE_MEDIA
5+
6+
#include "common.hpp"
7+
#include "nalunit.hpp"
8+
#include <cassert>
9+
#include <cstdint>
10+
#include <vector>
11+
12+
/*
13+
* Example “VP8NalUnit” derived from your base NalUnit class, mirroring
14+
* how "H265NalUnit" is done. In VP8, there is no true NAL unit concept,
15+
* but we can still parse the "VP8 payload descriptor" (RFC 7741 sec. 4.2)
16+
* from the front of the data, and store or retrieve key bits.
17+
*
18+
* IMPORTANT: We avoid calling NalUnit(std::move(data), Type) since
19+
* NalUnit has no such two-argument constructor. Instead, we do
20+
* NalUnit(std::move(data)) just like your H265 code.
21+
*/
22+
23+
namespace rtc {
24+
25+
#pragma pack(push, 1)
26+
27+
// The mandatory first byte of the VP8 payload descriptor.
28+
// (RFC 7741, Section 4.2)
29+
struct VP8PayloadDescriptorFirstByte {
30+
uint8_t raw = 0;
31+
32+
bool hasExtension() const { return (raw & 0x80) != 0; } // X
33+
bool isNonReference() const { return (raw & 0x20) != 0; } // N
34+
bool isStartOfPartition() const { return (raw & 0x10) != 0; } // S
35+
uint8_t partitionIndex() const { return (raw & 0x07); } // PID
36+
37+
void setHasExtension(bool val) {
38+
if(val) raw |= (1 << 7);
39+
else raw &= ~(1 << 7);
40+
}
41+
void setNonReference(bool val) {
42+
if(val) raw |= (1 << 5);
43+
else raw &= ~(1 << 5);
44+
}
45+
void setStartOfPartition(bool val) {
46+
if(val) raw |= (1 << 4);
47+
else raw &= ~(1 << 4);
48+
}
49+
void setPartitionIndex(uint8_t pid) {
50+
raw = (raw & 0xF8) | (pid & 0x07);
51+
}
52+
};
53+
54+
// Optional extension byte if the X bit = 1.
55+
struct VP8PayloadDescriptorExtensionByte {
56+
uint8_t raw = 0;
57+
58+
bool hasPictureID() const { return (raw & 0x80) != 0; } // I
59+
bool hasTL0PICIDX() const { return (raw & 0x40) != 0; } // L
60+
bool hasTID() const { return (raw & 0x20) != 0; } // T
61+
bool hasKEYIDX() const { return (raw & 0x10) != 0; } // K
62+
};
63+
64+
#pragma pack(pop)
65+
66+
// “VP8NalUnit” extends NalUnit but is really a container for one VP8 frame
67+
// (or partial frame) plus its RTP "payload descriptor" bits.
68+
struct VP8NalUnit : public NalUnit {
69+
public:
70+
// Match your H265NalUnit style:
71+
VP8NalUnit() : NalUnit(NalUnit::Type::VP8) {}
72+
VP8NalUnit(size_t size, bool includingHeader = true)
73+
: NalUnit(size, includingHeader, NalUnit::Type::VP8) {}
74+
VP8NalUnit(binary &&data)
75+
: NalUnit(std::move(data)) {} // call NalUnit(binary && data)
76+
VP8NalUnit(const VP8NalUnit&) = default;
77+
78+
// Parse the VP8 payload descriptor from the beginning of data().
79+
// Returns how many bytes of descriptor were consumed.
80+
size_t parseDescriptor();
81+
82+
// The actual VP8 bitstream data after the descriptor.
83+
binary payload() const;
84+
85+
// If this frame is a keyframe or not (based on the "P" bit in the
86+
// first 3 bytes of the actual VP8 payload when partitionIndex=0).
87+
bool isKeyFrame() const { return mIsKeyFrame; }
88+
89+
// The “S bit” in the first descriptor byte.
90+
bool isStartOfPartition() const { return mFirstByte.isStartOfPartition(); }
91+
92+
VP8PayloadDescriptorFirstByte mFirstByte {0};
93+
94+
// PictureID if present in the extension. (RFC 7741 Section 4.2)
95+
uint16_t pictureID() const { return mPictureID; }
96+
97+
// For demonstration, generating multiple “fragments” from a large frame
98+
// simulating the style of H.265 FU logic, though not standardized for VP8:
99+
static std::vector<binary> GenerateFragments(const std::vector<VP8NalUnit> &units,
100+
size_t maxFragmentSize);
101+
std::vector<VP8NalUnit> generateFragments(size_t maxFragmentSize) const;
102+
103+
private:
104+
bool mHasExtension = false;
105+
VP8PayloadDescriptorExtensionByte mExtByte {0};
106+
107+
bool mHasPictureID = false;
108+
uint16_t mPictureID = 0;
109+
bool mIsKeyFrame = false; // if “P=0” in the first-byte of actual VP8 data
110+
111+
// Implementation detail: parse out extension fields if X=1, etc.
112+
};
113+
114+
} // namespace rtc
115+
116+
#endif /* RTC_ENABLE_MEDIA */
117+
118+
#endif /* RTC_VP8_NAL_UNIT_H */

include/rtc/vp8rtpdepacketizer.hpp

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#ifndef RTC_VP8_RTP_DEPACKETIZER_H
2+
#define RTC_VP8_RTP_DEPACKETIZER_H
3+
4+
#if RTC_ENABLE_MEDIA
5+
6+
#include "common.hpp"
7+
#include "mediahandler.hpp"
8+
#include "message.hpp"
9+
#include "rtp.hpp"
10+
#include "vp8nalunit.hpp"
11+
12+
#include <vector>
13+
#include <cstdint>
14+
#include <algorithm>
15+
#include <memory>
16+
17+
namespace rtc {
18+
19+
/*
20+
* Minimal VP8 depacketizer example, paralleling H265RtpDepacketizer.
21+
* It collects consecutive RTP packets sharing the same timestamp,
22+
* then calls buildFrame() to combine them (sorted by sequence number)
23+
* into a single “frame” or partial frame. If the last packet's M-bit
24+
* is zero, you may be missing more data, but for simplicity we decode
25+
* partial frames anyway.
26+
*/
27+
class RTC_CPP_EXPORT VP8RtpDepacketizer : public MediaHandler {
28+
public:
29+
static constexpr uint32_t ClockRate = 90000; // 90 kHz for video
30+
31+
VP8RtpDepacketizer() = default;
32+
~VP8RtpDepacketizer() override = default;
33+
34+
void incoming(message_vector &messages, const message_callback &send) override;
35+
36+
private:
37+
std::vector<message_ptr> mRtpBuffer;
38+
39+
// Combine all packets [first .. last) with the same timestamp into one frame
40+
message_vector buildFrame(std::vector<message_ptr>::iterator first,
41+
std::vector<message_ptr>::iterator last,
42+
uint8_t payloadType,
43+
uint32_t timestamp);
44+
45+
static bool seqLess(uint16_t a, uint16_t b) {
46+
// Sort by ascending sequence number, with 16-bit wrap
47+
return (int16_t)(a - b) < 0;
48+
}
49+
};
50+
51+
} // namespace rtc
52+
53+
#endif // RTC_ENABLE_MEDIA
54+
55+
#endif // RTC_VP8_RTP_DEPACKETIZER_H

0 commit comments

Comments
 (0)