summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2016-03-19 16:48:54 -0400
committerLuke Shumaker <lukeshu@sbcglobal.net>2016-03-19 16:48:54 -0400
commitadbfb27a90dacca1cdea40521d8614f61fe3f7cb (patch)
tree451bc6788944cc42987aaf3f8512956dc2f7748b
parentf2d334a486f1fb6b5a942f32a8314579cac89082 (diff)
roll my own mpjpeg encoding (with libjpeg)
-rw-r--r--Makefile4
-rw-r--r--freenect-server-http.socket9
-rw-r--r--freenect-server.c (renamed from freenect-server--kinect.c)89
-rw-r--r--freenect-server.service4
-rw-r--r--freenect-server.sh25
-rw-r--r--freenect-server.socket8
-rw-r--r--freenect-server@.socket13
7 files changed, 87 insertions, 65 deletions
diff --git a/Makefile b/Makefile
index 5ae2d4b..f9df186 100644
--- a/Makefile
+++ b/Makefile
@@ -4,10 +4,10 @@ CFLAGS += -g -std=c99 -Wall -Werror -Wextra -pedantic
CPPFLAGS += -std=c99 -Wall -Werror -Wextra -pedantic
CPPFLAGS += -D_GNU_SOURCE
-all: freenect-server freenect-server--kinect multipart-replace-http-server
+all: freenect-server multipart-replace-http-server
.PHONY: all
-freenect-server--kinect: util.o -lfreenect -lusb-1.0
+freenect-server: util.o -lfreenect -lusb-1.0 -ljpeg
multipart-replace-http-server: util.o multipart-replace.o -lpthread
clean:
diff --git a/freenect-server-http.socket b/freenect-server-http.socket
new file mode 100644
index 0000000..3fc6244
--- /dev/null
+++ b/freenect-server-http.socket
@@ -0,0 +1,9 @@
+[Unit]
+Description=Kinect HTTP media streamer socket
+
+[Socket]
+ListenStream=5800
+
+[Install]
+WantedBy=sockets.target
+Also=freenect-server@accel.mjson.socket freenect-server@depth.mjpg.socket freenect-server@video.mjpg.socket
diff --git a/freenect-server--kinect.c b/freenect-server.c
index e6c9e7e..37e2a08 100644
--- a/freenect-server--kinect.c
+++ b/freenect-server.c
@@ -25,6 +25,7 @@
*/
#include <errno.h>
#include <error.h>
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h> /* atexit */
#include <unistd.h> /* dup2 */
@@ -32,6 +33,8 @@
#include <libfreenect/libfreenect.h>
#include <libusb-1.0/libusb.h>
+#include <jpeglib.h>
+
#include "util.h"
FILE *depth_stream = NULL;
@@ -39,29 +42,47 @@ FILE *video_stream = NULL;
FILE *accel_stream = NULL;
freenect_context *ctx;
-void dump_ffmpeg_24(FILE *stream, uint32_t timestamp UNUSED, void *data,
- size_t data_size)
-{
- fwrite(data, data_size, 1, stream);
-}
+struct jpeg_error_mgr jpeg_encoder_err;
+struct jpeg_compress_struct jpeg_encoder;
+unsigned char *jpeg_encoder_buf;
+unsigned long jpeg_encoder_len;
-void dump_ffmpeg_pad16(FILE *stream, uint32_t timestamp UNUSED, void *data_anon,
- size_t data_size)
-{
- uint16_t* data = data_anon;
- uint16_t* end = (void*)&((char*)data_anon)[data_size];
- while (data < end) {
- uint16_t z = *data;
- uint8_t out[3];
- memset(out, (uint8_t)(z*2.0/3.0), 3);
- fwrite(out, 3, 1, stream);
- data = &data[1];
- }
+void jpeg_init() {
+ jpeg_encoder.err = jpeg_std_error(&jpeg_encoder_err);
+ jpeg_create_compress(&jpeg_encoder);
+ jpeg_encoder.image_width = 640;
+ jpeg_encoder.image_height = 480;
+ jpeg_encoder.input_components = 3;
+ jpeg_encoder.in_color_space = JCS_RGB;
+ jpeg_set_defaults(&jpeg_encoder);
+ jpeg_mem_dest(&jpeg_encoder, &jpeg_encoder_buf, &jpeg_encoder_len);
}
+void write_imageframe(FILE *stream, JSAMPLE *data) {
+ JSAMPLE *row_pointers[480];
+ for (size_t i = 0; i < 480; i++)
+ row_pointers[i] = &data[i*640*3];
+
+ jpeg_start_compress(&jpeg_encoder, TRUE);
+ while (jpeg_encoder.next_scanline < jpeg_encoder.image_height)
+ jpeg_write_scanlines(&jpeg_encoder, &row_pointers[jpeg_encoder.next_scanline], 480-jpeg_encoder.next_scanline);
+ jpeg_finish_compress(&jpeg_encoder);
+
+ if (fprintf(stream,
+ "--ffserver\r\n"
+ "Content-type: image/jpeg\r\n"
+ "Content-length: %lu\r\n"
+ "\r\n",
+ jpeg_encoder_len) < 1)
+ error(EXIT_FAILURE, ferror(stream), "writing header");
+ if (fwrite(jpeg_encoder_buf, jpeg_encoder_len, 1, stream) < 1)
+ error(EXIT_FAILURE, ferror(stream), "writing body");
+ if (fwrite("\r\n", 2, 1, stream) < 1)
+ error(EXIT_FAILURE, ferror(stream), "writing footer");
+ fflush(stream);
+}
-void handle_accel(freenect_device *dev UNUSED, freenect_raw_tilt_state* data)
-{
+void handle_accel(freenect_device *dev UNUSED, freenect_raw_tilt_state* data) {
double x, y, z, angle;
freenect_get_mks_accel(data, &x, &y, &z);
angle = freenect_get_tilt_degs(data);
@@ -70,10 +91,13 @@ void handle_accel(freenect_device *dev UNUSED, freenect_raw_tilt_state* data)
switch (data->tilt_status) {
case TILT_STATUS_STOPPED:
motor = "stopped";
+ break;
case TILT_STATUS_LIMIT:
motor = "limit";
+ break;
case TILT_STATUS_MOVING:
motor = "moving";
+ break;
default:
motor = "unknown";
}
@@ -95,19 +119,28 @@ void handle_accel(freenect_device *dev UNUSED, freenect_raw_tilt_state* data)
"\r\n"
"%s\r\n",
len, json);
+ fflush(accel_stream);
}
-void handle_depth(freenect_device *dev UNUSED, void *depth, uint32_t timestamp)
-{
- dump_ffmpeg_pad16(depth_stream, timestamp, depth,
- freenect_find_depth_mode(FREENECT_RESOLUTION_MEDIUM,
- FREENECT_DEPTH_11BIT).bytes);
+uint8_t depth_rgb[640*480*3];
+void handle_depth(freenect_device *dev, void *depth, uint32_t timestamp UNUSED) {
+ uint32_t size = freenect_get_current_depth_mode(dev).bytes;
+ if (size != 460*480*2)
+ error(EXIT_FAILURE, 0, "handle_depth: expected 640*480*2 byte frame, but got %"PRId32, size);
+ /* scale the 11-bit values into 8-bit values */
+ uint16_t *depth_grey = depth;
+ for (size_t i = 0; i < 640*480; i++)
+ depth_rgb[i*3+0] = depth_rgb[i*3+1] = depth_rgb[i*3+2] = (uint8_t)(depth_grey[i]*8.0/11.0);
+ /* write the image */
+ write_imageframe(depth_stream, depth_rgb);
}
-void handle_video(freenect_device *dev, void *rgb, uint32_t timestamp)
-{
- dump_ffmpeg_24(video_stream, timestamp, rgb,
- freenect_get_current_video_mode(dev).bytes);
+void handle_video(freenect_device *dev, void *rgb, uint32_t timestamp UNUSED) {
+ uint32_t size = freenect_get_current_video_mode(dev).bytes;
+ if (size != 460*480*3)
+ error(EXIT_FAILURE, 0, "handle_video: expected 640*480*3 byte frame, but got %"PRId32, size);
+ /* write the image */
+ write_imageframe(video_stream, rgb);
}
void print_mode(const char *name, freenect_frame_mode mode) {
diff --git a/freenect-server.service b/freenect-server.service
index 5a2d4e2..fbc2035 100644
--- a/freenect-server.service
+++ b/freenect-server.service
@@ -1,7 +1,7 @@
[Unit]
-Description=Kinect media streamer
+Description=Kinect media streamer backend
After=network.target
-Requires=freenect-server.socket
+Requires=freenect-server@accel.socket freenect-server@depth.socket freenect-server@video.socket
[Service]
Type=simple
diff --git a/freenect-server.sh b/freenect-server.sh
deleted file mode 100644
index e88acbe..0000000
--- a/freenect-server.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/env bash
-# Copyright 2016 Luke Shumaker
-
-PATH="$PATH:$(dirname -- "$0")"
-
-t="$(mktemp -d --tmpdir "${0##*/}.XXXXXXXXXX")"
-
-mkfifo $t/video.rgb24
-mkfifo $t/depth.rgb24
-mkfifo $t/video.mjpg
-mkfifo $t/depth.mjpg
-mkfifo $t/accel.mjson
-
-( freenect-server--kinect -v $t/video.rgb24 -d $t/depth.rgb24 -a $t/accel.mjson; echo "EXITED: freenect-server--kinect: $?") & pids+=($!)
-( multipart-replace-http-server "$1" "$2" $t/video.mjpg $t/depth.mjpg $t/accel.mjson; echo "EXITED: freenect-server--http: $?") & pids+=($!)
-( ffmpeg -loglevel warning -pixel_format rgb24 -s 640x480 -f rawvideo -i $t/video.rgb24 -q:v 1 -f mpjpeg - > $t/video.mjpg; echo "EXITED: ffmpeg video: $?") & pids+=($!)
-( ffmpeg -loglevel warning -pixel_format rgb24 -s 640x480 -f rawvideo -i $t/depth.rgb24 -q:v 1 -f mpjpeg - > $t/depth.mjpg; echo "EXITED: ffmpeg depth: $?") & pids+=($!)
-
-cleanup() {
- kill -- "${pids[@]}" 2>/dev/null
- rm -rf -- "$t"
-}
-trap cleanup EXIT
-
-wait
diff --git a/freenect-server.socket b/freenect-server.socket
deleted file mode 100644
index 4b98eca..0000000
--- a/freenect-server.socket
+++ /dev/null
@@ -1,8 +0,0 @@
-[Unit]
-Description=Kinect media streamer socket
-
-[Socket]
-ListenStream=5800
-
-[Install]
-WantedBy=sockets.target
diff --git a/freenect-server@.socket b/freenect-server@.socket
new file mode 100644
index 0000000..841f2fd
--- /dev/null
+++ b/freenect-server@.socket
@@ -0,0 +1,13 @@
+[Unit]
+Description=Kinect media streamer internal %I stream
+After=network.target
+
+[Socket]
+SocketUser=alarm
+SocketGroup=alarm
+ListenFIFO=/run/freenect-server/Ii.fifo
+FileDescriptorName=%I
+Service=freenect-server.service
+
+[Install]
+WantedBy=sockets.target