Index: webrtc/modules/video_coding/codecs/vp8/default_temporal_layers.cc |
diff --git a/webrtc/modules/video_coding/codecs/vp8/default_temporal_layers.cc b/webrtc/modules/video_coding/codecs/vp8/default_temporal_layers.cc |
index 4f04743fc5d0359d62ff02117d9fe620e26fc309..2af8f41cd71d5798a14c83e4674f3974cea00f39 100644 |
--- a/webrtc/modules/video_coding/codecs/vp8/default_temporal_layers.cc |
+++ b/webrtc/modules/video_coding/codecs/vp8/default_temporal_layers.cc |
@@ -9,7 +9,6 @@ |
#include "webrtc/modules/video_coding/codecs/vp8/default_temporal_layers.h" |
-#include <assert.h> |
#include <stdlib.h> |
#include <string.h> |
@@ -26,26 +25,175 @@ |
namespace webrtc { |
+TemporalReferences::TemporalReferences(TemporalBufferUsage last, |
+ TemporalBufferUsage golden, |
+ TemporalBufferUsage arf) |
+ : TemporalReferences(last, golden, arf, false, false) {} |
+ |
+TemporalReferences::TemporalReferences(TemporalBufferUsage last, |
+ TemporalBufferUsage golden, |
+ TemporalBufferUsage arf, |
+ int extra_flags) |
+ : TemporalReferences(last, |
+ golden, |
+ arf, |
+ (extra_flags & kLayerSync) != 0, |
+ (extra_flags & kFreezeEntropy) != 0) {} |
+ |
+TemporalReferences::TemporalReferences(TemporalBufferUsage last, |
+ TemporalBufferUsage golden, |
+ TemporalBufferUsage arf, |
+ bool layer_sync, |
+ bool freeze_entropy) |
+ : reference_last((last & kReference) != 0), |
+ update_last((last & kUpdate) != 0), |
+ reference_golden((golden & kReference) != 0), |
+ update_golden((golden & kUpdate) != 0), |
+ reference_arf((arf & kReference) != 0), |
+ update_arf((arf & kUpdate) != 0), |
+ layer_sync(layer_sync), |
+ freeze_entropy(freeze_entropy) {} |
+ |
+namespace { |
+ |
+std::vector<unsigned int> GetTemporalIds(size_t num_layers) { |
+ switch (num_layers) { |
+ case 1: |
+ // Temporal layer structure (single layer): |
+ // 0 0 0 0 ... |
+ return {0}; |
+ case 2: |
+ // Temporal layer structure: |
+ // 1 1 ... |
+ // 0 0 ... |
+ return {0, 1}; |
+ case 3: |
+ // Temporal layer structure: |
+ // 2 2 2 2 ... |
+ // 1 1 ... |
+ // 0 0 ... |
+ return {0, 2, 1, 2}; |
+ case 4: |
+ // Temporal layer structure: |
+ // 3 3 3 3 3 3 3 3 ... |
+ // 2 2 2 2 ... |
+ // 1 1 ... |
+ // 0 0 ... |
+ return {0, 3, 2, 3, 1, 3, 2, 3}; |
+ default: |
+ RTC_NOTREACHED(); |
+ break; |
+ } |
+ RTC_NOTREACHED(); |
+ return {0}; |
+} |
+ |
+std::vector<TemporalReferences> GetTemporalPattern( |
+ size_t num_layers) { |
+ // For indexing in the patterns described below (which temporal layers they |
+ // belong to), see the diagram above. |
+ // Layer sync is done similarly for all patterns (except single stream) and |
+ // happens every 8 frames: |
+ // TL1 layer syncs by periodically by only referencing TL0 ('last'), but still |
+ // updating 'golden', so it can be used as a reference by future TL1 frames. |
+ // TL2 layer syncs just before TL1 by only depending on TL0 (and not depending |
+ // on TL1's buffer before TL1 has layer synced). |
+ // TODO(pbos): Consider cyclically updating 'arf' (and 'golden' for 1TL) for |
+ // the base layer in 1-3TL instead of 'last' periodically on long intervals, |
+ // so that if scene changes occur (user walks between rooms or rotates webcam) |
+ // the 'arf' (or 'golden' respectively) is not stuck on a no-longer relevant |
+ // keyframe. |
+ switch (num_layers) { |
+ case 1: |
+ // All frames reference all buffers and the 'last' buffer is updated. |
+ return {TemporalReferences(kReferenceAndUpdate, kReference, kReference)}; |
+ case 2: |
+ // All layers can reference but not update the 'alt' buffer, this means |
+ // that the 'alt' buffer reference is effectively the last keyframe. |
+ // TL0 also references and updates the 'last' buffer. |
+ // TL1 also references 'last' and references and updates 'golden'. |
+ return {TemporalReferences(kReferenceAndUpdate, kUpdate, kReference), |
+ TemporalReferences(kReference, kUpdate, kReference, kLayerSync), |
+ TemporalReferences(kReferenceAndUpdate, kNone, kReference), |
+ TemporalReferences(kReference, kReferenceAndUpdate, kReference), |
+ TemporalReferences(kReferenceAndUpdate, kNone, kReference), |
+ TemporalReferences(kReference, kReferenceAndUpdate, kReference), |
+ TemporalReferences(kReferenceAndUpdate, kNone, kReference), |
+ TemporalReferences(kReference, kReference, kReference, |
+ kFreezeEntropy)}; |
+ case 3: |
+ // All layers can reference but not update the 'alt' buffer, this means |
+ // that the 'alt' buffer reference is effectively the last keyframe. |
+ // TL0 also references and updates the 'last' buffer. |
+ // TL1 also references 'last' and references and updates 'golden'. |
+ // TL2 references both 'last' and 'golden' but updates no buffer. |
+ return {TemporalReferences(kReferenceAndUpdate, kUpdate, kReference), |
+ TemporalReferences(kReference, kNone, kReference, |
+ kLayerSync | kFreezeEntropy), |
+ TemporalReferences(kReference, kUpdate, kReference, kLayerSync), |
+ TemporalReferences(kReference, kReference, kReference, |
+ kFreezeEntropy), |
+ TemporalReferences(kReferenceAndUpdate, kNone, kReference), |
+ TemporalReferences(kReference, kReference, kReference, |
+ kFreezeEntropy), |
+ TemporalReferences(kReference, kReferenceAndUpdate, kReference), |
+ TemporalReferences(kReference, kReference, kReference, |
+ kFreezeEntropy)}; |
+ case 4: |
+ // TL0 references and updates only the 'last' buffer. |
+ // TL1 references 'last' and updates and references 'golden'. |
+ // TL2 references 'last' and 'golden', and references and updates 'arf'. |
+ // TL3 references all buffers but update none of them. |
+ return {TemporalReferences(kReferenceAndUpdate, kNone, kNone), |
+ TemporalReferences(kReference, kReference, kReference, |
+ kLayerSync | kFreezeEntropy), |
+ TemporalReferences(kReference, kNone, kUpdate, kLayerSync), |
+ TemporalReferences(kReference, kReference, kReference, |
+ kLayerSync | kFreezeEntropy), |
+ TemporalReferences(kReference, kUpdate, kNone, kLayerSync), |
+ TemporalReferences(kReference, kReference, kReference, |
+ kLayerSync | kFreezeEntropy), |
+ TemporalReferences(kReference, kReference, kReferenceAndUpdate), |
+ TemporalReferences(kReference, kReference, kReference, |
+ kLayerSync | kFreezeEntropy), |
+ TemporalReferences(kReferenceAndUpdate, kNone, kNone), |
+ TemporalReferences(kReference, kReference, kReference, |
+ kLayerSync | kFreezeEntropy), |
+ TemporalReferences(kReference, kReference, kReferenceAndUpdate), |
+ TemporalReferences(kReference, kReference, kReference, |
+ kLayerSync | kFreezeEntropy), |
+ TemporalReferences(kReference, kReferenceAndUpdate, kNone), |
+ TemporalReferences(kReference, kReference, kReference, |
+ kLayerSync | kFreezeEntropy), |
+ TemporalReferences(kReference, kReference, kReferenceAndUpdate), |
+ TemporalReferences(kReference, kReference, kReference, |
+ kLayerSync | kFreezeEntropy)}; |
+ default: |
+ RTC_NOTREACHED(); |
+ break; |
+ } |
+ RTC_NOTREACHED(); |
+ return {TemporalReferences(kNone, kNone, kNone)}; |
+} |
+ |
+} // namespace |
+ |
DefaultTemporalLayers::DefaultTemporalLayers(int number_of_temporal_layers, |
uint8_t initial_tl0_pic_idx) |
- : number_of_temporal_layers_(number_of_temporal_layers), |
- temporal_ids_length_(0), |
- temporal_pattern_length_(0), |
+ : num_layers_(std::max(1, number_of_temporal_layers)), |
+ temporal_ids_(GetTemporalIds(num_layers_)), |
+ temporal_pattern_(GetTemporalPattern(num_layers_)), |
tl0_pic_idx_(initial_tl0_pic_idx), |
pattern_idx_(255), |
timestamp_(0), |
last_base_layer_sync_(false) { |
RTC_CHECK_GE(kMaxTemporalStreams, number_of_temporal_layers); |
RTC_CHECK_GE(number_of_temporal_layers, 0); |
- memset(temporal_ids_, 0, sizeof(temporal_ids_)); |
- memset(temporal_pattern_, 0, sizeof(temporal_pattern_)); |
+ RTC_CHECK_LE(number_of_temporal_layers, 4); |
} |
int DefaultTemporalLayers::CurrentLayerId() const { |
- assert(temporal_ids_length_ > 0); |
- int index = pattern_idx_ % temporal_ids_length_; |
- assert(index >= 0); |
- return temporal_ids_[index]; |
+ return temporal_ids_[pattern_idx_ % temporal_ids_.size()]; |
} |
std::vector<uint32_t> DefaultTemporalLayers::OnRatesUpdated( |
@@ -53,17 +201,16 @@ std::vector<uint32_t> DefaultTemporalLayers::OnRatesUpdated( |
int max_bitrate_kbps, |
int framerate) { |
std::vector<uint32_t> bitrates; |
- const int num_layers = std::max(1, number_of_temporal_layers_); |
- for (int i = 0; i < num_layers; ++i) { |
+ for (size_t i = 0; i < num_layers_; ++i) { |
float layer_bitrate = |
- bitrate_kbps * kVp8LayerRateAlloction[num_layers - 1][i]; |
+ bitrate_kbps * kVp8LayerRateAlloction[num_layers_ - 1][i]; |
bitrates.push_back(static_cast<uint32_t>(layer_bitrate + 0.5)); |
} |
new_bitrates_kbps_ = rtc::Optional<std::vector<uint32_t>>(bitrates); |
// Allocation table is of aggregates, transform to individual rates. |
uint32_t sum = 0; |
- for (int i = 0; i < num_layers; ++i) { |
+ for (size_t i = 0; i < num_layers_; ++i) { |
uint32_t layer_bitrate = bitrates[i]; |
RTC_DCHECK_LE(sum, bitrates[i]); |
bitrates[i] -= sum; |
@@ -83,197 +230,46 @@ bool DefaultTemporalLayers::UpdateConfiguration(vpx_codec_enc_cfg_t* cfg) { |
if (!new_bitrates_kbps_) |
return false; |
- switch (number_of_temporal_layers_) { |
- case 0: |
- FALLTHROUGH(); |
- case 1: |
- temporal_ids_length_ = 1; |
- temporal_ids_[0] = 0; |
- cfg->ts_number_layers = number_of_temporal_layers_; |
- cfg->ts_periodicity = temporal_ids_length_; |
- cfg->ts_target_bitrate[0] = (*new_bitrates_kbps_)[0]; |
- cfg->ts_rate_decimator[0] = 1; |
- memcpy(cfg->ts_layer_id, temporal_ids_, |
- sizeof(unsigned int) * temporal_ids_length_); |
- temporal_pattern_length_ = 1; |
- temporal_pattern_[0] = kTemporalUpdateLastRefAll; |
- break; |
- case 2: |
- temporal_ids_length_ = 2; |
- temporal_ids_[0] = 0; |
- temporal_ids_[1] = 1; |
- cfg->ts_number_layers = number_of_temporal_layers_; |
- cfg->ts_periodicity = temporal_ids_length_; |
- // Split stream 60% 40%. |
- // Bitrate API for VP8 is the agregated bitrate for all lower layers. |
- cfg->ts_target_bitrate[0] = (*new_bitrates_kbps_)[0]; |
- cfg->ts_target_bitrate[1] = (*new_bitrates_kbps_)[1]; |
- cfg->ts_rate_decimator[0] = 2; |
- cfg->ts_rate_decimator[1] = 1; |
- memcpy(cfg->ts_layer_id, temporal_ids_, |
- sizeof(unsigned int) * temporal_ids_length_); |
- temporal_pattern_length_ = 8; |
- temporal_pattern_[0] = kTemporalUpdateLastAndGoldenRefAltRef; |
- temporal_pattern_[1] = kTemporalUpdateGoldenWithoutDependencyRefAltRef; |
- temporal_pattern_[2] = kTemporalUpdateLastRefAltRef; |
- temporal_pattern_[3] = kTemporalUpdateGoldenRefAltRef; |
- temporal_pattern_[4] = kTemporalUpdateLastRefAltRef; |
- temporal_pattern_[5] = kTemporalUpdateGoldenRefAltRef; |
- temporal_pattern_[6] = kTemporalUpdateLastRefAltRef; |
- temporal_pattern_[7] = kTemporalUpdateNone; |
- break; |
- case 3: |
- temporal_ids_length_ = 4; |
- temporal_ids_[0] = 0; |
- temporal_ids_[1] = 2; |
- temporal_ids_[2] = 1; |
- temporal_ids_[3] = 2; |
- cfg->ts_number_layers = number_of_temporal_layers_; |
- cfg->ts_periodicity = temporal_ids_length_; |
- // Split stream 40% 20% 40%. |
- // Bitrate API for VP8 is the agregated bitrate for all lower layers. |
- cfg->ts_target_bitrate[0] = (*new_bitrates_kbps_)[0]; |
- cfg->ts_target_bitrate[1] = (*new_bitrates_kbps_)[1]; |
- cfg->ts_target_bitrate[2] = (*new_bitrates_kbps_)[2]; |
- cfg->ts_rate_decimator[0] = 4; |
- cfg->ts_rate_decimator[1] = 2; |
- cfg->ts_rate_decimator[2] = 1; |
- memcpy(cfg->ts_layer_id, temporal_ids_, |
- sizeof(unsigned int) * temporal_ids_length_); |
- temporal_pattern_length_ = 8; |
- temporal_pattern_[0] = kTemporalUpdateLastAndGoldenRefAltRef; |
- temporal_pattern_[1] = kTemporalUpdateNoneNoRefGoldenRefAltRef; |
- temporal_pattern_[2] = kTemporalUpdateGoldenWithoutDependencyRefAltRef; |
- temporal_pattern_[3] = kTemporalUpdateNone; |
- temporal_pattern_[4] = kTemporalUpdateLastRefAltRef; |
- temporal_pattern_[5] = kTemporalUpdateNone; |
- temporal_pattern_[6] = kTemporalUpdateGoldenRefAltRef; |
- temporal_pattern_[7] = kTemporalUpdateNone; |
- break; |
- case 4: |
- temporal_ids_length_ = 8; |
- temporal_ids_[0] = 0; |
- temporal_ids_[1] = 3; |
- temporal_ids_[2] = 2; |
- temporal_ids_[3] = 3; |
- temporal_ids_[4] = 1; |
- temporal_ids_[5] = 3; |
- temporal_ids_[6] = 2; |
- temporal_ids_[7] = 3; |
- // Split stream 25% 15% 20% 40%. |
- // Bitrate API for VP8 is the agregated bitrate for all lower layers. |
- cfg->ts_number_layers = 4; |
- cfg->ts_periodicity = temporal_ids_length_; |
- cfg->ts_target_bitrate[0] = (*new_bitrates_kbps_)[0]; |
- cfg->ts_target_bitrate[1] = (*new_bitrates_kbps_)[1]; |
- cfg->ts_target_bitrate[2] = (*new_bitrates_kbps_)[2]; |
- cfg->ts_target_bitrate[3] = (*new_bitrates_kbps_)[3]; |
- cfg->ts_rate_decimator[0] = 8; |
- cfg->ts_rate_decimator[1] = 4; |
- cfg->ts_rate_decimator[2] = 2; |
- cfg->ts_rate_decimator[3] = 1; |
- memcpy(cfg->ts_layer_id, temporal_ids_, |
- sizeof(unsigned int) * temporal_ids_length_); |
- temporal_pattern_length_ = 16; |
- temporal_pattern_[0] = kTemporalUpdateLast; |
- temporal_pattern_[1] = kTemporalUpdateNone; |
- temporal_pattern_[2] = kTemporalUpdateAltrefWithoutDependency; |
- temporal_pattern_[3] = kTemporalUpdateNone; |
- temporal_pattern_[4] = kTemporalUpdateGoldenWithoutDependency; |
- temporal_pattern_[5] = kTemporalUpdateNone; |
- temporal_pattern_[6] = kTemporalUpdateAltref; |
- temporal_pattern_[7] = kTemporalUpdateNone; |
- temporal_pattern_[8] = kTemporalUpdateLast; |
- temporal_pattern_[9] = kTemporalUpdateNone; |
- temporal_pattern_[10] = kTemporalUpdateAltref; |
- temporal_pattern_[11] = kTemporalUpdateNone; |
- temporal_pattern_[12] = kTemporalUpdateGolden; |
- temporal_pattern_[13] = kTemporalUpdateNone; |
- temporal_pattern_[14] = kTemporalUpdateAltref; |
- temporal_pattern_[15] = kTemporalUpdateNone; |
- break; |
- default: |
- RTC_NOTREACHED(); |
- return false; |
+ for (size_t i = 0; i < num_layers_; ++i) { |
+ cfg->ts_target_bitrate[i] = (*new_bitrates_kbps_)[i]; |
+ // ..., 4, 2, 1 |
+ cfg->ts_rate_decimator[i] = 1 << (num_layers_ - i - 1); |
} |
+ cfg->ts_number_layers = num_layers_; |
+ cfg->ts_periodicity = temporal_ids_.size(); |
+ memcpy(cfg->ts_layer_id, &temporal_ids_[0], |
+ sizeof(unsigned int) * temporal_ids_.size()); |
+ |
new_bitrates_kbps_ = rtc::Optional<std::vector<uint32_t>>(); |
return true; |
} |
int DefaultTemporalLayers::EncodeFlags(uint32_t timestamp) { |
- assert(number_of_temporal_layers_ > 0); |
- assert(kMaxTemporalPattern >= temporal_pattern_length_); |
- assert(0 < temporal_pattern_length_); |
+ RTC_DCHECK_GT(num_layers_, 0); |
+ RTC_DCHECK_LT(0, temporal_pattern_.size()); |
int flags = 0; |
- int patternIdx = ++pattern_idx_ % temporal_pattern_length_; |
- assert(kMaxTemporalPattern >= patternIdx); |
- switch (temporal_pattern_[patternIdx]) { |
- case kTemporalUpdateLast: |
- flags |= VP8_EFLAG_NO_UPD_GF; |
- flags |= VP8_EFLAG_NO_UPD_ARF; |
- flags |= VP8_EFLAG_NO_REF_GF; |
- flags |= VP8_EFLAG_NO_REF_ARF; |
- break; |
- case kTemporalUpdateGoldenWithoutDependency: |
- flags |= VP8_EFLAG_NO_REF_GF; |
- // Deliberately no break here. |
- FALLTHROUGH(); |
- case kTemporalUpdateGolden: |
- flags |= VP8_EFLAG_NO_REF_ARF; |
- flags |= VP8_EFLAG_NO_UPD_ARF; |
- flags |= VP8_EFLAG_NO_UPD_LAST; |
- break; |
- case kTemporalUpdateAltrefWithoutDependency: |
- flags |= VP8_EFLAG_NO_REF_ARF; |
- flags |= VP8_EFLAG_NO_REF_GF; |
- // Deliberately no break here. |
- FALLTHROUGH(); |
- case kTemporalUpdateAltref: |
- flags |= VP8_EFLAG_NO_UPD_GF; |
- flags |= VP8_EFLAG_NO_UPD_LAST; |
- break; |
- case kTemporalUpdateNoneNoRefAltref: |
- flags |= VP8_EFLAG_NO_REF_ARF; |
- // Deliberately no break here. |
- FALLTHROUGH(); |
- case kTemporalUpdateNone: |
- flags |= VP8_EFLAG_NO_UPD_GF; |
- flags |= VP8_EFLAG_NO_UPD_ARF; |
- flags |= VP8_EFLAG_NO_UPD_LAST; |
- flags |= VP8_EFLAG_NO_UPD_ENTROPY; |
- break; |
- case kTemporalUpdateNoneNoRefGoldenRefAltRef: |
- flags |= VP8_EFLAG_NO_REF_GF; |
- flags |= VP8_EFLAG_NO_UPD_GF; |
- flags |= VP8_EFLAG_NO_UPD_ARF; |
- flags |= VP8_EFLAG_NO_UPD_LAST; |
- flags |= VP8_EFLAG_NO_UPD_ENTROPY; |
- break; |
- case kTemporalUpdateGoldenWithoutDependencyRefAltRef: |
- flags |= VP8_EFLAG_NO_REF_GF; |
- flags |= VP8_EFLAG_NO_UPD_ARF; |
- flags |= VP8_EFLAG_NO_UPD_LAST; |
- break; |
- case kTemporalUpdateLastRefAltRef: |
- flags |= VP8_EFLAG_NO_UPD_GF; |
- flags |= VP8_EFLAG_NO_UPD_ARF; |
- flags |= VP8_EFLAG_NO_REF_GF; |
- break; |
- case kTemporalUpdateGoldenRefAltRef: |
- flags |= VP8_EFLAG_NO_UPD_ARF; |
- flags |= VP8_EFLAG_NO_UPD_LAST; |
- break; |
- case kTemporalUpdateLastAndGoldenRefAltRef: |
- flags |= VP8_EFLAG_NO_UPD_ARF; |
- flags |= VP8_EFLAG_NO_REF_GF; |
- break; |
- case kTemporalUpdateLastRefAll: |
- flags |= VP8_EFLAG_NO_UPD_ARF; |
- flags |= VP8_EFLAG_NO_UPD_GF; |
- break; |
- } |
+ // TODO(pbos): Move pattern-update out of EncodeFlags. It's not obvious that |
+ // EncodeFlags() is non-const. |
+ const TemporalReferences& references = |
+ temporal_pattern_[++pattern_idx_ % temporal_pattern_.size()]; |
+ |
+ if (!references.reference_last) |
+ flags |= VP8_EFLAG_NO_REF_LAST; |
+ if (!references.update_last) |
+ flags |= VP8_EFLAG_NO_UPD_LAST; |
+ if (!references.reference_golden) |
+ flags |= VP8_EFLAG_NO_REF_GF; |
+ if (!references.update_golden) |
+ flags |= VP8_EFLAG_NO_UPD_GF; |
+ if (!references.reference_arf) |
+ flags |= VP8_EFLAG_NO_REF_ARF; |
+ if (!references.update_arf) |
+ flags |= VP8_EFLAG_NO_UPD_ARF; |
+ if (references.freeze_entropy) |
+ flags |= VP8_EFLAG_NO_UPD_ENTROPY; |
+ |
return flags; |
} |
@@ -281,10 +277,9 @@ void DefaultTemporalLayers::PopulateCodecSpecific( |
bool base_layer_sync, |
CodecSpecificInfoVP8* vp8_info, |
uint32_t timestamp) { |
- assert(number_of_temporal_layers_ > 0); |
- assert(0 < temporal_ids_length_); |
+ RTC_DCHECK_GT(num_layers_, 0); |
- if (number_of_temporal_layers_ == 1) { |
+ if (num_layers_ == 1) { |
vp8_info->temporalIdx = kNoTemporalIdx; |
vp8_info->layerSync = false; |
vp8_info->tl0PicIdx = kNoTl0PicIdx; |
@@ -295,19 +290,9 @@ void DefaultTemporalLayers::PopulateCodecSpecific( |
} else { |
vp8_info->temporalIdx = CurrentLayerId(); |
TemporalReferences temporal_reference = |
- temporal_pattern_[pattern_idx_ % temporal_pattern_length_]; |
- |
- if (temporal_reference == kTemporalUpdateAltrefWithoutDependency || |
- temporal_reference == kTemporalUpdateGoldenWithoutDependency || |
- temporal_reference == |
- kTemporalUpdateGoldenWithoutDependencyRefAltRef || |
- temporal_reference == kTemporalUpdateNoneNoRefGoldenRefAltRef || |
- (temporal_reference == kTemporalUpdateNone && |
- number_of_temporal_layers_ == 4)) { |
- vp8_info->layerSync = true; |
- } else { |
- vp8_info->layerSync = false; |
- } |
+ temporal_pattern_[pattern_idx_ % temporal_pattern_.size()]; |
+ |
+ vp8_info->layerSync = temporal_reference.layer_sync; |
} |
if (last_base_layer_sync_ && vp8_info->temporalIdx != 0) { |
// Regardless of pattern the frame after a base layer sync will always |