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