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(
__anon53d453f60302() 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()195 Status SuperResolutionPostProcessor::NotifyEos()
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 filterCallback_->OnOutputBufferAvailable(index, buffer);
233 }
234
OnOutputBufferAvailable(uint32_t index,const VpeBufferInfo & info)235 void SuperResolutionPostProcessor::OnOutputBufferAvailable(uint32_t index, const VpeBufferInfo& info)
236 {
237 auto buffer = AVBuffer::CreateAVBuffer();
238 if (buffer == nullptr) {
239 MEDIA_LOG_E("Create buffer failed");
240 ReleaseOutputBuffer(index, false);
241 return;
242 }
243 if (info.flag & static_cast<uint32_t>(VPE_BUFFER_FLAG_EOS)) {
244 buffer->flag_ |= static_cast<uint32_t>(Plugins::AVBufferFlag::EOS);
245 }
246 buffer->pts_ = info.presentationTimestamp;
247 filterCallback_->OnOutputBufferAvailable(index, buffer);
248 }
249
ReleaseOutputBuffer(uint32_t index,bool render)250 Status SuperResolutionPostProcessor::ReleaseOutputBuffer(uint32_t index, bool render)
251 {
252 std::shared_lock<std::shared_mutex> lock(mutex_);
253 FALSE_RETURN_V(postProcessor_ != nullptr, Status::ERROR_INVALID_STATE);
254 auto ret = postProcessor_->ReleaseOutputBuffer(index, render);
255 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_STATE);
256 return Status::OK;
257 }
258
RenderOutputBufferAtTime(uint32_t index,int64_t renderTimestampNs)259 Status SuperResolutionPostProcessor::RenderOutputBufferAtTime(uint32_t index, int64_t renderTimestampNs)
260 {
261 MEDIA_LOG_D("RenderOutputBufferAtTime timestamp: %{public}" PRId64, renderTimestampNs);
262 std::shared_lock<std::shared_mutex> lock(mutex_);
263 FALSE_RETURN_V(postProcessor_ != nullptr, Status::ERROR_INVALID_STATE);
264 auto ret = postProcessor_->RenderOutputBufferAtTime(index, renderTimestampNs);
265 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_STATE);
266 return Status::OK;
267 }
268
SetCallback(const std::shared_ptr<PostProcessorCallback> callback)269 Status SuperResolutionPostProcessor::SetCallback(const std::shared_ptr<PostProcessorCallback> callback)
270 {
271 filterCallback_ = callback;
272 return Status::OK;
273 }
274
SetPostProcessorOn(bool isPostProcessorOn)275 Status SuperResolutionPostProcessor::SetPostProcessorOn(bool isPostProcessorOn)
276 {
277 MEDIA_LOG_D("SetPostProcessorOn: %{public}d", isPostProcessorOn);
278 std::shared_lock<std::shared_mutex> lock(mutex_);
279 FALSE_RETURN_V(postProcessor_ != nullptr, Status::ERROR_INVALID_STATE);
280 VPEAlgoErrCode ret = VPEAlgoErrCode::VPE_ALGO_ERR_OK;
281 if (isPostProcessorOn) {
282 ret = postProcessor_->Enable();
283 } else {
284 ret = postProcessor_->Disable();
285 }
286 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_STATE);
287 return Status::OK;
288 }
289
SetEventReceiver(const std::shared_ptr<Pipeline::EventReceiver> & receiver)290 Status SuperResolutionPostProcessor::SetEventReceiver(const std::shared_ptr<Pipeline::EventReceiver> &receiver)
291 {
292 eventReceiver_ = receiver;
293 return Status::OK;
294 }
295
SetParameter(const Format & format)296 Status SuperResolutionPostProcessor::SetParameter(const Format &format)
297 {
298 MEDIA_LOG_D("Setparameter in");
299 std::shared_lock<std::shared_mutex> lock(mutex_);
300 FALSE_RETURN_V(postProcessor_ != nullptr, Status::ERROR_INVALID_STATE);
301 auto ret = postProcessor_->SetParameter(format);
302 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_PARAMETER);
303 return Status::OK;
304 }
305
SetQualityLevel(DetailEnhancerQualityLevel level)306 Status SuperResolutionPostProcessor::SetQualityLevel(DetailEnhancerQualityLevel level)
307 {
308 MEDIA_LOG_D("SetQualityLevel in");
309 Format parameter;
310 parameter.PutIntValue(ParameterKey::DETAIL_ENHANCER_QUALITY_LEVEL, level);
311 parameter.PutIntValue(ParameterKey::DETAIL_ENHANCER_AUTO_DOWNSHIFT, 0);
312 auto ret = postProcessor_->SetParameter(parameter);
313 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_PARAMETER);
314 return Status::OK;
315 }
316
SetVideoWindowSize(int32_t width,int32_t height)317 Status SuperResolutionPostProcessor::SetVideoWindowSize(int32_t width, int32_t height)
318 {
319 MEDIA_LOG_D("SetVideoWindowSize in");
320 std::shared_lock<std::shared_mutex> lock(mutex_);
321 FALSE_RETURN_V(postProcessor_ != nullptr, Status::ERROR_INVALID_STATE);
322 Format parameter;
323 VpeBufferSize outputSize = { width, height };
324 parameter.PutBuffer(ParameterKey::DETAIL_ENHANCER_TARGET_SIZE,
325 reinterpret_cast<const uint8_t*>(&outputSize), sizeof(VpeBufferSize));
326 auto ret = postProcessor_->SetParameter(parameter);
327 FALSE_RETURN_V(ret == VPEAlgoErrCode::VPE_ALGO_ERR_OK, Status::ERROR_INVALID_PARAMETER);
328 return Status::OK;
329 }
330
OnError(VPEAlgoErrCode errorCode)331 void SuperResolutionPostProcessor::OnError(VPEAlgoErrCode errorCode)
332 {
333 std::shared_lock<std::shared_mutex> lock(mutex_);
334 FALSE_RETURN_MSG(filterCallback_ != nullptr, "OnOutputFormatChanged callback_ is nullptr");
335 MEDIA_LOG_E("SuperResolutionPostProcessor error happened. ErrorCode: %{public}d", errorCode);
336 }
337
OnOutputFormatChanged(const Format & format)338 void SuperResolutionPostProcessor::OnOutputFormatChanged(const Format &format)
339 {
340 std::shared_lock<std::shared_mutex> lock(mutex_);
341 FALSE_RETURN_MSG(filterCallback_ != nullptr, "OnOutputFormatChanged callback_ is nullptr");
342 filterCallback_->OnOutputFormatChanged(format);
343 }
344
OnSuperResolutionChanged(bool enable)345 void SuperResolutionPostProcessor::OnSuperResolutionChanged(bool enable)
346 {
347 MEDIA_LOG_D("OnSuperResolutionChanged: %{public}d", enable);
348 std::shared_lock<std::shared_mutex> lock(mutex_);
349 isPostProcessorOn_ = enable;
350 if (eventReceiver_ != nullptr) {
351 eventReceiver_->OnEvent({"SuperResolutionPostProcessor", EventType::EVENT_SUPER_RESOLUTION_CHANGED, enable});
352 }
353 }
354
355 } // namespace Media
356 } // namespace OHOS