1 /*
2 * Copyright (C) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "temporal_scalability.h"
17 #include <cmath>
18 #include "meta/video_types.h"
19 #include "avcodec_log.h"
20 #include "avcodec_common.h"
21 #include "avcodec_errors.h"
22 #include "codec_ability_singleton.h"
23
24 namespace {
25 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FRAMEWORK, "TemporalScalability"};
26 } // namespace
27
28 constexpr int32_t DEFAULT_VIDEO_LTR_FRAME_NUM = 2;
29 constexpr int32_t ENABLE_PARAMETER_CALLBACK = 1;
30
31 namespace OHOS {
32 namespace MediaAVCodec {
33 using namespace Media;
34 using namespace Plugins;
35 using namespace std;
36
TemporalScalability(const string & name)37 TemporalScalability::TemporalScalability(const string &name) : name_(name)
38 {
39 inputIndexQueue_ = make_shared<BlockQueue<uint32_t>>("inputIndexQueue");
40 }
41
~TemporalScalability()42 TemporalScalability::~TemporalScalability()
43 {
44 inputIndexQueue_->Clear();
45 }
46
IsLTRSolution()47 bool TemporalScalability::IsLTRSolution()
48 {
49 if (tRefMode_ != static_cast<int32_t>(TemporalGopReferenceMode::UNIFORMLY_SCALED_REFERENCE)) {
50 return true;
51 }
52 if (temporalGopSize_ > DEFAULT_TEMPORAL_GOPSIZE) {
53 return true;
54 }
55 if (name_.find("avc") != string::npos && temporalGopSize_ > MIN_TEMPORAL_GOPSIZE) {
56 return true;
57 }
58 return false;
59 }
60
LTRFrameNumCalculate(int32_t tGopSize) const61 int32_t TemporalScalability::LTRFrameNumCalculate(int32_t tGopSize) const
62 {
63 if (tRefMode_ != static_cast<int32_t>(TemporalGopReferenceMode::UNIFORMLY_SCALED_REFERENCE)) {
64 return DEFAULT_VIDEO_LTR_FRAME_NUM;
65 }
66 return (tGopSize / DEFAULT_TEMPORAL_GOPSIZE) + 1;
67 }
68
ValidateTemporalGopParam(Format & format)69 void TemporalScalability::ValidateTemporalGopParam(Format &format)
70 {
71 if (!format.GetIntValue("video_encoder_gop_size", gopSize_)) {
72 gopSize_ = DEFAULT_GOPSIZE;
73 }
74
75 if (format.GetIntValue(Tag::VIDEO_ENCODER_TEMPORAL_GOP_SIZE, temporalGopSize_)) {
76 AVCODEC_LOGI("Set temporal gop size successfully, value is %{public}d.", temporalGopSize_);
77 } else {
78 temporalGopSize_ = gopSize_ <= DEFAULT_TEMPORAL_GOPSIZE ? MIN_TEMPORAL_GOPSIZE : DEFAULT_TEMPORAL_GOPSIZE;
79 AVCODEC_LOGI("Get temporal gop size failed, use default value %{public}d.", temporalGopSize_);
80 }
81 if (format.GetIntValue(Tag::VIDEO_ENCODER_TEMPORAL_GOP_REFERENCE_MODE, tRefMode_)) {
82 AVCODEC_LOGI("Set temporal reference mode successfully.");
83 } else {
84 tRefMode_ = static_cast<int32_t>(TemporalGopReferenceMode::ADJACENT_REFERENCE);
85 AVCODEC_LOGI("Get temporal reference mode failed, use default value ADJACENT_REFERENCE.");
86 }
87 svcLTR_ = IsLTRSolution();
88 if (svcLTR_) {
89 int32_t ltrFrameNum = LTRFrameNumCalculate(temporalGopSize_);
90 format.RemoveKey(Tag::VIDEO_ENCODER_ENABLE_TEMPORAL_SCALABILITY);
91 format.PutIntValue(Tag::VIDEO_ENCODER_LTR_FRAME_COUNT, ltrFrameNum);
92 format.PutIntValue(Tag::VIDEO_ENCODER_ENABLE_SURFACE_INPUT_CALLBACK, ENABLE_PARAMETER_CALLBACK);
93 }
94 AVCODEC_LOGI("Set temporal gop parameter successfully.");
95 }
96
StoreAVBuffer(uint32_t index,shared_ptr<AVBuffer> buffer)97 void TemporalScalability::StoreAVBuffer(uint32_t index, shared_ptr<AVBuffer> buffer)
98 {
99 inputIndexQueue_->Push(index);
100 lock_guard<shared_mutex> inputBufLock(inputBufMutex_);
101 inputBufferMap_.emplace(index, buffer);
102 }
103
GetFirstBufferIndex()104 uint32_t TemporalScalability::GetFirstBufferIndex()
105 {
106 return inputIndexQueue_->Front();
107 }
108
SetBlockQueueActive()109 void TemporalScalability::SetBlockQueueActive()
110 {
111 inputIndexQueue_->SetActive(false, false);
112 }
113
SetDisposableFlag(shared_ptr<Media::AVBuffer> buffer)114 void TemporalScalability::SetDisposableFlag(shared_ptr<Media::AVBuffer> buffer)
115 {
116 lock_guard<shared_mutex> frameFlagMapLock(frameFlagMapMutex_);
117 uint32_t flag = frameFlagMap_[outputFrameCounter_];
118 buffer->flag_ |= flag;
119 frameFlagMap_.erase(outputFrameCounter_);
120 outputFrameCounter_++;
121 }
122
MarkLTRDecision()123 void TemporalScalability::MarkLTRDecision()
124 {
125 if (temporalPoc_ % DEFAULT_TEMPORAL_GOPSIZE == 0) {
126 isMarkLTR_ = true;
127 } else {
128 isMarkLTR_ = false;
129 }
130 }
131
LTRPocDecision(int32_t tPoc)132 int32_t TemporalScalability::LTRPocDecision(int32_t tPoc)
133 {
134 int32_t layer = 0;
135 for (; tPoc % (MIN_TEMPORAL_GOPSIZE) == 0; layer++) {
136 tPoc /= MIN_TEMPORAL_GOPSIZE;
137 }
138 return static_cast<int32_t>(pow(MIN_TEMPORAL_GOPSIZE, layer));
139 }
140
AdjacentJumpLTRDecision()141 void TemporalScalability::AdjacentJumpLTRDecision()
142 {
143 if (temporalPoc_ == 0) {
144 isMarkLTR_ = true;
145 if (poc_ == 0) {
146 isUseLTR_ = false;
147 ltrPoc_ = 0;
148 } else {
149 isUseLTR_ = true;
150 ltrPoc_ = poc_ - temporalGopSize_;
151 }
152 } else if (temporalPoc_ == 1 || tRefMode_ == static_cast<int32_t>(TemporalGopReferenceMode::ADJACENT_REFERENCE)) {
153 isMarkLTR_ = false;
154 isUseLTR_ = false;
155 ltrPoc_ = poc_ - 1;
156 } else {
157 isMarkLTR_ = false;
158 isUseLTR_ = true;
159 ltrPoc_ = poc_ - temporalPoc_;
160 }
161 }
162
UniformlyScaledLTRDecision()163 void TemporalScalability::UniformlyScaledLTRDecision()
164 {
165 if (temporalPoc_ == 0 && poc_ == 0) {
166 isMarkLTR_ = true;
167 isUseLTR_ = false;
168 ltrPoc_ = 0;
169 } else if (temporalPoc_ == 0 && poc_ != 0) {
170 isMarkLTR_ = true;
171 isUseLTR_ = true;
172 ltrPoc_ = poc_ - temporalGopSize_;
173 } else {
174 if (temporalPoc_ % MIN_TEMPORAL_GOPSIZE != 0) {
175 isMarkLTR_ = false;
176 isUseLTR_ = false;
177 ltrPoc_ = poc_ - 1;
178 } else {
179 isUseLTR_ = true;
180 MarkLTRDecision();
181 ltrPoc_ = poc_ - LTRPocDecision(temporalPoc_);
182 }
183 }
184 }
185
LTRDecision()186 void TemporalScalability::LTRDecision()
187 {
188 poc_ = frameNum_ % gopSize_;
189 temporalPoc_ = poc_ % temporalGopSize_;
190 if (tRefMode_ != static_cast<int32_t>(TemporalGopReferenceMode::UNIFORMLY_SCALED_REFERENCE)) {
191 AdjacentJumpLTRDecision();
192 } else {
193 UniformlyScaledLTRDecision();
194 }
195 }
196
DisposableDecision() const197 uint32_t TemporalScalability::DisposableDecision() const
198 {
199 if (tRefMode_ != static_cast<int32_t>(TemporalGopReferenceMode::UNIFORMLY_SCALED_REFERENCE)) {
200 if (!isMarkLTR_) {
201 if (tRefMode_ == static_cast<int32_t>(TemporalGopReferenceMode::ADJACENT_REFERENCE) &&
202 temporalPoc_ != temporalGopSize_ - 1 && poc_ != gopSize_ - 1) {
203 return AVCODEC_BUFFER_FLAG_DISPOSABLE_EXT;
204 } else {
205 return AVCODEC_BUFFER_FLAG_DISPOSABLE;
206 }
207 }
208 } else {
209 if (temporalPoc_ % MIN_TEMPORAL_GOPSIZE != 0) {
210 return AVCODEC_BUFFER_FLAG_DISPOSABLE;
211 }
212 if (temporalPoc_ != 0 && temporalPoc_ % MIN_TEMPORAL_GOPSIZE == 0) {
213 return AVCODEC_BUFFER_FLAG_DISPOSABLE_EXT;
214 }
215 }
216 return AVCODEC_BUFFER_FLAG_NONE;
217 }
218
ConfigureLTR(uint32_t index)219 void TemporalScalability::ConfigureLTR(uint32_t index)
220 {
221 bool isFinded = false;
222 {
223 lock_guard<shared_mutex> inputBufLock(inputBufMutex_);
224 if (inputBufferMap_.find(index) != inputBufferMap_.end()) {
225 isFinded = true;
226 bool syncIDR;
227 if (inputBufferMap_[index]->meta_->GetData(Tag::VIDEO_REQUEST_I_FRAME, syncIDR) && syncIDR) {
228 frameNum_ = 0;
229 AVCODEC_LOGI("Request IDR frame.");
230 }
231 LTRDecision();
232 inputBufferMap_[index]->meta_->SetData(Tag::VIDEO_ENCODER_PER_FRAME_MARK_LTR, isMarkLTR_);
233 if (isUseLTR_) {
234 inputBufferMap_[index]->meta_->SetData(Tag::VIDEO_ENCODER_PER_FRAME_USE_LTR, ltrPoc_);
235 } else {
236 inputBufferMap_[index]->meta_->Remove(Tag::VIDEO_ENCODER_PER_FRAME_USE_LTR);
237 }
238 inputBufferMap_.erase(index);
239 inputIndexQueue_->Pop();
240 AVCODEC_LOGD(
241 "frame: %{public}d set ltrParam, isMarkLTR: %{public}d, isUseLTR: %{public}d, ltrPoc: %{public}d",
242 frameNum_, isMarkLTR_, isUseLTR_, ltrPoc_);
243 frameNum_++;
244 } else {
245 AVCODEC_LOGE("Find matched buffer failed, buffer ID is %{public}u.", index);
246 }
247 }
248 if (isFinded) {
249 uint32_t flag = DisposableDecision();
250 lock_guard<shared_mutex> frameFlagMapLock(frameFlagMapMutex_);
251 frameFlagMap_.emplace(inputFrameCounter_, flag);
252 inputFrameCounter_++;
253 }
254 }
255 } // namespace MediaAVCodec
256 } // namespace OHOS