cmd: add /status.json to describe what and how it works

This commit is contained in:
Kamil Trzcinski 2022-09-03 12:14:01 +02:00
parent aafd120af3
commit b2dfba5577
12 changed files with 195 additions and 12 deletions

View File

@ -13,6 +13,8 @@ extern unsigned char html_webrtc_html[];
extern unsigned int html_webrtc_html_len;
extern camera_t *camera;
void camera_status_json(http_worker_t *worker, FILE *stream);
static void http_once(FILE *stream, void (*fn)(FILE *stream, const char *data), void *headersp)
{
bool *headers = headersp;
@ -101,6 +103,7 @@ http_method_t http_methods[] = {
{ "GET", "/webrtc", http_content, "text/html", html_webrtc_html, 0, &html_webrtc_html_len },
{ "POST", "/webrtc", http_webrtc_offer },
{ "GET", "/option", camera_http_option },
{ "GET", "/status.json", camera_status_json },
{ "GET", "/", http_content, "text/html", html_index_html, 0, &html_index_html_len },
{ "OPTIONS", "*/", http_cors_options },
{ }

View File

@ -13,6 +13,7 @@ extern camera_options_t camera_options;
extern http_server_options_t http_options;
extern http_method_t http_methods[];
extern rtsp_options_t rtsp_options;
extern webrtc_options_t webrtc_options;
camera_t *camera;
@ -79,7 +80,9 @@ int main(int argc, char *argv[])
goto error;
}
webrtc_server();
if (!webrtc_options.disabled && webrtc_server(&webrtc_options) < 0) {
goto error;
}
while (true) {
camera = camera_open(&camera_options);

View File

@ -4,6 +4,7 @@
#include "util/opts/fourcc.h"
#include "device/camera/camera.h"
#include "output/rtsp/rtsp.h"
#include "output/webrtc/webrtc.h"
#include "output/output.h"
camera_options_t camera_options = {
@ -53,6 +54,9 @@ rtsp_options_t rtsp_options = {
.port = 0,
};
webrtc_options_t webrtc_options = {
};
option_value_t camera_formats[] = {
{ "DEFAULT", 0 },
{ "YUYV", V4L2_PIX_FMT_YUYV },

View File

@ -0,0 +1,139 @@
extern "C" {
#include "util/http/http.h"
#include "util/opts/fourcc.h"
#include "device/buffer_list.h"
#include "device/buffer_lock.h"
#include "device/camera/camera.h"
#include "output/rtsp/rtsp.h"
#include "output/webrtc/webrtc.h"
#include "output/output.h"
extern camera_t *camera;
extern http_server_options_t http_options;
extern rtsp_options_t rtsp_options;
extern webrtc_options_t webrtc_options;
};
#include <nlohmann/json.hpp>
static nlohmann::json serialize_buf_list(buffer_list_t *buf_list)
{
if (!buf_list)
return false;
nlohmann::json output;
output["name"] = buf_list->name;
output["width"] = buf_list->fmt.width;
output["height"] = buf_list->fmt.height;
output["format"] = fourcc_to_string(buf_list->fmt.format).buf;
output["nbufs"] = buf_list->nbufs;
return output;
}
static nlohmann::json serialize_buf_lock(buffer_lock_t *buf_lock)
{
if (!buf_lock)
return false;
nlohmann::json output;
output["name"] = buf_lock->name;
output["enabled"] = (buf_lock->buf_list != NULL);
if (buf_lock->buf_list) {
output["width"] = buf_lock->buf_list->fmt.width;
output["height"] = buf_lock->buf_list->fmt.height;
output["source"] = buf_lock->buf_list->name;
output["frames"] = buf_lock->counter;
output["refs"] = buf_lock->refs;
output["dropped"] = buf_lock->dropped;
}
return output;
}
static nlohmann::json devices_status_json()
{
nlohmann::json devices;
for (int i = 0; i < MAX_DEVICES; i++) {
if (!camera->devices[i])
continue;
device_t *device = camera->devices[i];
nlohmann::json device_json;
device_json["name"] = device->name;
device_json["path"] = device->path;
device_json["allow_dma"] = device->opts.allow_dma;
device_json["output"] = serialize_buf_list(device->output_list);
for (int j = 0; j < device->n_capture_list; j++) {
device_json["captures"][j] = serialize_buf_list(device->capture_lists[j]);
}
devices += device_json;
}
return devices;
}
static nlohmann::json links_status_json()
{
nlohmann::json links;
for (int i = 0; i < camera->nlinks; i++) {
link_t *link = &camera->links[i];
nlohmann::json link_json;
link_json["source"] = link->source->name;
for (int j = 0; link->sinks[j]; j++) {
link_json["sinks"][j] = link->sinks[j]->name;
}
for (int j = 0; j < link->n_callbacks; j++) {
link_json["callbacks"][j] = link->callbacks[j].name;
}
links += link_json;
}
return links;
}
static std::string strip_host_port(const char *host)
{
const char *sep = strchr(host, ':');
return sep ? std::string(host, sep) : host;
}
static nlohmann::json get_url(bool running, const char *output, const char *protocol, const char *host, int port, const char *path)
{
nlohmann::json endpoint;
endpoint["enabled"] = running;
if (running) {
endpoint["output"] = output;
endpoint["uri"] = std::string(protocol) + "://" + strip_host_port(host) + ":" + std::to_string(port) + path;
}
return endpoint;
}
extern "C" void camera_status_json(http_worker_t *worker, FILE *stream)
{
nlohmann::json message;
message["outputs"]["snapshot"] = serialize_buf_lock(&snapshot_lock);
message["outputs"]["stream"] = serialize_buf_lock(&stream_lock);
message["outputs"]["video"] = serialize_buf_lock(&video_lock);
message["devices"] = devices_status_json();
message["links"] = links_status_json();
message["endpoints"]["rtsp"] = get_url(video_lock.buf_list != NULL && rtsp_options.running, "video", "rtsp", worker->host, rtsp_options.port, "/stream.h264");
message["endpoints"]["webrtc"] = get_url(video_lock.buf_list != NULL && webrtc_options.running, "video", "http", worker->host, http_options.port, "/webrtc");
message["endpoints"]["video"] = get_url(video_lock.buf_list != NULL, "video", "http", worker->host, http_options.port, "/video");
message["endpoints"]["stream"] = get_url(stream_lock.buf_list != NULL, "stream", "http", worker->host, http_options.port, "/stream");
message["endpoints"]["snapshot"] = get_url(snapshot_lock.buf_list != NULL, "snapshot", "http", worker->host, http_options.port, "/stream");
http_write_response(stream, "200 OK", "application/json", message.dump().c_str(), 0);
}

View File

@ -244,6 +244,7 @@ extern "C" int rtsp_server(rtsp_options_t *options)
buffer_lock_register_notify_buffer(&video_lock, rtsp_h264_capture);
pthread_create(&rtsp_thread, NULL, rtsp_server_thread, env);
options->running = true;
return 0;
error:

View File

@ -1,6 +1,7 @@
#pragma once
typedef struct rtsp_options_s {
bool running;
uint port;
} rtsp_options_t;

View File

@ -5,6 +5,11 @@ extern "C" {
#include "device/buffer_lock.h"
#include "device/device.h"
#include "output/output.h"
#include "util/http/http.h"
#include "util/opts/log.h"
#include "util/opts/fourcc.h"
#include "util/opts/control.h"
#include "device/buffer.h"
};
#ifdef USE_LIBDATACHANNEL
@ -381,10 +386,12 @@ extern "C" void http_webrtc_offer(http_worker_t *worker, FILE *stream)
}
}
extern "C" void webrtc_server()
extern "C" int webrtc_server(webrtc_options_t *options)
{
buffer_lock_register_check_streaming(&video_lock, webrtc_h264_needs_buffer);
buffer_lock_register_notify_buffer(&video_lock, webrtc_h264_capture);
options->running = true;
return 0;
}
#else // USE_LIBDATACHANNEL
@ -394,8 +401,9 @@ extern "C" void http_webrtc_offer(http_worker_t *worker, FILE *stream)
http_404(stream, NULL);
}
extern "C" void webrtc_server()
extern "C" int webrtc_server(webrtc_options_t *options)
{
return 0;
}
#endif // USE_LIBDATACHANNEL

View File

@ -1,11 +1,14 @@
#pragma once
#include "util/http/http.h"
#include "util/opts/log.h"
#include "util/opts/fourcc.h"
#include "util/opts/control.h"
#include "device/buffer.h"
#include <stdio.h>
typedef struct http_worker_s http_worker_t;
typedef struct webrtc_options_s {
bool running;
bool disabled;
} webrtc_options_t;
// WebRTC
void http_webrtc_offer(http_worker_t *worker, FILE *stream);
void webrtc_server();
int webrtc_server(webrtc_options_t *options);

View File

@ -17,6 +17,7 @@
#define HEADER_RANGE "Range:"
#define HEADER_CONTENT_LENGTH "Content-Length:"
#define HEADER_USER_AGENT "User-Agent:"
#define HEADER_HOST "Host:"
static int http_listen(int port, int maxcons)
{
@ -92,6 +93,7 @@ static void http_process(http_worker_t *worker, FILE *stream)
worker->range_header[0] = 0;
worker->user_agent[0] = 0;
worker->host[0] = 0;
worker->content_length = -1;
// request_uri
@ -124,11 +126,13 @@ static void http_process(http_worker_t *worker, FILE *stream)
break;
if (strcasestr(line, HEADER_RANGE) == line) {
strcpy(worker->range_header, line);
strcpy(worker->range_header, trim(line));
} else if (strcasestr(line, HEADER_CONTENT_LENGTH) == line) {
worker->content_length = atoi(line + strlen(HEADER_CONTENT_LENGTH));
worker->content_length = atoi(trim(line + strlen(HEADER_CONTENT_LENGTH)));
} else if (strcasestr(line, HEADER_USER_AGENT) == line) {
strcpy(worker->user_agent, line + strlen(HEADER_USER_AGENT));
strcpy(worker->user_agent, trim(line + strlen(HEADER_USER_AGENT)));
} else if (strcasestr(line, HEADER_HOST) == line) {
strcpy(worker->host, trim(line + strlen(HEADER_HOST)));
}
}

View File

@ -44,6 +44,7 @@ typedef struct http_worker_s {
char client_method[BUFSIZE];
char range_header[BUFSIZE];
char user_agent[BUFSIZE];
char host[BUFSIZE];
char *request_method;
char *request_uri;
char *request_params;

View File

@ -2,6 +2,7 @@
#include "util/opts/opts.h"
#include <string.h>
#include <ctype.h>
char *
strstrn(const char *s, const char *find, size_t len)
@ -101,3 +102,17 @@ int ioctl_retried(const char *name, int fd, int request, void *arg)
}
return ret;
}
char *trim(char *s)
{
// skip left side white spaces
while (isspace (*s))
s++;
// skip right side white spaces
char *e = s + strlen(s) - 1;
while (e >= s && isspace(*e))
*e-- = 0;
return s;
}

View File

@ -49,6 +49,7 @@ bool filter_log(const char *filename);
uint64_t get_monotonic_time_us(struct timespec *ts, struct timeval *tv);
uint64_t get_time_us(clockid_t clock, struct timespec *ts, struct timeval *tv, int64_t delays_us);
int shrink_to_block(int size, int block);
char *trim(char *s);
int ioctl_retried(const char *name, int fd, int request, void *arg);