App zur Steuerung des mpv Mediaplayers auf einem Raspberry Pi über HTTP
undisclosed
2023-01-07 2f2aa7d344d41c6d4083149b1ea6b41e7fb1f683
commit | author | age
b388a5 1 package org.tw.pi.framebuffer;
U 2
3 /*
4 *        This file is the JNI Java part of a Raspberry Pi FrameBuffer project.
5 *
6 *        Created 2013 by Thomas Welsch (ttww@gmx.de).
7 *
8 *        Do whatever you want to do with it :-)
9 *
10 **/
11
12
13
14 import java.awt.Dimension;
15 import java.awt.Graphics;
16 import java.awt.image.BufferedImage;
17 import java.awt.image.DataBufferInt;
18
19 import javax.swing.JPanel;
20
21
22 /**
23 * This class is the Java front end for a simple to use FrameBuffer driver.
24 * Simple draw in the BufferedImage and all changes are transfered to the FrameBuffer device.<p>
25 * For testing purpose a dummy device is supported (via the devicename "dummy_160x128" instead of "/dev/fb1").<p<
26 * The Java process needs write access to the frame buffer device file.
27 * <p>
28 * It's used to drive small bit mapped screens connected via SPI, see
29 * http://www.sainsmart.com/blog/ada/
30 * <p>
31 * <p>
32 * My Linux kernel config for SPI display was:
33 * <pre>
34 * CONFIG_FB_ST7735=y
35 * CONFIG_FB_ST7735_PANEL_TYPE_RED_TAB=y
36 * CONFIG_FB_ST7735_RGB_ORDER_REVERSED=y
37 * CONFIG_FB_ST7735_MAP=y
38 * CONFIG_FB_ST7735_MAP_RST_GPIO=25
39 * CONFIG_FB_ST7735_MAP_DC_GPIO=24
40 * CONFIG_FB_ST7735_MAP_SPI_BUS_NUM=0
41 * CONFIG_FB_ST7735_MAP_SPI_BUS_CS=0
42 * CONFIG_FB_ST7735_MAP_SPI_BUS_SPEED=16000000
43 * CONFIG_FB_ST7735_MAP_SPI_BUS_MODE=0
44 * </pre>
45 * CONFIG_FB_ST7735_MAP_SPI_BUS_SPEED gives faster updates :-)
46 * <p>
47 * If you get the wrong colors, try the CONFIG_FB_ST7735_RGB_ORDER_REVERSED option !
48 */
49 public class FrameBuffer {
50
51         private static final int FPS = 60;                // Max. update rate
52
53         private        String                        deviceName;
54
55         private long                        deviceInfo;                // Private data from JNI C
56
57         private        int                                width,height;
58         private        int                                bits;
59
60         private BufferedImage        img;
61         private int[]                        imgBuffer;
62
63         // -----------------------------------------------------------------------------------------------------------------
64
65         private native long                openDevice(String device);
66         private native void                closeDevice(long di);
67         private native int                getDeviceWidth(long di);
68         private native int                getDeviceHeight(long di);
69         private native int                getDeviceBitsPerPixel(long di);
70         private native boolean        updateDeviceBuffer(long di,int[] buffer);
71
72         static {
73                 System.loadLibrary("FrameBufferJNI"); // FrameBufferJNI.dll (Windows) or FrameBufferJNI.so (Unixes)
74         }
75
76         // -----------------------------------------------------------------------------------------------------------------
77
78         /**
79          * Open the named frame buffer device and starts the automatic update thread between the internal
80          * BufferedImage and the device.
81          *
82          * @param deviceName        e.g. /dev/fb1 or dummy_320x200
83          */
84         public FrameBuffer(String deviceName) {
85                 this(deviceName,true);
86         }
87
88         // -----------------------------------------------------------------------------------------------------------------
89
90         /**
91          * Open the named frame buffer device.
92          *
93          * @param deviceName        e.g. /dev/fb1 or dummy_320x200
94          * @param autoUpdate        if true, starts the automatic update thread between the internal
95          *                                                BufferedImage and the device.
96          */
97         public FrameBuffer(String deviceName, boolean autoUpdate) {
98
99                 this.deviceName = deviceName;
100
101                 deviceInfo = openDevice(deviceName);
102
103                 if (deviceInfo < 10) {
104                         throw new IllegalArgumentException("Init. for frame buffer "+deviceName+" failed with error code "+deviceInfo);
105                 }
106
107                 this.width        = getDeviceWidth(deviceInfo);
108                 this.height        = getDeviceHeight(deviceInfo);
109
110                 System.err.println("Open with "+deviceName+" ("+deviceInfo+")");
111                 System.err.println(" width "+getDeviceWidth(deviceInfo));
112                 System.err.println(" height "+getDeviceHeight(deviceInfo));
113                 System.err.println(" bpp "+getDeviceBitsPerPixel(deviceInfo));
114
115                 // We always use ARGB image type.
116                 img                        = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
117                 imgBuffer        = ((DataBufferInt) img.getRaster().getDataBuffer()).getBankData()[0];
118
119                 if (autoUpdate) new UpdateThread().start();
120         }
121
122         // -----------------------------------------------------------------------------------------------------------------
123
124         private ScreenPanel        screenPanel;
125
126         /**
127          * Returns a JPanel which represents the actual frame buffer device.
128          *
129          * @return        JPanel...
130          */
131         public JPanel getScreenPanel() {
132                 synchronized (deviceName) {
133                         if (screenPanel != null) throw new IllegalStateException("Only one screen panel supported");
134
135                         screenPanel = new ScreenPanel();
136
137                         return screenPanel;
138                 }
139         }
140
141         // -----------------------------------------------------------------------------------------------------------------
142
143         /**
144          * Internal helper class for displaying the current frame buffer image via a JPanel.
145          */
146         @SuppressWarnings("serial")
147         private class ScreenPanel extends JPanel {
148                 public ScreenPanel() {
149                         setPreferredSize(new Dimension(FrameBuffer.this.width,FrameBuffer.this.height));
150                 }
151
152                 @Override
153                 protected void paintComponent(Graphics g) {
154                         super.paintComponent(g);
155                         g.drawImage(img, 0, 0, null);
156                 }
157         }
158
159         // -----------------------------------------------------------------------------------------------------------------
160
161         /**
162          * Internal helper class for refreshing the frame buffer display and/or JPanel.
163          */
164         private class UpdateThread extends Thread {
165
166                 UpdateThread() {
167                         setDaemon(true);
168                         setName("FB "+deviceName+ " update");
169                 }
170
171                 @Override
172                 public void run() {
173                         final int SLEEP_TIME = 1000 / FPS;
174
175                         while (deviceInfo != 0) {
176
177                                 if (updateScreen()) {
178                                         if (screenPanel != null) {
179                                                 screenPanel.repaint();
180                                         }
181                                 }
182
183                                 try {
184                                         sleep(SLEEP_TIME);
185                                 } catch (InterruptedException e) {
186                                         break;
187                                 }
188
189                         }        // while
190
191                 }
192
193         }        // class UpdateThread
194
195         // -----------------------------------------------------------------------------------------------------------------
196
197         /**
198          * Returns the BufferedImage for drawing. Anything your draw here is synchronizet to the frame buffer.
199          *
200          * @return        BufferedImage of type ARGB.
201          */
202         public BufferedImage getScreen() {
203                 return img;
204         }
205
206         // -----------------------------------------------------------------------------------------------------------------
207
208         /**
209          * Close the device.
210          */
211         public void close() {
212                 synchronized (deviceName) {
213                         closeDevice(deviceInfo);
214                         deviceInfo = 0;
215                         img        = null;
216                         imgBuffer = null;
217                 }
218         }
219
220         // -----------------------------------------------------------------------------------------------------------------
221
222         /**
223          * Update the screen if no automatic sync is used (see constructor autoUpdate flag).
224          * This method is normally called by the autoUpdate thread.
225          *
226          * @return        true if the BufferedImage was changed since the last call.
227          */
228         public boolean updateScreen() {
229                 synchronized (deviceName) {
230                         if (deviceInfo == 0) return false;
231                         return updateDeviceBuffer(deviceInfo,imgBuffer);
232                 }
233         }
234
235
236 }        // of class