1 /*
2 * Copyright (c) 2021-2021 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 #ifdef VIDEO_SUPPORT
17 #define SHOW_FRAME_RATE 0
18 #define HST_LOG_TAG "VideoSinkFilter"
19
20 #include "pipeline/filters/sink/video_sink/video_sink_filter.h"
21 #include "foundation/log.h"
22 #include "foundation/osal/utils/util.h"
23 #include "foundation/utils/steady_clock.h"
24 #include "pipeline/factory/filter_factory.h"
25 #include "pipeline/filters/common/plugin_settings.h"
26 #include "pipeline/filters/common/plugin_utils.h"
27 #include "plugin/common/plugin_time.h"
28 #ifndef OHOS_LITE
29 #include "plugin/common/surface_allocator.h"
30 #endif
31
32 namespace OHOS {
33 namespace Media {
34 namespace Pipeline {
35 namespace {
36 const uint32_t VSINK_DEFAULT_BUFFER_NUM = 8;
37 const uint32_t DEFAULT_FRAME_RATE = 30;
38 }
39 static AutoRegisterFilter<VideoSinkFilter> g_registerFilterHelper("builtin.player.videosink");
40
VideoSinkFilter(const std::string & name)41 VideoSinkFilter::VideoSinkFilter(const std::string& name) : MediaSynchronousSink(name)
42 {
43 refreshTime_ = 0;
44 syncerPriority_ = IMediaSynchronizer::VIDEO_SINK;
45 MEDIA_LOG_I("VideoSinkFilter ctor called...");
46 }
47
~VideoSinkFilter()48 VideoSinkFilter::~VideoSinkFilter()
49 {
50 MEDIA_LOG_D("VideoSinkFilter deCtor.");
51 if (renderTask_) {
52 renderTask_->Stop();
53 }
54 if (frameRateTask_) {
55 frameRateTask_->Stop();
56 }
57 if (plugin_) {
58 plugin_->Stop();
59 plugin_->Deinit();
60 }
61 if (inBufQueue_ != nullptr) {
62 inBufQueue_->SetActive(false);
63 inBufQueue_.reset();
64 }
65 }
66
Init(EventReceiver * receiver,FilterCallback * callback)67 void VideoSinkFilter::Init(EventReceiver* receiver, FilterCallback* callback)
68 {
69 MediaSynchronousSink::Init(receiver, callback);
70 outPorts_.clear();
71 if (inBufQueue_ == nullptr) {
72 inBufQueue_ = std::make_shared<BlockingQueue<AVBufferPtr>>("VideoSinkInBufQue", VSINK_DEFAULT_BUFFER_NUM);
73 }
74 if (renderTask_ == nullptr) {
75 renderTask_ = std::make_shared<OHOS::Media::OSAL::Task>("VideoSinkRenderThread");
76 renderTask_->RegisterHandler([this] { RenderFrame(); });
77 }
78 #if(SHOW_FRAME_RATE)
79 if (frameRateTask_ == nullptr) {
80 frameRateTask_ = std::make_shared<OHOS::Media::OSAL::Task>("CalcFrameRateThread");
81 frameRateTask_->RegisterHandler([this] { CalcFrameRate(); });
82 }
83 #endif
84 }
85
SetParameter(int32_t key,const Plugin::Any & value)86 ErrorCode VideoSinkFilter::SetParameter(int32_t key, const Plugin::Any& value)
87 {
88 Tag tag = Tag::INVALID;
89 if (!TranslateIntoParameter(key, tag)) {
90 MEDIA_LOG_I("SetParameter key " PUBLIC_LOG_D32 " is out of boundary", key);
91 return ErrorCode::ERROR_INVALID_PARAMETER_VALUE;
92 }
93 switch (tag) {
94 case Tag::VIDEO_SCALE_TYPE:
95 FALSE_RETURN_V_MSG_E(Plugin::Any::IsSameTypeWith<Plugin::VideoScaleType>(value),
96 ErrorCode::ERROR_INVALID_PARAMETER_TYPE,
97 "VIDEO_SCALE_TYPE type should be Plugin::VideoScaleType");
98 videoScaleType_ = Plugin::AnyCast<Plugin::VideoScaleType>(value);
99 if (plugin_) {
100 (void)plugin_->SetParameter(Tag::VIDEO_SCALE_TYPE, videoScaleType_);
101 }
102 break;
103 default:
104 break;
105 }
106 return ErrorCode::SUCCESS;
107 }
108
GetParameter(int32_t key,Plugin::Any & value)109 ErrorCode VideoSinkFilter::GetParameter(int32_t key, Plugin::Any& value)
110 {
111 if (state_.load() == FilterState::CREATED) {
112 return ErrorCode::ERROR_AGAIN;
113 }
114 Tag tag = Tag::INVALID;
115 if (!TranslateIntoParameter(key, tag)) {
116 MEDIA_LOG_I("GetParameter key " PUBLIC_LOG_D32 "is out of boundary", key);
117 return ErrorCode::ERROR_INVALID_PARAMETER_VALUE;
118 }
119 RETURN_AGAIN_IF_NULL(plugin_);
120 return TranslatePluginStatus(plugin_->GetParameter(tag, value));
121 }
122
HandleNegotiateParams(const Plugin::Meta & upstreamParams,Plugin::Meta & downstreamParams)123 void VideoSinkFilter::HandleNegotiateParams(const Plugin::Meta& upstreamParams, Plugin::Meta& downstreamParams)
124 {
125 #ifndef OHOS_LITE
126 MEDIA_LOG_I("Enter set surface buffer");
127 Plugin::Tag tag = Plugin::Tag::VIDEO_MAX_SURFACE_NUM;
128 auto ite = upstreamParams.Find(tag);
129 if (ite != std::end(upstreamParams)) {
130 if (Plugin::Any::IsSameTypeWith<uint32_t>(ite->second)) {
131 auto ret = plugin_->SetParameter(tag, Plugin::AnyCast<uint32_t>(ite->second));
132 if (ret != Plugin::Status::OK) {
133 MEDIA_LOG_W("Set max surface num to plugin fail");
134 }
135 }
136 }
137 auto pluginAllocator = plugin_->GetAllocator();
138 if (pluginAllocator != nullptr && pluginAllocator->GetMemoryType() == Plugin::MemoryType::SURFACE_BUFFER) {
139 MEDIA_LOG_D("plugin provide surface allocator");
140 auto allocator = Plugin::ReinterpretPointerCast<Plugin::SurfaceAllocator>(pluginAllocator);
141 downstreamParams.Set<Tag::BUFFER_ALLOCATOR>(allocator);
142 }
143 #endif
144 }
145
CreateVideoSinkPlugin(const std::shared_ptr<Plugin::PluginInfo> & selectedPluginInfo)146 bool VideoSinkFilter::CreateVideoSinkPlugin(const std::shared_ptr<Plugin::PluginInfo>& selectedPluginInfo)
147 {
148 if (plugin_ != nullptr) {
149 if (pluginInfo_ != nullptr && pluginInfo_->name == selectedPluginInfo->name) {
150 if (plugin_->Reset() == Plugin::Status::OK) {
151 return true;
152 }
153 MEDIA_LOG_W("reuse previous plugin " PUBLIC_LOG_S " failed, will create new plugin",
154 pluginInfo_->name.c_str());
155 }
156 plugin_->Deinit();
157 }
158 plugin_ = Plugin::PluginManager::Instance().CreateVideoSinkPlugin(selectedPluginInfo->name);
159 if (plugin_ == nullptr) {
160 MEDIA_LOG_E("cannot create plugin " PUBLIC_LOG_S, selectedPluginInfo->name.c_str());
161 return false;
162 }
163 #ifndef OHOS_LITE
164 (void)plugin_->SetParameter(Tag::VIDEO_SCALE_TYPE, videoScaleType_);
165 if (surface_ != nullptr) {
166 auto ret = TranslatePluginStatus(plugin_->SetParameter(Tag::VIDEO_SURFACE, surface_));
167 if (ret != ErrorCode::SUCCESS) {
168 MEDIA_LOG_W("Set surface to plugin fail, ret: " PUBLIC_LOG_U32, ret);
169 return false;
170 }
171 }
172 #endif
173 auto err = TranslatePluginStatus(plugin_->Init());
174 if (err != ErrorCode::SUCCESS) {
175 MEDIA_LOG_E("plugin " PUBLIC_LOG_S " init error", selectedPluginInfo->name.c_str());
176 return false;
177 }
178 pluginInfo_ = selectedPluginInfo;
179 return true;
180 }
181
Negotiate(const std::string & inPort,const std::shared_ptr<const Plugin::Capability> & upstreamCap,Plugin::Capability & negotiatedCap,const Plugin::Meta & upstreamParams,Plugin::Meta & downstreamParams)182 bool VideoSinkFilter::Negotiate(const std::string& inPort,
183 const std::shared_ptr<const Plugin::Capability>& upstreamCap,
184 Plugin::Capability& negotiatedCap,
185 const Plugin::Meta& upstreamParams,
186 Plugin::Meta& downstreamParams)
187 {
188 PROFILE_BEGIN("video sink negotiate start");
189 if (state_ != FilterState::PREPARING) {
190 MEDIA_LOG_W("Video sink filter is not in preparing when negotiate");
191 return false;
192 }
193 auto candidatePlugins = FindAvailablePlugins(*upstreamCap, Plugin::PluginType::VIDEO_SINK);
194 if (candidatePlugins.empty()) {
195 MEDIA_LOG_E("no available video sink plugin");
196 return false;
197 }
198 // always use first one
199 std::shared_ptr<Plugin::PluginInfo> selectedPluginInfo = candidatePlugins[0].first;
200 MEDIA_LOG_I("select plugin " PUBLIC_LOG_S, selectedPluginInfo->name.c_str());
201 for (const auto& onCap : selectedPluginInfo->inCaps) {
202 if (onCap.keys.count(CapabilityID::VIDEO_PIXEL_FORMAT) == 0) {
203 MEDIA_LOG_E("each in caps of sink must contains valid video pixel format");
204 return false;
205 }
206 }
207 negotiatedCap = candidatePlugins[0].second;
208 if (!CreateVideoSinkPlugin(selectedPluginInfo)) {
209 return false;
210 }
211 PROFILE_END("video sink negotiate end");
212 MEDIA_LOG_D("video sink negotiate success");
213 return true;
214 }
215
Configure(const std::string & inPort,const std::shared_ptr<const Plugin::Meta> & upstreamMeta,Plugin::Meta & upstreamParams,Plugin::Meta & downstreamParams)216 bool VideoSinkFilter::Configure(const std::string& inPort, const std::shared_ptr<const Plugin::Meta>& upstreamMeta,
217 Plugin::Meta& upstreamParams, Plugin::Meta& downstreamParams)
218 {
219 PROFILE_BEGIN("video sink configure start");
220 if (plugin_ == nullptr || pluginInfo_ == nullptr) {
221 MEDIA_LOG_E("cannot configure decoder when no plugin available");
222 return false;
223 }
224 auto err = ConfigurePluginToStartNoLocked(upstreamMeta);
225 if (err != ErrorCode::SUCCESS) {
226 MEDIA_LOG_E("sink configure error");
227 OnEvent(Event{name_, EventType::EVENT_ERROR, {err}});
228 return false;
229 }
230 if (!upstreamMeta->Get<Plugin::Tag::VIDEO_FRAME_RATE>(frameRate_)) {
231 MEDIA_LOG_I("frame rate is not found");
232 }
233 if (frameRate_ == 0) {
234 frameRate_ = DEFAULT_FRAME_RATE;
235 }
236 waitPrerolledTimeout_ = 1000 / frameRate_; // 1s = 1000ms
237 UpdateMediaTimeRange(*upstreamMeta);
238 HandleNegotiateParams(upstreamParams, downstreamParams);
239 state_ = FilterState::READY;
240 OnEvent(Event{name_, EventType::EVENT_READY, {}});
241 MEDIA_LOG_I("video sink send EVENT_READY");
242 PROFILE_END("video sink configure end");
243 return true;
244 }
245
ConfigurePluginParams(const std::shared_ptr<const Plugin::Meta> & meta)246 ErrorCode VideoSinkFilter::ConfigurePluginParams(const std::shared_ptr<const Plugin::Meta>& meta)
247 {
248 auto err = ErrorCode::SUCCESS;
249 uint32_t width;
250 if (meta->Get<Plugin::Tag::VIDEO_WIDTH>(width)) {
251 err = TranslatePluginStatus(plugin_->SetParameter(Tag::VIDEO_WIDTH, width));
252 FAIL_RETURN_MSG(err, "Set plugin width fail");
253 } else {
254 MEDIA_LOG_W("Get VIDEO_WIDTH failed.");
255 }
256 uint32_t height;
257 if (meta->Get<Plugin::Tag::VIDEO_HEIGHT>(height)) {
258 err = TranslatePluginStatus(plugin_->SetParameter(Tag::VIDEO_HEIGHT, height));
259 FAIL_RETURN_MSG(err, "Set plugin height fail");
260 } else {
261 MEDIA_LOG_W("Get VIDEO_HEIGHT fail");
262 }
263 Plugin::VideoPixelFormat pixelFormat;
264 if (meta->Get<Plugin::Tag::VIDEO_PIXEL_FORMAT>(pixelFormat)) {
265 err = TranslatePluginStatus(plugin_->SetParameter(Tag::VIDEO_PIXEL_FORMAT, pixelFormat));
266 FAIL_RETURN_MSG(err, "Set plugin pixel format fail");
267 } else {
268 MEDIA_LOG_W("Get VIDEO_PIXEL_FORMAT fail");
269 }
270 MEDIA_LOG_D("width: " PUBLIC_LOG_U32 ", height: " PUBLIC_LOG_U32 ", pixelFormat: " PUBLIC_LOG_U32,
271 width, height, pixelFormat);
272 return err;
273 }
274
ConfigurePluginToStartNoLocked(const std::shared_ptr<const Plugin::Meta> & meta)275 ErrorCode VideoSinkFilter::ConfigurePluginToStartNoLocked(const std::shared_ptr<const Plugin::Meta>& meta)
276 {
277 FAIL_RETURN_MSG(TranslatePluginStatus(plugin_->Init()), "Init plugin error");
278 plugin_->SetCallback(this);
279 FAIL_RETURN_MSG(ConfigurePluginParams(meta), "Configure plugin params fail");
280 FAIL_RETURN_MSG(TranslatePluginStatus(plugin_->Prepare()), "Prepare plugin fail");
281 FAIL_RETURN_MSG(TranslatePluginStatus(plugin_->Start()), "Start plugin fail");
282 return ErrorCode::SUCCESS;
283 }
284
RenderFrame()285 void VideoSinkFilter::RenderFrame()
286 {
287 MEDIA_LOG_DD("RenderFrame called, inBufQue size: " PUBLIC_LOG_ZU, inBufQueue_->Size());
288 auto frameBuffer = inBufQueue_->Pop();
289 if (frameBuffer == nullptr) {
290 MEDIA_LOG_D("Video sink find nullptr in esBufferQ");
291 return;
292 }
293 auto err = WriteToPluginRefTimeSync(frameBuffer);
294 if (err != ErrorCode::SUCCESS) {
295 MEDIA_LOG_E("Write to plugin fail: " PUBLIC_LOG_U32 ", buf.pts: " PUBLIC_LOG_D64, err, frameBuffer->pts);
296 return;
297 }
298 if (frameBuffer->flag & BUFFER_FLAG_EOS) {
299 Event event{
300 .srcFilter = name_,
301 .type = EventType::EVENT_COMPLETE,
302 };
303 OnEvent(event);
304 MEDIA_LOG_D("Video sink render frame send event_complete end.");
305 renderTask_->PauseAsync();
306 }
307 MEDIA_LOG_DD("RenderFrame success");
308 }
309
PushData(const std::string & inPort,const AVBufferPtr & buffer,int64_t offset)310 ErrorCode VideoSinkFilter::PushData(const std::string& inPort, const AVBufferPtr& buffer, int64_t offset)
311 {
312 MEDIA_LOG_DD("video sink push data started, state_: " PUBLIC_LOG_D32, state_.load());
313 if (isFlushing_ || state_.load() == FilterState::INITIALIZED) {
314 MEDIA_LOG_I("video sink is flushing ignore this buffer");
315 return ErrorCode::SUCCESS;
316 }
317 if (state_.load() != FilterState::RUNNING) {
318 pushThreadIsBlocking_ = true;
319 OSAL::ScopedLock lock(mutex_);
320 startWorkingCondition_.Wait(lock, [this] {
321 return state_ == FilterState::RUNNING || state_ == FilterState::INITIALIZED || isFlushing_;
322 });
323 pushThreadIsBlocking_ = false;
324 }
325 if (isFlushing_ || state_.load() == FilterState::INITIALIZED) {
326 MEDIA_LOG_I("PushData return due to: isFlushing_ = " PUBLIC_LOG_D32 ", state_ = " PUBLIC_LOG_D32,
327 isFlushing_.load(), static_cast<int>(state_.load()));
328 return ErrorCode::SUCCESS;
329 }
330 inBufQueue_->Push(buffer);
331 MEDIA_LOG_DD("video sink push data end, buffer->pts: " PUBLIC_LOG_D64, buffer->pts);
332 return ErrorCode::SUCCESS;
333 }
334
Start()335 ErrorCode VideoSinkFilter::Start()
336 {
337 MEDIA_LOG_DD("start called");
338 if (state_ != FilterState::READY && state_ != FilterState::PAUSED) {
339 MEDIA_LOG_W("sink is not ready when start, state_: " PUBLIC_LOG_D32, state_.load());
340 return ErrorCode::ERROR_INVALID_OPERATION;
341 }
342 inBufQueue_->SetActive(true);
343 renderTask_->Start();
344 auto err = FilterBase::Start();
345 if (err != ErrorCode::SUCCESS) {
346 MEDIA_LOG_E("Video sink filter start error");
347 return err;
348 }
349 plugin_->Start();
350 if (pushThreadIsBlocking_.load()) {
351 startWorkingCondition_.NotifyOne();
352 }
353 return ErrorCode::SUCCESS;
354 }
355
Stop()356 ErrorCode VideoSinkFilter::Stop()
357 {
358 MEDIA_LOG_I("VideoSinkFilter stop called.");
359 FAIL_RETURN_MSG(FilterBase::Stop(), "Video sink stop fail");
360 FAIL_RETURN_MSG(TranslatePluginStatus(plugin_->Stop()), "Stop plugin fail");
361 if (pushThreadIsBlocking_.load()) {
362 startWorkingCondition_.NotifyOne();
363 }
364 inBufQueue_->SetActive(false);
365 renderTask_->Stop();
366 if (frameRateTask_) {
367 frameRateTask_->Stop();
368 }
369 return ErrorCode::SUCCESS;
370 }
371
Pause()372 ErrorCode VideoSinkFilter::Pause()
373 {
374 MEDIA_LOG_D("Video sink filter pause start");
375 if (state_ != FilterState::READY && state_ != FilterState::RUNNING) {
376 MEDIA_LOG_W("video sink cannot pause when not working");
377 return ErrorCode::ERROR_INVALID_OPERATION;
378 }
379 FAIL_RETURN_MSG(FilterBase::Pause(), "Video sink pause fail");
380 FAIL_RETURN_MSG(TranslatePluginStatus(plugin_->Pause()), "Pause plugin fail");
381 inBufQueue_->SetActive(false);
382 renderTask_->Pause();
383 if (frameRateTask_) {
384 frameRateTask_->Pause();
385 }
386 MEDIA_LOG_D("Video sink filter pause end");
387 return ErrorCode::SUCCESS;
388 }
389
Resume()390 ErrorCode VideoSinkFilter::Resume()
391 {
392 MEDIA_LOG_D("Video sink filter resume");
393 // only worked when state_ is paused
394 if (state_ == FilterState::PAUSED) {
395 forceRenderNextFrame_ = true;
396 state_ = FilterState::RUNNING;
397 if (pushThreadIsBlocking_) {
398 startWorkingCondition_.NotifyOne();
399 }
400 auto err = TranslatePluginStatus(plugin_->Resume());
401 if (err != ErrorCode::SUCCESS) {
402 return err;
403 }
404 inBufQueue_->SetActive(true);
405 renderTask_->Start();
406 if (frameRateTask_) {
407 frameRateTask_->Start();
408 }
409 renderFrameCnt_ = 0;
410 discardFrameCnt_ = 0;
411 }
412 return ErrorCode::SUCCESS;
413 }
414
FlushStart()415 void VideoSinkFilter::FlushStart()
416 {
417 MEDIA_LOG_D("FlushStart entered");
418 isFlushing_ = true;
419 if (pushThreadIsBlocking_) {
420 startWorkingCondition_.NotifyOne();
421 }
422 if (inBufQueue_) {
423 inBufQueue_->SetActive(false);
424 }
425 renderTask_->Pause();
426 auto err = TranslatePluginStatus(plugin_->Flush());
427 if (err != ErrorCode::SUCCESS) {
428 MEDIA_LOG_E("Video sink filter flush failed.");
429 }
430 }
431
FlushEnd()432 void VideoSinkFilter::FlushEnd()
433 {
434 MEDIA_LOG_D("FlushEnd entered");
435 isFlushing_ = false;
436 if (inBufQueue_) {
437 inBufQueue_->SetActive(true);
438 }
439 renderTask_->Start();
440 ResetSyncInfo();
441 renderFrameCnt_ = 0;
442 discardFrameCnt_ = 0;
443 }
444
445 #ifndef OHOS_LITE
SetVideoSurface(sptr<Surface> surface)446 ErrorCode VideoSinkFilter::SetVideoSurface(sptr<Surface> surface)
447 {
448 if (!surface) {
449 MEDIA_LOG_W("surface is null");
450 return ErrorCode::ERROR_INVALID_PARAMETER_VALUE;
451 }
452 if (plugin_) {
453 auto ret = TranslatePluginStatus(plugin_->SetParameter(Tag::VIDEO_SURFACE, surface));
454 if (ret != ErrorCode::SUCCESS) {
455 MEDIA_LOG_W("Set surface to plugin fail");
456 return ret;
457 }
458 } else {
459 surface_ = surface;
460 }
461 MEDIA_LOG_D("SetVideoSurface success");
462 return ErrorCode::SUCCESS;
463 }
464 #endif
465
CheckBufferLatenessMayWait(AVBufferPtr buffer)466 bool VideoSinkFilter::CheckBufferLatenessMayWait(AVBufferPtr buffer)
467 {
468 auto syncCenter = syncCenter_.lock();
469 if (!syncCenter) {
470 return false;
471 }
472 auto ct4Buffer = syncCenter->GetClockTime(buffer->pts);
473 if (ct4Buffer != HST_TIME_NONE) {
474 bool tooLate = false;
475 auto nowCt = syncCenter->GetClockTimeNow();
476 uint64_t latency = 0;
477 plugin_->GetLatency(latency);
478 auto diff = nowCt + (int64_t) latency - ct4Buffer;
479 // diff < 0 or 0 < diff < 40ms(25Hz) render it
480 if (diff < 0) {
481 // buffer is early
482 auto waitTimeMs = Plugin::HstTime2Ms(0 - diff);
483 MEDIA_LOG_DD("buffer is eary, sleep for " PUBLIC_LOG_D64 " ms", waitTimeMs);
484 OSAL::SleepFor(waitTimeMs);
485 } else if (diff > 0 && Plugin::HstTime2Ms(diff) > 40) { // > 40ms
486 // buffer is late
487 tooLate = true;
488 MEDIA_LOG_DD("buffer is too late");
489 }
490 // buffer is too late and is not key frame drop it
491 if (tooLate && (buffer->flag & BUFFER_FLAG_KEY_FRAME) == 0) {
492 return true;
493 }
494 }
495 return false;
496 }
497
DoSyncWrite(const AVBufferPtr & buffer)498 ErrorCode VideoSinkFilter::DoSyncWrite(const AVBufferPtr& buffer)
499 {
500 bool shouldDrop = false;
501 bool render = true;
502 if ((buffer->flag & BUFFER_FLAG_EOS) == 0) {
503 if (isFirstFrame_) {
504 int64_t nowCt = 0;
505 auto syncCenter = syncCenter_.lock();
506 if (syncCenter) {
507 nowCt = syncCenter->GetClockTimeNow();
508 }
509 uint64_t latency = 0;
510 if (plugin_->GetLatency(latency) != Plugin::Status::OK) {
511 MEDIA_LOG_I("failed to get latency, treat as 0");
512 }
513 if (syncCenter) {
514 render = syncCenter->UpdateTimeAnchor(nowCt + latency, buffer->pts, this);
515 }
516 isFirstFrame_ = false;
517 OnEvent(Event{name_, EventType::EVENT_VIDEO_RENDERING_START, {}});
518 if (frameRateTask_) {
519 frameRateTask_->Start();
520 }
521 } else {
522 shouldDrop = CheckBufferLatenessMayWait(buffer);
523 }
524 if (forceRenderNextFrame_) {
525 shouldDrop = false;
526 forceRenderNextFrame_ = false;
527 }
528 }
529 if (shouldDrop) {
530 discardFrameCnt_++;
531 MEDIA_LOG_DD("drop buffer with pts " PUBLIC_LOG_D64 " due to too late", buffer->pts);
532 return ErrorCode::SUCCESS;
533 } else if (!render) {
534 discardFrameCnt_++;
535 MEDIA_LOG_DD("drop buffer with pts " PUBLIC_LOG_D64 " due to seek not need to render", buffer->pts);
536 return ErrorCode::SUCCESS;
537 } else {
538 renderFrameCnt_++;
539 return TranslatePluginStatus(plugin_->Write(buffer));
540 }
541 }
542
ResetSyncInfo()543 void VideoSinkFilter::ResetSyncInfo()
544 {
545 ResetPrerollReported();
546 isFirstFrame_ = true;
547 }
548
CalcFrameRate()549 void VideoSinkFilter::CalcFrameRate()
550 {
551 OSAL::SleepFor(1000); // 1000ms
552 MEDIA_LOG_I("Render fps: " PUBLIC_LOG_U64 ", discard frame count: " PUBLIC_LOG_U64,
553 renderFrameCnt_.load(), discardFrameCnt_.load());
554 renderFrameCnt_ = 0;
555 discardFrameCnt_ = 0;
556 }
557 } // namespace Pipeline
558 } // namespace Media
559 } // namespace OHOS
560 #endif