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_WITH_TAG("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 format.PutIntValue(Tag::VIDEO_ENCODER_TEMPORAL_GOP_SIZE, temporalGopSize_);
80 AVCODEC_LOGI_WITH_TAG("Get temporal gop size failed, use default value %{public}d", temporalGopSize_);
81 }
82 if (format.GetIntValue(Tag::VIDEO_ENCODER_TEMPORAL_GOP_REFERENCE_MODE, tRefMode_)) {
83 AVCODEC_LOGI_WITH_TAG("Set temporal reference mode successfully");
84 } else {
85 tRefMode_ = static_cast<int32_t>(TemporalGopReferenceMode::ADJACENT_REFERENCE);
86 format.PutIntValue(Tag::VIDEO_ENCODER_TEMPORAL_GOP_REFERENCE_MODE, tRefMode_);
87 AVCODEC_LOGI_WITH_TAG("Get temporal reference mode failed, use default value ADJACENT_REFERENCE");
88 }
89 svcLTR_ = IsLTRSolution();
90 if (svcLTR_) {
91 int32_t ltrFrameNum = LTRFrameNumCalculate(temporalGopSize_);
92 format.RemoveKey(Tag::VIDEO_ENCODER_ENABLE_TEMPORAL_SCALABILITY);
93 format.PutIntValue(Tag::VIDEO_ENCODER_LTR_FRAME_COUNT, ltrFrameNum);
94 format.PutIntValue(Tag::VIDEO_ENCODER_ENABLE_SURFACE_INPUT_CALLBACK, ENABLE_PARAMETER_CALLBACK);
95 }
96 AVCODEC_LOGI_WITH_TAG("Set temporal gop parameter successfully");
97 }
98
StoreAVBuffer(uint32_t index,shared_ptr<AVBuffer> buffer)99 void TemporalScalability::StoreAVBuffer(uint32_t index, shared_ptr<AVBuffer> buffer)
100 {
101 inputIndexQueue_->Push(index);
102 lock_guard<shared_mutex> inputBufLock(inputBufMutex_);
103 inputBufferMap_.emplace(index, buffer);
104 }
105
GetFirstBufferIndex()106 uint32_t TemporalScalability::GetFirstBufferIndex()
107 {
108 return inputIndexQueue_->Front();
109 }
110
SetBlockQueueActive()111 void TemporalScalability::SetBlockQueueActive()
112 {
113 inputIndexQueue_->SetActive(false, false);
114 }
115
SetDisposableFlag(shared_ptr<Media::AVBuffer> buffer)116 void TemporalScalability::SetDisposableFlag(shared_ptr<Media::AVBuffer> buffer)
117 {
118 lock_guard<shared_mutex> frameFlagMapLock(frameFlagMapMutex_);
119 uint32_t flag = frameFlagMap_[outputFrameCounter_];
120 buffer->flag_ |= flag;
121 frameFlagMap_.erase(outputFrameCounter_);
122 outputFrameCounter_++;
123 }
124
MarkLTRDecision()125 void TemporalScalability::MarkLTRDecision()
126 {
127 if (temporalPoc_ % DEFAULT_TEMPORAL_GOPSIZE == 0) {
128 isMarkLTR_ = true;
129 } else {
130 isMarkLTR_ = false;
131 }
132 }
133
LTRPocDecision(int32_t tPoc)134 int32_t TemporalScalability::LTRPocDecision(int32_t tPoc)
135 {
136 int32_t layer = 0;
137 for (; tPoc % (MIN_TEMPORAL_GOPSIZE) == 0; layer++) {
138 tPoc /= MIN_TEMPORAL_GOPSIZE;
139 }
140 return static_cast<int32_t>(pow(MIN_TEMPORAL_GOPSIZE, layer));
141 }
142
AdjacentJumpLTRDecision()143 void TemporalScalability::AdjacentJumpLTRDecision()
144 {
145 if (temporalPoc_ == 0) {
146 isMarkLTR_ = true;
147 if (poc_ == 0) {
148 isUseLTR_ = false;
149 ltrPoc_ = 0;
150 } else {
151 isUseLTR_ = true;
152 ltrPoc_ = poc_ - temporalGopSize_;
153 }
154 } else if (temporalPoc_ == 1 || tRefMode_ == static_cast<int32_t>(TemporalGopReferenceMode::ADJACENT_REFERENCE)) {
155 isMarkLTR_ = false;
156 isUseLTR_ = false;
157 ltrPoc_ = poc_ - 1;
158 } else {
159 isMarkLTR_ = false;
160 isUseLTR_ = true;
161 ltrPoc_ = poc_ - temporalPoc_;
162 }
163 }
164
UniformlyScaledLTRDecision()165 void TemporalScalability::UniformlyScaledLTRDecision()
166 {
167 if (temporalPoc_ == 0 && poc_ == 0) {
168 isMarkLTR_ = true;
169 isUseLTR_ = false;
170 ltrPoc_ = 0;
171 } else if (temporalPoc_ == 0 && poc_ != 0) {
172 isMarkLTR_ = true;
173 isUseLTR_ = true;
174 ltrPoc_ = poc_ - temporalGopSize_;
175 } else {
176 if (temporalPoc_ % MIN_TEMPORAL_GOPSIZE != 0) {
177 isMarkLTR_ = false;
178 isUseLTR_ = false;
179 ltrPoc_ = poc_ - 1;
180 } else {
181 isUseLTR_ = true;
182 MarkLTRDecision();
183 ltrPoc_ = poc_ - LTRPocDecision(temporalPoc_);
184 }
185 }
186 }
187
LTRDecision()188 void TemporalScalability::LTRDecision()
189 {
190 poc_ = frameNum_ % gopSize_;
191 temporalPoc_ = poc_ % temporalGopSize_;
192 if (tRefMode_ != static_cast<int32_t>(TemporalGopReferenceMode::UNIFORMLY_SCALED_REFERENCE)) {
193 AdjacentJumpLTRDecision();
194 } else {
195 UniformlyScaledLTRDecision();
196 }
197 }
198
DisposableDecision() const199 uint32_t TemporalScalability::DisposableDecision() const
200 {
201 if (tRefMode_ != static_cast<int32_t>(TemporalGopReferenceMode::UNIFORMLY_SCALED_REFERENCE)) {
202 if (!isMarkLTR_) {
203 if (tRefMode_ == static_cast<int32_t>(TemporalGopReferenceMode::ADJACENT_REFERENCE) &&
204 temporalPoc_ != temporalGopSize_ - 1 && poc_ != gopSize_ - 1) {
205 return AVCODEC_BUFFER_FLAG_DISPOSABLE_EXT;
206 } else {
207 return AVCODEC_BUFFER_FLAG_DISPOSABLE;
208 }
209 }
210 } else {
211 if (temporalPoc_ % MIN_TEMPORAL_GOPSIZE != 0) {
212 return AVCODEC_BUFFER_FLAG_DISPOSABLE;
213 }
214 if (temporalPoc_ != 0 && temporalPoc_ % MIN_TEMPORAL_GOPSIZE == 0) {
215 return AVCODEC_BUFFER_FLAG_DISPOSABLE_EXT;
216 }
217 }
218 return AVCODEC_BUFFER_FLAG_NONE;
219 }
220
ConfigureLTR(uint32_t index)221 void TemporalScalability::ConfigureLTR(uint32_t index)
222 {
223 bool isFinded = false;
224 {
225 lock_guard<shared_mutex> inputBufLock(inputBufMutex_);
226 if (inputBufferMap_.find(index) != inputBufferMap_.end()) {
227 isFinded = true;
228 bool syncIDR;
229 if (inputBufferMap_[index]->meta_->GetData(Tag::VIDEO_REQUEST_I_FRAME, syncIDR) && syncIDR) {
230 frameNum_ = 0;
231 AVCODEC_LOGI_WITH_TAG("Request IDR frame");
232 }
233 LTRDecision();
234 inputBufferMap_[index]->meta_->SetData(Tag::VIDEO_ENCODER_PER_FRAME_MARK_LTR, isMarkLTR_);
235 if (isUseLTR_) {
236 inputBufferMap_[index]->meta_->SetData(Tag::VIDEO_ENCODER_PER_FRAME_USE_LTR, ltrPoc_);
237 } else {
238 inputBufferMap_[index]->meta_->Remove(Tag::VIDEO_ENCODER_PER_FRAME_USE_LTR);
239 }
240 inputBufferMap_.erase(index);
241 inputIndexQueue_->Pop();
242 AVCODEC_LOGD_WITH_TAG(
243 "frame: %{public}d set ltrParam, isMarkLTR: %{public}d, isUseLTR: %{public}d, ltrPoc: %{public}d",
244 frameNum_, isMarkLTR_, isUseLTR_, ltrPoc_);
245 frameNum_++;
246 } else {
247 AVCODEC_LOGE_WITH_TAG("Find matched buffer failed, buffer ID is %{public}u", index);
248 }
249 }
250 if (isFinded) {
251 uint32_t flag = DisposableDecision();
252 lock_guard<shared_mutex> frameFlagMapLock(frameFlagMapMutex_);
253 frameFlagMap_.emplace(inputFrameCounter_, flag);
254 inputFrameCounter_++;
255 }
256 }
257 } // namespace MediaAVCodec
258 } // namespace OHOS