vdr-plugin-softhddevice-drm-gles 1.5.9-20e15de
grab.cpp
Go to the documentation of this file.
1
23extern "C" {
24#include <libavutil/imgutils.h>
25#include <libswscale/swscale.h>
26}
27
28#include <sys/mman.h>
29
30#include <drm_fourcc.h>
31
32#include "drmbuffer.h"
33#include "grab.h"
34#include "logger.h"
35#include "videorender.h"
36
37/****************************************************************************************
38 * Image data conversion helpers
39 ***************************************************************************************/
40#define OPAQUE 0xff
41#define TRANSPARENT 0x00
42#define UNMULTIPLY(color, alpha) ((0xff * color) / alpha)
43#define BLEND(back, front, alpha) ((front * alpha) + (back * (255 - alpha))) / 255
44
48enum AVPixelFormat DrmFormatToAVFormat(cDrmBuffer *buf)
49{
50 if (buf->PixFmt() == DRM_FORMAT_NV12)
51 return AV_PIX_FMT_NV12;
52
53 if (buf->PixFmt() == DRM_FORMAT_YUV420)
54 return AV_PIX_FMT_YUV420P;
55
56 if (buf->PixFmt() == DRM_FORMAT_ARGB8888)
57 return AV_PIX_FMT_RGBA;
58
59 if (buf->PixFmt() == DRM_FORMAT_P030)
60 return AV_PIX_FMT_NONE;
61
62 return AV_PIX_FMT_NONE;
63}
64
78static uint8_t *BufToRgb(cDrmBuffer *buf, int *size, int dstW, int dstH, enum AVPixelFormat dstPixFmt)
79{
80 uint8_t *srcData[4], *dstData[4];
81 int srcLinesize[4], dstLinesize[4];
82
83 int srcW = buf->Width();
84 int srcH = buf->Height();
85
86 enum AVPixelFormat src_pix_fmt = DrmFormatToAVFormat(buf);
87 if (src_pix_fmt == AV_PIX_FMT_NONE) {
88 LOGERROR("grab: %s: pixel format is not supported!", __FUNCTION__);
89 return NULL;
90 }
91
92 int dstBufsize = 0;
93 struct SwsContext *swsCtx;
94 int ret;
95 void *buffer = NULL;
96
97 // planes aren't mmapped, return
98 // this should be done before in VideoCloneBuf
99 if (!buf->Plane(0)) {
100 LOGERROR("grab: %s: prime data is not mapped!", __FUNCTION__);
101 return NULL;
102 }
103
104 // convert yuv to rgb
105 swsCtx = sws_getContext(srcW, srcH, src_pix_fmt,
106 dstW, dstH, dstPixFmt,
107 SWS_BILINEAR, NULL, NULL, NULL);
108 if (!swsCtx) {
109 LOGERROR("grab: %s: Could not create swsCtx", __FUNCTION__);
110 munmap(buffer, buf->Size(0));
111 return NULL;
112 }
113
114 if ((ret = av_image_alloc(dstData, dstLinesize, dstW, dstH, dstPixFmt, 1)) < 0) {
115 LOGERROR("grab: %s: Could not alloc dst image", __FUNCTION__);
116 munmap(buffer, buf->Size(0));
117 sws_freeContext(swsCtx);
118 return NULL;
119 }
120 dstBufsize = ret;
121
122 // copy src pitches and data
123 for (int i = 0; i < buf->NumPlanes(); i++) {
124 srcLinesize[i] = buf->Pitch(i);
125 srcData[i] = buf->Plane(i) + buf->Offset(i);
126 }
127
128 // scale image
129 sws_scale(swsCtx,
130 (const uint8_t * const*)srcData, srcLinesize, 0, srcH,
131 dstData, dstLinesize);
132
133 if (buffer)
134 munmap(buffer, buf->Size(0));
135 sws_freeContext(swsCtx);
136 *size = dstBufsize;
137
138 LOGDEBUG2(L_GRAB, "grab: %s: return image at %p size %d", __FUNCTION__, dstData[0], dstBufsize);
139 return dstData[0];
140}
141
156static uint8_t *ScaleRgb24(uint8_t *src, int *size, int srcW, int srcH, int dstW, int dstH)
157{
158 struct SwsContext *swsCtx;
159 int dstBufsize = 0;
160 int ret;
161
162 uint8_t *dstData[4];
163 int dstLinesize[4];
164 uint8_t *srcData[4] = {src, NULL, NULL, NULL};
165 int srcLinesize[4] = {3 * srcW, 0, 0, 0};
166
167 swsCtx = sws_getContext(srcW, srcH, AV_PIX_FMT_RGB24,
168 dstW, dstH, AV_PIX_FMT_RGB24,
169 SWS_BILINEAR, NULL, NULL, NULL);
170 if (!swsCtx) {
171 LOGERROR("grab: %s: Could not create swsCtx", __FUNCTION__);
172 return NULL;
173 }
174
175 if ((ret = av_image_alloc(dstData, dstLinesize, dstW, dstH, AV_PIX_FMT_RGB24, 1)) < 0) {
176 LOGERROR("grab: %s: Could not alloc dst image", __FUNCTION__);
177 sws_freeContext(swsCtx);
178 return NULL;
179 }
180 dstBufsize = ret;
181
182 sws_scale(swsCtx,
183 (const uint8_t * const*)srcData, srcLinesize, 0, srcH,
184 dstData, dstLinesize);
185
186 sws_freeContext(swsCtx);
187 *size = dstBufsize;
188
189 LOGDEBUG2(L_GRAB, "grab: %s: return scaled image at %p size %d", __FUNCTION__, dstData[0], dstBufsize);
190 return dstData[0];
191}
192
207static void AlphaBlend(uint8_t *result, uint8_t *front, uint8_t *back, const unsigned int width, const unsigned int height)
208{
209 for (unsigned long index = 0; index < width * height; index++) {
210 const uint8_t frontAlpha = front[3];
211
212 if (frontAlpha == TRANSPARENT) {
213 for (int i = 0; i < 3; i++) {
214 result[i] = back[i];
215 }
216 back += 3;
217 front += 4;
218 result += 3;
219 continue;
220 }
221
222 if (frontAlpha == OPAQUE) {
223 for (int i = 0; i < 3; i++) {
224 result[i] = front[i];
225 }
226 back += 3;
227 front += 4;
228 result += 3;
229 continue;
230 }
231
232 const uint8_t backR = back[0];
233 const uint8_t backG = back[1];
234 const uint8_t backB = back[2];
235
236 const uint8_t frontR = UNMULTIPLY(front[0], frontAlpha);
237 const uint8_t frontG = UNMULTIPLY(front[1], frontAlpha);
238 const uint8_t frontB = UNMULTIPLY(front[2], frontAlpha);
239
240 const uint8_t R = BLEND(backR, frontR, frontAlpha);
241 const uint8_t G = BLEND(backG, frontG, frontAlpha);
242 const uint8_t B = BLEND(backB, frontB, frontAlpha);
243
244 result[0] = R;
245 result[1] = G;
246 result[2] = B;
247
248 back += 3;
249 front += 4;
250 result += 3;
251 }
252}
253
268static int BlitVideo(uint8_t *dst, uint8_t *src, int dstW, int dstH, int dstX, int dstY, int srcW, int srcH)
269{
270 int srcStride = srcW * 3;
271 int dstStride = dstW * 3;
272
273 if ((dstX + srcW > dstW) || (dstY + srcH > dstH)) {
274 LOGDEBUG2(L_GRAB, "grab: %s: wrong dimensions, cropping not supported!", __FUNCTION__);
275 return -1;
276 }
277
278 // blit the (scaled) image into dst
279 for (int y = 0; y < srcH; y++) {
280 memcpy(&dst[((dstY + y) * dstStride + dstX * 3)], &src[y * srcStride], srcStride);
281 }
282
283 return 0;
284}
285
286/*****************************************************************************
287 * cGrabBuffer class
288 ****************************************************************************/
289
294{
295 if (!m_pBuf)
296 return;
297
298 for (int plane = 0; plane < m_pBuf->NumPlanes(); plane++) {
299 if (m_pBuf->Size(plane)) {
300 LOGDEBUG2(L_GRAB, "grab: %s: free buf %p (plane %d)", __FUNCTION__, m_pBuf->Plane(plane), plane);
301 free(m_pBuf->Plane(plane));
302 }
303 }
304 delete m_pBuf;
305
306 m_pBuf = nullptr;
307}
308
313{
314 m_pBuf = buf;
315 m_rect.Set(buf->GetScreenRect().Point(), buf->GetScreenRect().Size());
316}
317
318/*****************************************************************************
319 * cSoftHdGrab class
320 ****************************************************************************/
321
332bool cSoftHdGrab::Start(bool jpeg, int quality, int width, int height, int screenWidth, int screenHeight)
333{
334 if (width == 0 || height == 0) {
335 LOGDEBUG2(L_GRAB, "grab: %s: width and/or height must not be 0!", __FUNCTION__);
336 return false;
337 }
338
339 LOGDEBUG2(L_GRAB, "grab: starting grab for %s image (%dx%d, quality %d)", jpeg ? "jpg" : "pnm", width, height, quality);
340
341 m_isJpeg = jpeg;
342 m_screenWidth = screenWidth;
343 m_screenHeight = screenHeight;
344
345 // Set defaults
346 m_quality = quality < 0 ? 95 : quality;
347 m_grabbedWidth = width > 0 ? width : screenWidth;
348 m_grabbedHeight = height > 0 ? height : screenHeight;
349 m_grabbedImage = nullptr;
350
351 m_isActive = true;
352
353 if (m_pRender->TriggerGrab()) {
355 m_isActive = false;
356 LOGDEBUG2(L_GRAB, "grab: grabbing %s image (%dx%d, quality %d) failed", jpeg ? "jpg" : "pnm", width, height, quality);
357 return false;
358 }
359
360 return ProcessGrab();
361}
362
376uint8_t *cSoftHdGrab::GetGrab(int *size, int *width, int *height, int *x, int *y, Grabtype type)
377{
378 int psize = 0;
379 cGrabBuffer *grab = nullptr;
380
381 switch (type) {
384 break;
387 break;
390 break;
391 default:
392 LOGFATAL("grab: %s no valid type, bug!", __FUNCTION__);
393 }
394
395 cDrmBuffer *buf = grab->GetDrmBuf();
396
397 // early return if buf = NULL
398 if (!buf) {
399 grab->SetData(NULL);
400 grab->SetSize(0);
401 return nullptr;
402 }
403
404 for (int plane = 0; plane < buf->NumPlanes(); plane++) {
405 LOGDEBUG2(L_GRAB, "grab: %s: %s plane %d address %p pitch %d offset %d handle %d size %d", __FUNCTION__,
406 GrabtypeToString(type), plane, buf->Plane(plane), buf->Pitch(plane), buf->Offset(plane), buf->PrimeHandle(plane), buf->Size(plane));
407 }
408 // result's width and height are original dimensions how buffer is presented on the screen
409 uint8_t * result = BufToRgb(buf, &psize, grab->GetWidth(), grab->GetHeight(), type == Grabtype::GRABOSD ? AV_PIX_FMT_BGRA : AV_PIX_FMT_RGB24);
410 grab->SetData(result);
411 grab->SetSize(psize);
412 grab->FreeDrmBuf();
413
414 if (size)
415 *size = grab->GetSize();
416 if (width)
417 *width = grab->GetWidth();
418 if (height)
419 *height = grab->GetHeight();
420 if (x)
421 *x = grab->GetX();
422 if (y)
423 *y = grab->GetY();
424
425 return grab->GetData();
426}
427
431extern "C" uint8_t * CreateJpeg(uint8_t * image, int *size, int quality,
432 int width, int height)
433{
434 return (uint8_t *) RgbToJpeg((uchar *) image, width, height, *size, quality);
435}
436
451{
452 int screenSize = m_screenWidth * m_screenHeight * 3; // we want a RGB24
453
454 int videoSize = 0; // data size of the grabbed video
455 int videoWidth = m_screenWidth; // width of the grabbed video
456 int videoHeight = m_screenHeight; // height of the grabbed video
457 int videoX = 0, videoY = 0; // x, y of the grabbed video
458
459 int pipSize = 0; // data size of the grabbed pip video
460 int pipWidth = m_screenWidth; // width of the grabbed pip video
461 int pipHeight = m_screenHeight; // height of the grabbed pip video
462 int pipX = 0, pipY = 0; // x, y of the grabbed pip video
463
464 // fetch video data
465 // Video comes as RGB, width and height is original screen dimension (video is maybe scaled)
466 uint8_t *video = GetGrab(&videoSize, &videoWidth, &videoHeight, &videoX, &videoY, Grabtype::GRABVIDEO);
467 if (!video) {
468 LOGDEBUG2(L_GRAB, "grab: %s: no video data available, create black screen!", __FUNCTION__);
469 video = (uint8_t *)calloc(1, screenSize);
470 }
471
472 // fetch pip data
473 // Pip video comes as RGB, width and height is original screen dimension (video is maybe scaled)
474 uint8_t *pip = GetGrab(&pipSize, &pipWidth, &pipHeight, &pipX, &pipY, Grabtype::GRABPIP);
475 if (!pip)
476 LOGDEBUG2(L_GRAB, "grab: %s: no pip data available, skip it", __FUNCTION__);
477
478 // fetch osd data
479 // OSD comes as ARGB, width and height is original screen dimension (osd is always fullscreen)
480 uint8_t *osd = GetGrab(NULL, NULL, NULL, NULL, NULL, Grabtype::GRABOSD);
481 if (!osd)
482 LOGDEBUG2(L_GRAB, "grab: %s: no osd data available, skip it", __FUNCTION__);
483
484 // blit the video into a full black screen if scaled
485 uint8_t *videoResult = video;
486
487 bool needsScaling = (videoWidth != m_screenWidth || videoHeight != m_screenHeight || videoX != 0 || videoY != 0);
488 if (needsScaling) {
489 videoResult = (uint8_t *)calloc(1, screenSize);
490 if (BlitVideo(videoResult, video, m_screenWidth, m_screenHeight, videoX, videoY, videoWidth, videoHeight)) {
491 free(videoResult);
492 free(video);
493 m_isActive = false;
494 LOGDEBUG2(L_GRAB, "grab: grab failed during VIDEO blit");
495 return false;
496 }
497 free(video);
498 }
499
500 // blit the pip video into the main video if available
501 if (pip) {
502 if (BlitVideo(videoResult, pip, m_screenWidth, m_screenHeight, pipX, pipY, pipWidth, pipHeight)) {
503 free(videoResult);
504 free(pip);
505 m_isActive = false;
506 LOGDEBUG2(L_GRAB, "grab: grab failed during PIP blit");
507 return false;
508 }
509 free(pip);
510 }
511
512 // alphablend fullscreen video/pip with osd if available
513 uint8_t *result = videoResult;
514 if (osd) {
515 result = (uint8_t *)malloc(screenSize);
516 AlphaBlend(result, osd, videoResult, m_screenWidth, m_screenHeight);
517 free(videoResult);
518 free(osd);
519 }
520
521 // scale result to requested size width + height, if it differs from fullscreen
522 uint8_t *scaledResult = result;
523 int scaledSize = screenSize;
524
526 if (needsScaling) {
527 scaledResult = ScaleRgb24(result, &scaledSize, m_screenWidth, m_screenHeight, m_grabbedWidth, m_grabbedHeight);
528 free(result);
529 }
530
531 // make jpeg or pnm
532 if (m_isJpeg) {
534 } else { // add header to raw data
535 char buf[64];
536 int n = snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n", m_grabbedWidth, m_grabbedHeight);
537 m_grabbedImage = (uint8_t *)malloc(scaledSize + n);
538 memcpy(m_grabbedImage, buf, n);
539 memcpy(m_grabbedImage + n, scaledResult, scaledSize);
540 m_grabbedSize = scaledSize + n;
541 }
542
543 free(scaledResult);
544 m_isActive = false;
545
546 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);
547
548 return true;
549}
uint32_t Pitch(int idx)
Definition drmbuffer.h:93
uint32_t Width(void)
Definition drmbuffer.h:64
uint32_t Height(void)
Definition drmbuffer.h:66
uint8_t * Plane(int idx)
Definition drmbuffer.h:86
int NumPlanes(void)
Definition drmbuffer.h:80
cRect GetScreenRect(void)
Definition drmbuffer.h:103
uint32_t Size(int idx)
Definition drmbuffer.h:96
uint32_t PrimeHandle(int idx)
Definition drmbuffer.h:87
uint32_t PixFmt(void)
Definition drmbuffer.h:68
uint32_t Offset(int idx)
Definition drmbuffer.h:90
cGrabBuffer - Grab buffer class
Definition grab.h:53
void SetData(uint8_t *result)
Definition grab.h:61
void SetSize(int size)
Definition grab.h:62
uint8_t * GetData(void)
Definition grab.h:68
cRect m_rect
rect of the grabbed data
Definition grab.h:75
int GetHeight(void)
Definition grab.h:67
void FreeDrmBuf(void)
Free the grab buffer.
Definition grab.cpp:293
int GetSize(void)
Definition grab.h:69
int GetWidth(void)
Definition grab.h:66
void SetDrmBuf(cDrmBuffer *)
Set the grab buffer and the dimensions how it is presented on the screen.
Definition grab.cpp:312
struct cDrmBuffer * m_pBuf
pointer to original buffer
Definition grab.h:73
int GetY(void)
Definition grab.h:65
cDrmBuffer * GetDrmBuf(void)
Definition grab.h:70
int GetX(void)
Definition grab.h:64
int m_screenWidth
Definition grab.h:101
int m_quality
Definition grab.h:98
uint8_t * m_grabbedImage
Definition grab.h:93
int m_grabbedWidth
Definition grab.h:99
int m_screenHeight
Definition grab.h:102
uint8_t * GetGrab(int *, int *, int *, int *, int *, Grabtype)
Convert the cloned drm buffer data to RGB(void, pip) or ARGB (osd) and returns a pointer to the raw d...
Definition grab.cpp:376
bool Start(bool, int, int, int, int, int)
Start a grab in the video renderer.
Definition grab.cpp:332
bool m_isActive
Definition grab.h:95
int m_grabbedSize
Definition grab.h:94
bool m_isJpeg
Definition grab.h:97
bool ProcessGrab(void)
Start the conversion.
Definition grab.cpp:450
int m_grabbedHeight
Definition grab.h:100
cVideoRender * m_pRender
Definition grab.h:92
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.
#define UNMULTIPLY(color, alpha)
Definition grab.cpp:42
#define BLEND(back, front, alpha)
Definition grab.cpp:43
static uint8_t * ScaleRgb24(uint8_t *src, int *size, int srcW, int srcH, int dstW, int dstH)
Scale an image.
Definition grab.cpp:156
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:78
enum AVPixelFormat DrmFormatToAVFormat(cDrmBuffer *buf)
Convert a DRM format to a ffmpeg AV format.
Definition grab.cpp:48
#define TRANSPARENT
Definition grab.cpp:41
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:268
uint8_t * CreateJpeg(uint8_t *image, int *size, int quality, int width, int height)
Call rgb to jpeg for C Plugin.
Definition grab.cpp:431
#define OPAQUE
Definition grab.cpp:40
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:207
Grabber header file.
Grabtype
Definition grab.h:27
@ GRABPIP
Definition grab.h:29
@ GRABOSD
Definition grab.h:30
@ GRABVIDEO
Definition grab.h:28
const char * GrabtypeToString(Grabtype t)
Definition grab.h:33
Logger class header file.
#define LOGDEBUG2
Definition logger.h:45
#define LOGERROR
Definition logger.h:41
#define L_GRAB
Definition logger.h:66
#define LOGFATAL
Logger macros.
Definition logger.h:40
Rendering class header file.