blob: acc9e3ca1879641ae1cc45e43a24ae8198a3fe4b [file] [log] [blame]
Stefan Holmerf7044682018-07-17 08:16:411/*
2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "call/rtp_payload_params.h"
12
Yves Gerey3e707812018-11-28 15:47:4913#include <stddef.h>
Jonas Olssona4d87372019-07-05 17:08:3314
Elad Alonf5b216a2019-01-28 13:25:1715#include <algorithm>
Harald Alvestrand93c9aa12024-09-02 20:55:5216#include <cstdint>
17#include <optional>
Yves Gerey3e707812018-11-28 15:47:4918
19#include "absl/container/inlined_vector.h"
Erik Språngcbc0cba2020-04-18 12:36:5920#include "absl/strings/match.h"
Yves Gerey3e707812018-11-28 15:47:4921#include "absl/types/variant.h"
Harald Alvestrand93c9aa12024-09-02 20:55:5222#include "api/field_trials_view.h"
23#include "api/transport/rtp/dependency_descriptor.h"
24#include "api/video/encoded_image.h"
25#include "api/video/render_resolution.h"
26#include "api/video/video_codec_constants.h"
27#include "api/video/video_codec_type.h"
28#include "api/video/video_frame_type.h"
Yves Gerey3e707812018-11-28 15:47:4929#include "api/video/video_timing.h"
Harald Alvestrand93c9aa12024-09-02 20:55:5230#include "call/rtp_config.h"
31#include "common_video/generic_frame_descriptor/generic_frame_info.h"
32#include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor.h"
33#include "modules/rtp_rtcp/source/rtp_video_header.h"
Yves Gerey3e707812018-11-28 15:47:4934#include "modules/video_coding/codecs/h264/include/h264_globals.h"
35#include "modules/video_coding/codecs/interface/common_constants.h"
36#include "modules/video_coding/codecs/vp8/include/vp8_globals.h"
37#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Danil Chapovalov02d71fb2020-02-10 15:22:5738#include "modules/video_coding/frame_dependencies_calculator.h"
Harald Alvestrand93c9aa12024-09-02 20:55:5239#include "modules/video_coding/include/video_codec_interface.h"
Elad Alonf5b216a2019-01-28 13:25:1740#include "rtc_base/arraysize.h"
Stefan Holmerf7044682018-07-17 08:16:4141#include "rtc_base/checks.h"
philipelbf2b6202018-08-27 12:33:1842#include "rtc_base/logging.h"
Stefan Holmerf7044682018-07-17 08:16:4143#include "rtc_base/random.h"
Steve Anton10542f22019-01-11 17:11:0044#include "rtc_base/time_utils.h"
Stefan Holmerf7044682018-07-17 08:16:4145
46namespace webrtc {
Stefan Holmerf7044682018-07-17 08:16:4147namespace {
Danil Chapovalov5b298ab2022-06-08 09:18:5148
49constexpr int kMaxSimulatedSpatialLayers = 3;
50
Stefan Holmerf7044682018-07-17 08:16:4151void PopulateRtpWithCodecSpecifics(const CodecSpecificInfo& info,
Florent Castelli8037fc62024-08-29 13:00:4052 std::optional<int> spatial_index,
Stefan Holmerf7044682018-07-17 08:16:4153 RTPVideoHeader* rtp) {
54 rtp->codec = info.codecType;
Danil Chapovalov62a9a322020-11-11 15:15:0755 rtp->is_last_frame_in_picture = info.end_of_picture;
Fanny Linderborgdac08052024-09-03 11:23:3356 rtp->frame_instrumentation_data = info.frame_instrumentation_data;
Stefan Holmerf7044682018-07-17 08:16:4157 switch (info.codecType) {
58 case kVideoCodecVP8: {
Philip Eliassond52a1a62018-09-07 13:03:5559 auto& vp8_header = rtp->video_type_header.emplace<RTPVideoHeaderVP8>();
60 vp8_header.InitRTPVideoHeaderVP8();
61 vp8_header.nonReference = info.codecSpecific.VP8.nonReference;
62 vp8_header.temporalIdx = info.codecSpecific.VP8.temporalIdx;
63 vp8_header.layerSync = info.codecSpecific.VP8.layerSync;
64 vp8_header.keyIdx = info.codecSpecific.VP8.keyIdx;
Stefan Holmerf7044682018-07-17 08:16:4165 return;
66 }
67 case kVideoCodecVP9: {
philipel29d88462018-08-08 12:26:0068 auto& vp9_header = rtp->video_type_header.emplace<RTPVideoHeaderVP9>();
69 vp9_header.InitRTPVideoHeaderVP9();
70 vp9_header.inter_pic_predicted =
Stefan Holmerf7044682018-07-17 08:16:4171 info.codecSpecific.VP9.inter_pic_predicted;
philipel29d88462018-08-08 12:26:0072 vp9_header.flexible_mode = info.codecSpecific.VP9.flexible_mode;
73 vp9_header.ss_data_available = info.codecSpecific.VP9.ss_data_available;
74 vp9_header.non_ref_for_inter_layer_pred =
Stefan Holmerf7044682018-07-17 08:16:4175 info.codecSpecific.VP9.non_ref_for_inter_layer_pred;
philipel29d88462018-08-08 12:26:0076 vp9_header.temporal_idx = info.codecSpecific.VP9.temporal_idx;
philipel29d88462018-08-08 12:26:0077 vp9_header.temporal_up_switch = info.codecSpecific.VP9.temporal_up_switch;
78 vp9_header.inter_layer_predicted =
Stefan Holmerf7044682018-07-17 08:16:4179 info.codecSpecific.VP9.inter_layer_predicted;
philipel29d88462018-08-08 12:26:0080 vp9_header.gof_idx = info.codecSpecific.VP9.gof_idx;
81 vp9_header.num_spatial_layers = info.codecSpecific.VP9.num_spatial_layers;
Ilya Nikolaevskiyf5d87782020-02-04 10:06:3382 vp9_header.first_active_layer = info.codecSpecific.VP9.first_active_layer;
Niels Möllerd3b8c632018-08-27 13:33:4283 if (vp9_header.num_spatial_layers > 1) {
84 vp9_header.spatial_idx = spatial_index.value_or(kNoSpatialIdx);
85 } else {
86 vp9_header.spatial_idx = kNoSpatialIdx;
87 }
Stefan Holmerf7044682018-07-17 08:16:4188 if (info.codecSpecific.VP9.ss_data_available) {
philipel29d88462018-08-08 12:26:0089 vp9_header.spatial_layer_resolution_present =
Stefan Holmerf7044682018-07-17 08:16:4190 info.codecSpecific.VP9.spatial_layer_resolution_present;
91 if (info.codecSpecific.VP9.spatial_layer_resolution_present) {
92 for (size_t i = 0; i < info.codecSpecific.VP9.num_spatial_layers;
93 ++i) {
philipel29d88462018-08-08 12:26:0094 vp9_header.width[i] = info.codecSpecific.VP9.width[i];
95 vp9_header.height[i] = info.codecSpecific.VP9.height[i];
Stefan Holmerf7044682018-07-17 08:16:4196 }
97 }
philipel29d88462018-08-08 12:26:0098 vp9_header.gof.CopyGofInfoVP9(info.codecSpecific.VP9.gof);
Stefan Holmerf7044682018-07-17 08:16:4199 }
100
philipel29d88462018-08-08 12:26:00101 vp9_header.num_ref_pics = info.codecSpecific.VP9.num_ref_pics;
Stefan Holmerf7044682018-07-17 08:16:41102 for (int i = 0; i < info.codecSpecific.VP9.num_ref_pics; ++i) {
philipel29d88462018-08-08 12:26:00103 vp9_header.pid_diff[i] = info.codecSpecific.VP9.p_diff[i];
Stefan Holmerf7044682018-07-17 08:16:41104 }
Danil Chapovalov06bbeb32020-11-11 11:42:56105 vp9_header.end_of_picture = info.end_of_picture;
Stefan Holmerf7044682018-07-17 08:16:41106 return;
107 }
108 case kVideoCodecH264: {
philipel7d745e52018-08-02 12:03:53109 auto& h264_header = rtp->video_type_header.emplace<RTPVideoHeaderH264>();
110 h264_header.packetization_mode =
Stefan Holmerf7044682018-07-17 08:16:41111 info.codecSpecific.H264.packetization_mode;
Stefan Holmerf7044682018-07-17 08:16:41112 return;
113 }
Qiu Jianlinfaef5de2024-11-01 12:18:15114 // These codec types do not have codec-specifics.
Stefan Holmerf7044682018-07-17 08:16:41115 case kVideoCodecGeneric:
Qiu Jianlinfaef5de2024-11-01 12:18:15116 case kVideoCodecH265:
117 case kVideoCodecAV1:
Stefan Holmerf7044682018-07-17 08:16:41118 return;
119 }
120}
121
122void SetVideoTiming(const EncodedImage& image, VideoSendTiming* timing) {
123 if (image.timing_.flags == VideoSendTiming::TimingFrameFlags::kInvalid ||
124 image.timing_.flags == VideoSendTiming::TimingFrameFlags::kNotTriggered) {
125 timing->flags = VideoSendTiming::TimingFrameFlags::kInvalid;
126 return;
127 }
128
129 timing->encode_start_delta_ms = VideoSendTiming::GetDeltaCappedMs(
130 image.capture_time_ms_, image.timing_.encode_start_ms);
131 timing->encode_finish_delta_ms = VideoSendTiming::GetDeltaCappedMs(
132 image.capture_time_ms_, image.timing_.encode_finish_ms);
133 timing->packetization_finish_delta_ms = 0;
134 timing->pacer_exit_delta_ms = 0;
135 timing->network_timestamp_delta_ms = 0;
136 timing->network2_timestamp_delta_ms = 0;
137 timing->flags = image.timing_.flags;
138}
Danil Chapovalov5b298ab2022-06-08 09:18:51139
140// Returns structure that aligns with simulated generic info. The templates
141// allow to produce valid dependency descriptor for any stream where
142// `num_spatial_layers` * `num_temporal_layers` <= 32 (limited by
143// https://aomediacodec.github.io/av1-rtp-spec/#a82-syntax, see
144// template_fdiffs()). The set of the templates is not tuned for any paricular
145// structure thus dependency descriptor would use more bytes on the wire than
146// with tuned templates.
147FrameDependencyStructure MinimalisticStructure(int num_spatial_layers,
148 int num_temporal_layers) {
149 RTC_DCHECK_LE(num_spatial_layers, DependencyDescriptor::kMaxSpatialIds);
150 RTC_DCHECK_LE(num_temporal_layers, DependencyDescriptor::kMaxTemporalIds);
151 RTC_DCHECK_LE(num_spatial_layers * num_temporal_layers, 32);
152 FrameDependencyStructure structure;
153 structure.num_decode_targets = num_spatial_layers * num_temporal_layers;
154 structure.num_chains = num_spatial_layers;
155 structure.templates.reserve(num_spatial_layers * num_temporal_layers);
156 for (int sid = 0; sid < num_spatial_layers; ++sid) {
157 for (int tid = 0; tid < num_temporal_layers; ++tid) {
158 FrameDependencyTemplate a_template;
159 a_template.spatial_id = sid;
160 a_template.temporal_id = tid;
161 for (int s = 0; s < num_spatial_layers; ++s) {
162 for (int t = 0; t < num_temporal_layers; ++t) {
163 // Prefer kSwitch indication for frames that is part of the decode
164 // target because dependency descriptor information generated in this
165 // class use kSwitch indications more often that kRequired, increasing
166 // the chance of a good (or complete) template match.
167 a_template.decode_target_indications.push_back(
168 sid <= s && tid <= t ? DecodeTargetIndication::kSwitch
169 : DecodeTargetIndication::kNotPresent);
170 }
171 }
172 a_template.frame_diffs.push_back(tid == 0 ? num_spatial_layers *
173 num_temporal_layers
174 : num_spatial_layers);
175 a_template.chain_diffs.assign(structure.num_chains, 1);
176 structure.templates.push_back(a_template);
177
178 structure.decode_target_protected_by_chain.push_back(sid);
179 }
180 }
181 return structure;
182}
Stefan Holmerf7044682018-07-17 08:16:41183} // namespace
184
185RtpPayloadParams::RtpPayloadParams(const uint32_t ssrc,
Erik Språngcbc0cba2020-04-18 12:36:59186 const RtpPayloadState* state,
Jonas Orelande62c2f22022-03-29 09:04:48187 const FieldTrialsView& trials)
philipelbf2b6202018-08-27 12:33:18188 : ssrc_(ssrc),
189 generic_picture_id_experiment_(
Erik Språngcbc0cba2020-04-18 12:36:59190 absl::StartsWith(trials.Lookup("WebRTC-GenericPictureId"),
Danil Chapovalov5b298ab2022-06-08 09:18:51191 "Enabled")),
192 simulate_generic_structure_(absl::StartsWith(
193 trials.Lookup("WebRTC-GenericCodecDependencyDescriptor"),
194 "Enabled")) {
philipel626edea2024-03-19 08:38:01195 for (auto& spatial_layer : last_frame_id_)
philipelbf2b6202018-08-27 12:33:18196 spatial_layer.fill(-1);
197
Emil Lundmarkadfc7002021-07-30 07:45:10198 chain_last_frame_id_.fill(-1);
Elad Alonf5b216a2019-01-28 13:25:17199 buffer_id_to_frame_id_.fill(-1);
200
Stefan Holmerf7044682018-07-17 08:16:41201 Random random(rtc::TimeMicros());
202 state_.picture_id =
203 state ? state->picture_id : (random.Rand<int16_t>() & 0x7FFF);
204 state_.tl0_pic_idx = state ? state->tl0_pic_idx : (random.Rand<uint8_t>());
philipel626edea2024-03-19 08:38:01205 state_.frame_id = state ? state->frame_id : random.Rand<uint16_t>();
Stefan Holmerf7044682018-07-17 08:16:41206}
philipelbf2b6202018-08-27 12:33:18207
208RtpPayloadParams::RtpPayloadParams(const RtpPayloadParams& other) = default;
209
Stefan Holmerf7044682018-07-17 08:16:41210RtpPayloadParams::~RtpPayloadParams() {}
211
212RTPVideoHeader RtpPayloadParams::GetRtpVideoHeader(
213 const EncodedImage& image,
philipelbf2b6202018-08-27 12:33:18214 const CodecSpecificInfo* codec_specific_info,
Florent Castelli8037fc62024-08-29 13:00:40215 std::optional<int64_t> shared_frame_id) {
philipel626edea2024-03-19 08:38:01216 int64_t frame_id;
217 if (shared_frame_id) {
218 frame_id = *shared_frame_id;
219 } else {
220 frame_id = state_.frame_id++;
221 }
222
Stefan Holmerf7044682018-07-17 08:16:41223 RTPVideoHeader rtp_video_header;
224 if (codec_specific_info) {
Niels Möllerd3b8c632018-08-27 13:33:42225 PopulateRtpWithCodecSpecifics(*codec_specific_info, image.SpatialIndex(),
226 &rtp_video_header);
Stefan Holmerf7044682018-07-17 08:16:41227 }
Henrik Boströmc5a4c932023-02-21 14:53:43228 rtp_video_header.simulcastIdx = image.SimulcastIndex().value_or(0);
Zhaoliang Maf3dc47e2021-02-05 05:19:02229 rtp_video_header.frame_type = image._frameType;
Stefan Holmerf7044682018-07-17 08:16:41230 rtp_video_header.rotation = image.rotation_;
231 rtp_video_header.content_type = image.content_type_;
Danil Chapovalov06717772023-08-21 16:17:31232 rtp_video_header.playout_delay = image.PlayoutDelay();
philipelfab91292018-10-17 12:36:08233 rtp_video_header.width = image._encodedWidth;
234 rtp_video_header.height = image._encodedHeight;
Johannes Krond0b69a82018-12-03 13:18:53235 rtp_video_header.color_space = image.ColorSpace()
Florent Castelli8037fc62024-08-29 13:00:40236 ? std::make_optional(*image.ColorSpace())
237 : std::nullopt;
Jeremy Leconteb258c562021-03-18 12:50:42238 rtp_video_header.video_frame_tracking_id = image.VideoFrameTrackingId();
Stefan Holmerf7044682018-07-17 08:16:41239 SetVideoTiming(image, &rtp_video_header.video_timing);
240
Niels Möller8f7ce222019-03-21 14:43:58241 const bool is_keyframe = image._frameType == VideoFrameType::kVideoFrameKey;
Stefan Holmerf7044682018-07-17 08:16:41242 const bool first_frame_in_picture =
243 (codec_specific_info && codec_specific_info->codecType == kVideoCodecVP9)
244 ? codec_specific_info->codecSpecific.VP9.first_frame_in_picture
245 : true;
philipelbf2b6202018-08-27 12:33:18246
247 SetCodecSpecific(&rtp_video_header, first_frame_in_picture);
philipel569397f2018-09-26 10:25:31248
philipel626edea2024-03-19 08:38:01249 SetGeneric(codec_specific_info, frame_id, is_keyframe, &rtp_video_header);
philipelbf2b6202018-08-27 12:33:18250
Stefan Holmerf7044682018-07-17 08:16:41251 return rtp_video_header;
252}
253
254uint32_t RtpPayloadParams::ssrc() const {
255 return ssrc_;
256}
257
258RtpPayloadState RtpPayloadParams::state() const {
259 return state_;
260}
261
philipelbf2b6202018-08-27 12:33:18262void RtpPayloadParams::SetCodecSpecific(RTPVideoHeader* rtp_video_header,
263 bool first_frame_in_picture) {
Stefan Holmerf7044682018-07-17 08:16:41264 // Always set picture id. Set tl0_pic_idx iff temporal index is set.
265 if (first_frame_in_picture) {
266 state_.picture_id = (static_cast<uint16_t>(state_.picture_id) + 1) & 0x7FFF;
267 }
268 if (rtp_video_header->codec == kVideoCodecVP8) {
Philip Eliassond52a1a62018-09-07 13:03:55269 auto& vp8_header =
270 absl::get<RTPVideoHeaderVP8>(rtp_video_header->video_type_header);
271 vp8_header.pictureId = state_.picture_id;
Stefan Holmerf7044682018-07-17 08:16:41272
Philip Eliassond52a1a62018-09-07 13:03:55273 if (vp8_header.temporalIdx != kNoTemporalIdx) {
274 if (vp8_header.temporalIdx == 0) {
Stefan Holmerf7044682018-07-17 08:16:41275 ++state_.tl0_pic_idx;
276 }
Philip Eliassond52a1a62018-09-07 13:03:55277 vp8_header.tl0PicIdx = state_.tl0_pic_idx;
Stefan Holmerf7044682018-07-17 08:16:41278 }
279 }
280 if (rtp_video_header->codec == kVideoCodecVP9) {
philipel29d88462018-08-08 12:26:00281 auto& vp9_header =
282 absl::get<RTPVideoHeaderVP9>(rtp_video_header->video_type_header);
283 vp9_header.picture_id = state_.picture_id;
Stefan Holmerf7044682018-07-17 08:16:41284
285 // Note that in the case that we have no temporal layers but we do have
286 // spatial layers, packets will carry layering info with a temporal_idx of
287 // zero, and we then have to set and increment tl0_pic_idx.
philipel29d88462018-08-08 12:26:00288 if (vp9_header.temporal_idx != kNoTemporalIdx ||
289 vp9_header.spatial_idx != kNoSpatialIdx) {
Stefan Holmerf7044682018-07-17 08:16:41290 if (first_frame_in_picture &&
philipel29d88462018-08-08 12:26:00291 (vp9_header.temporal_idx == 0 ||
292 vp9_header.temporal_idx == kNoTemporalIdx)) {
Stefan Holmerf7044682018-07-17 08:16:41293 ++state_.tl0_pic_idx;
294 }
philipel29d88462018-08-08 12:26:00295 vp9_header.tl0_pic_idx = state_.tl0_pic_idx;
Stefan Holmerf7044682018-07-17 08:16:41296 }
297 }
philipelbf2b6202018-08-27 12:33:18298 if (generic_picture_id_experiment_ &&
299 rtp_video_header->codec == kVideoCodecGeneric) {
Danil Chapovalovb6bf0b22020-01-28 17:36:57300 rtp_video_header->video_type_header.emplace<RTPVideoHeaderLegacyGeneric>()
301 .picture_id = state_.picture_id;
philipelbf2b6202018-08-27 12:33:18302 }
Stefan Holmerf7044682018-07-17 08:16:41303}
philipelbf2b6202018-08-27 12:33:18304
Danil Chapovalov02d71fb2020-02-10 15:22:57305RTPVideoHeader::GenericDescriptorInfo
306RtpPayloadParams::GenericDescriptorFromFrameInfo(
307 const GenericFrameInfo& frame_info,
Danil Chapovalovcf1308f2020-11-18 17:27:37308 int64_t frame_id) {
Danil Chapovalov02d71fb2020-02-10 15:22:57309 RTPVideoHeader::GenericDescriptorInfo generic;
310 generic.frame_id = frame_id;
311 generic.dependencies = dependencies_calculator_.FromBuffersUsage(
Danil Chapovalovcf1308f2020-11-18 17:27:37312 frame_id, frame_info.encoder_buffers);
Danil Chapovalov4b860c12020-05-19 12:48:19313 generic.chain_diffs =
314 chains_calculator_.From(frame_id, frame_info.part_of_chain);
Danil Chapovalov02d71fb2020-02-10 15:22:57315 generic.spatial_index = frame_info.spatial_id;
316 generic.temporal_index = frame_info.temporal_id;
317 generic.decode_target_indications = frame_info.decode_target_indications;
Danil Chapovalove6ac8ff2020-06-26 11:51:08318 generic.active_decode_targets = frame_info.active_decode_targets;
Danil Chapovalov02d71fb2020-02-10 15:22:57319 return generic;
320}
321
Elad Alonf5b216a2019-01-28 13:25:17322void RtpPayloadParams::SetGeneric(const CodecSpecificInfo* codec_specific_info,
323 int64_t frame_id,
philipelbf2b6202018-08-27 12:33:18324 bool is_keyframe,
325 RTPVideoHeader* rtp_video_header) {
Danil Chapovalov02d71fb2020-02-10 15:22:57326 if (codec_specific_info && codec_specific_info->generic_frame_info &&
327 !codec_specific_info->generic_frame_info->encoder_buffers.empty()) {
Danil Chapovalov4b860c12020-05-19 12:48:19328 if (is_keyframe) {
329 // Key frame resets all chains it is in.
330 chains_calculator_.Reset(
331 codec_specific_info->generic_frame_info->part_of_chain);
332 }
Danil Chapovalovcf1308f2020-11-18 17:27:37333 rtp_video_header->generic = GenericDescriptorFromFrameInfo(
334 *codec_specific_info->generic_frame_info, frame_id);
Danil Chapovalov02d71fb2020-02-10 15:22:57335 return;
336 }
337
Elad Alonf5b216a2019-01-28 13:25:17338 switch (rtp_video_header->codec) {
339 case VideoCodecType::kVideoCodecGeneric:
philipel8aba8fe2019-06-13 13:13:16340 GenericToGeneric(frame_id, is_keyframe, rtp_video_header);
Elad Alonf5b216a2019-01-28 13:25:17341 return;
342 case VideoCodecType::kVideoCodecVP8:
343 if (codec_specific_info) {
344 Vp8ToGeneric(codec_specific_info->codecSpecific.VP8, frame_id,
345 is_keyframe, rtp_video_header);
346 }
347 return;
348 case VideoCodecType::kVideoCodecVP9:
Emil Lundmark823ba0b2021-10-18 09:27:26349 if (codec_specific_info != nullptr) {
Danil Chapovalovaf366442021-04-22 13:20:28350 Vp9ToGeneric(codec_specific_info->codecSpecific.VP9, frame_id,
351 *rtp_video_header);
352 }
353 return;
Danil Chapovalovdc368292019-11-26 13:48:20354 case VideoCodecType::kVideoCodecAV1:
Qiu Jianlinfaef5de2024-11-01 12:18:15355 // Codec-specifics is not supported for AV1. We convert from the
356 // generic_frame_info.
Elad Alonf5b216a2019-01-28 13:25:17357 return;
358 case VideoCodecType::kVideoCodecH264:
philipel8aba8fe2019-06-13 13:13:16359 if (codec_specific_info) {
360 H264ToGeneric(codec_specific_info->codecSpecific.H264, frame_id,
361 is_keyframe, rtp_video_header);
362 }
363 return;
qwu16ae82df72023-09-20 05:10:31364 case VideoCodecType::kVideoCodecH265:
Qiu Jianlinfaef5de2024-11-01 12:18:15365 // Codec-specifics is not supported for H.265. We convert from the
366 // generic_frame_info.
qwu16ae82df72023-09-20 05:10:31367 return;
philipelbf2b6202018-08-27 12:33:18368 }
Artem Titovd3251962021-11-15 15:57:07369 RTC_DCHECK_NOTREACHED() << "Unsupported codec.";
philipelbf2b6202018-08-27 12:33:18370}
371
Florent Castelli8037fc62024-08-29 13:00:40372std::optional<FrameDependencyStructure> RtpPayloadParams::GenericStructure(
Danil Chapovalov5b298ab2022-06-08 09:18:51373 const CodecSpecificInfo* codec_specific_info) {
374 if (codec_specific_info == nullptr) {
Florent Castelli8037fc62024-08-29 13:00:40375 return std::nullopt;
Danil Chapovalov5b298ab2022-06-08 09:18:51376 }
377 // This helper shouldn't be used when template structure is specified
378 // explicetly.
379 RTC_DCHECK(!codec_specific_info->template_structure.has_value());
380 switch (codec_specific_info->codecType) {
381 case VideoCodecType::kVideoCodecGeneric:
382 if (simulate_generic_structure_) {
383 return MinimalisticStructure(/*num_spatial_layers=*/1,
384 /*num_temporal_layer=*/1);
385 }
Florent Castelli8037fc62024-08-29 13:00:40386 return std::nullopt;
Danil Chapovalov5b298ab2022-06-08 09:18:51387 case VideoCodecType::kVideoCodecVP8:
388 return MinimalisticStructure(/*num_spatial_layers=*/1,
389 /*num_temporal_layer=*/kMaxTemporalStreams);
390 case VideoCodecType::kVideoCodecVP9: {
Florent Castelli8037fc62024-08-29 13:00:40391 std::optional<FrameDependencyStructure> structure = MinimalisticStructure(
392 /*num_spatial_layers=*/kMaxSimulatedSpatialLayers,
393 /*num_temporal_layer=*/kMaxTemporalStreams);
Danil Chapovalov5b298ab2022-06-08 09:18:51394 const CodecSpecificInfoVP9& vp9 = codec_specific_info->codecSpecific.VP9;
395 if (vp9.ss_data_available && vp9.spatial_layer_resolution_present) {
396 RenderResolution first_valid;
397 RenderResolution last_valid;
398 for (size_t i = 0; i < vp9.num_spatial_layers; ++i) {
399 RenderResolution r(vp9.width[i], vp9.height[i]);
400 if (r.Valid()) {
401 if (!first_valid.Valid()) {
402 first_valid = r;
403 }
404 last_valid = r;
405 }
406 structure->resolutions.push_back(r);
407 }
408 if (!last_valid.Valid()) {
409 // No valid resolution found. Do not send resolutions.
410 structure->resolutions.clear();
411 } else {
412 structure->resolutions.resize(kMaxSimulatedSpatialLayers, last_valid);
413 // VP9 encoder wrapper may disable first few spatial layers by
414 // setting invalid resolution (0,0). `structure->resolutions`
415 // doesn't support invalid resolution, so reset them to something
416 // valid.
417 for (RenderResolution& r : structure->resolutions) {
418 if (!r.Valid()) {
419 r = first_valid;
420 }
421 }
422 }
423 }
424 return structure;
425 }
Danil Chapovalov5b298ab2022-06-08 09:18:51426 case VideoCodecType::kVideoCodecH264:
Brennan Waters51fccaf2024-10-16 19:04:23427 return MinimalisticStructure(
428 /*num_spatial_layers=*/1,
429 /*num_temporal_layers=*/kMaxTemporalStreams);
430 case VideoCodecType::kVideoCodecAV1:
qwu16ae82df72023-09-20 05:10:31431 case VideoCodecType::kVideoCodecH265:
Florent Castelli8037fc62024-08-29 13:00:40432 return std::nullopt;
Danil Chapovalov5b298ab2022-06-08 09:18:51433 }
434 RTC_DCHECK_NOTREACHED() << "Unsupported codec.";
435}
436
philipel626edea2024-03-19 08:38:01437void RtpPayloadParams::GenericToGeneric(int64_t frame_id,
philipel8aba8fe2019-06-13 13:13:16438 bool is_keyframe,
439 RTPVideoHeader* rtp_video_header) {
440 RTPVideoHeader::GenericDescriptorInfo& generic =
441 rtp_video_header->generic.emplace();
442
philipel626edea2024-03-19 08:38:01443 generic.frame_id = frame_id;
philipel5b231de2021-09-01 13:21:16444 generic.decode_target_indications.push_back(DecodeTargetIndication::kSwitch);
philipel8aba8fe2019-06-13 13:13:16445
446 if (is_keyframe) {
philipel5b231de2021-09-01 13:21:16447 generic.chain_diffs.push_back(0);
philipel626edea2024-03-19 08:38:01448 last_frame_id_[0].fill(-1);
philipel8aba8fe2019-06-13 13:13:16449 } else {
philipel626edea2024-03-19 08:38:01450 int64_t last_frame_id = last_frame_id_[0][0];
451 RTC_DCHECK_NE(last_frame_id, -1);
452 RTC_DCHECK_LT(last_frame_id, frame_id);
453 generic.chain_diffs.push_back(frame_id - last_frame_id);
454 generic.dependencies.push_back(last_frame_id);
philipel8aba8fe2019-06-13 13:13:16455 }
456
philipel626edea2024-03-19 08:38:01457 last_frame_id_[0][0] = frame_id;
philipel8aba8fe2019-06-13 13:13:16458}
459
460void RtpPayloadParams::H264ToGeneric(const CodecSpecificInfoH264& h264_info,
philipel626edea2024-03-19 08:38:01461 int64_t frame_id,
philipel8aba8fe2019-06-13 13:13:16462 bool is_keyframe,
463 RTPVideoHeader* rtp_video_header) {
464 const int temporal_index =
465 h264_info.temporal_idx != kNoTemporalIdx ? h264_info.temporal_idx : 0;
466
467 if (temporal_index >= RtpGenericFrameDescriptor::kMaxTemporalLayers) {
468 RTC_LOG(LS_WARNING) << "Temporal and/or spatial index is too high to be "
469 "used with generic frame descriptor.";
470 return;
471 }
472
473 RTPVideoHeader::GenericDescriptorInfo& generic =
474 rtp_video_header->generic.emplace();
475
philipel626edea2024-03-19 08:38:01476 generic.frame_id = frame_id;
philipel8aba8fe2019-06-13 13:13:16477 generic.temporal_index = temporal_index;
478
Brennan Waters51fccaf2024-10-16 19:04:23479 // Generate decode target indications.
480 RTC_DCHECK_LT(temporal_index, kMaxTemporalStreams);
481 generic.decode_target_indications.resize(kMaxTemporalStreams);
482 auto it = std::fill_n(generic.decode_target_indications.begin(),
483 temporal_index, DecodeTargetIndication::kNotPresent);
484 std::fill(it, generic.decode_target_indications.end(),
485 DecodeTargetIndication::kSwitch);
486
philipel8aba8fe2019-06-13 13:13:16487 if (is_keyframe) {
488 RTC_DCHECK_EQ(temporal_index, 0);
philipel626edea2024-03-19 08:38:01489 last_frame_id_[/*spatial index*/ 0].fill(-1);
490 last_frame_id_[/*spatial index*/ 0][temporal_index] = frame_id;
philipel8aba8fe2019-06-13 13:13:16491 return;
492 }
493
494 if (h264_info.base_layer_sync) {
philipel626edea2024-03-19 08:38:01495 int64_t tl0_frame_id = last_frame_id_[/*spatial index*/ 0][0];
philipel8aba8fe2019-06-13 13:13:16496
497 for (int i = 1; i < RtpGenericFrameDescriptor::kMaxTemporalLayers; ++i) {
philipel626edea2024-03-19 08:38:01498 if (last_frame_id_[/*spatial index*/ 0][i] < tl0_frame_id) {
499 last_frame_id_[/*spatial index*/ 0][i] = -1;
philipel8aba8fe2019-06-13 13:13:16500 }
501 }
502
503 RTC_DCHECK_GE(tl0_frame_id, 0);
philipel626edea2024-03-19 08:38:01504 RTC_DCHECK_LT(tl0_frame_id, frame_id);
philipel8aba8fe2019-06-13 13:13:16505 generic.dependencies.push_back(tl0_frame_id);
506 } else {
507 for (int i = 0; i <= temporal_index; ++i) {
philipel626edea2024-03-19 08:38:01508 int64_t last_frame_id = last_frame_id_[/*spatial index*/ 0][i];
philipel8aba8fe2019-06-13 13:13:16509
philipel626edea2024-03-19 08:38:01510 if (last_frame_id != -1) {
511 RTC_DCHECK_LT(last_frame_id, frame_id);
512 generic.dependencies.push_back(last_frame_id);
philipel8aba8fe2019-06-13 13:13:16513 }
514 }
515 }
516
philipel626edea2024-03-19 08:38:01517 last_frame_id_[/*spatial_index*/ 0][temporal_index] = frame_id;
philipel8aba8fe2019-06-13 13:13:16518}
519
Elad Alonf5b216a2019-01-28 13:25:17520void RtpPayloadParams::Vp8ToGeneric(const CodecSpecificInfoVP8& vp8_info,
philipel626edea2024-03-19 08:38:01521 int64_t frame_id,
philipelbf2b6202018-08-27 12:33:18522 bool is_keyframe,
523 RTPVideoHeader* rtp_video_header) {
524 const auto& vp8_header =
525 absl::get<RTPVideoHeaderVP8>(rtp_video_header->video_type_header);
526 const int spatial_index = 0;
527 const int temporal_index =
528 vp8_header.temporalIdx != kNoTemporalIdx ? vp8_header.temporalIdx : 0;
529
530 if (temporal_index >= RtpGenericFrameDescriptor::kMaxTemporalLayers ||
531 spatial_index >= RtpGenericFrameDescriptor::kMaxSpatialLayers) {
532 RTC_LOG(LS_WARNING) << "Temporal and/or spatial index is too high to be "
533 "used with generic frame descriptor.";
534 return;
535 }
536
537 RTPVideoHeader::GenericDescriptorInfo& generic =
538 rtp_video_header->generic.emplace();
539
philipel626edea2024-03-19 08:38:01540 generic.frame_id = frame_id;
philipelbf2b6202018-08-27 12:33:18541 generic.spatial_index = spatial_index;
542 generic.temporal_index = temporal_index;
543
Emil Lundmark6c81a422022-05-18 15:13:34544 // Generate decode target indications.
545 RTC_DCHECK_LT(temporal_index, kMaxTemporalStreams);
546 generic.decode_target_indications.resize(kMaxTemporalStreams);
547 auto it = std::fill_n(generic.decode_target_indications.begin(),
548 temporal_index, DecodeTargetIndication::kNotPresent);
549 std::fill(it, generic.decode_target_indications.end(),
550 DecodeTargetIndication::kSwitch);
551
552 // Frame dependencies.
Qingsi Wang1c1b99e2020-01-07 19:16:33553 if (vp8_info.useExplicitDependencies) {
philipel626edea2024-03-19 08:38:01554 SetDependenciesVp8New(vp8_info, frame_id, is_keyframe, vp8_header.layerSync,
555 &generic);
Qingsi Wang1c1b99e2020-01-07 19:16:33556 } else {
philipel626edea2024-03-19 08:38:01557 SetDependenciesVp8Deprecated(vp8_info, frame_id, is_keyframe, spatial_index,
558 temporal_index, vp8_header.layerSync,
559 &generic);
Qingsi Wang1c1b99e2020-01-07 19:16:33560 }
Emil Lundmark6c81a422022-05-18 15:13:34561
562 // Calculate chains.
563 generic.chain_diffs = {
564 (is_keyframe || chain_last_frame_id_[0] < 0)
565 ? 0
philipel626edea2024-03-19 08:38:01566 : static_cast<int>(frame_id - chain_last_frame_id_[0])};
Emil Lundmark6c81a422022-05-18 15:13:34567 if (temporal_index == 0) {
philipel626edea2024-03-19 08:38:01568 chain_last_frame_id_[0] = frame_id;
Emil Lundmark6c81a422022-05-18 15:13:34569 }
Qingsi Wang1c1b99e2020-01-07 19:16:33570}
571
Dor Henbec70152024-10-29 12:47:48572void RtpPayloadParams::Vp9ToGeneric(const CodecSpecificInfoVP9& /* vp9_info */,
philipel626edea2024-03-19 08:38:01573 int64_t frame_id,
Danil Chapovalovaf366442021-04-22 13:20:28574 RTPVideoHeader& rtp_video_header) {
575 const auto& vp9_header =
576 absl::get<RTPVideoHeaderVP9>(rtp_video_header.video_type_header);
Danil Chapovalov5b298ab2022-06-08 09:18:51577 const int num_spatial_layers = kMaxSimulatedSpatialLayers;
Danil Chapovalov7f41b0b2023-08-03 11:29:29578 const int first_active_spatial_id = vp9_header.first_active_layer;
579 const int last_active_spatial_id = vp9_header.num_spatial_layers - 1;
Danil Chapovalovaf366442021-04-22 13:20:28580 const int num_temporal_layers = kMaxTemporalStreams;
Danil Chapovalov5b298ab2022-06-08 09:18:51581 static_assert(num_spatial_layers <=
582 RtpGenericFrameDescriptor::kMaxSpatialLayers);
583 static_assert(num_temporal_layers <=
584 RtpGenericFrameDescriptor::kMaxTemporalLayers);
585 static_assert(num_spatial_layers <= DependencyDescriptor::kMaxSpatialIds);
586 static_assert(num_temporal_layers <= DependencyDescriptor::kMaxTemporalIds);
Danil Chapovalovaf366442021-04-22 13:20:28587
588 int spatial_index =
589 vp9_header.spatial_idx != kNoSpatialIdx ? vp9_header.spatial_idx : 0;
590 int temporal_index =
591 vp9_header.temporal_idx != kNoTemporalIdx ? vp9_header.temporal_idx : 0;
592
Danil Chapovalov7f41b0b2023-08-03 11:29:29593 if (!(temporal_index < num_temporal_layers &&
594 first_active_spatial_id <= spatial_index &&
595 spatial_index <= last_active_spatial_id &&
596 last_active_spatial_id < num_spatial_layers)) {
Danil Chapovalovaf366442021-04-22 13:20:28597 // Prefer to generate no generic layering than an inconsistent one.
Danil Chapovalov7f41b0b2023-08-03 11:29:29598 RTC_LOG(LS_ERROR) << "Inconsistent layer id sid=" << spatial_index
599 << ",tid=" << temporal_index
600 << " in VP9 header. Active spatial ids: ["
601 << first_active_spatial_id << ","
602 << last_active_spatial_id << "]";
Danil Chapovalovaf366442021-04-22 13:20:28603 return;
604 }
605
606 RTPVideoHeader::GenericDescriptorInfo& result =
607 rtp_video_header.generic.emplace();
608
philipel626edea2024-03-19 08:38:01609 result.frame_id = frame_id;
Danil Chapovalovaf366442021-04-22 13:20:28610 result.spatial_index = spatial_index;
611 result.temporal_index = temporal_index;
612
613 result.decode_target_indications.reserve(num_spatial_layers *
614 num_temporal_layers);
615 for (int sid = 0; sid < num_spatial_layers; ++sid) {
616 for (int tid = 0; tid < num_temporal_layers; ++tid) {
617 DecodeTargetIndication dti;
618 if (sid < spatial_index || tid < temporal_index) {
619 dti = DecodeTargetIndication::kNotPresent;
620 } else if (spatial_index != sid &&
621 vp9_header.non_ref_for_inter_layer_pred) {
622 dti = DecodeTargetIndication::kNotPresent;
623 } else if (sid == spatial_index && tid == temporal_index) {
624 // Assume that if frame is decodable, all of its own layer is decodable.
625 dti = DecodeTargetIndication::kSwitch;
626 } else if (sid == spatial_index && vp9_header.temporal_up_switch) {
627 dti = DecodeTargetIndication::kSwitch;
628 } else if (!vp9_header.inter_pic_predicted) {
629 // Key frame or spatial upswitch
630 dti = DecodeTargetIndication::kSwitch;
631 } else {
632 // Make no other assumptions. That should be safe, though suboptimal.
633 // To provide more accurate dti, encoder wrapper should fill in
634 // CodecSpecificInfo::generic_frame_info
635 dti = DecodeTargetIndication::kRequired;
636 }
637 result.decode_target_indications.push_back(dti);
638 }
639 }
640
641 // Calculate frame dependencies.
642 static constexpr int kPictureDiffLimit = 128;
643 if (last_vp9_frame_id_.empty()) {
644 // Create the array only if it is ever used.
645 last_vp9_frame_id_.resize(kPictureDiffLimit);
646 }
philipel4e0bf2e2023-06-20 08:29:20647
648 if (vp9_header.flexible_mode) {
649 if (vp9_header.inter_layer_predicted && spatial_index > 0) {
Danil Chapovalovaf366442021-04-22 13:20:28650 result.dependencies.push_back(
philipel4e0bf2e2023-06-20 08:29:20651 last_vp9_frame_id_[vp9_header.picture_id % kPictureDiffLimit]
652 [spatial_index - 1]);
Danil Chapovalovaf366442021-04-22 13:20:28653 }
philipel4e0bf2e2023-06-20 08:29:20654 if (vp9_header.inter_pic_predicted) {
655 for (size_t i = 0; i < vp9_header.num_ref_pics; ++i) {
656 // picture_id is 15 bit number that wraps around. Though undeflow may
657 // produce picture that exceeds 2^15, it is ok because in this
658 // code block only last 7 bits of the picture_id are used.
659 uint16_t depend_on = vp9_header.picture_id - vp9_header.pid_diff[i];
660 result.dependencies.push_back(
661 last_vp9_frame_id_[depend_on % kPictureDiffLimit][spatial_index]);
662 }
663 }
664 last_vp9_frame_id_[vp9_header.picture_id % kPictureDiffLimit]
philipel626edea2024-03-19 08:38:01665 [spatial_index] = frame_id;
philipel4e0bf2e2023-06-20 08:29:20666 } else {
667 // Implementing general conversion logic for non-flexible mode requires some
668 // work and we will almost certainly never need it, so for now support only
669 // non-layerd streams.
670 if (spatial_index > 0 || temporal_index > 0) {
671 // Prefer to generate no generic layering than an inconsistent one.
672 rtp_video_header.generic.reset();
673 return;
674 }
675
676 if (vp9_header.inter_pic_predicted) {
677 // Since we only support non-scalable streams we only need to save the
678 // last frame id.
679 result.dependencies.push_back(last_vp9_frame_id_[0][0]);
680 }
philipel626edea2024-03-19 08:38:01681 last_vp9_frame_id_[0][0] = frame_id;
Danil Chapovalovaf366442021-04-22 13:20:28682 }
Danil Chapovalovaf366442021-04-22 13:20:28683
Danil Chapovalov5b298ab2022-06-08 09:18:51684 result.active_decode_targets =
Danil Chapovalov7f41b0b2023-08-03 11:29:29685 ((uint32_t{1} << num_temporal_layers * (last_active_spatial_id + 1)) -
686 1) ^
687 ((uint32_t{1} << num_temporal_layers * first_active_spatial_id) - 1);
Danil Chapovalov5b298ab2022-06-08 09:18:51688
Danil Chapovalovaf366442021-04-22 13:20:28689 // Calculate chains, asuming chain includes all frames with temporal_id = 0
690 if (!vp9_header.inter_pic_predicted && !vp9_header.inter_layer_predicted) {
691 // Assume frames without dependencies also reset chains.
Danil Chapovalov7f41b0b2023-08-03 11:29:29692 for (int sid = spatial_index; sid <= last_active_spatial_id; ++sid) {
Danil Chapovalovaf366442021-04-22 13:20:28693 chain_last_frame_id_[sid] = -1;
694 }
695 }
Danil Chapovalov5b298ab2022-06-08 09:18:51696 result.chain_diffs.resize(num_spatial_layers, 0);
Danil Chapovalov7f41b0b2023-08-03 11:29:29697 for (int sid = first_active_spatial_id; sid <= last_active_spatial_id;
698 ++sid) {
Danil Chapovalovaf366442021-04-22 13:20:28699 if (chain_last_frame_id_[sid] == -1) {
700 result.chain_diffs[sid] = 0;
701 continue;
702 }
philipel626edea2024-03-19 08:38:01703 int64_t chain_diff = frame_id - chain_last_frame_id_[sid];
Danil Chapovalov50ca7012023-08-02 09:28:58704 if (chain_diff >= 256) {
705 RTC_LOG(LS_ERROR)
706 << "Too many frames since last VP9 T0 frame for spatial layer #"
philipel626edea2024-03-19 08:38:01707 << sid << " at frame#" << frame_id;
Danil Chapovalov50ca7012023-08-02 09:28:58708 chain_last_frame_id_[sid] = -1;
709 chain_diff = 0;
710 }
711 result.chain_diffs[sid] = chain_diff;
Danil Chapovalovaf366442021-04-22 13:20:28712 }
713
714 if (temporal_index == 0) {
philipel626edea2024-03-19 08:38:01715 chain_last_frame_id_[spatial_index] = frame_id;
Danil Chapovalovaf366442021-04-22 13:20:28716 if (!vp9_header.non_ref_for_inter_layer_pred) {
Danil Chapovalov7f41b0b2023-08-03 11:29:29717 for (int sid = spatial_index + 1; sid <= last_active_spatial_id; ++sid) {
philipel626edea2024-03-19 08:38:01718 chain_last_frame_id_[sid] = frame_id;
Danil Chapovalovaf366442021-04-22 13:20:28719 }
720 }
721 }
722}
723
Qingsi Wang1c1b99e2020-01-07 19:16:33724void RtpPayloadParams::SetDependenciesVp8Deprecated(
725 const CodecSpecificInfoVP8& vp8_info,
philipel626edea2024-03-19 08:38:01726 int64_t frame_id,
Qingsi Wang1c1b99e2020-01-07 19:16:33727 bool is_keyframe,
728 int spatial_index,
729 int temporal_index,
730 bool layer_sync,
731 RTPVideoHeader::GenericDescriptorInfo* generic) {
732 RTC_DCHECK(!vp8_info.useExplicitDependencies);
733 RTC_DCHECK(!new_version_used_.has_value() || !new_version_used_.value());
734 new_version_used_ = false;
735
736 if (is_keyframe) {
737 RTC_DCHECK_EQ(temporal_index, 0);
philipel626edea2024-03-19 08:38:01738 last_frame_id_[spatial_index].fill(-1);
739 last_frame_id_[spatial_index][temporal_index] = frame_id;
Qingsi Wang1c1b99e2020-01-07 19:16:33740 return;
741 }
742
743 if (layer_sync) {
philipel626edea2024-03-19 08:38:01744 int64_t tl0_frame_id = last_frame_id_[spatial_index][0];
Qingsi Wang1c1b99e2020-01-07 19:16:33745
746 for (int i = 1; i < RtpGenericFrameDescriptor::kMaxTemporalLayers; ++i) {
philipel626edea2024-03-19 08:38:01747 if (last_frame_id_[spatial_index][i] < tl0_frame_id) {
748 last_frame_id_[spatial_index][i] = -1;
Qingsi Wang1c1b99e2020-01-07 19:16:33749 }
750 }
751
752 RTC_DCHECK_GE(tl0_frame_id, 0);
philipel626edea2024-03-19 08:38:01753 RTC_DCHECK_LT(tl0_frame_id, frame_id);
Qingsi Wang1c1b99e2020-01-07 19:16:33754 generic->dependencies.push_back(tl0_frame_id);
755 } else {
756 for (int i = 0; i <= temporal_index; ++i) {
philipel626edea2024-03-19 08:38:01757 int64_t last_frame_id = last_frame_id_[spatial_index][i];
Qingsi Wang1c1b99e2020-01-07 19:16:33758
philipel626edea2024-03-19 08:38:01759 if (last_frame_id != -1) {
760 RTC_DCHECK_LT(last_frame_id, frame_id);
761 generic->dependencies.push_back(last_frame_id);
Qingsi Wang1c1b99e2020-01-07 19:16:33762 }
763 }
764 }
765
philipel626edea2024-03-19 08:38:01766 last_frame_id_[spatial_index][temporal_index] = frame_id;
Qingsi Wang1c1b99e2020-01-07 19:16:33767}
768
769void RtpPayloadParams::SetDependenciesVp8New(
770 const CodecSpecificInfoVP8& vp8_info,
philipel626edea2024-03-19 08:38:01771 int64_t frame_id,
Qingsi Wang1c1b99e2020-01-07 19:16:33772 bool is_keyframe,
Dor Henbec70152024-10-29 12:47:48773 bool /* layer_sync */,
Qingsi Wang1c1b99e2020-01-07 19:16:33774 RTPVideoHeader::GenericDescriptorInfo* generic) {
775 RTC_DCHECK(vp8_info.useExplicitDependencies);
776 RTC_DCHECK(!new_version_used_.has_value() || new_version_used_.value());
777 new_version_used_ = true;
778
Elad Alonf5b216a2019-01-28 13:25:17779 if (is_keyframe) {
780 RTC_DCHECK_EQ(vp8_info.referencedBuffersCount, 0u);
philipel626edea2024-03-19 08:38:01781 buffer_id_to_frame_id_.fill(frame_id);
Elad Alonf5b216a2019-01-28 13:25:17782 return;
783 }
784
785 constexpr size_t kBuffersCountVp8 = CodecSpecificInfoVP8::kBuffersCount;
786
787 RTC_DCHECK_GT(vp8_info.referencedBuffersCount, 0u);
788 RTC_DCHECK_LE(vp8_info.referencedBuffersCount,
789 arraysize(vp8_info.referencedBuffers));
790
791 for (size_t i = 0; i < vp8_info.referencedBuffersCount; ++i) {
792 const size_t referenced_buffer = vp8_info.referencedBuffers[i];
793 RTC_DCHECK_LT(referenced_buffer, kBuffersCountVp8);
794 RTC_DCHECK_LT(referenced_buffer, buffer_id_to_frame_id_.size());
795
796 const int64_t dependency_frame_id =
797 buffer_id_to_frame_id_[referenced_buffer];
798 RTC_DCHECK_GE(dependency_frame_id, 0);
philipel626edea2024-03-19 08:38:01799 RTC_DCHECK_LT(dependency_frame_id, frame_id);
Elad Alonf5b216a2019-01-28 13:25:17800
801 const bool is_new_dependency =
Qingsi Wang1c1b99e2020-01-07 19:16:33802 std::find(generic->dependencies.begin(), generic->dependencies.end(),
803 dependency_frame_id) == generic->dependencies.end();
Elad Alonf5b216a2019-01-28 13:25:17804 if (is_new_dependency) {
Qingsi Wang1c1b99e2020-01-07 19:16:33805 generic->dependencies.push_back(dependency_frame_id);
Elad Alonf5b216a2019-01-28 13:25:17806 }
807 }
808
809 RTC_DCHECK_LE(vp8_info.updatedBuffersCount, kBuffersCountVp8);
810 for (size_t i = 0; i < vp8_info.updatedBuffersCount; ++i) {
811 const size_t updated_id = vp8_info.updatedBuffers[i];
philipel626edea2024-03-19 08:38:01812 buffer_id_to_frame_id_[updated_id] = frame_id;
Elad Alonf5b216a2019-01-28 13:25:17813 }
814
815 RTC_DCHECK_LE(buffer_id_to_frame_id_.size(), kBuffersCountVp8);
816}
817
Stefan Holmerf7044682018-07-17 08:16:41818} // namespace webrtc