diff --git a/device/buffer_lock.c b/device/buffer_lock.c index 3a92acc..73138e5 100644 --- a/device/buffer_lock.c +++ b/device/buffer_lock.c @@ -34,6 +34,9 @@ bool buffer_lock_needs_buffer(buffer_lock_t *buf_lock) if (buf_lock->refs > 0) { needs_buffer = true; } + for (int i = 0; !needs_buffer && buf_lock->notify_buffer[i] && i < BUFFER_LOCK_MAX_CALLBACKS; i++) { + needs_buffer = buf_lock->check_streaming[i](buf_lock); + } pthread_mutex_unlock(&buf_lock->lock); return needs_buffer; @@ -67,6 +70,10 @@ void buffer_lock_capture(buffer_lock_t *buf_lock, buffer_t *buf) (now - buf_lock->buf_time_us) / 1000.0f); buf_lock->buf_time_us = now; pthread_cond_broadcast(&buf_lock->cond_wait); + + for (int i = 0; buf_lock->notify_buffer[i] && i < BUFFER_LOCK_MAX_CALLBACKS; i++) { + buf_lock->notify_buffer[i](buf_lock, buf); + } } pthread_mutex_unlock(&buf_lock->lock); @@ -135,3 +142,37 @@ error: buffer_lock_use(buf_lock, -1); return -frames; } + +bool buffer_lock_register_check_streaming(buffer_lock_t *buf_lock, buffer_lock_check_streaming check_streaming) +{ + bool ret = false; + + pthread_mutex_lock(&buf_lock->lock); + for (int i = 0; i < BUFFER_LOCK_MAX_CALLBACKS; i++) { + if (!buf_lock->check_streaming[i]) { + buf_lock->check_streaming[i] = check_streaming; + ret = true; + break; + } + } + pthread_mutex_unlock(&buf_lock->lock); + + return ret; +} + +bool buffer_lock_register_notify_buffer(buffer_lock_t *buf_lock, buffer_lock_notify_buffer notify_buffer) +{ + bool ret = false; + + pthread_mutex_lock(&buf_lock->lock); + for (int i = 0; i < BUFFER_LOCK_MAX_CALLBACKS; i++) { + if (!buf_lock->notify_buffer[i]) { + buf_lock->notify_buffer[i] = notify_buffer; + ret = true; + break; + } + } + pthread_mutex_unlock(&buf_lock->lock); + + return ret; +} diff --git a/device/buffer_lock.h b/device/buffer_lock.h index de49819..33b44a4 100644 --- a/device/buffer_lock.h +++ b/device/buffer_lock.h @@ -5,9 +5,22 @@ #include typedef struct buffer_s buffer_t; +typedef struct buffer_list_s buffer_list_t; +typedef struct buffer_lock_s buffer_lock_t; + +typedef bool (*buffer_lock_check_streaming)(buffer_lock_t *buf_lock); +typedef void (*buffer_lock_notify_buffer)(buffer_lock_t *buf_lock, buffer_t *buf); + +#define BUFFER_LOCK_MAX_CALLBACKS 10 typedef struct buffer_lock_s { const char *name; + buffer_list_t *buf_list; + + buffer_lock_check_streaming check_streaming[BUFFER_LOCK_MAX_CALLBACKS]; + buffer_lock_notify_buffer notify_buffer[BUFFER_LOCK_MAX_CALLBACKS]; + + // private pthread_mutex_t lock; pthread_cond_t cond_wait; buffer_t *buf; @@ -40,3 +53,5 @@ bool buffer_lock_needs_buffer(buffer_lock_t *buf_lock); void buffer_lock_use(buffer_lock_t *buf_lock, int ref); bool buffer_lock_is_used(buffer_lock_t *buf_lock); int buffer_lock_write_loop(buffer_lock_t *buf_lock, int nframes, buffer_write_fn fn, void *data); +bool buffer_lock_register_check_streaming(buffer_lock_t *buf_lock, buffer_lock_check_streaming check_streaming); +bool buffer_lock_register_notify_buffer(buffer_lock_t *buf_lock, buffer_lock_notify_buffer notify_buffer); diff --git a/device/camera/camera.c b/device/camera/camera.c index 323244a..ea6af1a 100644 --- a/device/camera/camera.c +++ b/device/camera/camera.c @@ -3,6 +3,7 @@ #include "device/device.h" #include "device/device_list.h" #include "device/buffer_list.h" +#include "device/buffer_lock.h" #include "device/links.h" #include "util/opts/log.h" #include "util/opts/fourcc.h" @@ -82,6 +83,10 @@ void camera_capture_set_callbacks(camera_t *camera, buffer_list_t *capture, link { link_t *link = camera_ensure_capture(camera, capture); link->callbacks = callbacks; + + if (callbacks.buf_lock) { + callbacks.buf_lock->buf_list = capture; + } } int camera_set_params(camera_t *camera) diff --git a/device/camera/camera_output.c b/device/camera/camera_output.c index 68dbd3d..aa6d6ee 100644 --- a/device/camera/camera_output.c +++ b/device/camera/camera_output.c @@ -18,8 +18,8 @@ static const char *jpeg_names[2] = { }; static link_callbacks_t jpeg_callbacks[2] = { - { "JPEG-CAPTURE", http_jpeg_capture, http_jpeg_needs_buffer }, - { "JPEG-LOW-CAPTURE", http_jpeg_lowres_capture, http_jpeg_needs_buffer } + { .name = "JPEG-CAPTURE", .buf_lock = &http_jpeg }, + { .name = "JPEG-LOW-CAPTURE", .buf_lock = &http_jpeg_lowres } }; static const char *h264_names[2] = { @@ -27,26 +27,9 @@ static const char *h264_names[2] = { "H264-LOW" }; -static void h264_capture(buffer_t *buf) -{ - http_h264_capture(buf); - rtsp_h264_capture(buf); -} - -static void h264_lowres_capture(buffer_t *buf) -{ - http_h264_lowres_capture(buf); - rtsp_h264_low_res_capture(buf); -} - -static bool h264_needs_buffer() -{ - return http_h264_needs_buffer() | rtsp_h264_needs_buffer(); -} - static link_callbacks_t h264_callbacks[2] = { - { "H264-CAPTURE", h264_capture, h264_needs_buffer }, - { "H264-LOW-CAPTURE", h264_lowres_capture, h264_needs_buffer } + { .name = "H264-CAPTURE", .buf_lock = &http_h264 }, + { .name = "H264-LOW-CAPTURE", .buf_lock = &http_h264_lowres } }; static int camera_configure_h264_output(camera_t *camera, buffer_list_t *src_capture, int res) diff --git a/device/links.c b/device/links.c index 5779dd4..96d010e 100644 --- a/device/links.c +++ b/device/links.c @@ -2,6 +2,7 @@ #include "device/device.h" #include "device/buffer.h" #include "device/buffer_list.h" +#include "device/buffer_lock.h" #include "util/opts/log.h" #include "util/opts/fourcc.h" @@ -34,6 +35,10 @@ int _build_fds(link_t *all_links, struct pollfd *fds, link_t **links, buffer_lis paused = false; } + if (link->callbacks.buf_lock && buffer_lock_needs_buffer(link->callbacks.buf_lock)) { + paused = false; + } + for (int j = 0; link->sinks[j]; j++) { buffer_list_t *sink = link->sinks[j]; @@ -107,6 +112,10 @@ int links_enqueue_from_source(buffer_list_t *buf_list, link_t *link) link->callbacks.on_buffer(buf); } + if (link->callbacks.buf_lock) { + buffer_lock_capture(link->callbacks.buf_lock, buf); + } + return 0; error: @@ -296,10 +305,10 @@ void links_dump(link_t *all_links) links_dump_buf_list(line, link->sinks[j]); } - if (link->callbacks.callback_name) { + if (link->callbacks.name) { if (link->sinks[0]) strcat(line, ", "); - strcat(line, link->callbacks.callback_name); + strcat(line, link->callbacks.name); } strcat(line, "]"); diff --git a/device/links.h b/device/links.h index f750544..732daa4 100644 --- a/device/links.h +++ b/device/links.h @@ -7,6 +7,7 @@ typedef struct buffer_s buffer_t; typedef struct buffer_list_s buffer_list_t; +typedef struct buffer_lock_s buffer_lock_t; typedef struct link_s link_t; typedef void (*link_on_buffer)(buffer_t *buf); @@ -14,10 +15,11 @@ typedef bool (*link_check_streaming)(); typedef bool (*link_validate_buffer)(struct link_s *link, buffer_t *buf); typedef struct link_callbacks_s { - const char *callback_name; + const char *name; link_on_buffer on_buffer; link_check_streaming check_streaming; link_validate_buffer validate_buffer; + buffer_lock_t *buf_lock; } link_callbacks_t; typedef struct link_s { diff --git a/output/http_h264.c b/output/http_h264.c index 2d04157..529e47d 100644 --- a/output/http_h264.c +++ b/output/http_h264.c @@ -9,9 +9,6 @@ #include "device/buffer_list.h" #include "device/device.h" -DEFINE_BUFFER_LOCK(http_h264, 0); -DEFINE_BUFFER_LOCK(http_h264_lowres, 0); - static const char *const VIDEO_HEADER = "HTTP/1.0 200 OK\r\n" "Access-Control-Allow-Origin: *\r\n" @@ -19,24 +16,9 @@ static const char *const VIDEO_HEADER = "Content-Type: application/octet-stream\r\n" "\r\n"; -void http_h264_capture(buffer_t *buf) -{ - buffer_lock_capture(&http_h264, buf); -} - -void http_h264_lowres_capture(buffer_t *buf) -{ - buffer_lock_capture(&http_h264_lowres, buf); -} - -bool http_h264_needs_buffer() -{ - return buffer_lock_needs_buffer(&http_h264) | buffer_lock_needs_buffer(&http_h264_lowres); -} - buffer_lock_t *http_h264_buffer_for_res(http_worker_t *worker) { - if (strstr(worker->client_method, HTTP_LOW_RES_PARAM)) + if (strstr(worker->client_method, HTTP_LOW_RES_PARAM) && http_jpeg_lowres.buf_list) return &http_h264_lowres; else return &http_h264; diff --git a/output/http_jpeg.c b/output/http_jpeg.c index 918ce14..e20fbdd 100644 --- a/output/http_jpeg.c +++ b/output/http_jpeg.c @@ -6,9 +6,6 @@ #include "device/buffer.h" #include "device/buffer_lock.h" -DEFINE_BUFFER_LOCK(http_jpeg, 1000); -DEFINE_BUFFER_LOCK(http_jpeg_lowres, 1000); - #define PART_BOUNDARY "123456789000000000000987654321" #define CONTENT_TYPE "image/jpeg" #define CONTENT_LENGTH "Content-Length" @@ -23,24 +20,9 @@ static const char *const STREAM_PART = "Content-Type: " CONTENT_TYPE "\r\n" CONT static const char *const STREAM_BOUNDARY = "\r\n" "--" PART_BOUNDARY "\r\n"; -bool http_jpeg_needs_buffer() -{ - return buffer_lock_needs_buffer(&http_jpeg) | buffer_lock_needs_buffer(&http_jpeg_lowres); -} - -void http_jpeg_capture(buffer_t *buf) -{ - buffer_lock_capture(&http_jpeg, buf); -} - -void http_jpeg_lowres_capture(buffer_t *buf) -{ - buffer_lock_capture(&http_jpeg_lowres, buf); -} - buffer_lock_t *http_jpeg_buffer_for_res(http_worker_t *worker) { - if (strstr(worker->client_method, HTTP_LOW_RES_PARAM)) + if (strstr(worker->client_method, HTTP_LOW_RES_PARAM) && http_jpeg_lowres.buf_list) return &http_jpeg_lowres; else return &http_jpeg; diff --git a/output/output.c b/output/output.c new file mode 100644 index 0000000..5f84c35 --- /dev/null +++ b/output/output.c @@ -0,0 +1,7 @@ +#include "device/buffer_lock.h" + +DEFINE_BUFFER_LOCK(http_h264, 0); +DEFINE_BUFFER_LOCK(http_h264_lowres, 0); + +DEFINE_BUFFER_LOCK(http_jpeg, 1000); +DEFINE_BUFFER_LOCK(http_jpeg_lowres, 1000); diff --git a/output/output.h b/output/output.h index ef6c68c..f336ee6 100644 --- a/output/output.h +++ b/output/output.h @@ -5,20 +5,20 @@ struct http_worker_s; struct buffer_s; +extern struct buffer_lock_s http_h264; +extern struct buffer_lock_s http_h264_lowres; + +extern struct buffer_lock_s http_jpeg; +extern struct buffer_lock_s http_jpeg_lowres; + // M-JPEG void http_snapshot(struct http_worker_s *worker, FILE *stream); void http_stream(struct http_worker_s *worker, FILE *stream); -void http_jpeg_capture(struct buffer_s *buf); -void http_jpeg_lowres_capture(struct buffer_s *buf); -bool http_jpeg_needs_buffer(); void http_option(struct http_worker_s *worker, FILE *stream); // H264 -bool http_h264_needs_buffer(); -void http_h264_capture(struct buffer_s *buf); -void http_h264_lowres_capture(struct buffer_s *buf); -void http_h264_video(struct http_worker_s *worker, FILE *stream); bool h264_is_key_frame(struct buffer_s *buf); +void http_h264_video(struct http_worker_s *worker, FILE *stream); void http_mkv_video(struct http_worker_s *worker, FILE *stream); void http_mp4_video(struct http_worker_s *worker, FILE *stream); void http_mov_video(struct http_worker_s *worker, FILE *stream); diff --git a/output/rtsp/rtsp.cc b/output/rtsp/rtsp.cc index de28a1d..a9d4ea0 100644 --- a/output/rtsp/rtsp.cc +++ b/output/rtsp/rtsp.cc @@ -3,6 +3,7 @@ extern "C" { #include "util/http/http.h" #include "device/buffer.h" #include "device/buffer_list.h" +#include "device/buffer_lock.h" #include "device/device.h" #include "util/opts/log.h" #include "util/opts/fourcc.h" @@ -204,6 +205,33 @@ static void *rtsp_server_thread(void *opaque) return NULL; } +static bool rtsp_h264_needs_buffer(buffer_lock_t *buf_lock) +{ + return rtsp_streams != NULL; +} + +static void rtsp_h264_capture(buffer_lock_t *buf_lock, buffer_t *buf) +{ + pthread_mutex_lock(&rtsp_lock); + for (DynamicH264Stream *stream = rtsp_streams; stream; stream = stream->pNextStream) { + stream->receiveData(buf, false); + + if (!http_h264_lowres.buf_list) { + stream->receiveData(buf, true); + } + } + pthread_mutex_unlock(&rtsp_lock); +} + +static void rtsp_h264_low_res_capture(buffer_lock_t *buf_lock, buffer_t *buf) +{ + pthread_mutex_lock(&rtsp_lock); + for (DynamicH264Stream *stream = rtsp_streams; stream; stream = stream->pNextStream) { + stream->receiveData(buf, true); + } + pthread_mutex_unlock(&rtsp_lock); +} + extern "C" int rtsp_server(rtsp_options_t *options) { // Begin by setting up our usage environment: @@ -234,6 +262,11 @@ extern "C" int rtsp_server(rtsp_options_t *options) // LOG_INFO(NULL, "The RTSP-over-HTTP is not available."); // } + buffer_lock_register_check_streaming(&http_h264, rtsp_h264_needs_buffer); + buffer_lock_register_notify_buffer(&http_h264, rtsp_h264_capture); + buffer_lock_register_check_streaming(&http_h264_lowres, rtsp_h264_needs_buffer); + buffer_lock_register_notify_buffer(&http_h264_lowres, rtsp_h264_low_res_capture); + pthread_create(&rtsp_thread, NULL, rtsp_server_thread, env); return 0; @@ -241,29 +274,6 @@ error: return -1; } -extern "C" bool rtsp_h264_needs_buffer() -{ - return rtsp_streams != NULL; -} - -extern "C" void rtsp_h264_capture(buffer_t *buf) -{ - pthread_mutex_lock(&rtsp_lock); - for (DynamicH264Stream *stream = rtsp_streams; stream; stream = stream->pNextStream) { - stream->receiveData(buf, false); - } - pthread_mutex_unlock(&rtsp_lock); -} - -extern "C" void rtsp_h264_low_res_capture(struct buffer_s *buf) -{ - pthread_mutex_lock(&rtsp_lock); - for (DynamicH264Stream *stream = rtsp_streams; stream; stream = stream->pNextStream) { - stream->receiveData(buf, true); - } - pthread_mutex_unlock(&rtsp_lock); -} - #else // USE_RTSP extern "C" int rtsp_server() @@ -271,17 +281,4 @@ extern "C" int rtsp_server() return 0; } -extern "C" bool rtsp_h264_needs_buffer() -{ - return false; -} - -extern "C" void rtsp_h264_capture(buffer_t *buf) -{ -} - -extern "C" void rtsp_h264_low_res_capture(struct buffer_s *buf) -{ -} - #endif // USE_RTSP \ No newline at end of file diff --git a/output/rtsp/rtsp.h b/output/rtsp/rtsp.h index 93d1fee..9d7bf57 100644 --- a/output/rtsp/rtsp.h +++ b/output/rtsp/rtsp.h @@ -5,6 +5,3 @@ typedef struct rtsp_options_s { } rtsp_options_t; int rtsp_server(rtsp_options_t *options); -bool rtsp_h264_needs_buffer(); -void rtsp_h264_capture(struct buffer_s *buf); -void rtsp_h264_low_res_capture(struct buffer_s *buf);