diff options
author | Luke Shumaker <lukeshu@sbcglobal.net> | 2016-03-19 16:48:54 -0400 |
---|---|---|
committer | Luke Shumaker <lukeshu@sbcglobal.net> | 2016-03-19 16:48:54 -0400 |
commit | adbfb27a90dacca1cdea40521d8614f61fe3f7cb (patch) | |
tree | 451bc6788944cc42987aaf3f8512956dc2f7748b | |
parent | f2d334a486f1fb6b5a942f32a8314579cac89082 (diff) |
roll my own mpjpeg encoding (with libjpeg)
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | freenect-server-http.socket | 9 | ||||
-rw-r--r-- | freenect-server.c (renamed from freenect-server--kinect.c) | 89 | ||||
-rw-r--r-- | freenect-server.service | 4 | ||||
-rw-r--r-- | freenect-server.sh | 25 | ||||
-rw-r--r-- | freenect-server.socket | 8 | ||||
-rw-r--r-- | freenect-server@.socket | 13 |
7 files changed, 87 insertions, 65 deletions
@@ -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 |