• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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