mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-12 21:30:45 +01:00
Migrate VideoRtpDepacketizerVp9 implementation from BitBuffer to BitstreamReader
The new version is subjectivly cleaner and objectively generates smaller binary size Bug: None Change-Id: I662596c41f30690f7e81a51804dd7feb263510c3 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/231130 Reviewed-by: Åsa Persson <asapersson@webrtc.org> Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/main@{#34935}
This commit is contained in:
parent
f2b7396634
commit
b8dce95006
2 changed files with 64 additions and 124 deletions
|
@ -287,6 +287,7 @@ rtc_library("rtp_rtcp") {
|
|||
"../../logging:rtc_event_audio",
|
||||
"../../logging:rtc_event_rtp_rtcp",
|
||||
"../../modules/audio_coding:audio_coding_module_typedefs",
|
||||
"../../rtc_base:bitstream_reader",
|
||||
"../../rtc_base:checks",
|
||||
"../../rtc_base:divide_round",
|
||||
"../../rtc_base:gtest_prod",
|
||||
|
|
|
@ -15,20 +15,13 @@
|
|||
#include "api/video/video_codec_constants.h"
|
||||
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
|
||||
#include "modules/video_coding/codecs/interface/common_constants.h"
|
||||
#include "rtc_base/bit_buffer.h"
|
||||
#include "rtc_base/bitstream_reader.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
#define RETURN_FALSE_ON_ERROR(x) \
|
||||
if (!(x)) { \
|
||||
return false; \
|
||||
}
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
constexpr int kFailedToParse = 0;
|
||||
|
||||
// Picture ID:
|
||||
//
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
|
@ -37,66 +30,37 @@ constexpr int kFailedToParse = 0;
|
|||
// M: | EXTENDED PID |
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
//
|
||||
bool ParsePictureId(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) {
|
||||
uint32_t picture_id;
|
||||
uint32_t m_bit;
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadBits(1, m_bit));
|
||||
if (m_bit) {
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadBits(15, picture_id));
|
||||
void ParsePictureId(BitstreamReader& parser, RTPVideoHeaderVP9* vp9) {
|
||||
if (parser.ReadBit()) { // m_bit
|
||||
vp9->picture_id = parser.ReadBits(15);
|
||||
vp9->max_picture_id = kMaxTwoBytePictureId;
|
||||
} else {
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadBits(7, picture_id));
|
||||
vp9->picture_id = parser.ReadBits(7);
|
||||
vp9->max_picture_id = kMaxOneBytePictureId;
|
||||
}
|
||||
vp9->picture_id = picture_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Layer indices (flexible mode):
|
||||
// Layer indices :
|
||||
//
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
// L: | T |U| S |D|
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
//
|
||||
bool ParseLayerInfoCommon(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) {
|
||||
uint32_t t, u_bit, s, d_bit;
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadBits(3, t));
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadBits(1, u_bit));
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadBits(3, s));
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadBits(1, d_bit));
|
||||
vp9->temporal_idx = t;
|
||||
vp9->temporal_up_switch = u_bit ? true : false;
|
||||
if (s >= kMaxSpatialLayers)
|
||||
return false;
|
||||
vp9->spatial_idx = s;
|
||||
vp9->inter_layer_predicted = d_bit ? true : false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Layer indices (non-flexible mode):
|
||||
//
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
// L: | T |U| S |D|
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
// | TL0PICIDX |
|
||||
// | TL0PICIDX | (non-flexible mode only)
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
//
|
||||
bool ParseLayerInfoNonFlexibleMode(rtc::BitBuffer* parser,
|
||||
RTPVideoHeaderVP9* vp9) {
|
||||
uint8_t tl0picidx;
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadUInt8(tl0picidx));
|
||||
vp9->tl0_pic_idx = tl0picidx;
|
||||
return true;
|
||||
}
|
||||
void ParseLayerInfo(BitstreamReader& parser, RTPVideoHeaderVP9* vp9) {
|
||||
vp9->temporal_idx = parser.ReadBits(3);
|
||||
vp9->temporal_up_switch = parser.Read<bool>();
|
||||
vp9->spatial_idx = parser.ReadBits(3);
|
||||
vp9->inter_layer_predicted = parser.Read<bool>();
|
||||
if (vp9->spatial_idx >= kMaxSpatialLayers) {
|
||||
parser.Invalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
bool ParseLayerInfo(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) {
|
||||
if (!ParseLayerInfoCommon(parser, vp9))
|
||||
return false;
|
||||
|
||||
if (vp9->flexible_mode)
|
||||
return true;
|
||||
|
||||
return ParseLayerInfoNonFlexibleMode(parser, vp9);
|
||||
if (!vp9->flexible_mode) {
|
||||
vp9->tl0_pic_idx = parser.Read<uint8_t>();
|
||||
}
|
||||
}
|
||||
|
||||
// Reference indices:
|
||||
|
@ -106,19 +70,22 @@ bool ParseLayerInfo(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) {
|
|||
// +-+-+-+-+-+-+-+-+ N=1: An additional P_DIFF follows
|
||||
// current P_DIFF.
|
||||
//
|
||||
bool ParseRefIndices(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) {
|
||||
if (vp9->picture_id == kNoPictureId)
|
||||
return false;
|
||||
void ParseRefIndices(BitstreamReader& parser, RTPVideoHeaderVP9* vp9) {
|
||||
if (vp9->picture_id == kNoPictureId) {
|
||||
parser.Invalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
vp9->num_ref_pics = 0;
|
||||
uint32_t n_bit;
|
||||
bool n_bit;
|
||||
do {
|
||||
if (vp9->num_ref_pics == kMaxVp9RefPics)
|
||||
return false;
|
||||
if (vp9->num_ref_pics == kMaxVp9RefPics) {
|
||||
parser.Invalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t p_diff;
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadBits(7, p_diff));
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadBits(1, n_bit));
|
||||
uint8_t p_diff = parser.ReadBits(7);
|
||||
n_bit = parser.Read<bool>();
|
||||
|
||||
vp9->pid_diff[vp9->num_ref_pics] = p_diff;
|
||||
uint32_t scaled_pid = vp9->picture_id;
|
||||
|
@ -128,8 +95,6 @@ bool ParseRefIndices(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) {
|
|||
}
|
||||
vp9->ref_picture_id[vp9->num_ref_pics++] = scaled_pid - p_diff;
|
||||
} while (n_bit);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Scalability structure (SS).
|
||||
|
@ -152,54 +117,40 @@ bool ParseRefIndices(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) {
|
|||
// | P_DIFF | (OPTIONAL) . R times .
|
||||
// +-+-+-+-+-+-+-+-+ -| -|
|
||||
//
|
||||
bool ParseSsData(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) {
|
||||
uint32_t n_s, y_bit, g_bit;
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadBits(3, n_s));
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadBits(1, y_bit));
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadBits(1, g_bit));
|
||||
RETURN_FALSE_ON_ERROR(parser->ConsumeBits(3));
|
||||
vp9->num_spatial_layers = n_s + 1;
|
||||
vp9->spatial_layer_resolution_present = y_bit ? true : false;
|
||||
void ParseSsData(BitstreamReader& parser, RTPVideoHeaderVP9* vp9) {
|
||||
vp9->num_spatial_layers = parser.ReadBits(3) + 1;
|
||||
vp9->spatial_layer_resolution_present = parser.Read<bool>();
|
||||
bool g_bit = parser.Read<bool>();
|
||||
parser.ConsumeBits(3);
|
||||
vp9->gof.num_frames_in_gof = 0;
|
||||
|
||||
if (y_bit) {
|
||||
if (vp9->spatial_layer_resolution_present) {
|
||||
for (size_t i = 0; i < vp9->num_spatial_layers; ++i) {
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadUInt16(vp9->width[i]));
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadUInt16(vp9->height[i]));
|
||||
vp9->width[i] = parser.Read<uint16_t>();
|
||||
vp9->height[i] = parser.Read<uint16_t>();
|
||||
}
|
||||
}
|
||||
if (g_bit) {
|
||||
uint8_t n_g;
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadUInt8(n_g));
|
||||
vp9->gof.num_frames_in_gof = n_g;
|
||||
vp9->gof.num_frames_in_gof = parser.Read<uint8_t>();
|
||||
}
|
||||
for (size_t i = 0; i < vp9->gof.num_frames_in_gof; ++i) {
|
||||
uint32_t t, u_bit, r;
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadBits(3, t));
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadBits(1, u_bit));
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadBits(2, r));
|
||||
RETURN_FALSE_ON_ERROR(parser->ConsumeBits(2));
|
||||
vp9->gof.temporal_idx[i] = t;
|
||||
vp9->gof.temporal_up_switch[i] = u_bit ? true : false;
|
||||
vp9->gof.num_ref_pics[i] = r;
|
||||
vp9->gof.temporal_idx[i] = parser.ReadBits(3);
|
||||
vp9->gof.temporal_up_switch[i] = parser.Read<bool>();
|
||||
vp9->gof.num_ref_pics[i] = parser.ReadBits(2);
|
||||
parser.ConsumeBits(2);
|
||||
|
||||
for (uint8_t p = 0; p < vp9->gof.num_ref_pics[i]; ++p) {
|
||||
uint8_t p_diff;
|
||||
RETURN_FALSE_ON_ERROR(parser->ReadUInt8(p_diff));
|
||||
vp9->gof.pid_diff[i][p] = p_diff;
|
||||
vp9->gof.pid_diff[i][p] = parser.Read<uint8_t>();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
absl::optional<VideoRtpDepacketizer::ParsedRtpPayload>
|
||||
VideoRtpDepacketizerVp9::Parse(rtc::CopyOnWriteBuffer rtp_payload) {
|
||||
rtc::ArrayView<const uint8_t> payload(rtp_payload.cdata(),
|
||||
rtp_payload.size());
|
||||
absl::optional<ParsedRtpPayload> result(absl::in_place);
|
||||
int offset = ParseRtpPayload(payload, &result->video_header);
|
||||
if (offset == kFailedToParse)
|
||||
int offset = ParseRtpPayload(rtp_payload, &result->video_header);
|
||||
if (offset == 0)
|
||||
return absl::nullopt;
|
||||
RTC_DCHECK_LT(offset, rtp_payload.size());
|
||||
result->video_payload =
|
||||
|
@ -212,12 +163,8 @@ int VideoRtpDepacketizerVp9::ParseRtpPayload(
|
|||
RTPVideoHeader* video_header) {
|
||||
RTC_DCHECK(video_header);
|
||||
// Parse mandatory first byte of payload descriptor.
|
||||
rtc::BitBuffer parser(rtp_payload.data(), rtp_payload.size());
|
||||
uint8_t first_byte;
|
||||
if (!parser.ReadUInt8(first_byte)) {
|
||||
RTC_LOG(LS_ERROR) << "Payload length is zero.";
|
||||
return kFailedToParse;
|
||||
}
|
||||
BitstreamReader parser(rtp_payload);
|
||||
uint8_t first_byte = parser.Read<uint8_t>();
|
||||
bool i_bit = first_byte & 0b1000'0000; // PictureId present .
|
||||
bool p_bit = first_byte & 0b0100'0000; // Inter-picture predicted.
|
||||
bool l_bit = first_byte & 0b0010'0000; // Layer indices present.
|
||||
|
@ -247,23 +194,17 @@ int VideoRtpDepacketizerVp9::ParseRtpPayload(
|
|||
vp9_header.non_ref_for_inter_layer_pred = z_bit;
|
||||
|
||||
// Parse fields that are present.
|
||||
if (i_bit && !ParsePictureId(&parser, &vp9_header)) {
|
||||
RTC_LOG(LS_ERROR) << "Failed parsing VP9 picture id.";
|
||||
return kFailedToParse;
|
||||
if (i_bit) {
|
||||
ParsePictureId(parser, &vp9_header);
|
||||
}
|
||||
if (l_bit && !ParseLayerInfo(&parser, &vp9_header)) {
|
||||
RTC_LOG(LS_ERROR) << "Failed parsing VP9 layer info.";
|
||||
return kFailedToParse;
|
||||
if (l_bit) {
|
||||
ParseLayerInfo(parser, &vp9_header);
|
||||
}
|
||||
if (p_bit && f_bit && !ParseRefIndices(&parser, &vp9_header)) {
|
||||
RTC_LOG(LS_ERROR) << "Failed parsing VP9 ref indices.";
|
||||
return kFailedToParse;
|
||||
if (p_bit && f_bit) {
|
||||
ParseRefIndices(parser, &vp9_header);
|
||||
}
|
||||
if (v_bit) {
|
||||
if (!ParseSsData(&parser, &vp9_header)) {
|
||||
RTC_LOG(LS_ERROR) << "Failed parsing VP9 SS data.";
|
||||
return kFailedToParse;
|
||||
}
|
||||
ParseSsData(parser, &vp9_header);
|
||||
if (vp9_header.spatial_layer_resolution_present) {
|
||||
// TODO(asapersson): Add support for spatial layers.
|
||||
video_header->width = vp9_header.width[0];
|
||||
|
@ -273,15 +214,13 @@ int VideoRtpDepacketizerVp9::ParseRtpPayload(
|
|||
video_header->is_first_packet_in_frame =
|
||||
b_bit && (!l_bit || !vp9_header.inter_layer_predicted);
|
||||
|
||||
size_t byte_offset;
|
||||
size_t bit_offset;
|
||||
parser.GetCurrentOffset(&byte_offset, &bit_offset);
|
||||
RTC_DCHECK_EQ(bit_offset, 0);
|
||||
if (byte_offset == rtp_payload.size()) {
|
||||
// Empty vp9 payload data.
|
||||
return kFailedToParse;
|
||||
int num_remaining_bits = parser.RemainingBitCount();
|
||||
if (num_remaining_bits <= 0) {
|
||||
// Failed to parse or empty vp9 payload data.
|
||||
return 0;
|
||||
}
|
||||
|
||||
return byte_offset;
|
||||
// vp9 descriptor is byte aligned.
|
||||
RTC_DCHECK_EQ(num_remaining_bits % 8, 0);
|
||||
return rtp_payload.size() - num_remaining_bits / 8;
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
|
Loading…
Reference in a new issue