• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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