1 /*
2 * Copyright (c) 2020-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 #include <unistd.h>
17 #include <sys/time.h>
18 #include "player_video_sink.h"
19 #include "media_log.h"
20
21 namespace OHOS {
22 namespace Media {
23
24 const int32_t MAX_VIDEO_QUEUE_BUF_NUM = 32;
25 const float VIDEO_FRAME_RATE_MAX = 120.0f;
26 const int32_t FLOAT_INT_SCALE = 1000;
27 const int32_t SS2US = 1000000;
28 const int32_t US2MS = 1000;
29 const int32_t DEFAULT_REGION_WIDTH = 480;
30 const int32_t DEFAULT_REGION_HEIGHT = 480;
31
32 #define CHECK_FAILED_RETURN(value, target, ret, printfString) \
33 do { \
34 if ((value) != (target)) { \
35 MEDIA_ERR_LOG(" %s ", (printfString != nullptr) ? (printfString) : " "); \
36 return (ret); \
37 } \
38 } while (0)
39
40 #define CHECK_NULL_RETURN(value, ret, printfString) \
41 do { \
42 if ((value) == nullptr) { \
43 MEDIA_ERR_LOG(" %s ", (printfString != nullptr) ? (printfString) : " "); \
44 return (ret); \
45 } \
46 } while (0)
47
GetCurTimeUs()48 static int64_t GetCurTimeUs()
49 {
50 struct timeval ts;
51 ts.tv_sec = 0;
52 ts.tv_usec = 0;
53 gettimeofday(&ts, nullptr);
54 return ((static_cast<int64_t>(ts.tv_sec)) * SS2US) + (static_cast<int64_t>(ts.tv_usec));
55 }
56
GetCurTimeMs()57 static int64_t GetCurTimeMs()
58 {
59 int64_t curTimeUs = GetCurTimeUs();
60 return static_cast<int64_t>(curTimeUs / US2MS);
61 }
62
VideoSink(void)63 VideoSink::VideoSink(void)
64 :speed_(1.0f), paused_(false), started_(false), syncHdl_(nullptr),
65 renderFrameCnt_(0), renderMode_(RENDER_MODE_NORMAL), rendStartTime_(-1), lastRendPts_(AV_INVALID_PTS),
66 recievedEos_(false), EosPts_(AV_INVALID_PTS), pauseAfterPlay_(false), firstVidRend_(false),
67 lastRendCnt_(0), vidRendStartTime_(AV_INVALID_PTS), eosSended_(false), lastConfigRegionX_(-1),
68 lastConfigRegionY_(-1), lastConfigRegionW_(-1), lastConfigRegionH_(-1)
69 {
70 ResetRendStartTime();
71 attr_.sinkType = SINK_TYPE_BUT;
72 attr_.trackId = 0;
73 attr_.vidAttr.format = 0;
74 attr_.vidAttr.width = 0;
75 attr_.vidAttr.height = 0;
76 attr_.vidAttr.frameRate = 0.0;
77 attr_.vidAttr.surface = nullptr;
78 lastRendSysTimeMs_ = GetCurTimeMs();
79 callBack_.onEventCallback = nullptr;
80 callBack_.priv = nullptr;
81 frameCacheQue_.clear();
82 frameReleaseQue_.clear();
83 }
84
~VideoSink()85 VideoSink::~VideoSink()
86 {
87 (void)DeInit();
88 }
89
DeInit()90 int32_t VideoSink::DeInit()
91 {
92 int32_t ret = HI_SUCCESS;
93 layerFuncs_->DeinitDisplay(0);
94 return ret;
95 }
96
Init(SinkAttr & attr)97 int32_t VideoSink::Init(SinkAttr &attr)
98 {
99 attr_ = attr;
100 (void)LayerInitialize(&layerFuncs_);
101 layerFuncs_->InitDisplay(0);
102 return 0;
103 }
104
GetStatus(VideoSinkStatus & status)105 void VideoSink::GetStatus(VideoSinkStatus &status)
106 {
107 status.vidFrameCount = renderFrameCnt_;
108 status.decHeight = attr_.vidAttr.height;
109 status.decWidth = static_cast<uint32_t>(attr_.vidAttr.width);
110 if (vidRendStartTime_ != AV_INVALID_PTS) {
111 int64_t diffTimeMs = GetCurTimeMs() - vidRendStartTime_;
112 if (diffTimeMs > MS_SCALE) {
113 double frameCnt = lastRendCnt_;
114 double time = diffTimeMs;
115 double frameRate = frameCnt / time;
116 if (frameRate >= VIDEO_FRAME_RATE_MAX || frameRate < 0) {
117 status.fpsInteger = 0;
118 status.fpsDecimal = 0;
119 return;
120 }
121
122 uint32_t tmp = frameRate * FLOAT_INT_SCALE;
123 status.fpsInteger = (tmp / FLOAT_INT_SCALE);
124 status.fpsDecimal = (tmp % FLOAT_INT_SCALE);
125 return;
126 }
127 }
128 status.fpsInteger = 0;
129 status.fpsDecimal = 0;
130 }
131
SetDefaultDisplayRegionInfo(void)132 void VideoSink::SetDefaultDisplayRegionInfo(void)
133 {
134 lastConfigRegionX_ = 0;
135 lastConfigRegionY_ = 0;
136 lastConfigRegionW_ = DEFAULT_REGION_WIDTH;
137 lastConfigRegionH_ = DEFAULT_REGION_HEIGHT;
138 }
139
UpdateDisplayRegionInfo(int32_t x,int32_t y,int32_t w,int32_t h)140 void VideoSink::UpdateDisplayRegionInfo(int32_t x, int32_t y, int32_t w, int32_t h)
141 {
142 lastConfigRegionX_ = x;
143 lastConfigRegionY_ = y;
144 lastConfigRegionW_ = w;
145 lastConfigRegionH_ = h;
146 }
147
CreateAndConfigLayer(void)148 void VideoSink::CreateAndConfigLayer(void)
149 {
150 int32_t x;
151 int32_t y;
152 int32_t w;
153 int32_t h;
154 IRect attr;
155 uint32_t devId = 0;
156 uint32_t layerId = 0;
157 int32_t right = lastConfigRegionX_ + lastConfigRegionW_ - 1;
158 int32_t botttom = lastConfigRegionY_ + lastConfigRegionH_ - 1;
159 /* Make sure the coordinates are even */
160 x = lastConfigRegionX_ - lastConfigRegionX_ % 0x2;
161 y = lastConfigRegionY_ - lastConfigRegionY_ % 0x2;
162 w = right - x + 1;
163 h = botttom - y + 1;
164 w = w + w % 2;
165 h = h + h % 2;
166 attr.x = x;
167 attr.y = y;
168 attr.w = w;
169 attr.h = h;
170 LayerInfo lInfo;
171 lInfo.width = w;
172 lInfo.height = h;
173 if (layerFuncs_ != nullptr) {
174 layerFuncs_->CreateLayer(devId, &lInfo, &layerId);
175 layerFuncs_->SetLayerSize(devId, layerId, &attr);
176 }
177
178 }
179
CheckConfigVideoOutput(void)180 void VideoSink::CheckConfigVideoOutput(void)
181 {
182 Surface *surface = attr_.vidAttr.surface;
183 /* set default region if not set */
184 if (surface == nullptr) {
185 SetDefaultDisplayRegionInfo();
186 return CreateAndConfigLayer();
187 }
188 int32_t x = std::stoi(surface->GetUserData("region_position_x"));
189 int32_t y = std::stoi(surface->GetUserData("region_position_y"));
190 int32_t w = std::stoi(surface->GetUserData("region_width"));
191 int32_t h = std::stoi(surface->GetUserData("region_height"));
192 UpdateDisplayRegionInfo(x, y, w, h);
193
194 CreateAndConfigLayer();
195 }
196
Start()197 int32_t VideoSink::Start()
198 {
199 vidRendStartTime_ = GetCurTimeMs();
200 CheckConfigVideoOutput();
201 if (syncHdl_ != nullptr) {
202 syncHdl_->Start(SYNC_CHN_VID);
203 }
204 started_ = true;
205 return HI_SUCCESS;
206 }
207
SetRenderMode(RenderMode mode)208 void VideoSink::SetRenderMode(RenderMode mode)
209 {
210 // use to control report first video frame
211 renderMode_ = mode;
212 }
213
Stop()214 int32_t VideoSink::Stop()
215 {
216 ReleaseQueAllFrame();
217 ResetRendStartTime();
218 renderFrameCnt_ = 0;
219 if (layerFuncs_ != nullptr) {
220 layerFuncs_->CloseLayer(0, 0);
221 }
222 started_ = false;
223 return HI_SUCCESS;
224 }
225
Pause()226 int32_t VideoSink::Pause()
227 {
228 if (paused_) {
229 MEDIA_WARNING_LOG("vsink already paused");
230 return HI_SUCCESS;
231 }
232 if (!started_) {
233 MEDIA_ERR_LOG("vsink not in running");
234 return HI_FAILURE;
235 }
236
237 ResetRendStartTime();
238 paused_ = true;
239 return HI_SUCCESS;
240 }
241
Resume(void)242 int32_t VideoSink::Resume(void)
243 {
244 renderMode_ = RENDER_MODE_NORMAL;
245 if (!paused_) {
246 MEDIA_WARNING_LOG("vsink not in pause");
247 return HI_FAILURE;
248 }
249
250 vidRendStartTime_ = GetCurTimeMs();
251 lastRendSysTimeMs_ = GetCurTimeMs();
252 paused_ = false;
253 return HI_SUCCESS;
254 }
255
Flush(void)256 int32_t VideoSink::Flush(void)
257 {
258 if (!started_) {
259 MEDIA_ERR_LOG("vsink not in started");
260 return HI_FAILURE;
261 }
262 return HI_SUCCESS;
263 }
264
ResetRendStartTime()265 void VideoSink::ResetRendStartTime()
266 {
267 lastRendCnt_ = 0;
268 lastRendPts_ = AV_INVALID_PTS;
269 vidRendStartTime_ = AV_INVALID_PTS;
270 }
271
Reset()272 int32_t VideoSink::Reset()
273 {
274 ReleaseQueAllFrame();
275 Flush();
276 ResetRendStartTime();
277 recievedEos_ = false;
278 firstVidRend_ = false;
279 return HI_SUCCESS;
280 }
281
282
RegisterCallBack(PlayEventCallback & callback)283 int32_t VideoSink::RegisterCallBack(PlayEventCallback &callback)
284 {
285 callBack_ = callback;
286 return 0;
287 }
288
QueueRenderFrame(PlayerBufferInfo & frame,bool cacheQueue)289 void VideoSink::QueueRenderFrame(PlayerBufferInfo &frame, bool cacheQueue)
290 {
291 std::lock_guard<std::mutex> lock(mutex_);
292 if (frame.info.bufferCnt == 0) {
293 return;
294 }
295 if (cacheQueue) {
296 frameCacheQue_.push_back(frame);
297 } else {
298 frameReleaseQue_.push_back(frame);
299 }
300 }
301
GetRenderFrame(PlayerBufferInfo & renderFrame,PlayerBufferInfo & frame)302 int32_t VideoSink::GetRenderFrame(PlayerBufferInfo &renderFrame, PlayerBufferInfo &frame)
303 {
304 std::lock_guard<std::mutex> lock(mutex_);
305 int32_t ret = SINK_QUE_EMPTY;
306 if (frame.info.bufferCnt != 0) {
307 frameCacheQue_.push_back(frame);
308 }
309 if (frameCacheQue_.size() != 0) {
310 renderFrame = frameCacheQue_[0];
311 ret = SINK_SUCCESS;
312 }
313 return ret;
314 }
315
ReleaseQueHeadFrame(void)316 void VideoSink::ReleaseQueHeadFrame(void)
317 {
318 std::lock_guard<std::mutex> lock(mutex_);
319 if (frameCacheQue_.size() != 0) {
320 PlayerBufferInfo frame = frameCacheQue_[0];
321 frameCacheQue_.erase(frameCacheQue_.begin());
322 frameReleaseQue_.push_back(frame);
323 }
324 }
325
ReleaseQueAllFrame(void)326 void VideoSink::ReleaseQueAllFrame(void)
327 {
328 size_t i;
329 size_t queSize;
330 std::lock_guard<std::mutex> lock(mutex_);
331 queSize = frameCacheQue_.size();
332 if (queSize > MAX_VIDEO_QUEUE_BUF_NUM) {
333 return;
334 }
335 for (i = 0; i < queSize; i++) {
336 frameReleaseQue_.push_back(frameCacheQue_[i]);
337 }
338 frameCacheQue_.clear();
339 }
340
DequeReleaseFrame(PlayerBufferInfo & frame)341 int32_t VideoSink::DequeReleaseFrame(PlayerBufferInfo &frame)
342 {
343 std::lock_guard<std::mutex> lock(mutex_);
344 if (frameReleaseQue_.size() == 0) {
345 return SINK_QUE_EMPTY;
346 }
347 frame = frameReleaseQue_[0];
348 frameReleaseQue_.erase(frameReleaseQue_.begin());
349 return SINK_SUCCESS;
350 }
351
RenderRptEvent(EventCbType event)352 void VideoSink::RenderRptEvent(EventCbType event)
353 {
354 if (callBack_.onEventCallback != nullptr) {
355 if (event == EVNET_VIDEO_PLAY_EOS && eosSended_ == true) {
356 return;
357 }
358 callBack_.onEventCallback(callBack_.priv, event, 0, 0);
359 if (event == EVNET_VIDEO_PLAY_EOS) {
360 eosSended_ = true;
361 }
362 }
363 }
364
WriteToVideoDevice(CodecBuffer & renderFrame)365 int32_t VideoSink::WriteToVideoDevice(CodecBuffer &renderFrame)
366 {
367 if (layerFuncs_ != nullptr) {
368 LayerBuffer layerBuf;
369 layerBuf.data.virAddr = (void *)renderFrame.buffer[0].buf;
370 layerFuncs_->Flush(0, 0, &layerBuf);
371 }
372 ReleaseQueHeadFrame();
373 return SINK_SUCCESS;
374 }
375
RenderFrame(PlayerBufferInfo & frame)376 int32_t VideoSink::RenderFrame(PlayerBufferInfo &frame)
377 {
378 SyncRet syncRet = SYNC_RET_PLAY;
379 int64_t crtPlayPts = 0;
380 PlayerBufferInfo renderFrame;
381
382 /* the frame should be save to queue at state paused and none-started */
383 if (!started_ || paused_ || (renderMode_ == RENDER_MODE_PAUSE_AFTER_PLAY && renderFrameCnt_ == 1)) {
384 QueueRenderFrame(frame, started_ ? true : false);
385 return SINK_SUCCESS;
386 }
387
388 if (GetRenderFrame(renderFrame, frame) != SINK_SUCCESS) {
389 if (recievedEos_ == true) {
390 RenderRptEvent(EVNET_VIDEO_PLAY_EOS);
391 return SINK_RENDER_EOS;
392 }
393 return SINK_QUE_EMPTY;
394 }
395
396 crtPlayPts = renderFrame.info.timeStamp;
397 int32_t ret = (syncHdl_ != nullptr) ? syncHdl_->ProcVidFrame(crtPlayPts, syncRet) : HI_SUCCESS;
398 if (ret != HI_SUCCESS) {
399 ReleaseQueHeadFrame();
400 MEDIA_ERR_LOG("ProcVidFrame pts: %llu failed", renderFrame.info.timeStamp);
401 return SINK_RENDER_ERROR;
402 }
403
404 if (syncRet == SYNC_RET_PLAY) {
405 ret = WriteToVideoDevice(renderFrame.info);
406 if (renderFrameCnt_ == 0) {
407 callBack_.onEventCallback(callBack_.priv, EVNET_FIRST_VIDEO_REND, 0, 0);
408 }
409 renderFrameCnt_++;
410 } else if (syncRet == SYNC_RET_DROP) {
411 MEDIA_INFO_LOG("too late, drop, pts: %lld", renderFrame.info.timeStamp);
412 ReleaseQueHeadFrame();
413 ret = SINK_SUCCESS;
414 } else if (syncRet == SYNC_RET_REPEAT) {
415 ret = SINK_RENDER_DELAY;
416 } else {
417 MEDIA_ERR_LOG("video invalid sync ret: %d", syncRet);
418 ReleaseQueHeadFrame();
419 ret = SINK_RENDER_ERROR;
420 }
421
422 /* render pts update after the frame that have been processed */
423 if (ret == SINK_SUCCESS || ret == SINK_RENDER_ERROR) {
424 lastRendPts_ = (renderFrame.info.timeStamp > lastRendPts_) ? renderFrame.info.timeStamp : lastRendPts_;
425 }
426 return ret;
427 }
428
SetSync(PlayerSync * sync)429 void VideoSink::SetSync(PlayerSync *sync)
430 {
431 syncHdl_ = sync;
432 }
433
RenderEos(void)434 void VideoSink::RenderEos(void)
435 {
436 recievedEos_ = true;
437 EosPts_ = lastRendPts_;
438 }
439
GetRenderPosition(int64_t & position)440 void VideoSink::GetRenderPosition(int64_t &position)
441 {
442 position = lastRendPts_;
443 }
444 }
445 }
446