Make PayloadRouter own the picture id and tl0 pic idx sequences.
It previously owned only the picture id and only in the
WebRTC-VP8-Forced-Fallback-Encoder-v2 experiment.
Moving responsibility to PayloadRouter ensures that both
picture id and tl0 idx are continuous over codec changes,
as required by the specs for VP8 and VP9 over RTP.
Bug: webrtc:8830
Change-Id: Ie77356dfec6d1e372b6970189e4c3888451920e6
Reviewed-on: https://webrtc-review.googlesource.com/61640
Commit-Queue: Niels Moller <nisse@webrtc.org>
Reviewed-by: Åsa Persson <asapersson@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22448}
diff --git a/video/payload_router.cc b/video/payload_router.cc
index 4ecb620..f980bc4 100644
--- a/video/payload_router.cc
+++ b/video/payload_router.cc
@@ -16,7 +16,6 @@
#include "rtc_base/checks.h"
#include "rtc_base/random.h"
#include "rtc_base/timeutils.h"
-#include "system_wrappers/include/field_trial.h"
namespace webrtc {
@@ -28,11 +27,9 @@
case kVideoCodecVP8: {
rtp->codec = kRtpVideoVp8;
rtp->codecHeader.VP8.InitRTPVideoHeaderVP8();
- rtp->codecHeader.VP8.pictureId = info->codecSpecific.VP8.pictureId;
rtp->codecHeader.VP8.nonReference = info->codecSpecific.VP8.nonReference;
rtp->codecHeader.VP8.temporalIdx = info->codecSpecific.VP8.temporalIdx;
rtp->codecHeader.VP8.layerSync = info->codecSpecific.VP8.layerSync;
- rtp->codecHeader.VP8.tl0PicIdx = info->codecSpecific.VP8.tl0PicIdx;
rtp->codecHeader.VP8.keyIdx = info->codecSpecific.VP8.keyIdx;
rtp->simulcastIdx = info->codecSpecific.VP8.simulcastIdx;
return;
@@ -46,8 +43,6 @@
info->codecSpecific.VP9.flexible_mode;
rtp->codecHeader.VP9.ss_data_available =
info->codecSpecific.VP9.ss_data_available;
- rtp->codecHeader.VP9.picture_id = info->codecSpecific.VP9.picture_id;
- rtp->codecHeader.VP9.tl0_pic_idx = info->codecSpecific.VP9.tl0_pic_idx;
rtp->codecHeader.VP9.temporal_idx = info->codecSpecific.VP9.temporal_idx;
rtp->codecHeader.VP9.spatial_idx = info->codecSpecific.VP9.spatial_idx;
rtp->codecHeader.VP9.temporal_up_switch =
@@ -93,9 +88,8 @@
} // namespace
-// Currently only used if forced fallback for VP8 is enabled.
-// Consider adding tl0idx and set for VP8 and VP9.
-// Make picture id not codec specific.
+// State for setting picture id and tl0 pic idx, for VP8 and VP9
+// TODO(nisse): Make these properties not codec specific.
class PayloadRouter::RtpPayloadParams final {
public:
RtpPayloadParams(const uint32_t ssrc, const RtpPayloadState* state)
@@ -103,14 +97,42 @@
Random random(rtc::TimeMicros());
state_.picture_id =
state ? state->picture_id : (random.Rand<int16_t>() & 0x7FFF);
+ state_.tl0_pic_idx = state ? state->tl0_pic_idx : (random.Rand<uint8_t>());
}
~RtpPayloadParams() {}
- void Set(RTPVideoHeader* rtp_video_header) {
- if (rtp_video_header->codec == kRtpVideoVp8 &&
- rtp_video_header->codecHeader.VP8.pictureId != kNoPictureId) {
+ void Set(RTPVideoHeader* rtp_video_header, bool first_frame_in_picture) {
+ // Always set picture id. Set tl0_pic_idx iff temporal index is set.
+ if (first_frame_in_picture) {
+ state_.picture_id =
+ (static_cast<uint16_t>(state_.picture_id) + 1) & 0x7FFF;
+ }
+ if (rtp_video_header->codec == kRtpVideoVp8) {
rtp_video_header->codecHeader.VP8.pictureId = state_.picture_id;
- state_.picture_id = (state_.picture_id + 1) & 0x7FFF;
+
+ if (rtp_video_header->codecHeader.VP8.temporalIdx != kNoTemporalIdx) {
+ if (rtp_video_header->codecHeader.VP8.temporalIdx == 0) {
+ ++state_.tl0_pic_idx;
+ }
+ rtp_video_header->codecHeader.VP8.tl0PicIdx = state_.tl0_pic_idx;
+ }
+ }
+ if (rtp_video_header->codec == kRtpVideoVp9) {
+ rtp_video_header->codecHeader.VP9.picture_id = state_.picture_id;
+
+ // Note that in the case that we have no temporal layers but we do have
+ // spatial layers, packets will carry layering info with a temporal_idx of
+ // zero, and we then have to set and increment tl0_pic_idx.
+ if (rtp_video_header->codecHeader.VP9.temporal_idx != kNoTemporalIdx ||
+ rtp_video_header->codecHeader.VP9.spatial_idx != kNoSpatialIdx) {
+ if (first_frame_in_picture &&
+ (rtp_video_header->codecHeader.VP9.temporal_idx == 0 ||
+ rtp_video_header->codecHeader.VP9.temporal_idx ==
+ kNoTemporalIdx)) {
+ ++state_.tl0_pic_idx;
+ }
+ rtp_video_header->codecHeader.VP9.tl0_pic_idx = state_.tl0_pic_idx;
+ }
}
}
@@ -127,11 +149,7 @@
const std::vector<uint32_t>& ssrcs,
int payload_type,
const std::map<uint32_t, RtpPayloadState>& states)
- : active_(false),
- rtp_modules_(rtp_modules),
- payload_type_(payload_type),
- forced_fallback_enabled_((webrtc::field_trial::IsEnabled(
- "WebRTC-VP8-Forced-Fallback-Encoder-v2"))) {
+ : active_(false), rtp_modules_(rtp_modules), payload_type_(payload_type) {
RTC_DCHECK_EQ(ssrcs.size(), rtp_modules.size());
// SSRCs are assumed to be sorted in the same order as |rtp_modules|.
for (uint32_t ssrc : ssrcs) {
@@ -221,12 +239,14 @@
int stream_index = rtp_video_header.simulcastIdx;
RTC_DCHECK_LT(stream_index, rtp_modules_.size());
- if (forced_fallback_enabled_) {
- // Sets picture id. The SW and HW encoder have separate picture id
- // sequences, set picture id to not cause sequence discontinuties at encoder
- // changes.
- params_[stream_index].Set(&rtp_video_header);
- }
+
+ // Sets picture id and tl0 pic idx.
+ const bool first_frame_in_picture =
+ (codec_specific_info && codec_specific_info->codecType == kVideoCodecVP9)
+ ? codec_specific_info->codecSpecific.VP9.first_frame_in_picture
+ : true;
+ params_[stream_index].Set(&rtp_video_header, first_frame_in_picture);
+
uint32_t frame_id;
if (!rtp_modules_[stream_index]->Sending()) {
// The payload router could be active but this module isn't sending.