Skip to content

Commit 4daaa4c

Browse files
committed
Updates to server stuff
1 parent 618af16 commit 4daaa4c

File tree

6 files changed

+133
-35
lines changed

6 files changed

+133
-35
lines changed

src/au/edu/jcu/v4l4j/ImageFormatList.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,4 +476,16 @@ public ImageFormat getYVUEncodableFormat(String n) {
476476
public ImageFormat getYVUEncodableFormat(int i) {
477477
return getFormat(YVU420formats, i);
478478
}
479+
480+
/**
481+
* Looks for a native image format with the given palette
482+
* @param palette palette to search for a format with
483+
* @return found image format, or null
484+
*/
485+
public ImageFormat getNativeFormatOfType(ImagePalette palette) {
486+
for (ImageFormat imf : getNativeFormats())
487+
if (imf.getPalette() == palette)
488+
return imf;
489+
return null;
490+
}
479491
}

src/au/edu/jcu/v4l4j/VideoDevice.java

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,12 @@
2525
package au.edu.jcu.v4l4j;
2626

2727
import java.io.File;
28+
import java.util.Arrays;
29+
import java.util.HashSet;
30+
import java.util.Set;
31+
import java.util.Vector;
2832
import java.util.concurrent.Executors;
2933
import java.util.concurrent.ThreadFactory;
30-
import java.util.Vector;
3134

3235
import au.edu.jcu.v4l4j.exceptions.CaptureChannelException;
3336
import au.edu.jcu.v4l4j.exceptions.ImageDimensionsException;
@@ -151,6 +154,16 @@
151154
*/
152155
public class VideoDevice {
153156

157+
/**
158+
* Simple method to look for candidate video devices. Searches in the <code>/dev</code> folder
159+
* for files matching <code>video*</code>.
160+
* @return results
161+
*/
162+
public static Set<String> available() {
163+
File dev = new File("/dev");
164+
return new HashSet<>(Arrays.asList(dev.list((file, name)->(file == dev && name.startsWith("video")))));
165+
}
166+
154167
static {
155168
try {
156169
System.loadLibrary("v4l4j");
@@ -161,7 +174,7 @@ public class VideoDevice {
161174
}
162175

163176
/**
164-
* This JNI method initialises the libv4's struct video_device
177+
* This JNI method initializes the libv4's struct video_device
165178
*
166179
* @param device
167180
* the name of the device file
@@ -182,7 +195,7 @@ public class VideoDevice {
182195
private native void doRelease(long o);
183196

184197
/**
185-
* This JNI method initialises the control interface and returns an array of
198+
* This JNI method initializes the control interface and returns an array of
186199
* <code>Control</code>s.
187200
*
188201
* @param o
@@ -249,7 +262,7 @@ public class VideoDevice {
249262
private String deviceFile;
250263

251264
/**
252-
* The state of our VideoDevice (used for synchronisation)
265+
* The state of our VideoDevice (used for synchronization)
253266
*/
254267
private State state;
255268

@@ -310,12 +323,12 @@ public VideoDevice(String dev) throws V4L4JException {
310323
}
311324

312325
/**
313-
* This method initialises this VideoDevice with the information obtained
326+
* This method initializes this VideoDevice with the information obtained
314327
* from the {@link DeviceInfo}. This method must be called before any other
315328
* methods.
316329
*
317330
* @throws V4L4JException
318-
* if the device can not be initialised
331+
* if the device can not be initialized
319332
*/
320333
private void initDeviceInfo() throws V4L4JException {
321334
// initialize deviceInfo
@@ -1385,10 +1398,10 @@ public YVUFrameGrabber getYVUFrameGrabber(int w, int h, int input, int std) thro
13851398
* The returned {@link RawFrameGrabber} must be released when no longer used
13861399
* by calling {@link #releaseFrameGrabber()}.
13871400
*
1388-
* @param w
1401+
* @param width
13891402
* the desired frame width. This value may be adjusted to the
13901403
* closest supported by hardware.
1391-
* @param h
1404+
* @param height
13921405
* the desired frame height. This value may be adjusted to the
13931406
* closest supported by hardware.
13941407
* @param input
@@ -1420,15 +1433,15 @@ public YVUFrameGrabber getYVUFrameGrabber(int w, int h, int input, int std) thro
14201433
* if a {@link FrameGrabber} already exists or if the
14211434
* <code>VideoDevice</code> has been released.
14221435
*/
1423-
public RawFrameGrabber getRawFrameGrabber(int w, int h, int input, int std, ImageFormat format)
1436+
public RawFrameGrabber getRawFrameGrabber(int width, int height, int input, int std, ImageFormat format)
14241437
throws V4L4JException {
14251438
if (format == null)
14261439
throw new ImageFormatException("The image format can not be null");
14271440

14281441
synchronized (this) {
14291442
if (fg == null) {
14301443
state.get();
1431-
fg = new RawFrameGrabber(deviceInfo, v4l4jObject, w, h, input, std, findTuner(input), format,
1444+
fg = new RawFrameGrabber(deviceInfo, v4l4jObject, width, height, input, std, findTuner(input), format,
14321445
threadFactory);
14331446
try {
14341447
fg.init();
@@ -1451,7 +1464,7 @@ public RawFrameGrabber getRawFrameGrabber(int w, int h, int input, int std, Imag
14511464
return (RawFrameGrabber) fg;
14521465
else {
14531466
state.put();
1454-
throw new StateException("Another FrameGrabber object already " + "exists");
1467+
throw new StateException("Another FrameGrabber object already exists");
14551468
}
14561469
}
14571470
}
@@ -1465,10 +1478,10 @@ public RawFrameGrabber getRawFrameGrabber(int w, int h, int input, int std, Imag
14651478
* The {@link RawFrameGrabber} must be released when no longer used by
14661479
* calling {@link #releaseFrameGrabber()}.
14671480
*
1468-
* @param w
1481+
* @param width
14691482
* the desired frame width. This value may be adjusted to the
14701483
* closest supported by hardware.
1471-
* @param h
1484+
* @param height
14721485
* the desired frame height. This value may be adjusted to the
14731486
* closest supported by hardware.
14741487
* @param input
@@ -1494,11 +1507,11 @@ public RawFrameGrabber getRawFrameGrabber(int w, int h, int input, int std, Imag
14941507
* if a <code>FrameGrabber</code> already exists or if the
14951508
* <code>VideoDevice</code> has been released.
14961509
*/
1497-
public RawFrameGrabber getRawFrameGrabber(int w, int h, int input, int std) throws V4L4JException {
1510+
public RawFrameGrabber getRawFrameGrabber(int width, int height, int input, int std) throws V4L4JException {
14981511
if (deviceInfo == null)
14991512
throw new ImageFormatException(
15001513
"No DeviceInfo could be obtained. The device is probably used by another application");
1501-
return getRawFrameGrabber(w, h, input, std, deviceInfo.getFormatList().getNativeFormats().get(0));
1514+
return getRawFrameGrabber(width, height, input, std, deviceInfo.getFormatList().getNativeFormats().get(0));
15021515
}
15031516

15041517
/**

src/au/edu/jcu/v4l4j/encoder/h264/H264Test.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.junit.Test;
66

77
import au.edu.jcu.v4l4j.ImageFormat;
8+
import au.edu.jcu.v4l4j.ImagePalette;
89
import au.edu.jcu.v4l4j.VideoDevice;
910
import au.edu.jcu.v4l4j.exceptions.V4L4JException;
1011

@@ -46,10 +47,8 @@ public void testEncoder() throws Exception {
4647
H264Picture picIn = new H264Picture(width, height, csp);
4748

4849
VideoDevice device = new VideoDevice("/dev/video0");
49-
ImageFormat yuyvFormat;
50-
for (ImageFormat format : device.getDeviceInfo().getFormatList().getNativeFormats()) {
51-
System.out.println(format.getPalette());
52-
}
50+
ImageFormat yuyvFormat = device.getDeviceInfo().getFormatList().getNativeFormatOfType(ImagePalette.YUYV);
51+
System.out.println(yuyvFormat);
5352

5453
encoder.close();
5554
picIn.close();

src/au/edu/jcu/v4l4j/examples/server/CamHttpServer.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,25 +106,25 @@ public static void main(String[] args) throws V4L4JException, IOException {
106106
* @param fps
107107
* the frame rate used for capture
108108
* @throws V4L4JException
109-
* if a JPEG frame grabber cant be created
109+
* if a JPEG frame grabber can't be created
110110
* @throws IOException
111-
* if a server socket on the given port cant be created
111+
* if a server socket on the given port can't be created
112112
*/
113113
public CamHttpServer(String dev, int width, int height, int port, int fps) throws V4L4JException, IOException {
114114
this.videoDevice = new VideoDevice(dev);
115115
this.frameGrabber = videoDevice.getJPEGFrameGrabber(width, height, 0, 0, 80);
116116
this.frameGrabber.setCaptureCallback(this);
117117
try {
118-
System.out.println("setting frame rate to " + fps);
118+
System.out.println("Setting frame rate to " + fps);
119119
frameGrabber.setFrameInterval(1, fps);
120120
} catch (Exception e) {
121-
System.out.println("Couldnt set the frame interval");
121+
System.out.println("Couldn't set the frame interval");
122122
}
123123

124124
controlList = videoDevice.getControlList();
125125
clients = new Vector<ClientConnection>();
126126

127-
// initialise tcp port to listen on
127+
// initialize tcp port to listen on
128128
serverSocket = new ServerSocket(port);
129129

130130
System.out.println("Server listening at " + serverSocket.getInetAddress().getHostAddress() + ":"
@@ -288,6 +288,7 @@ private void serverMainLoop() throws IOException, V4L4JException {
288288
private int parseLine(BufferedReader in) throws IOException {
289289
// read the first line to determine which page to send
290290
httpLineFromClient = in.readLine();
291+
System.out.println(httpLineFromClient);
291292

292293
if (httpLineFromClient == null)
293294
throw new IOException("Read null line");
@@ -301,7 +302,7 @@ private int parseLine(BufferedReader in) throws IOException {
301302
return CONTROL_PAGE;
302303

303304
// if the line contains the word stream, we want the control list page
304-
if (httpLineFromClient.indexOf("stream") != -1)
305+
if (httpLineFromClient.indexOf("stream") != -1 || httpLineFromClient.endsWith("jpg"))
305306
return VIDEO_STREAM;
306307

307308
// if the line contains the word update, we want to update a control's

src/au/edu/jcu/v4l4j/examples/server/ClientConnection.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,28 @@ public class ClientConnection {
4040
private static String mainPageHTML = "HTTP/1.0 200 OK\r\n" + "Location: http://v4l4j_mini_server\r\n"
4141
+ "Expires: 0\r\n" + "Content-Type: text/html\r\n" + "\r\n"
4242
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Frameset//EN\" http://www.w3.org/TR/html4/frameset.dtd>"
43-
+ "<html>\n" + "<head>\n" + "<title>v4l4j mini server</title>\n" + "</head>\n" + "<frameset cols='4*,6*'>\n"
44-
+ "<frame src='control' name='control list'>\n" + "<frame src='webcam' name='video stream'>\n"
45-
+ "</frameset>\n" + "</html>";
43+
+ "<html>\n"
44+
+ "<head>\n"
45+
+ "<title>v4l4j mini server</title>\n"
46+
+ "</head>\n"
47+
+ "<frameset cols='4*,6*'>\n"
48+
+ "<frame src='control' name='control list'>\n"
49+
+ "<frame src='webcam' name='video stream'>\n"
50+
+ "</frameset>\n"
51+
+ "</html>";
4652

4753
private static String webcamPageHTML = "HTTP/1.0 200 OK\r\n" + "Location: http://v4l4j_mini_server\r\n"
48-
+ "Expires: 0\r\n" + "Content-Type: text/html\r\n" + "\r\n" + "<html>\n" + "<body>\n" + "<table>\n"
49-
+ "<td>\n" + "<tr>\n" + "<img src='stream.jpg'>\n" + "</tr>\n" + "</td>\n" + "</table>\n" + "</body>\n"
54+
+ "Expires: 0\r\n" + "Content-Type: text/html\r\n" + "\r\n"
55+
+ "<html>\n"
56+
+ "<body>\n"
57+
+ "<table>\n"
58+
+ "<td>\n"
59+
+ "<tr>\n"
60+
+ "<img src='stream.jpg'>\n"
61+
+ "</tr>\n"
62+
+ "</td>\n"
63+
+ "</table>\n"
64+
+ "</body>\n"
5065
+ "</html>";
5166

5267
private static String controlPageHTMLHeader = "HTTP/1.0 200 OK\r\n" + "Location: http://v4l4j_mini_server\r\n"

src/au/edu/jcu/v4l4j/examples/server/RtpServer.java

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,17 @@
33
import java.io.IOException;
44
import java.net.ServerSocket;
55
import java.net.Socket;
6+
import java.nio.ByteBuffer;
67
import java.util.LinkedList;
78
import java.util.Vector;
89

10+
import org.gstreamer.Gst;
11+
import org.gstreamer.Pipeline;
12+
913
import au.edu.jcu.v4l4j.CaptureCallback;
10-
import au.edu.jcu.v4l4j.JPEGFrameGrabber;
14+
import au.edu.jcu.v4l4j.ImageFormat;
15+
import au.edu.jcu.v4l4j.ImagePalette;
16+
import au.edu.jcu.v4l4j.RawFrameGrabber;
1117
import au.edu.jcu.v4l4j.VideoDevice;
1218
import au.edu.jcu.v4l4j.VideoFrame;
1319
import au.edu.jcu.v4l4j.encoder.h264.H264Encoder;
@@ -19,7 +25,7 @@ public class RtpServer implements Runnable, CaptureCallback {
1925
private ServerSocket serverSocket;
2026
private VideoDevice videoDevice;
2127
private H264Encoder encoder;
22-
private JPEGFrameGrabber frameGrabber;
28+
private RawFrameGrabber frameGrabber;
2329
private Thread serverThread;
2430
private LinkedList<ClientStreamingConnection> clients;
2531
private long frameCount;
@@ -68,13 +74,14 @@ public RtpServer(String dev, int width, int height, int port, int fps) throws V4
6874
h264Params.setCsp(X264.CSP_YV12);
6975
this.encoder = new H264Encoder(h264Params);
7076
}
71-
this.frameGrabber = videoDevice.getJPEGFrameGrabber(width, height, 0, 0, 80);
77+
ImageFormat imf = videoDevice.getDeviceInfo().getFormatList().getNativeFormatOfType(ImagePalette.YUYV);
78+
this.frameGrabber = videoDevice.getRawFrameGrabber(width, height, 0, 0, imf);
7279
this.frameGrabber.setCaptureCallback(this);
7380
try {
74-
System.out.println("setting frame rate to " + fps);
81+
System.out.println("Setting frame rate to " + fps);
7582
frameGrabber.setFrameInterval(1, fps);
7683
} catch (Exception e) {
77-
System.out.println("Couldnt set the frame interval");
84+
System.out.println("Couldn't set the frame interval: " + e.getMessage());
7885
}
7986

8087
clients = new LinkedList<>();
@@ -90,6 +97,7 @@ public RtpServer(String dev, int width, int height, int port, int fps) throws V4
9097
}
9198

9299
public void start() {
100+
Gst.init("GStreamer", new String[0]);
93101
// start the tcp server thread
94102
serverThread.start();
95103
}
@@ -158,6 +166,7 @@ private void serverMainLoop() throws IOException, V4L4JException {
158166

159167
System.out.println("Serving video stream");
160168

169+
161170
// add new client to clients list
162171
synchronized (clients) {
163172
clients.add(new ClientStreamingConnection(clientSocket));
@@ -217,6 +226,9 @@ public void nextFrame(VideoFrame frame) {
217226
lastFrameTimestamp = 0;
218227
}
219228
}
229+
230+
Pipeline pipe = Pipeline.launch("");
231+
220232
// send the frame to each client
221233
for (ClientStreamingConnection client : copyClients) {
222234
try {
@@ -248,4 +260,50 @@ public void exceptionReceived(V4L4JException e) {
248260
frameGrabber.stopCapture();
249261
}
250262

263+
static class RtpFrame {
264+
ByteBuffer buffer;
265+
boolean padding;
266+
boolean extension;
267+
byte csrc;//4 bits, 0 - 16
268+
boolean marker;
269+
byte payload;//7 bits
270+
short sequence;//16 bits
271+
int timestamp;//32 bits
272+
int ssrc;//32 bits
273+
byte[] csrcs = new byte[32 * 15];
274+
public void build() {
275+
byte tmp = (byte) (0b10000000);
276+
if (padding)
277+
tmp|= 0b100000;
278+
if (extension)
279+
tmp|= 0b10000;
280+
tmp|= csrc;
281+
buffer.put(tmp);
282+
283+
buffer.put((byte) ((marker ? (1<<7) : 0) | payload));
284+
285+
buffer.putShort(sequence);
286+
287+
buffer.putInt(timestamp);
288+
buffer.putInt(ssrc);
289+
290+
buffer.put(csrcs, 0, csrc * 4);
291+
}
292+
public void setPayload(byte payload) {
293+
buffer.put(1, (byte) ((marker ? (1<<7) : 0) | payload));
294+
this.payload = payload;
295+
}
296+
public void setTimestamp(int timestamp) {
297+
buffer.putInt(4, timestamp);
298+
this.timestamp = timestamp;
299+
}
300+
public void setNumCsrcs(byte num) {
301+
buffer.put(0, (byte) ((1<<7) | (padding?1<<5:0) | (extension?1<<4:0) | num));
302+
this.csrc = num;
303+
}
304+
public void setCsrc(int index, int csrc) {
305+
306+
}
307+
308+
}
251309
}

0 commit comments

Comments
 (0)