Skip to content
This repository was archived by the owner on May 6, 2021. It is now read-only.

Commit fb7e89a

Browse files
committed
Merge pull request #237 from Gamadril/master
Frambuffer grabber support
2 parents a620bcf + 34682c4 commit fb7e89a

File tree

12 files changed

+457
-2
lines changed

12 files changed

+457
-2
lines changed

CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ if(ENABLE_V4L2 AND NOT ENABLE_PROTOBUF)
3232
message(FATAL_ERROR "V4L2 grabber requires PROTOBUF. Disable V4L2 or enable PROTOBUF")
3333
endif(ENABLE_V4L2 AND NOT ENABLE_PROTOBUF)
3434

35+
option(ENABLE_FB "Enable the framebuffer grabber" OFF)
36+
message(STATUS "ENABLE_FB = " ${ENABLE_FB})
37+
38+
if(ENABLE_FB AND ENABLE_DISPMANX)
39+
message(FATAL_ERROR "dispmanx grabber and framebuffer grabber cannot be used at the same time")
40+
endif(ENABLE_FB AND ENABLE_DISPMANX)
41+
3542
# Createt the configuration file
3643
# configure a header file to pass some of the CMake settings
3744
# to the source code

CompileHowto.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ cd "$HYPERION_DIR/build"
2626
cmake ..
2727
# or if you are not compiling on the raspberry pi and need to disable the Dispmanx grabber and support for spi devices
2828
cmake -DENABLE_DISPMANX=OFF -DENABLE_SPIDEV=OFF -DENABLE_X11=ON ..
29+
# as an alternative for the dispmanx grabber on non-rpi devices (e.g. cubox-i) you could try the framebuffer grabber
30+
cmake -DENABLE_DISPMANX=OFF -DENABLE_SPIDEV=OFF -DENABLE_FB=ON ..
2931

3032
# run make to build Hyperion
3133
make

HyperionConfig.h.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,7 @@
1717

1818
// Define to enable PROTOBUF server
1919
#cmakedefine ENABLE_PROTOBUF
20+
21+
// Define to enable the framebuffer grabber
22+
#cmakedefine ENABLE_FB
23+

include/grabber/FramebufferWrapper.h

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#pragma once
2+
3+
// QT includes
4+
#include <QObject>
5+
#include <QTimer>
6+
7+
// Utils includes
8+
#include <utils/Image.h>
9+
#include <utils/ColorRgb.h>
10+
#include <utils/ColorRgba.h>
11+
#include <utils/GrabbingMode.h>
12+
#include <utils/VideoMode.h>
13+
14+
// Forward class declaration
15+
class FramebufferFrameGrabber;
16+
class Hyperion;
17+
class ImageProcessor;
18+
19+
///
20+
/// The FramebufferWrapper uses an instance of the FramebufferFrameGrabber to obtain ImageRgb's from the
21+
/// displayed content. This ImageRgb is processed to a ColorRgb for each led and commmited to the
22+
/// attached Hyperion.
23+
///
24+
class FramebufferWrapper: public QObject
25+
{
26+
Q_OBJECT
27+
public:
28+
///
29+
/// Constructs the framebuffer frame grabber with a specified grab size and update rate.
30+
///
31+
/// @param[in] device Framebuffer device name/path
32+
/// @param[in] grabWidth The width of the grabbed image [pixels]
33+
/// @param[in] grabHeight The height of the grabbed images [pixels]
34+
/// @param[in] updateRate_Hz The image grab rate [Hz]
35+
/// @param[in] hyperion The instance of Hyperion used to write the led values
36+
///
37+
FramebufferWrapper(const std::string & device, const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, Hyperion * hyperion);
38+
39+
///
40+
/// Destructor of this framebuffer frame grabber. Releases any claimed resources.
41+
///
42+
virtual ~FramebufferWrapper();
43+
44+
public slots:
45+
///
46+
/// Starts the grabber wich produces led values with the specified update rate
47+
///
48+
void start();
49+
50+
///
51+
/// Performs a single frame grab and computes the led-colors
52+
///
53+
void action();
54+
55+
///
56+
/// Stops the grabber
57+
///
58+
void stop();
59+
60+
///
61+
/// Set the grabbing mode
62+
/// @param[in] mode The new grabbing mode
63+
///
64+
void setGrabbingMode(const GrabbingMode mode);
65+
66+
///
67+
/// Set the video mode (2D/3D)
68+
/// @param[in] mode The new video mode
69+
///
70+
void setVideoMode(const VideoMode videoMode);
71+
72+
private:
73+
/// The update rate [Hz]
74+
const int _updateInterval_ms;
75+
/// The timeout of the led colors [ms]
76+
const int _timeout_ms;
77+
/// The priority of the led colors
78+
const int _priority;
79+
80+
/// The timer for generating events with the specified update rate
81+
QTimer _timer;
82+
83+
/// The image used for grabbing frames
84+
Image<ColorRgba> _image;
85+
/// The actual grabber
86+
FramebufferFrameGrabber * _frameGrabber;
87+
/// The processor for transforming images to led colors
88+
ImageProcessor * _processor;
89+
90+
/// The list with computed led colors
91+
std::vector<ColorRgb> _ledColors;
92+
93+
/// Pointer to Hyperion for writing led values
94+
Hyperion * _hyperion;
95+
};

include/utils/Image.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ class Image
142142
/// @param height The height of the image
143143
void resize(const unsigned width, const unsigned height)
144144
{
145-
if ((width*height) > (_endOfPixels-_pixels))
145+
if ((width*height) > unsigned((_endOfPixels-_pixels)))
146146
{
147147
delete[] _pixels;
148148
_pixels = new Pixel_T[width*height + 1];

libsrc/grabber/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ if (ENABLE_DISPMANX)
22
add_subdirectory(dispmanx)
33
endif (ENABLE_DISPMANX)
44

5+
if (ENABLE_FB)
6+
add_subdirectory(framebuffer)
7+
endif (ENABLE_FB)
8+
59
if (ENABLE_V4L2)
610
add_subdirectory(v4l2)
711
endif (ENABLE_V4L2)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
2+
# Find the BCM-package (VC control)
3+
# find_package(BCM REQUIRED)
4+
# include_directories(${BCM_INCLUDE_DIRS})
5+
6+
# Define the current source locations
7+
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber)
8+
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/framebuffer)
9+
10+
# Group the headers that go through the MOC compiler
11+
SET(FramebufferGrabberQT_HEADERS
12+
${CURRENT_HEADER_DIR}/FramebufferWrapper.h
13+
)
14+
15+
SET(FramebufferGrabberHEADERS
16+
${CURRENT_SOURCE_DIR}/FramebufferFrameGrabber.h
17+
)
18+
19+
SET(FramebufferGrabberSOURCES
20+
${CURRENT_SOURCE_DIR}/FramebufferWrapper.cpp
21+
${CURRENT_SOURCE_DIR}/FramebufferFrameGrabber.cpp
22+
)
23+
24+
QT4_WRAP_CPP(FramebufferGrabberHEADERS_MOC ${FramebufferGrabberQT_HEADERS})
25+
26+
add_library(framebuffer-grabber
27+
${FramebufferGrabberHEADERS}
28+
${FramebufferGrabberQT_HEADERS}
29+
${FramebufferGrabberHEADERS_MOC}
30+
${FramebufferGrabberSOURCES}
31+
)
32+
33+
target_link_libraries(framebuffer-grabber
34+
hyperion
35+
${QT_LIBRARIES})
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#include <sys/types.h>
2+
#include <sys/stat.h>
3+
#include <fcntl.h>
4+
#include <unistd.h>
5+
#include <linux/fb.h>
6+
#include <sys/mman.h>
7+
#include <sys/ioctl.h>
8+
#include <math.h>
9+
10+
// STL includes
11+
#include <cassert>
12+
#include <iostream>
13+
14+
// Local includes
15+
#include "FramebufferFrameGrabber.h"
16+
17+
FramebufferFrameGrabber::FramebufferFrameGrabber(const std::string & device, const unsigned width, const unsigned height) :
18+
_fbfd(0),
19+
_fbp(0),
20+
_fbDevice(device),
21+
_width(width),
22+
_height(height),
23+
_xScale(1),
24+
_yScale(1)
25+
{
26+
int result;
27+
struct fb_var_screeninfo vinfo;
28+
29+
// Check if the framebuffer device can be opened and display the current resolution
30+
_fbfd = open(_fbDevice.c_str(), O_RDONLY);
31+
assert(_fbfd > 0);
32+
33+
// get variable screen information
34+
result = ioctl (_fbfd, FBIOGET_VSCREENINFO, &vinfo);
35+
assert(result == 0);
36+
37+
std::cout << "Framebuffer opened with resolution: " << vinfo.xres << "x" << vinfo.yres << "@" << vinfo.bits_per_pixel << "bit" << std::endl;
38+
39+
close(_fbfd);
40+
}
41+
42+
FramebufferFrameGrabber::~FramebufferFrameGrabber()
43+
{
44+
}
45+
46+
void FramebufferFrameGrabber::setVideoMode(const VideoMode videoMode)
47+
{
48+
switch (videoMode) {
49+
case VIDEO_3DSBS:
50+
_xScale = 2;
51+
_yScale = 1;
52+
break;
53+
case VIDEO_3DTAB:
54+
_xScale = 1;
55+
_yScale = 2;
56+
break;
57+
case VIDEO_2D:
58+
default:
59+
_xScale = 1;
60+
_yScale = 1;
61+
break;
62+
}
63+
}
64+
65+
void FramebufferFrameGrabber::grabFrame(Image<ColorRgba> & image)
66+
{
67+
struct fb_var_screeninfo vinfo;
68+
unsigned capSize, px, py, index, bytesPerPixel;
69+
float x_scale, y_scale;
70+
71+
/* resize the given image if needed */
72+
if (image.width() != _width || image.height() != _height)
73+
{
74+
image.resize(_width, _height);
75+
}
76+
77+
/* Open the framebuffer device */
78+
_fbfd = open(_fbDevice.c_str(), O_RDONLY);
79+
80+
/* get variable screen information */
81+
ioctl (_fbfd, FBIOGET_VSCREENINFO, &vinfo);
82+
83+
bytesPerPixel = vinfo.bits_per_pixel / 8;
84+
capSize = vinfo.xres * vinfo.yres * bytesPerPixel;
85+
86+
/* map the device to memory */
87+
_fbp = (unsigned char*)mmap(0, capSize, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, _fbfd, 0);
88+
89+
/* nearest neighbor downscaling */
90+
x_scale = (vinfo.xres / float(_xScale)) / float(_width);
91+
y_scale = (vinfo.yres / float(_yScale)) / float(_height);
92+
93+
ColorRgba *pPixel = image.memptr();
94+
for (unsigned i=0; i < _height; i++) {
95+
for (unsigned j=0; j < _width; j++) {
96+
px = floor(j * x_scale);
97+
py = floor(i * y_scale);
98+
index = (py * vinfo.xres + px) * bytesPerPixel;
99+
100+
if (vinfo.bits_per_pixel == 16) {
101+
pPixel->blue = (_fbp[index] & 0x1f) << 3;
102+
pPixel->green = (((_fbp[index + 1] & 0x7) << 3) | (_fbp[index] & 0xE0) >> 5) << 2;
103+
pPixel->red = (_fbp[index + 1] & 0xF8);
104+
pPixel->alpha = 255;
105+
} else if(vinfo.bits_per_pixel == 24) {
106+
pPixel->blue = _fbp[index];
107+
pPixel->green = _fbp[index + 1];
108+
pPixel->red = _fbp[index + 2];
109+
pPixel->alpha = 255;
110+
} else if(vinfo.bits_per_pixel == 32) {
111+
pPixel->blue = _fbp[index];
112+
pPixel->green = _fbp[index + 1];
113+
pPixel->red = _fbp[index + 2];
114+
pPixel->alpha = _fbp[index + 3];
115+
}
116+
117+
pPixel++;
118+
}
119+
}
120+
121+
munmap(_fbp, capSize);
122+
close(_fbfd);
123+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#pragma once
2+
3+
// Utils includes
4+
#include <utils/Image.h>
5+
#include <utils/ColorRgba.h>
6+
#include <utils/VideoMode.h>
7+
8+
///
9+
/// The FramebufferFrameGrabber is used for creating snapshots of the display (screenshots)
10+
///
11+
class FramebufferFrameGrabber
12+
{
13+
public:
14+
///
15+
/// Construct a FramebufferFrameGrabber that will capture snapshots with specified dimensions.
16+
///
17+
/// @param[in] device The framebuffer device name/path
18+
/// @param[in] width The width of the captured screenshot
19+
/// @param[in] height The heigth of the captured screenshot
20+
///
21+
FramebufferFrameGrabber(const std::string & device, const unsigned width, const unsigned height);
22+
~FramebufferFrameGrabber();
23+
24+
///
25+
/// Set the video mode (2D/3D)
26+
/// @param[in] mode The new video mode
27+
///
28+
void setVideoMode(const VideoMode videoMode);
29+
30+
///
31+
/// Captures a single snapshot of the display and writes the data to the given image. The
32+
/// provided image should have the same dimensions as the configured values (_width and
33+
/// _height)
34+
///
35+
/// @param[out] image The snapped screenshot (should be initialized with correct width and
36+
/// height)
37+
///
38+
void grabFrame(Image<ColorRgba> & image);
39+
40+
private:
41+
/// Framebuffer file descriptor
42+
int _fbfd;
43+
44+
/// Pointer to framebuffer
45+
unsigned char * _fbp;
46+
47+
/// Framebuffer device e.g. /dev/fb0
48+
const std::string _fbDevice;
49+
50+
/// With of the captured snapshot [pixels]
51+
const unsigned _width;
52+
53+
/// Height of the captured snapshot [pixels]
54+
const unsigned _height;
55+
56+
/// width scale factor for 3D image processing
57+
float _xScale;
58+
59+
/// height scale factor for 3D image processing
60+
float _yScale;
61+
};

0 commit comments

Comments
 (0)