vdr-plugin-softhddevice-drm-gles 1.6.2
grab.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
15extern "C" {
16#include <libavutil/imgutils.h>
17#include <libswscale/swscale.h>
18}
19
20#include <sys/mman.h>
21
22#include <drm_fourcc.h>
23
24#include "drmbuffer.h"
25#include "grab.h"
26#include "logger.h"
27#include "videorender.h"
28
34/****************************************************************************************
35 * Image data conversion helpers
36 ***************************************************************************************/
37#define OPAQUE 0xff
38#define TRANSPARENT 0x00
39#define UNMULTIPLY(color, alpha) ((0xff * color) / alpha)
40#define BLEND(back, front, alpha) ((front * alpha) + (back * (255 - alpha))) / 255
41
46{
47 if (buf->PixFmt() == DRM_FORMAT_NV12)
48 return AV_PIX_FMT_NV12;
49
50 if (buf->PixFmt() == DRM_FORMAT_YUV420)
51 return AV_PIX_FMT_YUV420P;
52
53 if (buf->PixFmt() == DRM_FORMAT_ARGB8888)
54 return AV_PIX_FMT_RGBA;
55
56 if (buf->PixFmt() == DRM_FORMAT_P030)
57 return AV_PIX_FMT_NONE;
58
59 return AV_PIX_FMT_NONE;
60}
61
75static uint8_t *BufToRgb(cDrmBuffer *buf, int *size, int dstW, int dstH, enum AVPixelFormat dstPixFmt)
76{
77 uint8_t *srcData[4], *dstData[4];
78 int srcLinesize[4], dstLinesize[4];
79
80 int srcW = buf->Width();
81 int srcH = buf->Height();
82
85 LOGERROR("grab: %s: pixel format is not supported!", __FUNCTION__);
86 return NULL;
87 }
88
89 int dstBufsize = 0;
90 struct SwsContext *swsCtx;
91 int ret;
92 void *buffer = NULL;
93
94 // planes aren't mmapped, return
95 // this should be done before in VideoCloneBuf
96 if (!buf->Plane(0)) {
97 LOGERROR("grab: %s: prime data is not mapped!", __FUNCTION__);
98 return NULL;
99 }
100
101 // convert yuv to rgb
105 if (!swsCtx) {
106 LOGERROR("grab: %s: Could not create swsCtx", __FUNCTION__);
107 munmap(buffer, buf->Size(0));
108 return NULL;
109 }
110
112 LOGERROR("grab: %s: Could not alloc dst image", __FUNCTION__);
113 munmap(buffer, buf->Size(0));
115 return NULL;
116 }
117 dstBufsize = ret;
118
119 // copy src pitches and data
120 for (int i = 0; i < buf->NumPlanes(); i++) {
121 srcLinesize[i] = buf->Pitch(i);
122 srcData[i] = buf->Plane(i) + buf->Offset(i);
123 }
124
125 // scale image
127 (const uint8_t * const*)srcData, srcLinesize, 0, srcH,
129
130 if (buffer)
131 munmap(buffer, buf->Size(0));
133 *size = dstBufsize;
134
135 LOGDEBUG2(L_GRAB, "grab: %s: return image at %p size %d", __FUNCTION__, dstData[0], dstBufsize);
136 return dstData[0];
137}
138
153static uint8_t *ScaleRgb24(uint8_t *src, int *size, int srcW, int srcH, int dstW, int dstH)
154{
155 struct SwsContext *swsCtx;
156 int dstBufsize = 0;
157 int ret;
158
159 uint8_t *dstData[4];
160 int dstLinesize[4];
161 uint8_t *srcData[4] = {src, NULL, NULL, NULL};
162 int srcLinesize[4] = {3 * srcW, 0, 0, 0};
163
167 if (!swsCtx) {
168 LOGERROR("grab: %s: Could not create swsCtx", __FUNCTION__);
169 return NULL;
170 }
171
173 LOGERROR("grab: %s: Could not alloc dst image", __FUNCTION__);
175 return NULL;
176 }
177 dstBufsize = ret;
178
180 (const uint8_t * const*)srcData, srcLinesize, 0, srcH,
182
184 *size = dstBufsize;
185
186 LOGDEBUG2(L_GRAB, "grab: %s: return scaled image at %p size %d", __FUNCTION__, dstData[0], dstBufsize);
187 return dstData[0];
188}
189
204static void AlphaBlend(uint8_t *result, uint8_t *front, uint8_t *back, const unsigned int width, const unsigned int height)
205{
206 for (unsigned long index = 0; index < width * height; index++) {
207 const uint8_t frontAlpha = front[3];
208
209 if (frontAlpha == TRANSPARENT) {
210 for (int i = 0; i < 3; i++) {
211 result[i] = back[i];
212 }
213 back += 3;
214 front += 4;
215 result += 3;
216 continue;
217 }
218
219 if (frontAlpha == OPAQUE) {
220 for (int i = 0; i < 3; i++) {
221 result[i] = front[i];
222 }
223 back += 3;
224 front += 4;
225 result += 3;
226 continue;
227 }
228
229 const uint8_t backR = back[0];
230 const uint8_t backG = back[1];
231 const uint8_t backB = back[2];
232
236
240
241 result[0] = R;
242 result[1] = G;
243 result[2] = B;
244
245 back += 3;
246 front += 4;
247 result += 3;
248 }
249}
250
265static int BlitVideo(uint8_t *dst, uint8_t *src, int dstW, int dstH, int dstX, int dstY, int srcW, int srcH)
266{
267 int srcStride = srcW * 3;
268 int dstStride = dstW * 3;
269
270 if ((dstX + srcW > dstW) || (dstY + srcH > dstH)) {
271 LOGDEBUG2(L_GRAB, "grab: %s: wrong dimensions, cropping not supported!", __FUNCTION__);
272 return -1;
273 }
274
275 // blit the (scaled) image into dst
276 for (int y = 0; y < srcH; y++) {
277 memcpy(&dst[((dstY + y) * dstStride + dstX * 3)], &src[y * srcStride], srcStride);
278 }
279
280 return 0;
281}
282
283/*****************************************************************************
284 * cGrabBuffer class
285 ****************************************************************************/
286
291{
292 if (!m_pBuf)
293 return;
294
295 for (int plane = 0; plane < m_pBuf->NumPlanes(); plane++) {
296 if (m_pBuf->Size(plane)) {
297 LOGDEBUG2(L_GRAB, "grab: %s: free buf %p (plane %d)", __FUNCTION__, m_pBuf->Plane(plane), plane);
298 free(m_pBuf->Plane(plane));
299 }
300 }
301 delete m_pBuf;
302
303 m_pBuf = nullptr;
304}
305
310{
311 m_pBuf = buf;
312 m_rect.Set(buf->GetScreenRect().Point(), buf->GetScreenRect().Size());
313}
314
315/*****************************************************************************
316 * cSoftHdGrab class
317 ****************************************************************************/
318
329bool cSoftHdGrab::Start(bool jpeg, int quality, int width, int height, int screenWidth, int screenHeight)
330{
331 if (width == 0 || height == 0) {
332 LOGDEBUG2(L_GRAB, "grab: %s: width and/or height must not be 0!", __FUNCTION__);
333 return false;
334 }
335
336 LOGDEBUG2(L_GRAB, "grab: starting grab for %s image (%dx%d, quality %d)", jpeg ? "jpg" : "pnm", width, height, quality);
337
338 m_isJpeg = jpeg;
341
342 // Set defaults
343 m_quality = quality < 0 ? 95 : quality;
344 m_grabbedWidth = width > 0 ? width : screenWidth;
345 m_grabbedHeight = height > 0 ? height : screenHeight;
346 m_grabbedImage = nullptr;
347
348 m_isActive = true;
349
350 if (m_pRender->TriggerGrab()) {
352 m_isActive = false;
353 LOGDEBUG2(L_GRAB, "grab: grabbing %s image (%dx%d, quality %d) failed", jpeg ? "jpg" : "pnm", width, height, quality);
354 return false;
355 }
356
357 return ProcessGrab();
358}
359
373uint8_t *cSoftHdGrab::GetGrab(int *size, int *width, int *height, int *x, int *y, Grabtype type)
374{
375 int psize = 0;
376 cGrabBuffer *grab = nullptr;
377
378 switch (type) {
381 break;
384 break;
387 break;
388 default:
389 LOGFATAL("grab: %s no valid type, bug!", __FUNCTION__);
390 }
391
392 cDrmBuffer *buf = grab->GetDrmBuf();
393
394 // early return if buf = NULL
395 if (!buf) {
396 grab->SetData(NULL);
397 grab->SetSize(0);
398 return nullptr;
399 }
400
401 for (int plane = 0; plane < buf->NumPlanes(); plane++) {
402 LOGDEBUG2(L_GRAB, "grab: %s: %s plane %d address %p pitch %d offset %d handle %d size %d", __FUNCTION__,
403 GrabtypeToString(type), plane, buf->Plane(plane), buf->Pitch(plane), buf->Offset(plane), buf->PrimeHandle(plane), buf->Size(plane));
404 }
405 // result's width and height are original dimensions how buffer is presented on the screen
406 uint8_t * result = BufToRgb(buf, &psize, grab->GetWidth(), grab->GetHeight(), type == Grabtype::GRABOSD ? AV_PIX_FMT_BGRA : AV_PIX_FMT_RGB24);
407 grab->SetData(result);
408 grab->SetSize(psize);
409 grab->FreeDrmBuf();
410
411 if (size)
412 *size = grab->GetSize();
413 if (width)
414 *width = grab->GetWidth();
415 if (height)
416 *height = grab->GetHeight();
417 if (x)
418 *x = grab->GetX();
419 if (y)
420 *y = grab->GetY();
421
422 return grab->GetData();
423}
424
428extern "C" uint8_t * CreateJpeg(uint8_t * image, int *size, int quality,
429 int width, int height)
430{
431 return (uint8_t *) RgbToJpeg((uchar *) image, width, height, *size, quality);
432}
433
448{
449 int screenSize = m_screenWidth * m_screenHeight * 3; // we want a RGB24
450
451 int videoSize = 0; // data size of the grabbed video
452 int videoWidth = m_screenWidth; // width of the grabbed video
453 int videoHeight = m_screenHeight; // height of the grabbed video
454 int videoX = 0, videoY = 0; // x, y of the grabbed video
455
456 int pipSize = 0; // data size of the grabbed pip video
457 int pipWidth = m_screenWidth; // width of the grabbed pip video
458 int pipHeight = m_screenHeight; // height of the grabbed pip video
459 int pipX = 0, pipY = 0; // x, y of the grabbed pip video
460
461 // fetch video data
462 // Video comes as RGB, width and height is original screen dimension (video is maybe scaled)
464 if (!video) {
465 LOGDEBUG2(L_GRAB, "grab: %s: no video data available, create black screen!", __FUNCTION__);
466 video = (uint8_t *)calloc(1, screenSize);
467 }
468
469 // fetch pip data
470 // Pip video comes as RGB, width and height is original screen dimension (video is maybe scaled)
472 if (!pip)
473 LOGDEBUG2(L_GRAB, "grab: %s: no pip data available, skip it", __FUNCTION__);
474
475 // fetch osd data
476 // OSD comes as ARGB, width and height is original screen dimension (osd is always fullscreen)
478 if (!osd)
479 LOGDEBUG2(L_GRAB, "grab: %s: no osd data available, skip it", __FUNCTION__);
480
481 // blit the video into a full black screen if scaled
482 uint8_t *videoResult = video;
483
485 if (needsScaling) {
489 free(video);
490 m_isActive = false;
491 LOGDEBUG2(L_GRAB, "grab: grab failed during VIDEO blit");
492 return false;
493 }
494 free(video);
495 }
496
497 // blit the pip video into the main video if available
498 if (pip) {
501 free(pip);
502 m_isActive = false;
503 LOGDEBUG2(L_GRAB, "grab: grab failed during PIP blit");
504 return false;
505 }
506 free(pip);
507 }
508
509 // alphablend fullscreen video/pip with osd if available
511 if (osd) {
515 free(osd);
516 }
517
518 // scale result to requested size width + height, if it differs from fullscreen
521
523 if (needsScaling) {
525 free(result);
526 }
527
528 // make jpeg or pnm
529 if (m_isJpeg) {
531 } else { // add header to raw data
532 char buf[64];
533 int n = snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n", m_grabbedWidth, m_grabbedHeight);
538 }
539
541 m_isActive = false;
542
543 LOGDEBUG2(L_GRAB, "grab: finished %s image (%dx%d, quality %d) at %p (size %d)", m_isJpeg ? "jpg" : "pnm", m_grabbedWidth, m_grabbedHeight, m_isJpeg ? m_quality : 0, m_grabbedImage, m_grabbedSize);
544
545 return true;
546}
547
DRM Buffer.
Definition drmbuffer.h:47
Grabbing Buffer.
Definition grab.h:49
cRect m_rect
rect of the grabbed data
Definition grab.h:71
struct cDrmBuffer * m_pBuf
pointer to original buffer
Definition grab.h:69
int m_screenWidth
pixel screenwidth
Definition grab.h:98
int m_quality
quality of the jpeg image
Definition grab.h:95
uint8_t * m_grabbedImage
pointer to the finished grabbed image
Definition grab.h:90
int m_grabbedWidth
pixel width of the grabbed image
Definition grab.h:96
int m_screenHeight
pixel screenheight
Definition grab.h:99
bool m_isActive
true, if a grab process is currently running
Definition grab.h:92
int m_grabbedSize
data size of the grabbed image
Definition grab.h:91
bool m_isJpeg
true, if a jpeg image was requested
Definition grab.h:94
int m_grabbedHeight
pixel height of the grabbed image
Definition grab.h:97
cVideoRender * m_pRender
pointer to cVideoRender object
Definition grab.h:89
cGrabBuffer * GetGrabbedPipBuffer(void)
cGrabBuffer * GetGrabbedVideoBuffer(void)
cGrabBuffer * GetGrabbedOsdBuffer(void)
DRM Buffer Header File.
Grabbing Interface Header File.
int plane
#define UNMULTIPLY(color, alpha)
Definition grab.cpp:39
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:42
#define BLEND(back, front, alpha)
Definition grab.cpp:40
#define LOGERROR
log to LOG_ERR
Definition logger.h:34
static uint8_t * ScaleRgb24(uint8_t *src, int *size, int srcW, int srcH, int dstW, int dstH)
Scale an image.
Definition grab.cpp:153
static uint8_t * BufToRgb(cDrmBuffer *buf, int *size, int dstW, int dstH, enum AVPixelFormat dstPixFmt)
Convert a DRM buffer to rgb format image.
Definition grab.cpp:75
uint8_t * GetGrab(int *, int *, int *, int *, int *, Grabtype)
Convert the cloned drm buffer data to RGB(void, pip) or ARGB (osd) and return a pointer to the raw da...
Definition grab.cpp:373
enum AVPixelFormat DrmFormatToAVFormat(cDrmBuffer *buf)
Convert a DRM format to a ffmpeg AV format.
Definition grab.cpp:45
bool Start(bool, int, int, int, int, int)
Start a grab in the video renderer.
Definition grab.cpp:329
void FreeDrmBuf(void)
Free the grabbed drm buffer.
Definition grab.cpp:290
#define TRANSPARENT
Definition grab.cpp:38
static int BlitVideo(uint8_t *dst, uint8_t *src, int dstW, int dstH, int dstX, int dstY, int srcW, int srcH)
Blit the video on black background.
Definition grab.cpp:265
void SetDrmBuf(cDrmBuffer *)
Set the grab buffer and the dimensions how it is presented on the screen.
Definition grab.cpp:309
uint8_t * CreateJpeg(uint8_t *image, int *size, int quality, int width, int height)
Call rgb to jpeg for C Plugin.
Definition grab.cpp:428
#define OPAQUE
Definition grab.cpp:37
bool ProcessGrab(void)
Start the conversion.
Definition grab.cpp:447
#define LOGFATAL
log to LOG_ERR and abort
Definition logger.h:32
static void AlphaBlend(uint8_t *result, uint8_t *front, uint8_t *back, const unsigned int width, const unsigned int height)
Blend two images.
Definition grab.cpp:204
Grabtype
Definition grab.h:27
const char * GrabtypeToString(Grabtype t)
Definition grab.h:33
@ GRABPIP
Definition grab.h:29
@ GRABOSD
Definition grab.h:30
@ GRABVIDEO
Definition grab.h:28
@ L_GRAB
grabbing logs
Definition logger.h:64
int TriggerGrab(void)
Trigger a screen grab.
void ClearGrabBuffers(void)
Clear the grab drm buffers.
Logger Header File.
Video Renderer (Display) Header File.