1 /*
2 * Copyright (c) 2025 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 "super_resolution_post_processor.h"
17
18 namespace {
19 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_SYSTEM_PLAYER, "SuperResolutionPostProcessor" };
20 }
21
22 namespace OHOS {
23 namespace Media {
24
25 namespace {
26 constexpr int32_t MAX_WIDTH = 1920;
27 constexpr int32_t MAX_HEIGHT = 1080;
28 }
29
30 using namespace VideoProcessingEngine;
31
isSuperResolutionSupported(const std::shared_ptr<Meta> & meta)32 static bool isSuperResolutionSupported(const std::shared_ptr<Meta>& meta)
33 {
34 FALSE_RETURN_V(meta != nullptr, false);
35
36 int32_t width = 0;
37 int32_t height = 0;
38 bool isDrmProtected = false;
39 bool isHdrVivid = false;
40 meta->GetData(Tag::VIDEO_WIDTH, width);
41 meta->GetData(Tag::VIDEO_HEIGHT, height);
42 meta->GetData(Tag::VIDEO_IS_HDR_VIVID, isHdrVivid);
43 meta->GetData(Tag::AV_PLAYER_IS_DRM_PROTECTED, isDrmProtected);
44 bool isVideoSizeValid = (width > 0 && width <= MAX_WIDTH) &&
45 (height > 0 && height <= MAX_HEIGHT);
46 bool canCreatePostProcessor = !isDrmProtected && !isHdrVivid && isVideoSizeValid;
47 if (!canCreatePostProcessor) {
48 MEDIA_LOG_E("invalid input stream for super resolution! width: " PUBLIC_LOG_D32
49 ", height: " PUBLIC_LOG_D32 ", isHdrVivid: " PUBLIC_LOG_D32 ", drm: " PUBLIC_LOG_D32,
50 width, height, isHdrVivid, isDrmProtected);
51 }
52 return canCreatePostProcessor;
53 }
54
55 static AutoRegisterPostProcessor<SuperResolutionPostProcessor> g_registerSuperResolutionPostProcessor(
__anoneb5cbc980302() 56 VideoPostProcessorType::SUPER_RESOLUTION, []() -> std::shared_ptr<BaseVideoPostProcessor> {
57 auto postProcessor = std::make_shared<SuperResolutionPostProcessor>();
58 if (postProcessor == nullptr || !postProcessor->IsValid()) {
59 return nullptr;
60 } else {
61 return postProcessor;
62 }
63 }, &isSuperResolutionSupported);
64
65 class VPECallback : public VpeVideoCallback {
66 public:
VPECallback(std::shared_ptr<SuperResolutionPostProcessor> postProcessor)67 explicit VPECallback(std::shared_ptr<SuperResolutionPostProcessor> postProcessor)
68 : postProcessor_(postProcessor) {}
69 ~VPECallback() = default;
70
OnError(VPEAlgoErrCode errorCode)71 void OnError(VPEAlgoErrCode errorCode)
72 {
73 if (auto postProcessor = postProcessor_.lock()) {
74 postProcessor->OnError(errorCode);
75 } else {
76 MEDIA_LOG_I("invalid decoderSurfaceFilter");
77 }
78 }
OnState(VPEAlgoState state)79 void OnState(VPEAlgoState state)
80 {
81 }
OnEffectChange(uint32_t type)82 void OnEffectChange(uint32_t type)
83 {
84 if (auto postProcessor = postProcessor_.lock()) {
85 postProcessor->OnSuperResolutionChanged(type == VIDEO_TYPE_DETAIL_ENHANCER);
86 } else {
87 MEDIA_LOG_I("invalid decoderSurfaceFilter");
88 }
89 }
OnOutputFormatChanged(const Format & format)90 void OnOutputFormatChanged(const Format& format)
91 {
92 size_t addrSize;
93 uint8_t* addr = nullptr;
94 if (!format.GetBuffer(ParameterKey::DETAIL_ENHANCER_TARGET_SIZE, &addr, addrSize)) {
95 MEDIA_LOG_I("can not get target size");
96 return;
97 }
98 FALSE_RETURN_MSG(addr != nullptr && addrSize == sizeof(VpeBufferSize),
99 "Invalid input: addr is null or addrSize=%{public}zu(Expected:%{public}zu)!",
100 addrSize, sizeof(VpeBufferSize));
101 auto size = reinterpret_cast<VpeBufferSize*>(addr);
102
103 MEDIA_LOG_D("OnOutputFormatChanged nextW=" PUBLIC_LOG_D32 " nextH=" PUBLIC_LOG_D32, size->width, size->height);
104 if (size->width <= 0 || size->height <= 0) {
105 MEDIA_LOG_W("invaild video size");
106 return;
107 }
108 }
OnOutputBufferAvailable(uint32_t index,VpeBufferFlag flag)109 void OnOutputBufferAvailable(uint32_t index, VpeBufferFlag flag)
110 {
111 }
OnOutputBufferAvailable(uint32_t index,const VpeBufferInfo & info)112 void OnOutputBufferAvailable(uint32_t index, const VpeBufferInfo& info)
113 {
114 if (auto postProcessor = postProcessor_.lock()) {
115 postProcessor->OnOutputBufferAvailable(index, info);
116 } else {
117 MEDIA_LOG_I("invalid decoderSurfaceFilter");
118 }
119 }
120
121 private:
122 std::weak_ptr<SuperResolutionPostProcessor> postProcessor_;
123 };
124
SuperResolutionPostProcessor()125 SuperResolutionPostProcessor::SuperResolutionPostProcessor()
126 {
127 postProcessor_ = VpeVideo::Create(VIDEO_TYPE_DETAIL_ENHANCER);
128 isPostProcessorOn_ = true;
129 }
130
~SuperResolutionPostProcessor()131 SuperResolutionPostProcessor::~SuperResolutionPostProcessor()
132 {
133 std::unique_lock<std::shared_mutex> lock(mutex_);
134 postProcessor_ = nullptr;
135 }
136
IsValid()137 bool SuperResolutionPostProcessor::IsValid()
138 {
139 return postProcessor_ != nullptr;
140 }
141
Init()142 Status SuperResolutionPostProcessor::Init()
143 {
144 MEDIA_LOG_D("Init in");
145 std::shared_lock<std::shared_mutex> lock(mutex_);
146 FALSE_RETURN_V(postProcessor_ != nullptr, Status::ERROR_INVALID_STATE);
147
148 auto ret = SetQualityLevel(DEFAULT_QUALITY_LEVEL);
149 FALSE_RETURN_V(ret == Status::OK, ret);
150 auto callback = std::make_shared<VPECallback>(shared_from_this());
151 return postProcessor_->RegisterCallback(callback) == VPEAlgoErrCode::VPE_ALGO_ERR_OK ?
152 Status::OK : Status::ERROR_INVALID_STATE;
153 }
154
Flush()155 Status SuperResolutionPostProcessor::Flush()
156 {
157 MEDIA_LOG_D("Flush in");
158 std::shared_lock<std::shared_mutex> lock(mutex_);
159 FALSE_RETURN_V(postProcessor_ != nullptr, Status::ERROR_INVALID_STATE);
160 auto ret = postProcessor_->Flush();
161 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_STATE);
162 return Status::OK;
163 }
164
Stop()165 Status SuperResolutionPostProcessor::Stop()
166 {
167 MEDIA_LOG_D("Stop in");
168 std::shared_lock<std::shared_mutex> lock(mutex_);
169 FALSE_RETURN_V(postProcessor_ != nullptr, Status::ERROR_INVALID_STATE);
170 auto ret = postProcessor_->Stop();
171 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_STATE);
172 return Release();
173 }
174
Start()175 Status SuperResolutionPostProcessor::Start()
176 {
177 MEDIA_LOG_D("Start in");
178 std::shared_lock<std::shared_mutex> lock(mutex_);
179 FALSE_RETURN_V(postProcessor_ != nullptr, Status::ERROR_INVALID_STATE);
180 auto ret = postProcessor_->Start();
181 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_STATE);
182 return Status::OK;
183 }
184
Release()185 Status SuperResolutionPostProcessor::Release()
186 {
187 MEDIA_LOG_D("Release in");
188 std::shared_lock<std::shared_mutex> lock(mutex_);
189 FALSE_RETURN_V(postProcessor_ != nullptr, Status::ERROR_INVALID_STATE);
190 auto ret = postProcessor_->Release();
191 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_STATE);
192 return Status::OK;
193 }
194
NotifyEos(int64_t eosPts)195 Status SuperResolutionPostProcessor::NotifyEos(int64_t eosPts)
196 {
197 MEDIA_LOG_D("Notify eos");
198 std::shared_lock<std::shared_mutex> lock(mutex_);
199 FALSE_RETURN_V(postProcessor_ != nullptr, Status::ERROR_INVALID_STATE);
200 auto ret = postProcessor_->NotifyEos();
201 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_PARAMETER);
202 return Status::OK;
203 }
204
GetInputSurface()205 sptr<Surface> SuperResolutionPostProcessor::GetInputSurface()
206 {
207 std::shared_lock<std::shared_mutex> lock(mutex_);
208 FALSE_RETURN_V(postProcessor_ != nullptr, nullptr);
209 return postProcessor_->GetInputSurface();
210 }
211
SetOutputSurface(sptr<Surface> surface)212 Status SuperResolutionPostProcessor::SetOutputSurface(sptr<Surface> surface)
213 {
214 std::shared_lock<std::shared_mutex> lock(mutex_);
215 FALSE_RETURN_V(postProcessor_ != nullptr, Status::ERROR_INVALID_STATE);
216 auto ret = postProcessor_->SetOutputSurface(surface);
217 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_PARAMETER);
218 return Status::OK;
219 }
220
OnOutputBufferAvailable(uint32_t index,VpeBufferFlag flag)221 void SuperResolutionPostProcessor::OnOutputBufferAvailable(uint32_t index, VpeBufferFlag flag)
222 {
223 auto buffer = AVBuffer::CreateAVBuffer();
224 if (buffer == nullptr) {
225 MEDIA_LOG_E("Create buffer failed");
226 ReleaseOutputBuffer(index, false);
227 return;
228 }
229 if (flag & static_cast<uint32_t>(VPE_BUFFER_FLAG_EOS)) {
230 buffer->flag_ |= static_cast<uint32_t>(Plugins::AVBufferFlag::EOS);
231 }
232 FALSE_RETURN_MSG(filterCallback_ != nullptr, "filterCallback_ is nullptr");
233 filterCallback_->OnOutputBufferAvailable(index, buffer);
234 }
235
OnOutputBufferAvailable(uint32_t index,const VpeBufferInfo & info)236 void SuperResolutionPostProcessor::OnOutputBufferAvailable(uint32_t index, const VpeBufferInfo& info)
237 {
238 auto buffer = AVBuffer::CreateAVBuffer();
239 if (buffer == nullptr) {
240 MEDIA_LOG_E("Create buffer failed");
241 ReleaseOutputBuffer(index, false);
242 return;
243 }
244 if (info.flag & static_cast<uint32_t>(VPE_BUFFER_FLAG_EOS)) {
245 buffer->flag_ |= static_cast<uint32_t>(Plugins::AVBufferFlag::EOS);
246 }
247 buffer->pts_ = info.presentationTimestamp;
248 FALSE_RETURN_MSG(filterCallback_ != nullptr, "filterCallback_ is nullptr");
249 filterCallback_->OnOutputBufferAvailable(index, buffer);
250 }
251
ReleaseOutputBuffer(uint32_t index,bool render)252 Status SuperResolutionPostProcessor::ReleaseOutputBuffer(uint32_t index, bool render)
253 {
254 std::shared_lock<std::shared_mutex> lock(mutex_);
255 FALSE_RETURN_V(postProcessor_ != nullptr, Status::ERROR_INVALID_STATE);
256 auto ret = postProcessor_->ReleaseOutputBuffer(index, render);
257 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_STATE);
258 return Status::OK;
259 }
260
RenderOutputBufferAtTime(uint32_t index,int64_t renderTimestampNs)261 Status SuperResolutionPostProcessor::RenderOutputBufferAtTime(uint32_t index, int64_t renderTimestampNs)
262 {
263 MEDIA_LOG_D("RenderOutputBufferAtTime timestamp: %{public}" PRId64, renderTimestampNs);
264 std::shared_lock<std::shared_mutex> lock(mutex_);
265 FALSE_RETURN_V(postProcessor_ != nullptr, Status::ERROR_INVALID_STATE);
266 auto ret = postProcessor_->RenderOutputBufferAtTime(index, renderTimestampNs);
267 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_STATE);
268 return Status::OK;
269 }
270
SetCallback(const std::shared_ptr<PostProcessorCallback> callback)271 Status SuperResolutionPostProcessor::SetCallback(const std::shared_ptr<PostProcessorCallback> callback)
272 {
273 filterCallback_ = callback;
274 return Status::OK;
275 }
276
SetPostProcessorOn(bool isPostProcessorOn)277 Status SuperResolutionPostProcessor::SetPostProcessorOn(bool isPostProcessorOn)
278 {
279 MEDIA_LOG_D("SetPostProcessorOn: %{public}d", isPostProcessorOn);
280 std::shared_lock<std::shared_mutex> lock(mutex_);
281 FALSE_RETURN_V(postProcessor_ != nullptr, Status::ERROR_INVALID_STATE);
282 VPEAlgoErrCode ret = VPEAlgoErrCode::VPE_ALGO_ERR_OK;
283 if (isPostProcessorOn) {
284 ret = postProcessor_->Enable();
285 } else {
286 ret = postProcessor_->Disable();
287 }
288 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_STATE);
289 return Status::OK;
290 }
291
SetEventReceiver(const std::shared_ptr<Pipeline::EventReceiver> & receiver)292 Status SuperResolutionPostProcessor::SetEventReceiver(const std::shared_ptr<Pipeline::EventReceiver> &receiver)
293 {
294 eventReceiver_ = receiver;
295 return Status::OK;
296 }
297
SetParameter(const Format & format)298 Status SuperResolutionPostProcessor::SetParameter(const Format &format)
299 {
300 MEDIA_LOG_D("Setparameter in");
301 std::shared_lock<std::shared_mutex> lock(mutex_);
302 FALSE_RETURN_V(postProcessor_ != nullptr, Status::ERROR_INVALID_STATE);
303 auto ret = postProcessor_->SetParameter(format);
304 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_PARAMETER);
305 return Status::OK;
306 }
307
SetQualityLevel(DetailEnhancerQualityLevel level)308 Status SuperResolutionPostProcessor::SetQualityLevel(DetailEnhancerQualityLevel level)
309 {
310 MEDIA_LOG_D("SetQualityLevel in");
311 Format parameter;
312 parameter.PutIntValue(ParameterKey::DETAIL_ENHANCER_QUALITY_LEVEL, level);
313 parameter.PutIntValue(ParameterKey::DETAIL_ENHANCER_AUTO_DOWNSHIFT, 0);
314 auto ret = postProcessor_->SetParameter(parameter);
315 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_PARAMETER);
316 return Status::OK;
317 }
318
SetVideoWindowSize(int32_t width,int32_t height)319 Status SuperResolutionPostProcessor::SetVideoWindowSize(int32_t width, int32_t height)
320 {
321 MEDIA_LOG_D("SetVideoWindowSize in");
322 std::shared_lock<std::shared_mutex> lock(mutex_);
323 FALSE_RETURN_V(postProcessor_ != nullptr, Status::ERROR_INVALID_STATE);
324 Format parameter;
325 VpeBufferSize outputSize = { width, height };
326 parameter.PutBuffer(ParameterKey::DETAIL_ENHANCER_TARGET_SIZE,
327 reinterpret_cast<const uint8_t*>(&outputSize), sizeof(VpeBufferSize));
328 auto ret = postProcessor_->SetParameter(parameter);
329 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_PARAMETER);
330 return Status::OK;
331 }
332
OnError(VPEAlgoErrCode errorCode)333 void SuperResolutionPostProcessor::OnError(VPEAlgoErrCode errorCode)
334 {
335 std::shared_lock<std::shared_mutex> lock(mutex_);
336 FALSE_RETURN_MSG(filterCallback_ != nullptr, "filterCallback_ is nullptr");
337 MEDIA_LOG_E("SuperResolutionPostProcessor error happened. ErrorCode: %{public}d", errorCode);
338 }
339
OnOutputFormatChanged(const Format & format)340 void SuperResolutionPostProcessor::OnOutputFormatChanged(const Format &format)
341 {
342 std::shared_lock<std::shared_mutex> lock(mutex_);
343 FALSE_RETURN_MSG(filterCallback_ != nullptr, "filterCallback_ is nullptr");
344 filterCallback_->OnOutputFormatChanged(format);
345 }
346
OnSuperResolutionChanged(bool enable)347 void SuperResolutionPostProcessor::OnSuperResolutionChanged(bool enable)
348 {
349 MEDIA_LOG_D("OnSuperResolutionChanged: %{public}d", enable);
350 std::shared_lock<std::shared_mutex> lock(mutex_);
351 isPostProcessorOn_ = enable;
352 if (eventReceiver_ != nullptr) {
353 eventReceiver_->OnEvent({"SuperResolutionPostProcessor", EventType::EVENT_SUPER_RESOLUTION_CHANGED, enable});
354 }
355 }
356
357 } // namespace Media
358 } // namespace OHOS