1 /*
2 * Copyright (c) 2023-2023 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 "video_sink.h"
17
18 #include <algorithm>
19
20 #include "common/log.h"
21 #include "media_sync_manager.h"
22 #include "osal/task/jobutils.h"
23 #include "syspara/parameters.h"
24
25 namespace OHOS {
26 namespace Media {
27 namespace Pipeline {
GetvideoLatencyFixDelay()28 int64_t GetvideoLatencyFixDelay()
29 {
30 constexpr uint64_t defaultValue = 120 * HST_USECOND;
31 static uint64_t fixDelay = OHOS::system::GetUintParameter("debug.media_service.video_sync_fix_delay", defaultValue);
32 MEDIA_LOG_I("video_sync_fix_delay, pid:%{public}d, fixdelay: " PUBLIC_LOG_U64, getpid(), fixDelay);
33 return (int64_t)fixDelay;
34 }
35
36 /// Video Key Frame Flag
37 constexpr int BUFFER_FLAG_KEY_FRAME = 0x00000002;
38
39 constexpr int64_t WAIT_TIME_US_THRESHOLD = 1500000; // max sleep time 1.5s
40
VideoSink()41 VideoSink::VideoSink()
42 {
43 refreshTime_ = 0;
44 syncerPriority_ = IMediaSynchronizer::VIDEO_SINK;
45 fixDelay_ = GetvideoLatencyFixDelay();
46 MEDIA_LOG_I("VideoSink ctor called...");
47 }
48
~VideoSink()49 VideoSink::~VideoSink()
50 {
51 MEDIA_LOG_I("VideoSink dtor called...");
52 this->eventReceiver_ = nullptr;
53 }
54
DoSyncWrite(const std::shared_ptr<OHOS::Media::AVBuffer> & buffer)55 bool VideoSink::DoSyncWrite(const std::shared_ptr<OHOS::Media::AVBuffer>& buffer)
56 {
57 FALSE_RETURN_V(buffer != nullptr, false);
58 bool shouldDrop = false;
59 bool render = true;
60 if ((buffer->flag_ & BUFFER_FLAG_EOS) == 0) {
61 if (isFirstFrame_) {
62 eventReceiver_->OnEvent({"video_sink", EventType::EVENT_VIDEO_RENDERING_START, Status::OK});
63 int64_t nowCt = 0;
64 auto syncCenter = syncCenter_.lock();
65 FALSE_RETURN_V(syncCenter != nullptr, false);
66 if (syncCenter) {
67 nowCt = syncCenter->GetClockTimeNow();
68 }
69 uint64_t latency = 0;
70 if (GetLatency(latency) != Status::OK) {
71 MEDIA_LOG_I("failed to get latency, treat as 0");
72 }
73 if (syncCenter) {
74 render = syncCenter->UpdateTimeAnchor(nowCt, latency, buffer->pts_ - firstPts_,
75 buffer->pts_, buffer->duration_, this);
76 }
77 isFirstFrame_ = false;
78 } else {
79 shouldDrop = CheckBufferLatenessMayWait(buffer);
80 }
81 if (forceRenderNextFrame_) {
82 shouldDrop = false;
83 forceRenderNextFrame_ = false;
84 }
85 lastTimeStamp_ = buffer->pts_ - firstPts_;
86 } else {
87 MEDIA_LOG_I("Video sink EOS");
88 return false;
89 }
90 if (shouldDrop) {
91 discardFrameCnt_++;
92 MEDIA_LOG_DD("drop buffer with pts " PUBLIC_LOG_D64 " due to too late", buffer->pts_);
93 return false;
94 } else if (!render) {
95 discardFrameCnt_++;
96 MEDIA_LOG_DD("drop buffer with pts " PUBLIC_LOG_D64 " due to seek not need to render", buffer->pts_);
97 return false;
98 } else {
99 renderFrameCnt_++;
100 return true;
101 }
102 }
103
ResetSyncInfo()104 void VideoSink::ResetSyncInfo()
105 {
106 ResetPrerollReported();
107 isFirstFrame_ = true;
108 lastTimeStamp_ = HST_TIME_NONE;
109 lastBufferTime_ = HST_TIME_NONE;
110 seekFlag_ = false;
111 }
112
GetLatency(uint64_t & nanoSec)113 Status VideoSink::GetLatency(uint64_t& nanoSec)
114 {
115 nanoSec = 10; // 10 ns
116 return Status::OK;
117 }
118
SetSeekFlag()119 void VideoSink::SetSeekFlag()
120 {
121 seekFlag_ = true;
122 }
123
CheckBufferLatenessMayWait(const std::shared_ptr<OHOS::Media::AVBuffer> & buffer)124 bool VideoSink::CheckBufferLatenessMayWait(const std::shared_ptr<OHOS::Media::AVBuffer>& buffer)
125 {
126 FALSE_RETURN_V(buffer != nullptr, true);
127 bool tooLate = false;
128 auto syncCenter = syncCenter_.lock();
129 FALSE_RETURN_V(syncCenter != nullptr, true);
130 auto pts = buffer->pts_ - firstPts_;
131 auto ct4Buffer = syncCenter->GetClockTime(pts);
132
133 MEDIA_LOG_D("VideoSink cur pts: " PUBLIC_LOG_D64 " us, ct4Buffer: " PUBLIC_LOG_D64
134 " us, fixDelay: " PUBLIC_LOG_D64 " us", pts, ct4Buffer, fixDelay_);
135 if (ct4Buffer != Plugins::HST_TIME_NONE) {
136 if (lastBufferTime_ != HST_TIME_NONE && seekFlag_ == false) {
137 int64_t thisBufferTime = lastBufferTime_ + pts - lastTimeStamp_;
138 int64_t deltaTime = ct4Buffer - thisBufferTime;
139 deltaTimeAccu_ = (deltaTimeAccu_ * 9 + deltaTime) / 10; // 9 10 for smoothing
140 if (std::abs(deltaTimeAccu_) < 5 * HST_USECOND) { // 5ms
141 ct4Buffer = thisBufferTime;
142 }
143 MEDIA_LOG_D("VideoSink lastBufferTime_: " PUBLIC_LOG_D64
144 " us, lastTimeStamp_: " PUBLIC_LOG_D64,
145 lastBufferTime_, lastTimeStamp_);
146 } else {
147 seekFlag_ = (seekFlag_ == true) ? false : seekFlag_;
148 }
149 auto nowCt = syncCenter->GetClockTimeNow();
150 uint64_t latency = 0;
151 GetLatency(latency);
152 auto diff = nowCt + (int64_t) latency - ct4Buffer + fixDelay_;
153 MEDIA_LOG_D("VideoSink ct4Buffer: " PUBLIC_LOG_D64 " us, diff: " PUBLIC_LOG_D64
154 " us, nowCt: " PUBLIC_LOG_D64, ct4Buffer, diff, nowCt);
155 // diff < 0 or 0 < diff < 40ms(25Hz) render it
156 if (diff < 0) {
157 // buffer is early
158 int64_t waitTimeUs = 0 - diff;
159 if (waitTimeUs > WAIT_TIME_US_THRESHOLD) {
160 MEDIA_LOG_W("buffer is too early waitTimeUs: " PUBLIC_LOG_D64, waitTimeUs);
161 waitTimeUs = WAIT_TIME_US_THRESHOLD;
162 }
163 usleep(waitTimeUs);
164 } else if (diff > 0 && Plugins::HstTime2Ms(diff * HST_USECOND) > 40) { // > 40ms
165 // buffer is late
166 tooLate = true;
167 MEDIA_LOG_DD("buffer is too late");
168 }
169 lastBufferTime_ = ct4Buffer;
170 // buffer is too late and is not key frame drop it
171 if (tooLate && (buffer->flag_ & BUFFER_FLAG_KEY_FRAME) == 0) {
172 return true;
173 }
174 }
175 return false;
176 }
177
SetSyncCenter(std::shared_ptr<Pipeline::MediaSyncManager> syncCenter)178 void VideoSink::SetSyncCenter(std::shared_ptr<Pipeline::MediaSyncManager> syncCenter)
179 {
180 syncCenter_ = syncCenter;
181 MediaSynchronousSink::Init();
182 }
183
SetEventReceiver(const std::shared_ptr<EventReceiver> & receiver)184 void VideoSink::SetEventReceiver(const std::shared_ptr<EventReceiver> &receiver)
185 {
186 this->eventReceiver_ = receiver;
187 }
188
SetFirstPts(int64_t pts)189 void VideoSink::SetFirstPts(int64_t pts)
190 {
191 if (firstPts_ == HST_TIME_NONE) {
192 firstPts_ = pts;
193 MEDIA_LOG_I("video DoSyncWrite set firstPts = " PUBLIC_LOG_D64, firstPts_);
194 }
195 }
196 } // namespace Pipeline
197 } // namespace MEDIA
198 } // namespace OHOS