Fix is_first_packet_in_frame when receiving multiple slices per H264 frame
Bug: webrtc:346608838 Change-Id: I70ad3a952f37dde878f77d35c959c6973d283b9c Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/354460 Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Reviewed-by: Sergey Silkin <ssilkin@webrtc.org> Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42497}
This commit is contained in:
parent
a0b22af9e1
commit
e19ce9b3db
@ -53,21 +53,26 @@ bool PpsParser::ParsePpsIds(const uint8_t* data,
|
|||||||
return reader.Ok();
|
return reader.Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::optional<uint32_t> PpsParser::ParsePpsIdFromSlice(const uint8_t* data,
|
absl::optional<PpsParser::SliceHeader> PpsParser::ParseSliceHeader(
|
||||||
size_t length) {
|
const uint8_t* data,
|
||||||
|
size_t length) {
|
||||||
std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data, length);
|
std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data, length);
|
||||||
BitstreamReader slice_reader(unpacked_buffer);
|
BitstreamReader slice_reader(unpacked_buffer);
|
||||||
|
PpsParser::SliceHeader slice_header;
|
||||||
|
|
||||||
// first_mb_in_slice: ue(v)
|
// first_mb_in_slice: ue(v)
|
||||||
slice_reader.ReadExponentialGolomb();
|
slice_header.first_mb_in_slice = slice_reader.ReadExponentialGolomb();
|
||||||
// slice_type: ue(v)
|
// slice_type: ue(v)
|
||||||
slice_reader.ReadExponentialGolomb();
|
slice_reader.ReadExponentialGolomb();
|
||||||
// pic_parameter_set_id: ue(v)
|
// pic_parameter_set_id: ue(v)
|
||||||
uint32_t slice_pps_id = slice_reader.ReadExponentialGolomb();
|
slice_header.pic_parameter_set_id = slice_reader.ReadExponentialGolomb();
|
||||||
|
|
||||||
|
// The rest of the slice header requires information from the SPS to parse.
|
||||||
|
|
||||||
if (!slice_reader.Ok()) {
|
if (!slice_reader.Ok()) {
|
||||||
return absl::nullopt;
|
return absl::nullopt;
|
||||||
}
|
}
|
||||||
return slice_pps_id;
|
return slice_header;
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::optional<PpsParser::PpsState> PpsParser::ParseInternal(
|
absl::optional<PpsParser::PpsState> PpsParser::ParseInternal(
|
||||||
|
|||||||
@ -37,6 +37,13 @@ class PpsParser {
|
|||||||
uint32_t sps_id = 0;
|
uint32_t sps_id = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SliceHeader {
|
||||||
|
SliceHeader() = default;
|
||||||
|
|
||||||
|
uint32_t first_mb_in_slice = 0;
|
||||||
|
uint32_t pic_parameter_set_id = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// Unpack RBSP and parse PPS state from the supplied buffer.
|
// Unpack RBSP and parse PPS state from the supplied buffer.
|
||||||
static absl::optional<PpsState> ParsePps(const uint8_t* data, size_t length);
|
static absl::optional<PpsState> ParsePps(const uint8_t* data, size_t length);
|
||||||
|
|
||||||
@ -45,7 +52,7 @@ class PpsParser {
|
|||||||
uint32_t* pps_id,
|
uint32_t* pps_id,
|
||||||
uint32_t* sps_id);
|
uint32_t* sps_id);
|
||||||
|
|
||||||
static absl::optional<uint32_t> ParsePpsIdFromSlice(const uint8_t* data,
|
static absl::optional<SliceHeader> ParseSliceHeader(const uint8_t* data,
|
||||||
size_t length);
|
size_t length);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@ -214,7 +214,7 @@ TEST_F(PpsParserTest, MaxPps) {
|
|||||||
RunTest();
|
RunTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PpsParserTest, PpsIdFromSlice) {
|
TEST_F(PpsParserTest, ParseSliceHeader) {
|
||||||
std::vector<H264::NaluIndex> nalu_indices =
|
std::vector<H264::NaluIndex> nalu_indices =
|
||||||
H264::FindNaluIndices(kH264BitstreamChunk, sizeof(kH264BitstreamChunk));
|
H264::FindNaluIndices(kH264BitstreamChunk, sizeof(kH264BitstreamChunk));
|
||||||
EXPECT_EQ(nalu_indices.size(), 3ull);
|
EXPECT_EQ(nalu_indices.size(), 3ull);
|
||||||
@ -222,9 +222,14 @@ TEST_F(PpsParserTest, PpsIdFromSlice) {
|
|||||||
H264::NaluType nalu_type =
|
H264::NaluType nalu_type =
|
||||||
H264::ParseNaluType(kH264BitstreamChunk[index.payload_start_offset]);
|
H264::ParseNaluType(kH264BitstreamChunk[index.payload_start_offset]);
|
||||||
if (nalu_type == H264::NaluType::kIdr) {
|
if (nalu_type == H264::NaluType::kIdr) {
|
||||||
absl::optional<uint32_t> pps_id = PpsParser::ParsePpsIdFromSlice(
|
// Skip NAL type header and parse slice header.
|
||||||
kH264BitstreamChunk + index.payload_start_offset, index.payload_size);
|
absl::optional<PpsParser::SliceHeader> slice_header =
|
||||||
EXPECT_EQ(pps_id, 0u);
|
PpsParser::ParseSliceHeader(
|
||||||
|
kH264BitstreamChunk + index.payload_start_offset + 1,
|
||||||
|
index.payload_size - 1);
|
||||||
|
ASSERT_TRUE(slice_header.has_value());
|
||||||
|
EXPECT_EQ(slice_header->first_mb_in_slice, 0u);
|
||||||
|
EXPECT_EQ(slice_header->pic_parameter_set_id, 0u);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -196,10 +196,13 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ProcessStapAOrSingleNalu(
|
|||||||
VideoFrameType::kVideoFrameKey;
|
VideoFrameType::kVideoFrameKey;
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case H264::NaluType::kSlice: {
|
case H264::NaluType::kSlice: {
|
||||||
absl::optional<uint32_t> pps_id = PpsParser::ParsePpsIdFromSlice(
|
absl::optional<PpsParser::SliceHeader> slice_header =
|
||||||
&payload_data[start_offset], end_offset - start_offset);
|
PpsParser::ParseSliceHeader(&payload_data[start_offset],
|
||||||
if (pps_id) {
|
end_offset - start_offset);
|
||||||
nalu.pps_id = *pps_id;
|
if (slice_header) {
|
||||||
|
nalu.pps_id = slice_header->pic_parameter_set_id;
|
||||||
|
parsed_payload->video_header.is_first_packet_in_frame &=
|
||||||
|
slice_header->first_mb_in_slice == 0;
|
||||||
} else {
|
} else {
|
||||||
RTC_LOG(LS_WARNING) << "Failed to parse PPS id from slice of type: "
|
RTC_LOG(LS_WARNING) << "Failed to parse PPS id from slice of type: "
|
||||||
<< static_cast<int>(nalu.type);
|
<< static_cast<int>(nalu.type);
|
||||||
@ -237,21 +240,26 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ParseFuaNalu(
|
|||||||
uint8_t fnri = rtp_payload.cdata()[0] & (kH264FBit | kH264NriMask);
|
uint8_t fnri = rtp_payload.cdata()[0] & (kH264FBit | kH264NriMask);
|
||||||
uint8_t original_nal_type = rtp_payload.cdata()[1] & kH264TypeMask;
|
uint8_t original_nal_type = rtp_payload.cdata()[1] & kH264TypeMask;
|
||||||
bool first_fragment = (rtp_payload.cdata()[1] & kH264SBit) > 0;
|
bool first_fragment = (rtp_payload.cdata()[1] & kH264SBit) > 0;
|
||||||
|
bool is_first_packet_in_frame = false;
|
||||||
NaluInfo nalu;
|
NaluInfo nalu;
|
||||||
nalu.type = original_nal_type;
|
nalu.type = original_nal_type;
|
||||||
nalu.sps_id = -1;
|
nalu.sps_id = -1;
|
||||||
nalu.pps_id = -1;
|
nalu.pps_id = -1;
|
||||||
if (first_fragment) {
|
if (first_fragment) {
|
||||||
absl::optional<uint32_t> pps_id =
|
if (original_nal_type == H264::NaluType::kIdr ||
|
||||||
PpsParser::ParsePpsIdFromSlice(rtp_payload.cdata() + 2 * kNalHeaderSize,
|
original_nal_type == H264::NaluType::kSlice) {
|
||||||
rtp_payload.size() - 2 * kNalHeaderSize);
|
absl::optional<PpsParser::SliceHeader> slice_header =
|
||||||
if (pps_id) {
|
PpsParser::ParseSliceHeader(rtp_payload.cdata() + 2 * kNalHeaderSize,
|
||||||
nalu.pps_id = *pps_id;
|
rtp_payload.size() - 2 * kNalHeaderSize);
|
||||||
} else {
|
if (slice_header) {
|
||||||
RTC_LOG(LS_WARNING)
|
nalu.pps_id = slice_header->pic_parameter_set_id;
|
||||||
<< "Failed to parse PPS from first fragment of FU-A NAL "
|
is_first_packet_in_frame = slice_header->first_mb_in_slice == 0;
|
||||||
"unit with original type: "
|
} else {
|
||||||
<< static_cast<int>(nalu.type);
|
RTC_LOG(LS_WARNING)
|
||||||
|
<< "Failed to parse PPS from first fragment of FU-A NAL "
|
||||||
|
"unit with original type: "
|
||||||
|
<< static_cast<int>(nalu.type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
uint8_t original_nal_header = fnri | original_nal_type;
|
uint8_t original_nal_header = fnri | original_nal_type;
|
||||||
rtp_payload =
|
rtp_payload =
|
||||||
@ -272,7 +280,8 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ParseFuaNalu(
|
|||||||
parsed_payload->video_header.height = 0;
|
parsed_payload->video_header.height = 0;
|
||||||
parsed_payload->video_header.codec = kVideoCodecH264;
|
parsed_payload->video_header.codec = kVideoCodecH264;
|
||||||
parsed_payload->video_header.simulcastIdx = 0;
|
parsed_payload->video_header.simulcastIdx = 0;
|
||||||
parsed_payload->video_header.is_first_packet_in_frame = first_fragment;
|
parsed_payload->video_header.is_first_packet_in_frame =
|
||||||
|
is_first_packet_in_frame;
|
||||||
auto& h264_header = parsed_payload->video_header.video_type_header
|
auto& h264_header = parsed_payload->video_header.video_type_header
|
||||||
.emplace<RTPVideoHeaderH264>();
|
.emplace<RTPVideoHeaderH264>();
|
||||||
h264_header.packetization_type = kH264FuA;
|
h264_header.packetization_type = kH264FuA;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user