blob: 3ed33184e571f4c8b9255fbdde4c0e4c4b802240 [file] [log] [blame]
fei.dengf7a0cd32023-08-29 09:36:37 +00001/*
2 * Copyright (C) 2021 Amlogic Corporation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include <errno.h>
17#include <sys/mman.h>
18#include <xf86drm.h>
19#include <xf86drmMode.h>
20#include <drm_fourcc.h>
21#include <linux/videodev2.h>
22#include <meson_drm.h>
23#include "drm_display.h"
24#include "Logger.h"
25#include "drm_framepost.h"
26#include "drm_framerecycle.h"
27
28using namespace Tls;
29
30#define TAG "rlib:drm_display"
31
32#define BLACK_FRAME_WIDTH 64
33#define BLACK_FRAME_HEIGHT 64
34
35DrmDisplay::DrmDisplay(DrmPlugin *plugin)
36 : mPlugin(plugin)
37{
38 mDrmHandle = NULL;
39 mBlackFrame = 0;
40 mIsPip = false;
41 mDrmFramePost = NULL;
42 mDrmFrameRecycle = NULL;
43 mVideoFormat = VIDEO_FORMAT_UNKNOWN;
44 mWinRect.x = 0;
45 mWinRect.y = 0;
46 mWinRect.w = 0;
47 mWinRect.h = 0;
48 mFrameWidth = 0;
49 mFrameHeight = 0;
50 mBlackFrame = NULL;
51 mBlackFrameAddr = NULL;
52 mHideVideo = false;
53 mIsDropFrames = false;
54 mKeepLastFrame = false;
55 mDrmMesonLib = drmMesonLoadLib();
56}
57
58DrmDisplay::~DrmDisplay()
59{
60 if (mDrmHandle) {
61 if (mDrmMesonLib) {
62 mDrmMesonLib->libDrmDisplayDestroy(mDrmHandle);
63 mDrmHandle = NULL;
64 }
65 }
66 //free dlopen resources
67 if (mDrmMesonLib) {
68 drmMesonUnloadLib(mDrmMesonLib);
69 mDrmMesonLib = NULL;
70 }
71}
72
73bool DrmDisplay::start(bool pip)
74{
75 mIsPip = pip;
76
77 DEBUG("start pip:%d",pip);
78 if (mDrmMesonLib) {
79 mDrmHandle = mDrmMesonLib->libDrmDisplayInit();
80 }
81
82 if (!mDrmHandle) {
83 ERROR("drm display init failed");
84 return false;
85 }
86#ifdef SUPPORT_DRM_FREEZEN
87 //set keep last frame if needed;
88 if (mKeepLastFrame) {
89 mDrmHandle->freeze = 1;
90 } else {
91 mDrmHandle->freeze = 0;
92 }
93 INFO("set keep last frame %d", mDrmHandle->freeze);
94#endif
95
96 if (!mDrmFramePost) {
97 mDrmFramePost = new DrmFramePost(this);
98 mDrmFramePost->start();
99 /*if window size set, we set to frame post,this needed
100 when yts resize case,window size must effect when post
101 buffer to drm
102 */
103 if (mWinRect.w > 0 && mWinRect.h > 0) {
104 mDrmFramePost->setWindowSize(mWinRect.x, mWinRect.y, mWinRect.w, mWinRect.h);
105 }
106 }
107
108 if (!mDrmFrameRecycle) {
109 mDrmFrameRecycle = new DrmFrameRecycle(this);
110 mDrmFrameRecycle->start();
111 }
112 return true;
113}
114
115bool DrmDisplay::stop()
116{
117 if (mDrmFramePost) {
118 DEBUG("stop frame post thread");
119 mDrmFramePost->stop();
120 delete mDrmFramePost;
121 mDrmFramePost = NULL;
122 }
123 if (mDrmFrameRecycle) {
124 DEBUG("stop frame recycle thread");
125 mDrmFrameRecycle->stop();
126 delete mDrmFrameRecycle;
127 mDrmFrameRecycle = NULL;
128 }
129 if (mBlackFrameAddr) {
130 munmap (mBlackFrameAddr, mBlackFrame->width * mBlackFrame->height * 2);
131 mBlackFrameAddr = NULL;
132 }
133 if (mBlackFrame) {
134 if (mDrmMesonLib) {
135 mDrmMesonLib->libDrmFreeBuf(mBlackFrame);
136 }
137 mBlackFrame = NULL;
138 }
139 if (mDrmHandle) {
140 if (mDrmMesonLib) {
141 mDrmMesonLib->libDrmDisplayDestroy(mDrmHandle);
142 mDrmHandle = NULL;
143 }
144 }
145 return true;
146}
147
148bool DrmDisplay::displayFrame(RenderBuffer *buf, int64_t displayTime)
149{
150 int ret;
151
152 FrameEntity *frameEntity = createFrameEntity(buf, displayTime);
153 if (frameEntity) {
154 if (mDrmFramePost) {
155 //if hided video and commit hide frame to drm,drop all frame
156 if (mIsDropFrames) {
157 handleDropedFrameEntity(frameEntity);
158 handleReleaseFrameEntity(frameEntity);
159 } else {
160 mDrmFramePost->readyPostFrame(frameEntity);
161 }
162 if (mHideVideo) {
163 mIsDropFrames = true;
164 }
165 } else {
166 WARNING("no frame post service");
167 handleDropedFrameEntity(frameEntity);
168 handleReleaseFrameEntity(frameEntity);
169 }
170 } else { //drop and release render buffer
171 if (mPlugin) {
172 mPlugin->handleFrameDropped(buf);
173 mPlugin->handleBufferRelease(buf);
174 }
175 }
176
177 return true;
178}
179
180void DrmDisplay::flush()
181{
182 DEBUG("flush");
183 std::lock_guard<std::mutex> lck(mMutex);
184 if (mDrmFramePost) {
185 mDrmFramePost->flush();
186 }
187}
188
189void DrmDisplay::pause()
190{
191 mDrmFramePost->pause();
192}
193
194void DrmDisplay::resume()
195{
196 mDrmFramePost->resume();
197}
198
199void DrmDisplay::setVideoFormat(RenderVideoFormat videoFormat)
200{
201 mVideoFormat = videoFormat;
202 DEBUG("video format:%d",mVideoFormat);
203}
204
205void DrmDisplay::setWindowSize(int x, int y, int w, int h)
206{
207 mWinRect.x = x;
208 mWinRect.y = y;
209 mWinRect.w = w;
210 mWinRect.h = h;
211 DEBUG("window size:(%dx%dx%dx%d)",x, y,w,h);
212 if (mDrmFramePost) {
213 mDrmFramePost->setWindowSize(x, y, w, h);
214 }
215}
216
217void DrmDisplay::setFrameSize(int width, int height)
218{
219 mFrameWidth = width;
220 mFrameHeight = height;
221 DEBUG("frame size:%dx%d",width, height);
222}
223
224void DrmDisplay::showBlackFrame()
225{
226 int rc;
227 struct drm_buf_metadata info;
228
229 memset(&info, 0 , sizeof(struct drm_buf_metadata));
230
231 /* use single planar for black frame */
232 info.width = BLACK_FRAME_WIDTH;
233 info.height = BLACK_FRAME_HEIGHT;
234 info.flags = 0;
235 info.fourcc = DRM_FORMAT_YUYV;
236
237 if (!mIsPip)
238 info.flags |= MESON_USE_VD1;
239 else
240 info.flags |= MESON_USE_VD2;
241
242 if (mDrmHandle && mDrmMesonLib) {
243 mBlackFrame = mDrmMesonLib->libDrmAllocBuf(mDrmHandle, &info);
244 }
245
246 if (!mBlackFrame) {
247 ERROR("Unable to alloc drm buf");
248 goto tag_error;
249 }
250
251 mBlackFrameAddr = mmap (NULL, info.width * info.height * 2, PROT_WRITE,
252 MAP_SHARED, mBlackFrame->fd[0], mBlackFrame->offsets[0]);
253 if (mBlackFrameAddr == MAP_FAILED) {
254 ERROR("mmap fail %d", errno);
255 mBlackFrameAddr = NULL;
256 }
257
258 /* full screen black frame */
259 memset (mBlackFrameAddr, 0, info.width * info.height * 2);
260 mBlackFrame->crtc_x = 0;
261 mBlackFrame->crtc_y = 0;
262 mBlackFrame->crtc_w = -1;
263 mBlackFrame->crtc_h = -1;
264
265 //post black frame buf to drm
266 if (mDrmHandle && mDrmMesonLib) {
267 rc = mDrmMesonLib->libDrmPostBuf(mDrmHandle, mBlackFrame);
268 }
269 if (rc) {
270 ERROR("post black frame to drm failed");
271 goto tag_error;
272 }
273
274 return;
275tag_error:
276 if (mBlackFrameAddr) {
277 munmap (mBlackFrameAddr, mBlackFrame->width * mBlackFrame->height * 2);
278 mBlackFrameAddr = NULL;
279 }
280 if (mBlackFrame) {
281 if (mDrmMesonLib) {
282 mDrmMesonLib->libDrmFreeBuf(mBlackFrame);
283 }
284
285 mBlackFrame = NULL;
286 }
287 return;
288}
289
290void DrmDisplay::setImmediatelyOutout(bool on)
291{
292 if (mDrmFramePost) {
293 mDrmFramePost->setImmediatelyOutout(on);
294 }
295}
296
297void DrmDisplay::setHideVideo(bool hide) {
298 INFO("hide video:%d",hide);
299 mHideVideo = hide;
300 mIsDropFrames = false;
301}
302
303void DrmDisplay::setKeepLastFrame(bool keep)
304{
305 int kp = keep? 1: 0;
306 mKeepLastFrame = keep;
307
308#ifdef SUPPORT_DRM_FREEZEN
309 if (mDrmHandle) {
310 mDrmHandle->freeze = kp;
311 }
312 INFO("set keep last frame %d(%d)", keep,mDrmHandle->freeze);
313#endif
314}
315
316FrameEntity *DrmDisplay::createFrameEntity(RenderBuffer *buf, int64_t displayTime)
317{
318 struct drm_buf_import info;
319 FrameEntity* frame = NULL;
320 struct drm_buf * drmBuf = NULL;
321
322 frame = (FrameEntity*)calloc(1, sizeof(FrameEntity));
323 if (!frame) {
324 ERROR("oom calloc FrameEntity mem failed");
325 goto tag_error;
326 }
327
328 frame->displayTime = displayTime;
329 frame->renderBuf = buf;
330
331 memset(&info, 0 , sizeof(struct drm_buf_import));
332
333 info.width = buf->dma.width;
334 info.height = buf->dma.height;
335 info.flags = 0;
336 switch (mVideoFormat)
337 {
338 case VIDEO_FORMAT_NV21: {
339 info.fourcc = DRM_FORMAT_NV21;
340 } break;
341 case VIDEO_FORMAT_NV12: {
342 info.fourcc = DRM_FORMAT_NV12;
343 } break;
344
345 default: {
346 info.fourcc = DRM_FORMAT_YUYV;
347 WARNING("unknown video format, set to default YUYV format");
348 }
349 }
350
351 if (!mIsPip) {
352 info.flags |= MESON_USE_VD1;
353 } else {
354 info.flags |= MESON_USE_VD2;
355 }
356
357 /*warning: must dup fd, because drm_free_buf will close buf fd
358 if not dup buf fd, fd will be double free*/
359 for (int i = 0; i < buf->dma.planeCnt; i++) {
360 info.fd[i] = dup(buf->dma.fd[i]);
361 TRACE("dup fd[%d]:%d->%d",i,buf->dma.fd[i],info.fd[i]);
362 }
363
364 if (mDrmHandle && mDrmMesonLib) {
365 drmBuf = mDrmMesonLib->libDrmImportBuf(mDrmHandle, &info);
366 }
367
368 if (!drmBuf) {
369 ERROR("unable drm_import_buf");
370 goto tag_error;
371 }
372
373 //set source content's size
374 drmBuf->src_x = 0;
375 drmBuf->src_y = 0;
376 drmBuf->src_w = buf->dma.width;
377 drmBuf->src_h = buf->dma.height;
378
379 /*default set window size to full screen
380 *if window size set,the crtc size will be reset
381 *before post drm buffer
382 */
383 drmBuf->crtc_x = 0;
384 drmBuf->crtc_y = 0;
385 drmBuf->crtc_w = mDrmHandle->width;
386 drmBuf->crtc_h = mDrmHandle->height;
387#ifdef SUPPORT_DRM_FREEZEN
388 if (mHideVideo) {
389 drmBuf->disable_plane = 1;
390 } else {
391 drmBuf->disable_plane = 0;
392 }
393#endif
394
395 frame->drmBuf = drmBuf;
396 TRACE("crtc(%d,%d,%d,%d),src(%d,%d,%d,%d)",drmBuf->crtc_x,drmBuf->crtc_y,drmBuf->crtc_w,drmBuf->crtc_h,
397 drmBuf->src_x,drmBuf->src_y,drmBuf->src_w,drmBuf->src_h);
398
399 return frame;
400tag_error:
401 for (int i = 0; i < buf->dma.planeCnt; i++) {
402 if (info.fd[i] > 0) {
403 close(info.fd[i]);
404 info.fd[i] = -1;
405 }
406 }
407 if (frame) {
408 free(frame);
409 }
410 return NULL;
411}
412
413void DrmDisplay::destroyFrameEntity(FrameEntity * frameEntity)
414{
415 int rc;
416
417 if (!frameEntity) {
418 return;
419 }
420 if (frameEntity->drmBuf) {
421 if (mDrmMesonLib) {
422 rc = mDrmMesonLib->libDrmFreeBuf(frameEntity->drmBuf);
423 }
424
425 if (rc) {
426 WARNING("drm_free_buf free %p failed",frameEntity->drmBuf);
427 }
428 TRACE("drm_free_buf displaytime:%lld(pts:%lld ms)",frameEntity->displayTime,frameEntity->renderBuf->pts/1000000);
429 }
430 free(frameEntity);
431}
432
433void DrmDisplay::handlePostedFrameEntity(FrameEntity * frameEntity)
434{
435 if (mDrmFrameRecycle) {
436 mDrmFrameRecycle->recycleFrame(frameEntity);
437 }
438}
439
440void DrmDisplay::handleDropedFrameEntity(FrameEntity * frameEntity)
441{
442 if (mPlugin) {
443 mPlugin->handleFrameDropped(frameEntity->renderBuf);
444 }
445}
446
447void DrmDisplay::handleDisplayedFrameEntity(FrameEntity * frameEntity)
448{
449 if (mPlugin) {
450 mPlugin->handleFrameDisplayed(frameEntity->renderBuf);
451 }
452}
453
454void DrmDisplay::handleReleaseFrameEntity(FrameEntity * frameEntity)
455{
456 if (mPlugin) {
457 mPlugin->handleBufferRelease(frameEntity->renderBuf);
458 }
459 destroyFrameEntity(frameEntity);
460}
461
462void DrmDisplay::handleMsg(int type, void *detail)
463{
464 if (mPlugin) {
465 mPlugin->handleMsgNotify(type, detail);
466 }
467}