vdr-plugin-softhddevice-drm-gles 1.6.4-d0291bb
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
286extern "C" uint8_t * CreateJpeg(uint8_t * image, int *size, int quality,
287 int width, int height)
288{
289 return (uint8_t *) RgbToJpeg((uchar *) image, width, height, *size, quality);
290}
291
294/*****************************************************************************
295 * cGrabBuffer class
296 ****************************************************************************/
297
302{
303 if (!m_pBuf)
304 return;
305
306 for (int plane = 0; plane < m_pBuf->NumPlanes(); plane++) {
307 if (m_pBuf->Size(plane)) {
308 LOGDEBUG2(L_GRAB, "grab: %s: free buf %p (plane %d)", __FUNCTION__, m_pBuf->Plane(plane), plane);
309 free(m_pBuf->Plane(plane));
310 }
311 }
312 delete m_pBuf;
313
314 m_pBuf = nullptr;
315}
316
321{
322 m_pBuf = buf;
323 m_rect.Set(buf->GetScreenRect().Point(), buf->GetScreenRect().Size());
324}
325
326/*****************************************************************************
327 * cSoftHdGrab class
328 ****************************************************************************/
329
340bool cSoftHdGrab::Start(bool jpeg, int quality, int width, int height, int screenWidth, int screenHeight)
341{
342 if (width == 0 || height == 0) {
343 LOGDEBUG2(L_GRAB, "grab: %s: width and/or height must not be 0!", __FUNCTION__);
344 return false;
345 }
346
347 LOGDEBUG2(L_GRAB, "grab: starting grab for %s image (%dx%d, quality %d)", jpeg ? "jpg" : "pnm", width, height, quality);
348
349 m_isJpeg = jpeg;
352
353 // Set defaults
354 m_quality = quality < 0 ? 95 : quality;
355 m_grabbedWidth = width > 0 ? width : screenWidth;
356 m_grabbedHeight = height > 0 ? height : screenHeight;
357 m_grabbedImage = nullptr;
358
359 m_isActive = true;
360
361 if (m_pRender->TriggerGrab()) {
363 m_isActive = false;
364 LOGDEBUG2(L_GRAB, "grab: grabbing %s image (%dx%d, quality %d) failed", jpeg ? "jpg" : "pnm", width, height, quality);
365 return false;
366 }
367
368 return ProcessGrab();
369}
370
384uint8_t *cSoftHdGrab::GetGrab(int *size, int *width, int *height, int *x, int *y, Grabtype type)
385{
386 int psize = 0;
387 cGrabBuffer *grab = nullptr;
388
389 switch (type) {
392 break;
395 break;
398 break;
399 default:
400 LOGFATAL("grab: %s no valid type, bug!", __FUNCTION__);
401 }
402
403 cDrmBuffer *buf = grab->GetDrmBuf();
404
405 // early return if buf = NULL
406 if (!buf) {
407 grab->SetData(NULL);
408 grab->SetSize(0);
409 return nullptr;
410 }
411
412 for (int plane = 0; plane < buf->NumPlanes(); plane++) {
413 LOGDEBUG2(L_GRAB, "grab: %s: %s plane %d address %p pitch %d offset %d handle %d size %d", __FUNCTION__,
414 GrabtypeToString(type), plane, buf->Plane(plane), buf->Pitch(plane), buf->Offset(plane), buf->PrimeHandle(plane), buf->Size(plane));
415 }
416 // result's width and height are original dimensions how buffer is presented on the screen
417 uint8_t * result = BufToRgb(buf, &psize, grab->GetWidth(), grab->GetHeight(), type == Grabtype::GRABOSD ? AV_PIX_FMT_BGRA : AV_PIX_FMT_RGB24);
418 grab->SetData(result);
419 grab->SetSize(psize);
420 grab->FreeDrmBuf();
421
422 if (size)
423 *size = grab->GetSize();
424 if (width)
425 *width = grab->GetWidth();
426 if (height)
427 *height = grab->GetHeight();
428 if (x)
429 *x = grab->GetX();
430 if (y)
431 *y = grab->GetY();
432
433 return grab->GetData();
434}
435
450{
451 int screenSize = m_screenWidth * m_screenHeight * 3; // we want a RGB24
452
453 int videoSize = 0; // data size of the grabbed video
454 int videoWidth = m_screenWidth; // width of the grabbed video
455 int videoHeight = m_screenHeight; // height of the grabbed video
456 int videoX = 0, videoY = 0; // x, y of the grabbed video
457
458 int pipSize = 0; // data size of the grabbed pip video
459 int pipWidth = m_screenWidth; // width of the grabbed pip video
460 int pipHeight = m_screenHeight; // height of the grabbed pip video
461 int pipX = 0, pipY = 0; // x, y of the grabbed pip video
462
463 // fetch video data
464 // Video comes as RGB, width and height is original screen dimension (video is maybe scaled)
466 if (!video) {
467 LOGDEBUG2(L_GRAB, "grab: %s: no video data available, create black screen!", __FUNCTION__);
468 video = (uint8_t *)calloc(1, screenSize);
469 }
470
471 // fetch pip data
472 // Pip video comes as RGB, width and height is original screen dimension (video is maybe scaled)
474 if (!pip)
475 LOGDEBUG2(L_GRAB, "grab: %s: no pip data available, skip it", __FUNCTION__);
476
477 // fetch osd data
478 // OSD comes as ARGB, width and height is original screen dimension (osd is always fullscreen)
480 if (!osd)
481 LOGDEBUG2(L_GRAB, "grab: %s: no osd data available, skip it", __FUNCTION__);
482
483 // blit the video into a full black screen if scaled
484 uint8_t *videoResult = video;
485
487 if (needsScaling) {
491 free(video);
492 m_isActive = false;
493 LOGDEBUG2(L_GRAB, "grab: grab failed during VIDEO blit");
494 return false;
495 }
496 free(video);
497 }
498
499 // blit the pip video into the main video if available
500 if (pip) {
503 free(pip);
504 m_isActive = false;
505 LOGDEBUG2(L_GRAB, "grab: grab failed during PIP blit");
506 return false;
507 }
508 free(pip);
509 }
510
511 // alphablend fullscreen video/pip with osd if available
513 if (osd) {
517 free(osd);
518 }
519
520 // scale result to requested size width + height, if it differs from fullscreen
523
525 if (needsScaling) {
527 free(result);
528 }
529
530 // make jpeg or pnm
531 if (m_isJpeg) {
533 } else { // add header to raw data
534 char buf[64];
535 int n = snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n", m_grabbedWidth, m_grabbedHeight);
540 }
541
543 m_isActive = false;
544
545 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);
546
547 return true;
548}
DRM Buffer.
Definition drmbuffer.h:46
Grabbing Buffer.
Definition grab.h:53
cRect m_rect
rect of the grabbed data
Definition grab.h:75
void FreeDrmBuf(void)
Free the grabbed drm buffer.
Definition grab.cpp:301
void SetDrmBuf(cDrmBuffer *)
Set the grab buffer and the dimensions how it is presented on the screen.
Definition grab.cpp:320
struct cDrmBuffer * m_pBuf
pointer to original buffer
Definition grab.h:73
int m_screenWidth
pixel screenwidth
Definition grab.h:104
int m_quality
quality of the jpeg image
Definition grab.h:101
uint8_t * m_grabbedImage
pointer to the finished grabbed image
Definition grab.h:96
int m_grabbedWidth
pixel width of the grabbed image
Definition grab.h:102
int m_screenHeight
pixel screenheight
Definition grab.h:105
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:384
bool Start(bool, int, int, int, int, int)
Start a grab in the video renderer.
Definition grab.cpp:340
bool m_isActive
true, if a grab process is currently running
Definition grab.h:98
int m_grabbedSize
data size of the grabbed image
Definition grab.h:97
bool m_isJpeg
true, if a jpeg image was requested
Definition grab.h:100
bool ProcessGrab(void)
Start the conversion.
Definition grab.cpp:449
int m_grabbedHeight
pixel height of the grabbed image
Definition grab.h:103
cVideoRender * m_pRender
pointer to cVideoRender object
Definition grab.h:95
cGrabBuffer * GetGrabbedPipBuffer(void)
cGrabBuffer * GetGrabbedVideoBuffer(void)
cGrabBuffer * GetGrabbedOsdBuffer(void)
int TriggerGrab(void)
Trigger a screen grab.
void ClearGrabBuffers(void)
Clear the grab drm buffers.
DRM Buffer Header File.
int plane
Grabbing Interface Header File.
#define UNMULTIPLY(color, alpha)
Definition grab.cpp:39
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:47
#define BLEND(back, front, alpha)
Definition grab.cpp:40
#define LOGERROR
log to LOG_ERR
Definition logger.h:39
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
enum AVPixelFormat DrmFormatToAVFormat(cDrmBuffer *buf)
Convert a DRM format to a ffmpeg AV format.
Definition grab.cpp:45
#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
uint8_t * CreateJpeg(uint8_t *image, int *size, int quality, int width, int height)
Call rgb to jpeg for C Plugin.
Definition grab.cpp:286
#define OPAQUE
Definition grab.cpp:37
#define LOGFATAL
log to LOG_ERR and abort
Definition logger.h:37
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:69
Logger Header File.
Video Renderer (Display) Header File.