GCC Code Coverage Report


Directory: ./
File: channeloutput/VirtualDisplayBase.h
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 10 54 18.5%
Functions: 1 1 100.0%
Branches: 8 34 23.5%

Line Branch Exec Source
1 #pragma once
2 /*
3 * This file is part of the Falcon Player (FPP) and is Copyright (C)
4 * 2013-2022 by the Falcon Player Developers.
5 *
6 * The Falcon Player (FPP) is free software, and is covered under
7 * multiple Open Source licenses. Please see the included 'LICENSES'
8 * file for descriptions of what files are covered by each license.
9 *
10 * This source file is covered under the LGPL v2.1 as described in the
11 * included LICENSE.LGPL file.
12 */
13
14 #include <string>
15 #include "fpp-json-fwd.h"
16 #include <vector>
17
18 #include "ChannelOutput.h"
19
20 typedef enum virtualPixelColor {
21 kVPC_RGB,
22 kVPC_RBG,
23 kVPC_GRB,
24 kVPC_GBR,
25 kVPC_BRG,
26 kVPC_BGR,
27 kVPC_RGBW,
28 kVPC_Red,
29 kVPC_White,
30 kVPC_Blue,
31 kVPC_Green,
32 kVPC_Custom,
33 } VirtualPixelColor;
34
35 typedef struct virtualDisplayPixel {
36 int x;
37 int y;
38 int z;
39 int xs;
40 int ys;
41 int zs;
42 int ch;
43 int r;
44 int g;
45 int b;
46 int cpp;
47 unsigned char customR;
48 unsigned char customG;
49 unsigned char customB;
50
51 VirtualPixelColor vpc;
52 } VirtualDisplayPixel;
53
54 class VirtualDisplayBaseOutput : public ChannelOutput {
55 public:
56 VirtualDisplayBaseOutput(unsigned int startChannel, unsigned int channelCount);
57 virtual ~VirtualDisplayBaseOutput();
58
59 virtual int Init(Json::Value config) override;
60
61 int InitializePixelMap(void);
62 int ScaleBackgroundImage(std::string& bgFile, std::string& rgbFile);
63 void LoadBackgroundImage(void);
64
65 void GetPixelRGB(VirtualDisplayPixel& pixel, unsigned char* channelData,
66 unsigned char& r, unsigned char& g, unsigned char& b);
67 void DrawPixel(int rOffset, int gOffset, int bOffset,
68 unsigned char r, unsigned char g, unsigned char b);
69 virtual void DrawPixels(unsigned char* channelData);
70
71 virtual void DumpConfig(void) override;
72
73 virtual void GetRequiredChannelRanges(const std::function<void(int, int)>& addRange) override;
74
75 std::string m_backgroundFilename;
76 float m_backgroundBrightness;
77 int m_width;
78 int m_height;
79 int m_bytesPerPixel;
80 int m_bpp;
81 float m_scale;
82 int m_previewWidth;
83 int m_previewHeight;
84 std::string m_fitTo;
85 std::string m_colorOrder;
86 unsigned char* m_virtualDisplay;
87 int m_pixelSize;
88
89 uint16_t*** m_rgb565map;
90
91 std::vector<VirtualDisplayPixel> m_pixels;
92
93 protected:
94 // Byte size of a w*h buffer at bpp bytes per pixel, or 0 when the
95 // dimensions cannot form one (non-positive, or the product would overflow
96 // a signed int -- every downstream offset multiplies the same factors, so
97 // capping the total at INT_MAX keeps all of that arithmetic safe too).
98 // Callers fail init instead of heap-smashing. Static: no vtable/object
99 // impact on plugin-facing classes.
100 static size_t virtualDisplayBufferBytes(int w, int h, int bpp);
101
102 public:
103 // Historically public: external channel-output plugins may reference this
104 // directly, so it stays public while the helper above stays protected.
105 bool m_allowDuplicatePixels; // Set to true for 3D mode where multiple pixels can be at same coords
106 };
107
108 1536543 inline void VirtualDisplayBaseOutput::GetPixelRGB(VirtualDisplayPixel& pixel,
109 unsigned char* channelData, unsigned char& r, unsigned char& g, unsigned char& b) {
110 // every path below sets all three; a combination none of them handles
111 // shows black rather than whatever the caller's variables held (the last
112 // pixel's colour, or uninitialised stack)
113 1536543 r = g = b = 0;
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1536543 times.
1536543 if (pixel.vpc == kVPC_Custom) {
115 ✗ r = pixel.customR;
116 ✗ g = pixel.customG;
117 ✗ b = pixel.customB;
118
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 1536477 times.
1536543 } else if ((pixel.cpp == 3) ||
119
2/4
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
66 ((pixel.cpp == 4) && (channelData[pixel.ch + 3] == 0))) {
120 // RGBW with W off shows its RGB part; xLights writes "RGBW" for
121 // every RGBW model
122
3/4
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 1536477 times.
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
1536543 if (pixel.vpc == kVPC_RGB || pixel.vpc == kVPC_RGBW) {
123 1536543 r = channelData[pixel.ch];
124 1536543 g = channelData[pixel.ch + 1];
125 1536543 b = channelData[pixel.ch + 2];
126 ✗ } else if (pixel.vpc == kVPC_RBG) {
127 ✗ r = channelData[pixel.ch];
128 ✗ g = channelData[pixel.ch + 2];
129 ✗ b = channelData[pixel.ch + 1];
130 ✗ } else if (pixel.vpc == kVPC_GRB) {
131 ✗ r = channelData[pixel.ch + 1];
132 ✗ g = channelData[pixel.ch];
133 ✗ b = channelData[pixel.ch + 2];
134 ✗ } else if (pixel.vpc == kVPC_GBR) {
135 ✗ r = channelData[pixel.ch + 2];
136 ✗ g = channelData[pixel.ch];
137 ✗ b = channelData[pixel.ch + 1];
138 ✗ } else if (pixel.vpc == kVPC_BRG) {
139 ✗ r = channelData[pixel.ch + 1];
140 ✗ g = channelData[pixel.ch + 2];
141 ✗ b = channelData[pixel.ch];
142 ✗ } else if (pixel.vpc == kVPC_BGR) {
143 ✗ r = channelData[pixel.ch + 2];
144 ✗ g = channelData[pixel.ch + 1];
145 ✗ b = channelData[pixel.ch];
146 }
147 ✗ } else if (pixel.cpp == 4) {
148 ✗ r = channelData[pixel.ch + 3];
149 ✗ g = channelData[pixel.ch + 3];
150 ✗ b = channelData[pixel.ch + 3];
151 ✗ } else if (pixel.cpp == 1) {
152 ✗ if (pixel.vpc == kVPC_Red) {
153 ✗ r = channelData[pixel.ch];
154 ✗ g = 0;
155 ✗ b = 0;
156 ✗ } else if (pixel.vpc == kVPC_Green) {
157 ✗ r = 0;
158 ✗ g = channelData[pixel.ch];
159 ✗ b = 0;
160 ✗ } else if (pixel.vpc == kVPC_Blue) {
161 ✗ r = 0;
162 ✗ g = 0;
163 ✗ b = channelData[pixel.ch];
164 ✗ } else if (pixel.vpc == kVPC_White) {
165 ✗ r = channelData[pixel.ch];
166 ✗ g = channelData[pixel.ch];
167 ✗ b = channelData[pixel.ch];
168 }
169 }
170 1536543 }
171