Record H264 NALU type in the h264 header.

BUG=
R=niklas.enbom@webrtc.org, stefan@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/48999004

Cr-Commit-Position: refs/heads/master@{#9072}
This commit is contained in:
Noah Richards
2015-04-23 11:15:08 -07:00
parent fe7a80c38c
commit 9728241e6a
5 changed files with 49 additions and 27 deletions

View File

@ -61,9 +61,25 @@ struct RTPVideoHeaderVP8 {
// in a VP8 partition. Otherwise false
};
// The packetization types that we support: single, aggregated, and fragmented.
enum H264PacketizationTypes {
kH264SingleNalu, // This packet contains a single NAL unit.
kH264StapA, // This packet contains STAP-A (single time
// aggregation) packets. If this packet has an
// associated NAL unit type, it'll be for the
// first such aggregated packet.
kH264FuA, // This packet contains a FU-A (fragmentation
// unit) packet, meaning it is a part of a frame
// that was too large to fit into a single packet.
};
struct RTPVideoHeaderH264 {
bool stap_a;
bool single_nalu;
uint8_t nalu_type; // The NAL unit type. If this is a header for a
// fragmented packet, it's the NAL unit type of
// the original data. If this is the header for an
// aggregated packet, it's the NAL unit type of
// the first NAL unit in the packet.
H264PacketizationTypes packetization_type;
};
union RTPVideoTypeHeader {

View File

@ -46,14 +46,15 @@ void ParseSingleNalu(RtpDepacketizer::ParsedPayload* parsed_payload,
parsed_payload->type.Video.isFirstPacket = true;
RTPVideoHeaderH264* h264_header =
&parsed_payload->type.Video.codecHeader.H264;
h264_header->single_nalu = true;
h264_header->stap_a = false;
uint8_t nal_type = payload_data[0] & kTypeMask;
if (nal_type == kStapA) {
nal_type = payload_data[3] & kTypeMask;
h264_header->stap_a = true;
h264_header->packetization_type = kH264StapA;
} else {
h264_header->packetization_type = kH264SingleNalu;
}
h264_header->nalu_type = nal_type;
switch (nal_type) {
case kSps:
@ -95,8 +96,8 @@ void ParseFuaNalu(RtpDepacketizer::ParsedPayload* parsed_payload,
parsed_payload->type.Video.isFirstPacket = first_fragment;
RTPVideoHeaderH264* h264_header =
&parsed_payload->type.Video.codecHeader.H264;
h264_header->single_nalu = false;
h264_header->stap_a = false;
h264_header->packetization_type = kH264FuA;
h264_header->nalu_type = original_nal_type;
}
} // namespace

View File

@ -207,9 +207,9 @@ TEST(RtpPacketizerH264Test, TestSingleNaluTwoPackets) {
TEST(RtpPacketizerH264Test, TestStapA) {
const size_t kFrameSize =
kMaxPayloadSize - 3 * kLengthFieldLength - kNalHeaderSize;
uint8_t frame[kFrameSize] = {0x07, 0xFF, // F=0, NRI=0, Type=7.
0x08, 0xFF, // F=0, NRI=0, Type=8.
0x05}; // F=0, NRI=0, Type=5.
uint8_t frame[kFrameSize] = {0x07, 0xFF, // F=0, NRI=0, Type=7 (SPS).
0x08, 0xFF, // F=0, NRI=0, Type=8 (PPS).
0x05}; // F=0, NRI=0, Type=5 (IDR).
const size_t kPayloadOffset = 5;
for (size_t i = 0; i < kFrameSize - kPayloadOffset; ++i)
frame[i + kPayloadOffset] = i;
@ -398,7 +398,7 @@ class RtpDepacketizerH264Test : public ::testing::Test {
};
TEST_F(RtpDepacketizerH264Test, TestSingleNalu) {
uint8_t packet[2] = {0x05, 0xFF}; // F=0, NRI=0, Type=5.
uint8_t packet[2] = {0x05, 0xFF}; // F=0, NRI=0, Type=5 (IDR).
RtpDepacketizer::ParsedPayload payload;
ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet)));
@ -406,15 +406,17 @@ TEST_F(RtpDepacketizerH264Test, TestSingleNalu) {
EXPECT_EQ(kVideoFrameKey, payload.frame_type);
EXPECT_EQ(kRtpVideoH264, payload.type.Video.codec);
EXPECT_TRUE(payload.type.Video.isFirstPacket);
EXPECT_TRUE(payload.type.Video.codecHeader.H264.single_nalu);
EXPECT_FALSE(payload.type.Video.codecHeader.H264.stap_a);
EXPECT_EQ(kH264SingleNalu,
payload.type.Video.codecHeader.H264.packetization_type);
EXPECT_EQ(kIdr, payload.type.Video.codecHeader.H264.nalu_type);
}
TEST_F(RtpDepacketizerH264Test, TestStapAKey) {
uint8_t packet[16] = {kStapA, // F=0, NRI=0, Type=24.
// Length, nal header, payload.
0, 0x02, kIdr, 0xFF, 0, 0x03, kIdr, 0xFF,
0x00, 0, 0x04, kIdr, 0xFF, 0x00, 0x11};
0, 0x02, kSps, 0xFF,
0, 0x03, kPps, 0xFF, 0x00,
0, 0x04, kIdr, 0xFF, 0x00, 0x11};
RtpDepacketizer::ParsedPayload payload;
ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet)));
@ -422,8 +424,9 @@ TEST_F(RtpDepacketizerH264Test, TestStapAKey) {
EXPECT_EQ(kVideoFrameKey, payload.frame_type);
EXPECT_EQ(kRtpVideoH264, payload.type.Video.codec);
EXPECT_TRUE(payload.type.Video.isFirstPacket);
EXPECT_TRUE(payload.type.Video.codecHeader.H264.single_nalu);
EXPECT_TRUE(payload.type.Video.codecHeader.H264.stap_a);
EXPECT_EQ(kH264StapA, payload.type.Video.codecHeader.H264.packetization_type);
// NALU type for aggregated packets is the type of the first packet only.
EXPECT_EQ(kSps, payload.type.Video.codecHeader.H264.nalu_type);
}
TEST_F(RtpDepacketizerH264Test, TestStapADelta) {
@ -438,8 +441,9 @@ TEST_F(RtpDepacketizerH264Test, TestStapADelta) {
EXPECT_EQ(kVideoFrameDelta, payload.frame_type);
EXPECT_EQ(kRtpVideoH264, payload.type.Video.codec);
EXPECT_TRUE(payload.type.Video.isFirstPacket);
EXPECT_TRUE(payload.type.Video.codecHeader.H264.single_nalu);
EXPECT_TRUE(payload.type.Video.codecHeader.H264.stap_a);
EXPECT_EQ(kH264StapA, payload.type.Video.codecHeader.H264.packetization_type);
// NALU type for aggregated packets is the type of the first packet only.
EXPECT_EQ(kSlice, payload.type.Video.codecHeader.H264.nalu_type);
}
TEST_F(RtpDepacketizerH264Test, TestFuA) {
@ -473,8 +477,8 @@ TEST_F(RtpDepacketizerH264Test, TestFuA) {
EXPECT_EQ(kVideoFrameKey, payload.frame_type);
EXPECT_EQ(kRtpVideoH264, payload.type.Video.codec);
EXPECT_TRUE(payload.type.Video.isFirstPacket);
EXPECT_FALSE(payload.type.Video.codecHeader.H264.single_nalu);
EXPECT_FALSE(payload.type.Video.codecHeader.H264.stap_a);
EXPECT_EQ(kH264FuA, payload.type.Video.codecHeader.H264.packetization_type);
EXPECT_EQ(kIdr, payload.type.Video.codecHeader.H264.nalu_type);
// Following packets will be 2 bytes shorter since they will only be appended
// onto the first packet.
@ -484,8 +488,8 @@ TEST_F(RtpDepacketizerH264Test, TestFuA) {
EXPECT_EQ(kVideoFrameKey, payload.frame_type);
EXPECT_EQ(kRtpVideoH264, payload.type.Video.codec);
EXPECT_FALSE(payload.type.Video.isFirstPacket);
EXPECT_FALSE(payload.type.Video.codecHeader.H264.single_nalu);
EXPECT_FALSE(payload.type.Video.codecHeader.H264.stap_a);
EXPECT_EQ(kH264FuA, payload.type.Video.codecHeader.H264.packetization_type);
EXPECT_EQ(kIdr, payload.type.Video.codecHeader.H264.nalu_type);
payload = RtpDepacketizer::ParsedPayload();
ASSERT_TRUE(depacketizer_->Parse(&payload, packet3, sizeof(packet3)));
@ -493,7 +497,7 @@ TEST_F(RtpDepacketizerH264Test, TestFuA) {
EXPECT_EQ(kVideoFrameKey, payload.frame_type);
EXPECT_EQ(kRtpVideoH264, payload.type.Video.codec);
EXPECT_FALSE(payload.type.Video.isFirstPacket);
EXPECT_FALSE(payload.type.Video.codecHeader.H264.single_nalu);
EXPECT_FALSE(payload.type.Video.codecHeader.H264.stap_a);
EXPECT_EQ(kH264FuA, payload.type.Video.codecHeader.H264.packetization_type);
EXPECT_EQ(kIdr, payload.type.Video.codecHeader.H264.nalu_type);
}
} // namespace webrtc

View File

@ -123,7 +123,7 @@ void VCMPacket::CopyCodecSpecifics(const RTPVideoHeader& videoHeader) {
if (isFirstPacket)
insertStartCode = true;
if (videoHeader.codecHeader.H264.single_nalu) {
if (isFirstPacket && markerBit) {
completeNALU = kNaluComplete;
} else if (isFirstPacket) {
completeNALU = kNaluStart;

View File

@ -136,7 +136,8 @@ size_t VCMSessionInfo::InsertBuffer(uint8_t* frame_buffer,
const size_t kH264NALHeaderLengthInBytes = 1;
const size_t kLengthFieldLength = 2;
if (packet.codecSpecificHeader.codec == kRtpVideoH264 &&
packet.codecSpecificHeader.codecHeader.H264.stap_a) {
packet.codecSpecificHeader.codecHeader.H264.packetization_type ==
kH264StapA) {
size_t required_length = 0;
const uint8_t* nalu_ptr = packet_buffer + kH264NALHeaderLengthInBytes;
while (nalu_ptr < packet_buffer + packet.sizeBytes) {