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