Commit 58b71759 authored by Sven Gestegård Robertz's avatar Sven Gestegård Robertz
Browse files

major rewrite and cleanup for 2017

parent cabe69cb
......@@ -20,16 +20,21 @@ LD=${COMPILER_DIR}/bin/mipsisa32r2el-axis-linux-gnu-ld
# Tell the compiler where to look for header files used in the auxilliary native methods for the camera classes
#CPPFLAGS+=-I${AXIS_PATH}/include -I${AXIS_PATH}/usr/include
CPPFLAGS+=-I${AXIS_PATH}/usr/include -I${COMPILER_DIR}/mipsisa32r2el-axis-linux-gnu/sys-include
CPPFLAGS+=-DINT_TYPE_SIZEOF_POINTER=int
CPPFLAGS+=-DFORMAT_FOR_SIZE_T=\"%u\"
AXIS_LIBCAP=-lcapture # This is needed for the native camera classes to fetch images
AXIS_LIBCAP_DEP=-ldbus-1 -lgobject-2.0 -ldbus-glib-1 -lgthread-2.0 -lglib-2.0 -lrapp -lpthread # Dependencies of libcapture
LDFLAGS+=${AXIS_LIBCAP} ${AXIS_LIBCAP_DEP} ${AXIS_LIBCAP} -L${AXIS_PATH}/lib -L${AXIS_PATH}/usr/lib # Specify which libs are used and set search path for them
CFLAGS+=-O3 -g -Wall
LDLIBS+=-lpthread
all: http_server
all: http_server motion_server
http_server: http_server.o camera.o
http_server: http_server.o camera.o server_common.o
http_server.o: http_server.c camera.h
motion_server: motion_server.o server_common.o
motion_server.o: motion_server.c
server_common.o: server_common.c server_common.h
camera.o: camera.c camera.h fakecapture.h
clean:
......
......@@ -4,15 +4,24 @@
CC=gcc
.PHONY: all clean
all: fake_server
all: fake_server motion_server_host motion_client
CPPFLAGS+=-DFAKE -DDISABLE_SANITY_CHECKS
CFLAGS+=-DFAKE -DDISABLE_SANITY_CHECKS
CFLAGS+=-Wall
CPPFLAGS+=-DUSE_POSIX_FUNCTION
CPPFLAGS+=-DINFO
# CPPFLAGS+=-DDEBUG
# CPPFLAGS+=-DSHORT_NUMBER_FRAME_SEQUENCE
CFLAGS+=-g -Wall
LDLIBS=-lpthread
fake_server: http_server.c fakecapture.h fakecapture.c camera.h camera.c
$(CC) -o $@ $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) http_server.c fakecapture.c camera.c $(LDLIBS)
fake_server: http_server.c fakecapture.h fakecapture.c camera.h camera.c server_common.c
$(CC) -o $@ $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) http_server.c fakecapture.c camera.c server_common.c $(LDLIBS)
motion_server_host: motion_server.c server_common.c
$(CC) -o $@ $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) motion_server.c server_common.c $(LDLIBS)
motion_client: motion_client.c server_common.c
$(CC) -o $@ $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) motion_client.c server_common.c $(LDLIBS)
clean:
-rm fake_server
-rm fake_server motion_server_host motion_client
#include "camera.h"
#include <stdio.h>
#include <string.h> // for memcpy
#include <stdlib.h> // for abs
camera* camera_open(){
camera *cam = malloc(sizeof(camera));
......@@ -8,6 +10,10 @@ camera* camera_open(){
return NULL;
}
#ifdef FAKE
#ifdef DEBUG
printf("fake camera: camera_open\n");
#endif
cam->frame_nbr = 0;
#endif
cam->stream = capture_open_stream(IMAGE_JPEG, "fps=25&resolution=640x480");
......@@ -22,52 +28,21 @@ void camera_close(camera* cam){
frame* camera_get_frame(camera* cam){
frame *f = malloc(sizeof(frame));
f->fr = capture_get_frame(cam->stream);
#ifdef FAKE
++cam->frame_nbr;
#endif
#ifdef DEBUG
#ifdef FAKE
f->motion = (cam->frame_nbr >= 86 && cam->frame_nbr <= 240);
cam->frame_nbr = (cam->frame_nbr % 247) + 1;
printf("camera_get_frame: number=%d\n", cam->frame_nbr);
#else
//TODO
//f->motion = analyseframes(capture_get_frame(cam->stream, */prev_frame*/);
printf("camera_get_frame: ts=%llu\n", get_frame_timestamp(f));
#endif
#endif
return f;
}
//From axis example code
static int analyse_frames(media_frame *cur_frame, media_frame *prev_frame){
int i, j;
char *prev_data = NULL;
int prev_width;
int prev_height;
//int prev_stride;
char *cur_data = NULL;
int cur_width;
int cur_height;
//int cur_stride;
int result = 0;
prev_data = (char *)capture_frame_data(prev_frame);
prev_width = capture_frame_width(prev_frame);
prev_height = capture_frame_height(prev_frame);
//prev_stride = capture_frame_stride(prev_frame);
cur_data = (char *)capture_frame_data(cur_frame);
cur_width = capture_frame_width(cur_frame);
cur_height = capture_frame_height(cur_frame);
//cur_stride = capture_frame_stride(cur_frame);;
/* simple pixel diff */
for (i = 0; i < cur_height; i++) {
for (j = 0; j < cur_width; j++) {
int c_pos = i /* * cur_stride */ + j;
int p_pos = i /* * prev_stride */ + j;
result += abs(cur_data[c_pos] - prev_data[p_pos]);
}
}
result /= (cur_width * cur_height);
return result > 20; //Arbitrary value used in the axis example
}
byte* get_frame_bytes(frame* f){
return (byte *) capture_frame_data(f->fr);
}
......@@ -80,9 +55,11 @@ capture_time get_frame_timestamp(frame* f){
return capture_frame_timestamp(f->fr);
}
#ifdef MOTION_FLAG_IN_FRAMES
int get_frame_motion(frame* f){
return f->motion;
}
#endif
size_t get_frame_height(frame* f){
return capture_frame_height(f->fr);
......
......@@ -6,6 +6,7 @@
#define IMAGE_JPEG "image/jpeg"
#undef MOTION_FLAG_IN_FRAMES
/* A wrapper for the Axis capture API
*/
......@@ -23,14 +24,12 @@ typedef struct camera camera;
typedef struct frame frame;
typedef char byte;
#ifdef FRAME_NOT_NEEDED
typedef frame media_frame;
#else
struct frame{
media_frame* fr;
#ifdef MOTION_FLAG_IN_FRAMES
int motion;
};
#endif
};
struct camera* camera_open();
void camera_close(struct camera*);
......@@ -43,7 +42,9 @@ size_t get_frame_size(struct frame*);
capture_time get_frame_timestamp(struct frame*);
#ifdef MOTION_FLAG_IN_FRAMES
int get_frame_motion(struct frame*);
#endif
size_t get_frame_height(struct frame*);
......
#include <math.h>
#ifndef NO_FAKE_MOTION
#include "server_common.h"
#include <time.h>
#endif
#include "fakecapture.h"
#define DEBUG
// compile-time options:
// prefereably, set using -D<MACRONAME> in the Makefile
// or on the command line
//
// define to enable debug output,
// #define DEBUG
//
// define to use a short sequence of frames with numbers 1 -- 5,
// undefine to use an actual film sequence (man in corridor)
// #define SHORT_NUMBER_FRAME_SEQUENCE
//
// we need sockets for fake motion detection,
// define to turn fake motion detection off
// #define NO_FAKE_MOTION
#ifdef SHORT_NUMBER_FRAME_SEQUENCE
#define MEDIA_FRAME_STR "media/%d.jpg"
#define START_FRAME 1
#define NUM_FRAMES 5
#else
#define MEDIA_FRAME_STR "media/film%03d.jpg"
#ifndef START_FRAME
// to skip directly to the parts with motion,
// define START_FRAME to (a bit less than) 86
#define START_FRAME 1
#endif
#define NUM_FRAMES 247
#endif
#define FILEPATH_LENGTH 100
static int frame_nr = START_FRAME;
#ifndef NO_FAKE_MOTION
// we need sockets for fake motion detection
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
// #include <stdlib.h>
// #include <unistd.h>
#include <errno.h>
// #include <string.h> // for memcpy, memset, strlen
static void fake_motion_detect(int frame_nr);
static void fake_motion_init();
static void fake_motion_free();
int motionfd;
struct hostent *motion_server;
struct sockaddr_in motion_serv_addr;
#endif
// for portability with MacOs
#ifdef __MACH__
#define UNUSED_VALUE 1
#define CLOCK_MONOTONIC UNUSED_VALUE
......@@ -27,6 +77,10 @@ media_stream *
capture_open_stream(const char *media_type, const char *media_props)
{
media_stream *res = malloc(sizeof(media_stream));
res->frame_nr = START_FRAME;
#ifndef NO_FAKE_MOTION
fake_motion_init();
#endif
return res;
}
......@@ -36,11 +90,13 @@ capture_get_frame(media_stream *stream)
int fd;
char fname[FILEPATH_LENGTH];
fname[FILEPATH_LENGTH - 1]='\0';
snprintf(fname, FILEPATH_LENGTH - 1, "media/film%03d.jpg", frame_nr++);
if(frame_nr > NUM_FRAMES) {
frame_nr = START_FRAME;
snprintf(fname, FILEPATH_LENGTH - 1, MEDIA_FRAME_STR, stream->frame_nr++);
if(stream->frame_nr > NUM_FRAMES) {
stream->frame_nr = START_FRAME;
};
#ifdef INFO
printf("trying to open %s\n", fname);
#endif
fd = open(fname, O_RDONLY);
if(fd < 0) {
perror("fakecapture:capture_get_frame:open");
......@@ -62,6 +118,10 @@ capture_get_frame(media_stream *stream)
perror("Warning! fakecapture:capture_get_frame:close");
}
#ifndef NO_FAKE_MOTION
fake_motion_detect(stream->frame_nr);
#endif
return res;
}
......@@ -141,4 +201,70 @@ void
capture_close_stream(media_stream *stream)
{
free(stream);
#ifndef NO_FAKE_MOTION
fake_motion_free();
#endif
}
#ifndef NO_FAKE_MOTION
#ifndef MOTION_PORT
#define MOTION_PORT 9090
#endif
static void fake_motion_notify()
{
char msg[100];
snprintf(msg, 100, "GET /motion?Message=%ld\n",time(0));
#ifdef DEBUG
printf("fake_motion_notify: %s\n", msg);
#endif
fake_motion_init();
if (connect(motionfd, (struct sockaddr*)&motion_serv_addr, sizeof(motion_serv_addr)) < 0) {
perror("ERROR connecting");
} else {
if(write_string(motionfd, msg) < 0){
perror("ERROR writing to motion server");
}
close(motionfd);
}
}
static void fake_motion_detect(int frame_nr)
{
#ifdef SHORT_NUMBER_FRAME_SEQUENCE
// START_FRAME 1
// NUM_FRAMES 5
fake_motion_notify();
#else
// START_FRAME 55
// NUM_FRAMES 247
if(frame_nr > 86 && frame_nr < 219 && (frame_nr % 5 == 0)){
fake_motion_notify();
}
#endif
}
static void fake_motion_init()
{
motionfd = socket(AF_INET, SOCK_STREAM, 0);
if (motionfd < 0) {
perror("creating motion socket");
//TODO: set error flag to avoid using motion
}
motion_server = gethostbyname("localhost");
if (motion_server == NULL) {
fprintf(stderr,"ERROR, motion_server name not found\n");
}
bzero((char *) &motion_serv_addr, sizeof(motion_serv_addr));
motion_serv_addr.sin_family = AF_INET;
bcopy((char *)motion_server->h_addr, (char *)&motion_serv_addr.sin_addr.s_addr, motion_server->h_length);
motion_serv_addr.sin_port = htons(MOTION_PORT);
}
static void fake_motion_free()
{
//TODO: any more cleanup needed?
if (close(motionfd)) {
perror("closing motion socket");
}
}
#endif
......@@ -16,6 +16,7 @@
typedef unsigned long long capture_time;
struct _media_stream {
int frame_nr;
};
struct _media_frame {
......
#include "server_common.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
......@@ -9,16 +10,24 @@
#include <pthread.h>
#define USE_CAMERA
#define INFO
#undef DEBUG
// some diagnostic printouts
// #define INFO
// more diagnostic printouts
// #undef DEBUG
// the strncasecmp function is not in the ISO C standard
#define USE_POSIX_FUNCTION
// #define USE_POSIX_FUNCTION
#ifdef USE_CAMERA
#include "camera.h"
#endif
#ifndef MOTION_PORT
#define MOTION_PORT 9090
#endif
#define BUFSIZE 50000
struct client{
int connfd;
......@@ -28,8 +37,28 @@ struct client{
byte* frame_data;
#endif
};
struct global_state {
int listenfd;
int running;
int quit;
pthread_t main_thread;
pthread_t client_thread;
pthread_t ui_thread;
pthread_t bg_thread;
struct pollfd pfd;
int motionfd;
#ifdef USE_CAMERA
camera* cam;
#endif
};
int client_write_string(struct client* client);
int client_write_n(struct client* client, size_t n);
void* serve_client(void *ctxt);
void server_quit(struct global_state* s);
void signal_to_bg_task();
/////////////// camera stuff
......@@ -38,21 +67,30 @@ int client_write_n(struct client* client, size_t n);
struct client;
//TODO: move these into the global_state struct?
pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t global_cond = PTHREAD_COND_INITIALIZER;
#ifdef USE_CAMERA
int try_open_camera(struct client* client)
int try_open_camera(struct global_state* state)
{
client->cam = camera_open();
if (!client->cam){ // Check if null
state->cam = camera_open();
if (!state->cam){ // Check if null
printf("axism3006v: Stream is null, can't connect to camera");
return ERR_OPEN_STREAM;
}
return 0;
}
void close_camera(struct global_state* state)
{
if(state->cam) {
camera_close(state->cam);
state->cam = NULL;
}
}
/* Sets up the packet structure in client->sendBuff.
* This is a minimal HTTP header for an image/jpeg
......@@ -65,7 +103,7 @@ int try_open_camera(struct client* client)
ssize_t setup_packet(struct client* client, uint32_t frame_sz)
{
size_t header_size;
snprintf(client->sendBuff, sizeof(client->sendBuff),
snprintf(client->sendBuff, sizeof(client->sendBuff),
"HTTP/1.0 200 OK\nContent-Length: %d\nContent-Type: image/jpeg\n\n", frame_sz);
header_size = strlen(client->sendBuff);
if(header_size + frame_sz > sizeof(client->sendBuff)) {
......@@ -73,16 +111,17 @@ ssize_t setup_packet(struct client* client, uint32_t frame_sz)
}
client->frame_data = client->sendBuff + header_size;
#ifdef DEBUG
printf("Header size = %d\n", header_size);
printf("Header size = " FORMAT_FOR_SIZE_T "\n", header_size);
#endif
return header_size+frame_sz;
}
/* send packet with frame
* returns 0 on success
*/
int client_send_frame(struct client* client, frame* fr)
{
// this should be a compile-time check
// this should really be a compile-time check, but that is complicated
#ifndef DISABLE_SANITY_CHECKS
if(sizeof(size_t) != sizeof(uint32_t)) {
printf("sizeof(size_t)=%d, sizeof(uint32_t)=%d\n", sizeof(size_t), sizeof(uint32_t));
......@@ -98,21 +137,19 @@ int client_send_frame(struct client* client, frame* fr)
ssize_t packet_sz = setup_packet(client, frame_sz);
if(packet_sz < 0) {
printf("Frame too big for send buffer(%d > %d), skipping.\n", frame_sz, sizeof(client->sendBuff));
printf("Frame too big for send buffer(" FORMAT_FOR_SIZE_T " > " FORMAT_FOR_SIZE_T "), skipping.\n", frame_sz, sizeof(client->sendBuff));
result = 1;
} else {
int written;
#ifdef INFO
printf("encode size (%X=%d) + data\n", frame_sz, frame_sz);
#endif
#ifdef DEBUG
printf("sizeof(size_t)=%d, sizeof(uint32_t)=%d\n", sizeof(size_t), sizeof(uint32_t));
printf("encode size:" FORMAT_FOR_SIZE_T "\n", frame_sz);
printf("sizeof(size_t)=" FORMAT_FOR_SIZE_T ", sizeof(uint32_t)=" FORMAT_FOR_SIZE_T "\n", sizeof(size_t), sizeof(uint32_t));
#endif
memcpy(client->frame_data, data, frame_sz);
written=client_write_n(client, packet_sz);
if(written != packet_sz) {
printf("WARNING! packet_sz=%d, written=%d\n", packet_sz, written);
printf("WARNING! packet_sz=" FORMAT_FOR_SIZE_T ", written=%d\n", packet_sz, written);
result = 3;
} else {
result = 0;
......@@ -142,17 +179,7 @@ int try_get_frame(struct client* client)
int client_write_string(struct client* client)
{
size_t n = strlen(client->sendBuff);
size_t written = 0;
while (written < n) {
ssize_t tmp = write(client->connfd, client->sendBuff, n-written);
if (tmp < 0) {
perror("write_n ERROR");
return tmp;
}
written += tmp;
}
return written;
return write_string(client->connfd, client->sendBuff);
}
/*
......@@ -163,16 +190,7 @@ int client_write_string(struct client* client)
*/
int client_write_n(struct client* client, size_t n)
{
size_t written = 0;
while (written < n) {
ssize_t tmp = write(client->connfd, client->sendBuff, n-written);
if (tmp < 0) {
perror("write_n ERROR");
return tmp;
}
written += tmp;
}
return written;
return write_n(client->connfd, client->sendBuff,n);
}
......@@ -201,55 +219,78 @@ int parse_http_request(const char* buf, size_t sz)
}
}
static void send_internal_error(struct client* client,const char* msg)
{
snprintf(client->sendBuff, sizeof(client->sendBuff),
"HTTP/1.0 500 Internal Error\nContent-Length: " FORMAT_FOR_SIZE_T "\nContent-Type: text/plain\n\n%s",
strlen(msg), msg);
client_write_string(client);
}
/* The function for a thread that processes a single client request.
* The client struct pointer is passed as void* due to the pthreads API
*/
void* serve_client(void *ctxt)
{
char buf[1024];
char buf[1024] = {};
struct client* client = ctxt;
memset(client->sendBuff, '0', sizeof(client->sendBuff));
memset(client->sendBuff, 0, sizeof(client->sendBuff));
int rres = read(client->connfd, buf, 1024);
if(rres < 0) {
perror("motion_task: read");
return (void*) (intptr_t) errno;
}
#ifdef DEBUG
printf("read: rres = %d\n", rres);
printf("buf[%s]\n", buf);
#endif
int hres = parse_http_request(buf, 1024);
if(hres == 0) {
#ifdef USE_CAMERA
if( try_open_camera(client)) {
printf("ERROR opening camera\n");
} else {
try_get_frame(client);
}
int cres=0;
if( !client->cam || (cres=try_get_frame(client))) {
printf("ERROR getting frame from camera: %d\n",cres);
send_internal_error(client, "Error getting frame from camera\n");
}
#else
snprintf(client->sendBuff, sizeof(client->sendBuff), "Hello...\n");
client_write_string(client);
#endif
} else if (hres == 404) {
const char* msg = "404: File not found";
snprintf(client->sendBuff, sizeof(client->sendBuff), "HTTP/1.0 404 Not Found\nContent-Length: %d\nContent-Type: text/plain\n\n%s",strlen(msg), msg);
} else {
const char* msg = "501: Not implemented";
snprintf(client->sendBuff, sizeof(client->sendBuff), "HTTP/1.0 501 Not Implemented\nContent-Length: %d\nContent-Type: text/plain\n\n%s",strlen(msg), msg);
if (hres == 404) {
const char* msg = "404: File not found.\n\nI only have image.jpg";
snprintf(client->sendBuff, sizeof(client->sendBuff),
"HTTP/1.0 404 Not Found\nContent-Length: " FORMAT_FOR_SIZE_T
"\nContent-Type: text/plain\n\n%s",
strlen(msg), msg);
} else {
const char* msg = "501: Not implemented";
snprintf(client->sendBuff, sizeof(client->sendBuff),
"HTTP/1.0 501 Not Implemented\nContent-Length: " FORMAT_FOR_SIZE_T
"\nContent-Type: text/plain\n\n%s",
strlen(msg), msg);
}
client_write_string(client);
}
#ifndef USE_CAMERA
client_write_string(client);
#endif
return (void*) close(client->connfd);
return (void*) (intptr_t) close(client->connfd);
}
struct global_state {
int listenfd;
int running;