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