From 3c7564da19e32badeb858d73bcf98875349dfaff Mon Sep 17 00:00:00 2001 From: Maxim Devaev Date: Thu, 22 Feb 2024 03:57:38 +0200 Subject: [PATCH] big refactoring --- janus/src/client.c | 20 +- janus/src/config.c | 15 +- janus/src/memsinkfd.c | 3 +- janus/src/plugin.c | 26 +- janus/src/rtp.c | 3 +- janus/src/rtpa.c | 5 +- janus/src/rtpv.c | 20 +- janus/src/tc358743.c | 5 +- linters/tox.ini | 2 +- python/src/ustreamer.c | 89 +++---- src/dump/main.c | 19 +- src/{ustreamer => libs}/device.c | 410 +++++++++++++++---------------- src/{ustreamer => libs}/device.h | 13 +- src/libs/memsink.c | 20 +- src/libs/tools.h | 3 +- src/libs/unjpeg.c | 6 +- src/ustreamer/blank.c | 21 +- src/ustreamer/encoder.h | 2 +- src/ustreamer/http/bev.c | 2 - src/ustreamer/http/server.c | 210 ++++++++-------- src/ustreamer/http/server.h | 2 +- src/ustreamer/http/static.c | 12 +- src/ustreamer/http/unix.c | 11 +- src/ustreamer/main.c | 2 +- src/ustreamer/options.h | 2 +- src/ustreamer/stream.h | 2 +- 26 files changed, 436 insertions(+), 489 deletions(-) rename src/{ustreamer => libs}/device.c (75%) rename src/{ustreamer => libs}/device.h (96%) diff --git a/janus/src/client.c b/janus/src/client.c index 61e46af..7986868 100644 --- a/janus/src/client.c +++ b/janus/src/client.c @@ -99,16 +99,16 @@ static void *_common_thread(void *v_client, bool video) { atomic_load(&client->transmit) && (video || atomic_load(&client->transmit_audio)) ) { - janus_plugin_rtp packet = {0}; - packet.video = rtp->video; - packet.buffer = (char *)rtp->datagram; - packet.length = rtp->used; -# if JANUS_PLUGIN_API_VERSION >= 100 - // The uStreamer Janus plugin places video in stream index 0 and audio - // (if available) in stream index 1. - packet.mindex = (rtp->video ? 0 : 1); -# endif - + janus_plugin_rtp packet = { + .video = rtp->video, + .buffer = (char *)rtp->datagram, + .length = rtp->used, +# if JANUS_PLUGIN_API_VERSION >= 100 + // The uStreamer Janus plugin places video in stream index 0 and audio + // (if available) in stream index 1. + .mindex = (rtp->video ? 0 : 1), +# endif + }; janus_plugin_rtp_extensions_reset(&packet.extensions); /*if (rtp->zero_playout_delay) { // https://github.com/pikvm/pikvm/issues/784 diff --git a/janus/src/config.c b/janus/src/config.c index a6581ec..58ac221 100644 --- a/janus/src/config.c +++ b/janus/src/config.c @@ -59,13 +59,14 @@ us_config_s *us_config_init(const char *config_dir_path) { } goto ok; - error: - us_config_destroy(config); - config = NULL; - ok: - US_DELETE(jcfg, janus_config_destroy); - free(config_file_path); - return config; + +error: + US_DELETE(config, us_config_destroy); + +ok: + US_DELETE(jcfg, janus_config_destroy); + free(config_file_path); + return config; } void us_config_destroy(us_config_s *config) { diff --git a/janus/src/memsinkfd.c b/janus/src/memsinkfd.c index 964a345..5c1bcf0 100644 --- a/janus/src/memsinkfd.c +++ b/janus/src/memsinkfd.c @@ -66,8 +66,7 @@ us_frame_s *us_memsink_fd_get_frame(int fd, us_memsink_shared_s *mem, uint64_t * ok = false; } if (!ok) { - us_frame_destroy(frame); - frame = NULL; + US_DELETE(frame, us_frame_destroy); } return frame; } diff --git a/janus/src/plugin.c b/janus/src/plugin.c index da0e7b5..5891c70 100644 --- a/janus/src/plugin.c +++ b/janus/src/plugin.c @@ -169,15 +169,11 @@ static void *_video_sink_thread(void *arg) { } } - close_memsink: - if (mem != NULL) { - US_JLOG_INFO("video", "Memsink closed"); - us_memsink_shared_unmap(mem); - } - if (fd >= 0) { - close(fd); - } - sleep(1); // error_delay + close_memsink: + US_DELETE(mem, us_memsink_shared_unmap); + US_CLOSE_FD(fd, close); + US_JLOG_INFO("video", "Memsink closed"); + sleep(1); // error_delay } return NULL; } @@ -237,9 +233,9 @@ static void *_audio_thread(void *arg) { } } - close_audio: - US_DELETE(audio, us_audio_destroy); - sleep(1); // error_delay + close_audio: + US_DELETE(audio, us_audio_destroy); + sleep(1); // error_delay } return NULL; } @@ -501,9 +497,9 @@ static struct janus_plugin_result *_plugin_handle_message( PUSH_ERROR(405, "Not implemented"); } - ok_wait: - FREE_MSG_JSEP; - return janus_plugin_result_new(JANUS_PLUGIN_OK_WAIT, NULL, NULL); +ok_wait: + FREE_MSG_JSEP; + return janus_plugin_result_new(JANUS_PLUGIN_OK_WAIT, NULL, NULL); # undef PUSH_STATUS # undef PUSH_ERROR diff --git a/janus/src/rtp.c b/janus/src/rtp.c index a7eaacb..81765e3 100644 --- a/janus/src/rtp.c +++ b/janus/src/rtp.c @@ -55,7 +55,8 @@ void us_rtp_write_header(us_rtp_s *rtp, uint32_t pts, bool marked) { word0 |= rtp->seq; ++rtp->seq; -# define WRITE_BE_U32(_offset, _value) *((uint32_t *)(rtp->datagram + _offset)) = __builtin_bswap32(_value) +# define WRITE_BE_U32(x_offset, x_value) \ + *((uint32_t *)(rtp->datagram + x_offset)) = __builtin_bswap32(x_value) WRITE_BE_U32(0, word0); WRITE_BE_U32(4, pts); WRITE_BE_U32(8, rtp->ssrc); diff --git a/janus/src/rtpa.c b/janus/src/rtpa.c index 73f7dc5..ebc4db9 100644 --- a/janus/src/rtpa.c +++ b/janus/src/rtpa.c @@ -37,7 +37,7 @@ void us_rtpa_destroy(us_rtpa_s *rtpa) { } char *us_rtpa_make_sdp(us_rtpa_s *rtpa) { -# define PAYLOAD rtpa->rtp->payload + const unsigned pl = rtpa->rtp->payload; char *sdp; US_ASPRINTF(sdp, "m=audio 1 RTP/SAVPF %u" RN @@ -49,10 +49,9 @@ char *us_rtpa_make_sdp(us_rtpa_s *rtpa) { "a=rtcp-fb:%u goog-remb" RN "a=ssrc:%" PRIu32 " cname:ustreamer" RN "a=sendonly" RN, - PAYLOAD, PAYLOAD, PAYLOAD, PAYLOAD, PAYLOAD, // PAYLOAD, + pl, pl, pl, pl, pl, // pl, rtpa->rtp->ssrc ); -# undef PAYLOAD return sdp; } diff --git a/janus/src/rtpv.c b/janus/src/rtpv.c index 48c2a1a..70b7438 100644 --- a/janus/src/rtpv.c +++ b/janus/src/rtpv.c @@ -45,9 +45,9 @@ void us_rtpv_destroy(us_rtpv_s *rtpv) { } char *us_rtpv_make_sdp(us_rtpv_s *rtpv) { -# define PAYLOAD rtpv->rtp->payload // https://tools.ietf.org/html/rfc6184 // https://github.com/meetecho/janus-gateway/issues/2443 + const unsigned pl = rtpv->rtp->payload; char *sdp; US_ASPRINTF(sdp, "m=video 1 RTP/SAVPF %u" RN @@ -61,12 +61,11 @@ char *us_rtpv_make_sdp(us_rtpv_s *rtpv) { "a=ssrc:%" PRIu32 " cname:ustreamer" RN "a=extmap:1 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay" RN "a=sendonly" RN, - PAYLOAD, PAYLOAD, PAYLOAD, PAYLOAD, - PAYLOAD, PAYLOAD, PAYLOAD, + pl, pl, pl, pl, + pl, pl, pl, rtpv->rtp->ssrc ); return sdp; -# undef PAYLOAD } #define _PRE 3 // Annex B prefix length @@ -110,14 +109,13 @@ void us_rtpv_wrap(us_rtpv_s *rtpv, const us_frame_s *frame, bool zero_playout_de } void _rtpv_process_nalu(us_rtpv_s *rtpv, const uint8_t *data, size_t size, uint32_t pts, bool marked) { -# define DG rtpv->rtp->datagram - const unsigned ref_idc = (data[0] >> 5) & 3; const unsigned type = data[0] & 0x1F; + uint8_t *dg = rtpv->rtp->datagram; if (size + US_RTP_HEADER_SIZE <= US_RTP_DATAGRAM_SIZE) { us_rtp_write_header(rtpv->rtp, pts, marked); - memcpy(DG + US_RTP_HEADER_SIZE, data, size); + memcpy(dg + US_RTP_HEADER_SIZE, data, size); rtpv->rtp->used = size + US_RTP_HEADER_SIZE; rtpv->callback(rtpv->rtp); return; @@ -138,7 +136,7 @@ void _rtpv_process_nalu(us_rtpv_s *rtpv, const uint8_t *data, size_t size, uint3 us_rtp_write_header(rtpv->rtp, pts, (marked && last)); - DG[US_RTP_HEADER_SIZE] = 28 | (ref_idc << 5); + dg[US_RTP_HEADER_SIZE] = 28 | (ref_idc << 5); uint8_t fu = type; if (first) { @@ -147,9 +145,9 @@ void _rtpv_process_nalu(us_rtpv_s *rtpv, const uint8_t *data, size_t size, uint3 if (last) { fu |= 0x40; } - DG[US_RTP_HEADER_SIZE + 1] = fu; + dg[US_RTP_HEADER_SIZE + 1] = fu; - memcpy(DG + fu_overhead, src, frag_size); + memcpy(dg + fu_overhead, src, frag_size); rtpv->rtp->used = fu_overhead + frag_size; rtpv->callback(rtpv->rtp); @@ -157,8 +155,6 @@ void _rtpv_process_nalu(us_rtpv_s *rtpv, const uint8_t *data, size_t size, uint3 remaining -= frag_size; first = false; } - -# undef DG } static ssize_t _find_annexb(const uint8_t *data, size_t size) { diff --git a/janus/src/tc358743.c b/janus/src/tc358743.c index e4b3489..a2c04f2 100644 --- a/janus/src/tc358743.c +++ b/janus/src/tc358743.c @@ -44,8 +44,7 @@ int us_tc358743_read_info(const char *path, us_tc358743_info_s *info) { } # define READ_CID(x_cid, x_field) { \ - struct v4l2_control m_ctl = {0}; \ - m_ctl.id = x_cid; \ + struct v4l2_control m_ctl = {.id = x_cid}; \ if (us_xioctl(fd, VIDIOC_G_CTRL, &m_ctl) < 0) { \ US_JLOG_PERROR("audio", "Can't get value of " #x_cid); \ close(fd); \ @@ -53,10 +52,8 @@ int us_tc358743_read_info(const char *path, us_tc358743_info_s *info) { } \ info->x_field = m_ctl.value; \ } - READ_CID(TC358743_CID_AUDIO_PRESENT, has_audio); READ_CID(TC358743_CID_AUDIO_SAMPLING_RATE, audio_hz); - # undef READ_CID close(fd); diff --git a/linters/tox.ini b/linters/tox.ini index c945456..468fbd2 100644 --- a/linters/tox.ini +++ b/linters/tox.ini @@ -19,7 +19,7 @@ commands = cppcheck \ --inline-suppr \ --library=python \ --include=linters/cppcheck.h \ - src python/*.? janus/*.? + src python/src/*.? janus/src/*.? [testenv:flake8] allowlist_externals = bash diff --git a/python/src/ustreamer.c b/python/src/ustreamer.c index 3ccc432..04154d7 100644 --- a/python/src/ustreamer.c +++ b/python/src/ustreamer.c @@ -35,23 +35,10 @@ typedef struct { } _MemsinkObject; -#define _MEM(x_next) self->mem->x_next -#define _FRAME(x_next) self->frame->x_next - - static void _MemsinkObject_destroy_internals(_MemsinkObject *self) { - if (self->mem != NULL) { - us_memsink_shared_unmap(self->mem); - self->mem = NULL; - } - if (self->fd >= 0) { - close(self->fd); - self->fd = -1; - } - if (self->frame != NULL) { - us_frame_destroy(self->frame); - self->frame = NULL; - } + US_DELETE(self->mem, us_memsink_shared_unmap); + US_CLOSE_FD(self->fd, close); + US_DELETE(self->frame, us_frame_destroy); } static int _MemsinkObject_init(_MemsinkObject *self, PyObject *args, PyObject *kwargs) { @@ -65,17 +52,15 @@ static int _MemsinkObject_init(_MemsinkObject *self, PyObject *args, PyObject *k return -1; } -# define SET_DOUBLE(_field, _cond) { \ - if (!(self->_field _cond)) { \ - PyErr_SetString(PyExc_ValueError, #_field " must be " #_cond); \ +# define SET_DOUBLE(x_field, x_cond) { \ + if (!(self->x_field x_cond)) { \ + PyErr_SetString(PyExc_ValueError, #x_field " must be " #x_cond); \ return -1; \ } \ } - SET_DOUBLE(lock_timeout, > 0); SET_DOUBLE(wait_timeout, > 0); SET_DOUBLE(drop_same_frames, >= 0); - # undef SET_DOUBLE self->frame = us_frame_init(); @@ -84,17 +69,15 @@ static int _MemsinkObject_init(_MemsinkObject *self, PyObject *args, PyObject *k PyErr_SetFromErrno(PyExc_OSError); goto error; } - if ((self->mem = us_memsink_shared_map(self->fd)) == NULL) { PyErr_SetFromErrno(PyExc_OSError); goto error; } - return 0; - error: - _MemsinkObject_destroy_internals(self); - return -1; +error: + _MemsinkObject_destroy_internals(self); + return -1; } static PyObject *_MemsinkObject_repr(_MemsinkObject *self) { @@ -142,14 +125,15 @@ static int _wait_frame(_MemsinkObject *self) { RETURN_OS_ERROR; } else if (retval == 0) { - if (_MEM(magic) == US_MEMSINK_MAGIC && _MEM(version) == US_MEMSINK_VERSION && _MEM(id) != self->frame_id) { + us_memsink_shared_s *mem = self->mem; + if (mem->magic == US_MEMSINK_MAGIC && mem->version == US_MEMSINK_VERSION && mem->id != self->frame_id) { if (self->drop_same_frames > 0) { if ( US_FRAME_COMPARE_META_USED_NOTS(self->mem, self->frame) && (self->frame_ts + self->drop_same_frames > now) - && !memcmp(_FRAME(data), _MEM(data), _MEM(used)) + && !memcmp(self->frame->data, mem->data, mem->used) ) { - self->frame_id = _MEM(id); + self->frame_id = mem->id; goto drop; } } @@ -163,22 +147,18 @@ static int _wait_frame(_MemsinkObject *self) { } } - drop: - + drop: if (usleep(1000) < 0) { RETURN_OS_ERROR; } - Py_END_ALLOW_THREADS - if (PyErr_CheckSignals() < 0) { return -1; } } while (now < deadline_ts); -# undef RETURN_OS_ERROR - return -2; +# undef RETURN_OS_ERROR } static PyObject *_MemsinkObject_wait_frame(_MemsinkObject *self, PyObject *args, PyObject *kwargs) { @@ -199,13 +179,14 @@ static PyObject *_MemsinkObject_wait_frame(_MemsinkObject *self, PyObject *args, default: return NULL; } - us_frame_set_data(self->frame, _MEM(data), _MEM(used)); + us_memsink_shared_s *mem = self->mem; + us_frame_set_data(self->frame, mem->data, mem->used); US_FRAME_COPY_META(self->mem, self->frame); - self->frame_id = _MEM(id); + self->frame_id = mem->id; self->frame_ts = us_get_now_monotonic(); - _MEM(last_client_ts) = self->frame_ts; + mem->last_client_ts = self->frame_ts; if (key_required) { - _MEM(key_requested) = true; + mem->key_requested = true; } if (flock(self->fd, LOCK_UN) < 0) { @@ -217,18 +198,18 @@ static PyObject *_MemsinkObject_wait_frame(_MemsinkObject *self, PyObject *args, return NULL; } -# define SET_VALUE(_key, _maker) { \ - PyObject *_tmp = _maker; \ - if (_tmp == NULL) { \ +# define SET_VALUE(x_key, x_maker) { \ + PyObject *m_tmp = x_maker; \ + if (m_tmp == NULL) { \ return NULL; \ } \ - if (PyDict_SetItemString(dict_frame, _key, _tmp) < 0) { \ - Py_DECREF(_tmp); \ + if (PyDict_SetItemString(dict_frame, x_key, m_tmp) < 0) { \ + Py_DECREF(m_tmp); \ return NULL; \ } \ - Py_DECREF(_tmp); \ + Py_DECREF(m_tmp); \ } -# define SET_NUMBER(_key, _from, _to) SET_VALUE(#_key, Py##_to##_From##_from(_FRAME(_key))) +# define SET_NUMBER(x_key, x_from, x_to) SET_VALUE(#x_key, Py##x_to##_From##x_from(self->frame->x_key)) SET_NUMBER(width, Long, Long); SET_NUMBER(height, Long, Long); @@ -240,7 +221,7 @@ static PyObject *_MemsinkObject_wait_frame(_MemsinkObject *self, PyObject *args, SET_NUMBER(grab_ts, Double, Float); SET_NUMBER(encode_begin_ts, Double, Float); SET_NUMBER(encode_end_ts, Double, Float); - SET_VALUE("data", PyBytes_FromStringAndSize((const char *)_FRAME(data), _FRAME(used))); + SET_VALUE("data", PyBytes_FromStringAndSize((const char *)self->frame->data, self->frame->used)); # undef SET_NUMBER # undef SET_VALUE @@ -252,21 +233,19 @@ static PyObject *_MemsinkObject_is_opened(_MemsinkObject *self, PyObject *Py_UNU return PyBool_FromLong(self->mem != NULL && self->fd > 0); } -#define FIELD_GETTER(_field, _from, _to) \ - static PyObject *_MemsinkObject_getter_##_field(_MemsinkObject *self, void *Py_UNUSED(closure)) { \ - return Py##_to##_From##_from(self->_field); \ +#define FIELD_GETTER(x_field, x_from, x_to) \ + static PyObject *_MemsinkObject_getter_##x_field(_MemsinkObject *self, void *Py_UNUSED(closure)) { \ + return Py##x_to##_From##x_from(self->x_field); \ } - FIELD_GETTER(obj, String, Unicode) FIELD_GETTER(lock_timeout, Double, Float) FIELD_GETTER(wait_timeout, Double, Float) FIELD_GETTER(drop_same_frames, Double, Float) - #undef FIELD_GETTER static PyMethodDef _MemsinkObject_methods[] = { -# define ADD_METHOD(_name, _method, _flags) \ - {.ml_name = _name, .ml_meth = (PyCFunction)_MemsinkObject_##_method, .ml_flags = (_flags)} +# define ADD_METHOD(x_name, x_method, x_flags) \ + {.ml_name = x_name, .ml_meth = (PyCFunction)_MemsinkObject_##x_method, .ml_flags = (x_flags)} ADD_METHOD("close", close, METH_NOARGS), ADD_METHOD("__enter__", enter, METH_NOARGS), ADD_METHOD("__exit__", exit, METH_VARARGS), @@ -277,7 +256,7 @@ static PyMethodDef _MemsinkObject_methods[] = { }; static PyGetSetDef _MemsinkObject_getsets[] = { -# define ADD_GETTER(_field) {.name = #_field, .get = (getter)_MemsinkObject_getter_##_field} +# define ADD_GETTER(x_field) {.name = #x_field, .get = (getter)_MemsinkObject_getter_##x_field} ADD_GETTER(obj), ADD_GETTER(lock_timeout), ADD_GETTER(wait_timeout), diff --git a/src/dump/main.c b/src/dump/main.c index 46c1152..c75831f 100644 --- a/src/dump/main.c +++ b/src/dump/main.c @@ -231,6 +231,8 @@ static int _dump_sink( bool key_required, _output_context_s *ctx) { + int retval = -1; + if (count == 0) { count = -1; } @@ -300,18 +302,13 @@ static int _dump_sink( } } - int retval = 0; - goto ok; + retval = 0; - error: - retval = -1; - - ok: - US_DELETE(sink, us_memsink_destroy); - us_frame_destroy(frame); - - US_LOG_INFO("Bye-bye"); - return retval; +error: + US_DELETE(sink, us_memsink_destroy); + us_frame_destroy(frame); + US_LOG_INFO("Bye-bye"); + return retval; } static void _help(FILE *fp) { diff --git a/src/ustreamer/device.c b/src/libs/device.c similarity index 75% rename from src/ustreamer/device.c rename to src/libs/device.c index 22f2ff9..c45ccba 100644 --- a/src/ustreamer/device.c +++ b/src/libs/device.c @@ -84,11 +84,6 @@ static const char *_standard_to_string(v4l2_std_id standard); static const char *_io_method_to_string_supported(enum v4l2_memory io_method); -#define _RUN(x_next) dev->run->x_next -#define _D_XIOCTL(...) us_xioctl(_RUN(fd), __VA_ARGS__) -#define _D_IS_MPLANE (_RUN(capture_type) == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - - us_device_s *us_device_init(void) { us_device_runtime_s *run; US_CALLOC(run, 1); @@ -143,11 +138,13 @@ int us_device_parse_io_method(const char *str) { } int us_device_open(us_device_s *dev) { - if ((_RUN(fd) = open(dev->path, O_RDWR|O_NONBLOCK)) < 0) { + us_device_runtime_s *const run = dev->run; + + if ((run->fd = open(dev->path, O_RDWR|O_NONBLOCK)) < 0) { US_LOG_PERROR("Can't open device"); goto error; } - US_LOG_INFO("Device fd=%d opened", _RUN(fd)); + US_LOG_INFO("Device fd=%d opened", run->fd); if (_device_open_check_cap(dev) < 0) { goto error; @@ -168,117 +165,106 @@ int us_device_open(us_device_s *dev) { } _device_apply_controls(dev); - US_LOG_DEBUG("Device fd=%d initialized", _RUN(fd)); + US_LOG_DEBUG("Device fd=%d initialized", run->fd); return 0; - error: - us_device_close(dev); - return -1; +error: + us_device_close(dev); + return -1; } void us_device_close(us_device_s *dev) { - _RUN(persistent_timeout_reported) = false; + us_device_runtime_s *const run = dev->run; - if (_RUN(hw_bufs) != NULL) { + run->persistent_timeout_reported = false; + + if (run->hw_bufs != NULL) { US_LOG_DEBUG("Releasing device buffers ..."); - for (unsigned index = 0; index < _RUN(n_bufs); ++index) { -# define HW(x_next) _RUN(hw_bufs)[index].x_next + for (unsigned index = 0; index < run->n_bufs; ++index) { + us_hw_buffer_s *hw = &run->hw_bufs[index]; - if (HW(dma_fd) >= 0) { - close(HW(dma_fd)); - HW(dma_fd) = -1; - } + US_CLOSE_FD(hw->dma_fd, close); if (dev->io_method == V4L2_MEMORY_MMAP) { - if (HW(raw.allocated) > 0 && HW(raw.data) != NULL) { - if (munmap(HW(raw.data), HW(raw.allocated)) < 0) { + if (hw->raw.allocated > 0 && hw->raw.data != NULL) { + if (munmap(hw->raw.data, hw->raw.allocated) < 0) { US_LOG_PERROR("Can't unmap device buffer=%u", index); } } } else { // V4L2_MEMORY_USERPTR - US_DELETE(HW(raw.data), free); + US_DELETE(hw->raw.data, free); } - if (_D_IS_MPLANE) { - free(HW(buf.m.planes)); + if (run->capture_mplane) { + free(hw->buf.m.planes); } - -# undef HW } - _RUN(n_bufs) = 0; - free(_RUN(hw_bufs)); - _RUN(hw_bufs) = NULL; + US_DELETE(run->hw_bufs, free); + run->n_bufs = 0; } - if (_RUN(fd) >= 0) { + if (run->fd >= 0) { US_LOG_DEBUG("Closing device ..."); - if (close(_RUN(fd)) < 0) { - US_LOG_PERROR("Can't close device fd=%d", _RUN(fd)); + if (close(run->fd) < 0) { + US_LOG_PERROR("Can't close device fd=%d", run->fd); } else { - US_LOG_INFO("Device fd=%d closed", _RUN(fd)); + US_LOG_INFO("Device fd=%d closed", run->fd); } - _RUN(fd) = -1; + run->fd = -1; } } int us_device_export_to_dma(us_device_s *dev) { -# define DMA_FD _RUN(hw_bufs[index].dma_fd) - - for (unsigned index = 0; index < _RUN(n_bufs); ++index) { - struct v4l2_exportbuffer exp = {0}; - exp.type = _RUN(capture_type); - exp.index = index; + us_device_runtime_s *const run = dev->run; + for (unsigned index = 0; index < run->n_bufs; ++index) { + struct v4l2_exportbuffer exp = { + .type = run->capture_type, + .index = index, + }; US_LOG_DEBUG("Exporting device buffer=%u to DMA ...", index); - if (_D_XIOCTL(VIDIOC_EXPBUF, &exp) < 0) { + if (us_xioctl(run->fd, VIDIOC_EXPBUF, &exp) < 0) { US_LOG_PERROR("Can't export device buffer=%u to DMA", index); goto error; } - DMA_FD = exp.fd; + run->hw_bufs[index].dma_fd = exp.fd; } - return 0; - error: - for (unsigned index = 0; index < _RUN(n_bufs); ++index) { - if (DMA_FD >= 0) { - close(DMA_FD); - DMA_FD = -1; - } - } - return -1; - -# undef DMA_FD +error: + for (unsigned index = 0; index < run->n_bufs; ++index) { + US_CLOSE_FD(run->hw_bufs[index].dma_fd, close); + } + return -1; } int us_device_switch_capturing(us_device_s *dev, bool enable) { - if (enable != _RUN(capturing)) { - enum v4l2_buf_type type = _RUN(capture_type); + us_device_runtime_s *const run = dev->run; + + if (enable != run->capturing) { + enum v4l2_buf_type type = run->capture_type; US_LOG_DEBUG("%s device capturing ...", (enable ? "Starting" : "Stopping")); - if (_D_XIOCTL((enable ? VIDIOC_STREAMON : VIDIOC_STREAMOFF), &type) < 0) { + if (us_xioctl(run->fd, (enable ? VIDIOC_STREAMON : VIDIOC_STREAMOFF), &type) < 0) { US_LOG_PERROR("Can't %s capturing", (enable ? "start" : "stop")); if (enable) { return -1; } } - - _RUN(capturing) = enable; + run->capturing = enable; US_LOG_INFO("Capturing %s", (enable ? "started" : "stopped")); } return 0; } int us_device_select(us_device_s *dev, bool *has_read, bool *has_write, bool *has_error) { - int retval; + us_device_runtime_s *const run = dev->run; # define INIT_FD_SET(x_set) \ - fd_set x_set; FD_ZERO(&x_set); FD_SET(_RUN(fd), &x_set); - + fd_set x_set; FD_ZERO(&x_set); FD_SET(run->fd, &x_set); INIT_FD_SET(read_fds); INIT_FD_SET(write_fds); INIT_FD_SET(error_fds); - # undef INIT_FD_SET struct timeval timeout; @@ -287,11 +273,11 @@ int us_device_select(us_device_s *dev, bool *has_read, bool *has_write, bool *ha US_LOG_DEBUG("Calling select() on video device ..."); - retval = select(_RUN(fd) + 1, &read_fds, &write_fds, &error_fds, &timeout); + int retval = select(run->fd + 1, &read_fds, &write_fds, &error_fds, &timeout); if (retval > 0) { - *has_read = FD_ISSET(_RUN(fd), &read_fds); - *has_write = FD_ISSET(_RUN(fd), &write_fds); - *has_error = FD_ISSET(_RUN(fd), &error_fds); + *has_read = FD_ISSET(run->fd, &read_fds); + *has_write = FD_ISSET(run->fd, &write_fds); + *has_error = FD_ISSET(run->fd, &error_fds); } else { *has_read = false; *has_write = false; @@ -300,12 +286,12 @@ int us_device_select(us_device_s *dev, bool *has_read, bool *has_write, bool *ha US_LOG_DEBUG("Device select() --> %d", retval); if (retval > 0) { - _RUN(persistent_timeout_reported) = false; + run->persistent_timeout_reported = false; } else if (retval == 0) { if (dev->persistent) { - if (!_RUN(persistent_timeout_reported)) { + if (!run->persistent_timeout_reported) { US_LOG_ERROR("Persistent device timeout (unplugged)"); - _RUN(persistent_timeout_reported) = true; + run->persistent_timeout_reported = true; } } else { // Если устройство не персистентное, то таймаут является ошибкой @@ -316,11 +302,13 @@ int us_device_select(us_device_s *dev, bool *has_read, bool *has_write, bool *ha } int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) { + us_device_runtime_s *const run = dev->run; + *hw = NULL; struct v4l2_buffer buf = {0}; struct v4l2_plane buf_planes[VIDEO_MAX_PLANES] = {0}; - if (_D_IS_MPLANE) { + if (run->capture_mplane) { // Just for _v4l2_buffer_copy(), buf.length is not needed here buf.m.planes = buf_planes; } @@ -334,23 +322,23 @@ int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) { do { struct v4l2_buffer new = {0}; struct v4l2_plane new_planes[VIDEO_MAX_PLANES] = {0}; - new.type = _RUN(capture_type); + new.type = run->capture_type; new.memory = dev->io_method; - if (_D_IS_MPLANE) { + if (run->capture_mplane) { new.length = VIDEO_MAX_PLANES; new.m.planes = new_planes; } - const bool new_got = (_D_XIOCTL(VIDIOC_DQBUF, &new) >= 0); + const bool new_got = (us_xioctl(run->fd, VIDIOC_DQBUF, &new) >= 0); if (new_got) { - if (new.index >= _RUN(n_bufs)) { - US_LOG_ERROR("V4L2 error: grabbed invalid device buffer=%u, n_bufs=%u", new.index, _RUN(n_bufs)); + if (new.index >= run->n_bufs) { + US_LOG_ERROR("V4L2 error: grabbed invalid device buffer=%u, n_bufs=%u", new.index, run->n_bufs); return -1; } -# define GRABBED(x_buf) _RUN(hw_bufs)[x_buf.index].grabbed -# define FRAME_DATA(x_buf) _RUN(hw_bufs)[x_buf.index].raw.data +# define GRABBED(x_buf) run->hw_bufs[x_buf.index].grabbed +# define FRAME_DATA(x_buf) run->hw_bufs[x_buf.index].raw.data if (GRABBED(new)) { US_LOG_ERROR("V4L2 error: grabbed device buffer=%u is already used", new.index); @@ -358,14 +346,14 @@ int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) { } GRABBED(new) = true; - if (_D_IS_MPLANE) { + if (run->capture_mplane) { new.bytesused = new.m.planes[0].bytesused; } broken = !_device_is_buffer_valid(dev, &new, FRAME_DATA(new)); if (broken) { US_LOG_DEBUG("Releasing device buffer=%u (broken frame) ...", new.index); - if (_D_XIOCTL(VIDIOC_QBUF, &new) < 0) { + if (us_xioctl(run->fd, VIDIOC_QBUF, &new) < 0) { US_LOG_PERROR("Can't release device buffer=%u (broken frame)", new.index); return -1; } @@ -374,7 +362,7 @@ int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) { } if (buf_got) { - if (_D_XIOCTL(VIDIOC_QBUF, &buf) < 0) { + if (us_xioctl(run->fd, VIDIOC_QBUF, &buf) < 0) { US_LOG_PERROR("Can't release device buffer=%u (skipped frame)", buf.index); return -1; } @@ -402,29 +390,26 @@ int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) { } } while (true); -# define HW(x_next) _RUN(hw_bufs)[buf.index].x_next - HW(raw.dma_fd) = HW(dma_fd); - HW(raw.used) = buf.bytesused; - HW(raw.width) = _RUN(width); - HW(raw.height) = _RUN(height); - HW(raw.format) = _RUN(format); - HW(raw.stride) = _RUN(stride); - HW(raw.online) = true; - _v4l2_buffer_copy(&buf, &HW(buf)); - HW(raw.grab_ts) = (long double)((buf.timestamp.tv_sec * (uint64_t)1000) + (buf.timestamp.tv_usec / 1000)) / 1000; - US_LOG_DEBUG("Grabbed new frame: buffer=%u, bytesused=%u, grab_ts=%.3Lf, latency=%.3Lf, skipped=%u", - buf.index, buf.bytesused, HW(raw.grab_ts), us_get_now_monotonic() - HW(raw.grab_ts), skipped); -# undef HW + *hw = &run->hw_bufs[buf.index]; + (*hw)->raw.dma_fd = (*hw)->dma_fd; + (*hw)->raw.used = buf.bytesused; + (*hw)->raw.width = run->width; + (*hw)->raw.height = run->height; + (*hw)->raw.format = run->format; + (*hw)->raw.stride = run->stride; + (*hw)->raw.online = true; + _v4l2_buffer_copy(&buf, &(*hw)->buf); + (*hw)->raw.grab_ts = (long double)((buf.timestamp.tv_sec * (uint64_t)1000) + (buf.timestamp.tv_usec / 1000)) / 1000; - *hw = &_RUN(hw_bufs[buf.index]); + US_LOG_DEBUG("Grabbed new frame: buffer=%u, bytesused=%u, grab_ts=%.3Lf, latency=%.3Lf, skipped=%u", + buf.index, buf.bytesused, (*hw)->raw.grab_ts, us_get_now_monotonic() - (*hw)->raw.grab_ts, skipped); return buf.index; } int us_device_release_buffer(us_device_s *dev, us_hw_buffer_s *hw) { const unsigned index = hw->buf.index; US_LOG_DEBUG("Releasing device buffer=%u ...", index); - - if (_D_XIOCTL(VIDIOC_QBUF, &hw->buf) < 0) { + if (us_xioctl(dev->run->fd, VIDIOC_QBUF, &hw->buf) < 0) { US_LOG_PERROR("Can't release device buffer=%u", index); return -1; } @@ -434,9 +419,8 @@ int us_device_release_buffer(us_device_s *dev, us_hw_buffer_s *hw) { int us_device_consume_event(us_device_s *dev) { struct v4l2_event event; - US_LOG_DEBUG("Consuming V4L2 event ..."); - if (_D_XIOCTL(VIDIOC_DQEVENT, &event) == 0) { + if (us_xioctl(dev->run->fd, VIDIOC_DQEVENT, &event) == 0) { switch (event.type) { case V4L2_EVENT_SOURCE_CHANGE: US_LOG_INFO("Got V4L2_EVENT_SOURCE_CHANGE: source changed"); @@ -501,19 +485,22 @@ bool _device_is_buffer_valid(us_device_s *dev, const struct v4l2_buffer *buf, co } static int _device_open_check_cap(us_device_s *dev) { - struct v4l2_capability cap = {0}; + us_device_runtime_s *const run = dev->run; + struct v4l2_capability cap = {0}; US_LOG_DEBUG("Querying device capabilities ..."); - if (_D_XIOCTL(VIDIOC_QUERYCAP, &cap) < 0) { + if (us_xioctl(run->fd, VIDIOC_QUERYCAP, &cap) < 0) { US_LOG_PERROR("Can't query device capabilities"); return -1; } if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) { - _RUN(capture_type) = V4L2_BUF_TYPE_VIDEO_CAPTURE; + run->capture_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + run->capture_mplane = false; US_LOG_INFO("Using capture type: single-planar"); } else if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) { - _RUN(capture_type) = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + run->capture_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + run->capture_mplane = true; US_LOG_INFO("Using capture type: multi-planar"); } else { US_LOG_ERROR("Video capture is not supported by device"); @@ -525,10 +512,10 @@ static int _device_open_check_cap(us_device_s *dev) { return -1; } - if (!_D_IS_MPLANE) { + if (!run->capture_mplane) { int input = dev->input; // Needs a pointer to int for ioctl() US_LOG_INFO("Using input channel: %d", input); - if (_D_XIOCTL(VIDIOC_S_INPUT, &input) < 0) { + if (us_xioctl(run->fd, VIDIOC_S_INPUT, &input) < 0) { US_LOG_ERROR("Can't set input channel"); return -1; } @@ -536,7 +523,7 @@ static int _device_open_check_cap(us_device_s *dev) { if (dev->standard != V4L2_STD_UNKNOWN) { US_LOG_INFO("Using TV standard: %s", _standard_to_string(dev->standard)); - if (_D_XIOCTL(VIDIOC_S_STD, &dev->standard) < 0) { + if (us_xioctl(run->fd, VIDIOC_S_STD, &dev->standard) < 0) { US_LOG_ERROR("Can't set video standard"); return -1; } @@ -555,11 +542,9 @@ static int _device_open_dv_timings(us_device_s *dev) { return -1; } - struct v4l2_event_subscription sub = {0}; - sub.type = V4L2_EVENT_SOURCE_CHANGE; - + struct v4l2_event_subscription sub = {.type = V4L2_EVENT_SOURCE_CHANGE}; US_LOG_DEBUG("Subscribing to DV-timings events ...") - if (_D_XIOCTL(VIDIOC_SUBSCRIBE_EVENT, &sub) < 0) { + if (us_xioctl(dev->run->fd, VIDIOC_SUBSCRIBE_EVENT, &sub) < 0) { US_LOG_PERROR("Can't subscribe to DV-timings events"); return -1; } @@ -568,10 +553,12 @@ static int _device_open_dv_timings(us_device_s *dev) { } static int _device_apply_dv_timings(us_device_s *dev) { + us_device_runtime_s *const run = dev->run; // cppcheck-suppress constVariablePointer + struct v4l2_dv_timings dv = {0}; US_LOG_DEBUG("Calling us_xioctl(VIDIOC_QUERY_DV_TIMINGS) ..."); - if (_D_XIOCTL(VIDIOC_QUERY_DV_TIMINGS, &dv) == 0) { + if (us_xioctl(run->fd, VIDIOC_QUERY_DV_TIMINGS, &dv) == 0) { if (dv.type == V4L2_DV_BT_656_1120) { // See v4l2_print_dv_timings() in the kernel const unsigned htot = V4L2_DV_BT_FRAME_WIDTH(&dv.bt); @@ -587,7 +574,7 @@ static int _device_apply_dv_timings(us_device_s *dev) { } US_LOG_DEBUG("Calling us_xioctl(VIDIOC_S_DV_TIMINGS) ..."); - if (_D_XIOCTL(VIDIOC_S_DV_TIMINGS, &dv) < 0) { + if (us_xioctl(run->fd, VIDIOC_S_DV_TIMINGS, &dv) < 0) { US_LOG_PERROR("Failed to set DV-timings"); return -1; } @@ -598,9 +585,9 @@ static int _device_apply_dv_timings(us_device_s *dev) { } else { US_LOG_DEBUG("Calling us_xioctl(VIDIOC_QUERYSTD) ..."); - if (_D_XIOCTL(VIDIOC_QUERYSTD, &dev->standard) == 0) { + if (us_xioctl(run->fd, VIDIOC_QUERYSTD, &dev->standard) == 0) { US_LOG_INFO("Applying the new VIDIOC_S_STD: %s ...", _standard_to_string(dev->standard)); - if (_D_XIOCTL(VIDIOC_S_STD, &dev->standard) < 0) { + if (us_xioctl(run->fd, VIDIOC_S_STD, &dev->standard) < 0) { US_LOG_PERROR("Can't set video standard"); return -1; } @@ -609,21 +596,23 @@ static int _device_apply_dv_timings(us_device_s *dev) { return 0; } -static int _device_open_format(us_device_s *dev, bool first) { // FIXME - const unsigned stride = us_align_size(_RUN(width), 32) << 1; +static int _device_open_format(us_device_s *dev, bool first) { + us_device_runtime_s *const run = dev->run; + + const unsigned stride = us_align_size(run->width, 32) << 1; struct v4l2_format fmt = {0}; - fmt.type = _RUN(capture_type); - if (_D_IS_MPLANE) { - fmt.fmt.pix_mp.width = _RUN(width); - fmt.fmt.pix_mp.height = _RUN(height); + fmt.type = run->capture_type; + if (run->capture_mplane) { + fmt.fmt.pix_mp.width = run->width; + fmt.fmt.pix_mp.height = run->height; fmt.fmt.pix_mp.pixelformat = dev->format; fmt.fmt.pix_mp.field = V4L2_FIELD_ANY; fmt.fmt.pix_mp.flags = 0; fmt.fmt.pix_mp.num_planes = 1; } else { - fmt.fmt.pix.width = _RUN(width); - fmt.fmt.pix.height = _RUN(height); + fmt.fmt.pix.width = run->width; + fmt.fmt.pix.height = run->height; fmt.fmt.pix.pixelformat = dev->format; fmt.fmt.pix.field = V4L2_FIELD_ANY; fmt.fmt.pix.bytesperline = stride; @@ -631,24 +620,24 @@ static int _device_open_format(us_device_s *dev, bool first) { // FIXME // Set format US_LOG_DEBUG("Probing device format=%s, stride=%u, resolution=%ux%u ...", - _format_to_string_supported(dev->format), stride, _RUN(width), _RUN(height)); - if (_D_XIOCTL(VIDIOC_S_FMT, &fmt) < 0) { + _format_to_string_supported(dev->format), stride, run->width, run->height); + if (us_xioctl(run->fd, VIDIOC_S_FMT, &fmt) < 0) { US_LOG_PERROR("Can't set device format"); return -1; } - if (fmt.type != _RUN(capture_type)) { + if (fmt.type != run->capture_type) { US_LOG_ERROR("Capture format mismatch, please report to the developer"); return -1; } -# define FMT(x_next) (_D_IS_MPLANE ? fmt.fmt.pix_mp.x_next : fmt.fmt.pix.x_next) -# define FMTS(x_next) (_D_IS_MPLANE ? fmt.fmt.pix_mp.plane_fmt[0].x_next : fmt.fmt.pix.x_next) +# define FMT(x_next) (run->capture_mplane ? fmt.fmt.pix_mp.x_next : fmt.fmt.pix.x_next) +# define FMTS(x_next) (run->capture_mplane ? fmt.fmt.pix_mp.plane_fmt[0].x_next : fmt.fmt.pix.x_next) // Check resolution bool retry = false; - if (FMT(width) != _RUN(width) || FMT(height) != _RUN(height)) { - US_LOG_ERROR("Requested resolution=%ux%u is unavailable", _RUN(width), _RUN(height)); + if (FMT(width) != run->width || FMT(height) != run->height) { + US_LOG_ERROR("Requested resolution=%ux%u is unavailable", run->width, run->height); retry = true; } if (_device_apply_resolution(dev, FMT(width), FMT(height)) < 0) { @@ -657,7 +646,7 @@ static int _device_open_format(us_device_s *dev, bool first) { // FIXME if (first && retry) { return _device_open_format(dev, false); } - US_LOG_INFO("Using resolution: %ux%u", _RUN(width), _RUN(height)); + US_LOG_INFO("Using resolution: %ux%u", run->width, run->height); // Check format if (FMT(pixelformat) != dev->format) { @@ -676,12 +665,12 @@ static int _device_open_format(us_device_s *dev, bool first) { // FIXME } } - _RUN(format) = FMT(pixelformat); - US_LOG_INFO("Using format: %s", _format_to_string_supported(_RUN(format))); + run->format = FMT(pixelformat); + US_LOG_INFO("Using format: %s", _format_to_string_supported(run->format)); - _RUN(stride) = FMTS(bytesperline); - _RUN(raw_size) = FMTS(sizeimage); // Only for userptr + run->stride = FMTS(bytesperline); + run->raw_size = FMTS(sizeimage); // Only for userptr # undef FMTS # undef FMT @@ -690,13 +679,13 @@ static int _device_open_format(us_device_s *dev, bool first) { // FIXME } static void _device_open_hw_fps(us_device_s *dev) { - _RUN(hw_fps) = 0; + us_device_runtime_s *const run = dev->run; - struct v4l2_streamparm setfps = {0}; - setfps.type = _RUN(capture_type); + run->hw_fps = 0; + struct v4l2_streamparm setfps = {.type = run->capture_type}; US_LOG_DEBUG("Querying HW FPS ..."); - if (_D_XIOCTL(VIDIOC_G_PARM, &setfps) < 0) { + if (us_xioctl(run->fd, VIDIOC_G_PARM, &setfps) < 0) { if (errno == ENOTTY) { // Quiet message for TC358743 US_LOG_INFO("Querying HW FPS changing is not supported"); } else { @@ -713,11 +702,11 @@ static void _device_open_hw_fps(us_device_s *dev) { # define SETFPS_TPF(x_next) setfps.parm.capture.timeperframe.x_next US_MEMSET_ZERO(setfps); - setfps.type = _RUN(capture_type); + setfps.type = run->capture_type; SETFPS_TPF(numerator) = 1; SETFPS_TPF(denominator) = (dev->desired_fps == 0 ? 255 : dev->desired_fps); - if (_D_XIOCTL(VIDIOC_S_PARM, &setfps) < 0) { + if (us_xioctl(run->fd, VIDIOC_S_PARM, &setfps) < 0) { US_LOG_PERROR("Can't set HW FPS"); return; } @@ -732,35 +721,33 @@ static void _device_open_hw_fps(us_device_s *dev) { return; } - _RUN(hw_fps) = SETFPS_TPF(denominator); - if (dev->desired_fps != _RUN(hw_fps)) { - US_LOG_INFO("Using HW FPS: %u -> %u (coerced)", dev->desired_fps, _RUN(hw_fps)); + run->hw_fps = SETFPS_TPF(denominator); + if (dev->desired_fps != run->hw_fps) { + US_LOG_INFO("Using HW FPS: %u -> %u (coerced)", dev->desired_fps, run->hw_fps); } else { - US_LOG_INFO("Using HW FPS: %u", _RUN(hw_fps)); + US_LOG_INFO("Using HW FPS: %u", run->hw_fps); } # undef SETFPS_TPF } static void _device_open_jpeg_quality(us_device_s *dev) { + us_device_runtime_s *const run = dev->run; unsigned quality = 0; - - if (us_is_jpeg(_RUN(format))) { + if (us_is_jpeg(run->format)) { struct v4l2_jpegcompression comp = {0}; - - if (_D_XIOCTL(VIDIOC_G_JPEGCOMP, &comp) < 0) { + if (us_xioctl(run->fd, VIDIOC_G_JPEGCOMP, &comp) < 0) { US_LOG_ERROR("Device doesn't support setting of HW encoding quality parameters"); } else { comp.quality = dev->jpeg_quality; - if (_D_XIOCTL(VIDIOC_S_JPEGCOMP, &comp) < 0) { + if (us_xioctl(run->fd, VIDIOC_S_JPEGCOMP, &comp) < 0) { US_LOG_ERROR("Can't change MJPEG quality for JPEG source with HW pass-through encoder"); } else { quality = dev->jpeg_quality; } } } - - _RUN(jpeg_quality) = quality; + run->jpeg_quality = quality; } static int _device_open_io_method(us_device_s *dev) { @@ -774,13 +761,15 @@ static int _device_open_io_method(us_device_s *dev) { } static int _device_open_io_method_mmap(us_device_s *dev) { - struct v4l2_requestbuffers req = {0}; - req.count = dev->n_bufs; - req.type = _RUN(capture_type); - req.memory = V4L2_MEMORY_MMAP; + us_device_runtime_s *const run = dev->run; + struct v4l2_requestbuffers req = { + .count = dev->n_bufs, + .type = run->capture_type, + .memory = V4L2_MEMORY_MMAP, + }; US_LOG_DEBUG("Requesting %u device buffers for MMAP ...", req.count); - if (_D_XIOCTL(VIDIOC_REQBUFS, &req) < 0) { + if (us_xioctl(run->fd, VIDIOC_REQBUFS, &req) < 0) { US_LOG_PERROR("Device '%s' doesn't support MMAP method", dev->path); return -1; } @@ -794,64 +783,60 @@ static int _device_open_io_method_mmap(us_device_s *dev) { US_LOG_DEBUG("Allocating device buffers ..."); - US_CALLOC(_RUN(hw_bufs), req.count); - for (_RUN(n_bufs) = 0; _RUN(n_bufs) < req.count; ++_RUN(n_bufs)) { + US_CALLOC(run->hw_bufs, req.count); + + for (run->n_bufs = 0; run->n_bufs < req.count; ++run->n_bufs) { struct v4l2_buffer buf = {0}; struct v4l2_plane planes[VIDEO_MAX_PLANES] = {0}; - buf.type = _RUN(capture_type); + buf.type = run->capture_type; buf.memory = V4L2_MEMORY_MMAP; - buf.index = _RUN(n_bufs); - if (_D_IS_MPLANE) { + buf.index = run->n_bufs; + if (run->capture_mplane) { buf.m.planes = planes; buf.length = VIDEO_MAX_PLANES; } - US_LOG_DEBUG("Calling us_xioctl(VIDIOC_QUERYBUF) for device buffer=%u ...", _RUN(n_bufs)); - if (_D_XIOCTL(VIDIOC_QUERYBUF, &buf) < 0) { + US_LOG_DEBUG("Calling us_xioctl(VIDIOC_QUERYBUF) for device buffer=%u ...", run->n_bufs); + if (us_xioctl(run->fd, VIDIOC_QUERYBUF, &buf) < 0) { US_LOG_PERROR("Can't VIDIOC_QUERYBUF"); return -1; } -# define HW(x_next) _RUN(hw_bufs)[_RUN(n_bufs)].x_next + us_hw_buffer_s *hw = &run->hw_bufs[run->n_bufs]; + const size_t buf_size = (run->capture_mplane ? buf.m.planes[0].length : buf.length); + const off_t buf_offset = (run->capture_mplane ? buf.m.planes[0].m.mem_offset : buf.m.offset); - HW(dma_fd) = -1; - - const size_t buf_size = (_D_IS_MPLANE ? buf.m.planes[0].length : buf.length); - const off_t buf_offset = (_D_IS_MPLANE ? buf.m.planes[0].m.mem_offset : buf.m.offset); - - US_LOG_DEBUG("Mapping device buffer=%u ...", _RUN(n_bufs)); - if ((HW(raw.data) = mmap( - NULL, - buf_size, - PROT_READ | PROT_WRITE, - MAP_SHARED, - _RUN(fd), - buf_offset + US_LOG_DEBUG("Mapping device buffer=%u ...", run->n_bufs); + if ((hw->raw.data = mmap( + NULL, buf_size, + PROT_READ | PROT_WRITE, MAP_SHARED, + run->fd, buf_offset )) == MAP_FAILED) { - US_LOG_PERROR("Can't map device buffer=%u", _RUN(n_bufs)); + US_LOG_PERROR("Can't map device buffer=%u", run->n_bufs); return -1; } - assert(HW(raw.data) != NULL); + assert(hw->raw.data != NULL); + hw->raw.allocated = buf_size; - HW(raw.allocated) = buf_size; - - if (_D_IS_MPLANE) { - US_CALLOC(HW(buf.m.planes), VIDEO_MAX_PLANES); + if (run->capture_mplane) { + US_CALLOC(hw->buf.m.planes, VIDEO_MAX_PLANES); } -# undef HW + hw->dma_fd = -1; } return 0; } static int _device_open_io_method_userptr(us_device_s *dev) { - struct v4l2_requestbuffers req = {0}; - req.count = dev->n_bufs; - req.type = _RUN(capture_type); - req.memory = V4L2_MEMORY_USERPTR; + us_device_runtime_s *const run = dev->run; + struct v4l2_requestbuffers req = { + .count = dev->n_bufs, + .type = run->capture_type, + .memory = V4L2_MEMORY_USERPTR, + }; US_LOG_DEBUG("Requesting %u device buffers for USERPTR ...", req.count); - if (_D_XIOCTL(VIDIOC_REQBUFS, &req) < 0) { + if (us_xioctl(run->fd, VIDIOC_REQBUFS, &req) < 0) { US_LOG_PERROR("Device '%s' doesn't support USERPTR method", dev->path); return -1; } @@ -865,32 +850,33 @@ static int _device_open_io_method_userptr(us_device_s *dev) { US_LOG_DEBUG("Allocating device buffers ..."); - US_CALLOC(_RUN(hw_bufs), req.count); + US_CALLOC(run->hw_bufs, req.count); const unsigned page_size = getpagesize(); - const unsigned buf_size = us_align_size(_RUN(raw_size), page_size); + const unsigned buf_size = us_align_size(run->raw_size, page_size); - for (_RUN(n_bufs) = 0; _RUN(n_bufs) < req.count; ++_RUN(n_bufs)) { -# define HW(x_next) _RUN(hw_bufs)[_RUN(n_bufs)].x_next - assert((HW(raw.data) = aligned_alloc(page_size, buf_size)) != NULL); - memset(HW(raw.data), 0, buf_size); - HW(raw.allocated) = buf_size; - if (_D_IS_MPLANE) { - US_CALLOC(HW(buf.m.planes), VIDEO_MAX_PLANES); + for (run->n_bufs = 0; run->n_bufs < req.count; ++run->n_bufs) { + us_hw_buffer_s *hw = &run->hw_bufs[run->n_bufs]; + assert((hw->raw.data = aligned_alloc(page_size, buf_size)) != NULL); + memset(hw->raw.data, 0, buf_size); + hw->raw.allocated = buf_size; + if (run->capture_mplane) { + US_CALLOC(hw->buf.m.planes, VIDEO_MAX_PLANES); } -# undef HW } return 0; } static int _device_open_queue_buffers(us_device_s *dev) { - for (unsigned index = 0; index < _RUN(n_bufs); ++index) { + us_device_runtime_s *const run = dev->run; + + for (unsigned index = 0; index < run->n_bufs; ++index) { struct v4l2_buffer buf = {0}; struct v4l2_plane planes[VIDEO_MAX_PLANES] = {0}; - buf.type = _RUN(capture_type); + buf.type = run->capture_type; buf.memory = dev->io_method; buf.index = index; - if (_D_IS_MPLANE) { + if (run->capture_mplane) { buf.m.planes = planes; buf.length = 1; } @@ -898,12 +884,12 @@ static int _device_open_queue_buffers(us_device_s *dev) { if (dev->io_method == V4L2_MEMORY_USERPTR) { // I am not sure, may be this is incorrect for mplane device, // but i don't have one which supports V4L2_MEMORY_USERPTR - buf.m.userptr = (unsigned long)_RUN(hw_bufs)[index].raw.data; - buf.length = _RUN(hw_bufs)[index].raw.allocated; + buf.m.userptr = (unsigned long)run->hw_bufs[index].raw.data; + buf.length = run->hw_bufs[index].raw.allocated; } US_LOG_DEBUG("Calling us_xioctl(VIDIOC_QBUF) for buffer=%u ...", index); - if (_D_XIOCTL(VIDIOC_QBUF, &buf) < 0) { + if (us_xioctl(run->fd, VIDIOC_QBUF, &buf) < 0) { US_LOG_PERROR("Can't VIDIOC_QBUF"); return -1; } @@ -922,8 +908,8 @@ static int _device_apply_resolution(us_device_s *dev, unsigned width, unsigned h width, height, US_VIDEO_MAX_WIDTH, US_VIDEO_MAX_HEIGHT); return -1; } - _RUN(width) = width; - _RUN(height) = height; + dev->run->width = width; + dev->run->height = height; return 0; } @@ -991,7 +977,7 @@ static int _device_query_control( US_MEMSET_ZERO(*query); query->id = cid; - if (_D_XIOCTL(VIDIOC_QUERYCTRL, query) < 0 || query->flags & V4L2_CTRL_FLAG_DISABLED) { + if (us_xioctl(dev->run->fd, VIDIOC_QUERYCTRL, query) < 0 || query->flags & V4L2_CTRL_FLAG_DISABLED) { if (!quiet) { US_LOG_ERROR("Changing control %s is unsupported", name); } @@ -1012,11 +998,11 @@ static void _device_set_control( return; } - struct v4l2_control ctl = {0}; - ctl.id = cid; - ctl.value = value; - - if (_D_XIOCTL(VIDIOC_S_CTRL, &ctl) < 0) { + struct v4l2_control ctl = { + .id = cid, + .value = value, + }; + if (us_xioctl(dev->run->fd, VIDIOC_S_CTRL, &ctl) < 0) { if (!quiet) { US_LOG_PERROR("Can't set control %s", name); } diff --git a/src/ustreamer/device.h b/src/libs/device.h similarity index 96% rename from src/ustreamer/device.h rename to src/libs/device.h index 7316d91..26f22e3 100644 --- a/src/ustreamer/device.h +++ b/src/libs/device.h @@ -41,12 +41,12 @@ #include #include -#include "../libs/tools.h" -#include "../libs/array.h" -#include "../libs/logging.h" -#include "../libs/threading.h" -#include "../libs/frame.h" -#include "../libs/xioctl.h" +#include "tools.h" +#include "array.h" +#include "logging.h" +#include "threading.h" +#include "frame.h" +#include "xioctl.h" #define US_VIDEO_MIN_WIDTH ((unsigned)160) @@ -86,6 +86,7 @@ typedef struct { unsigned n_bufs; us_hw_buffer_s *hw_bufs; enum v4l2_buf_type capture_type; + bool capture_mplane; bool capturing; bool persistent_timeout_reported; } us_device_runtime_s; diff --git a/src/libs/memsink.c b/src/libs/memsink.c index 323235a..000e597 100644 --- a/src/libs/memsink.c +++ b/src/libs/memsink.c @@ -58,12 +58,11 @@ us_memsink_s *us_memsink_init( US_LOG_PERROR("%s-sink: Can't mmap shared memory", name); goto error; } - return sink; - error: - us_memsink_destroy(sink); - return NULL; +error: + us_memsink_destroy(sink); + return NULL; } void us_memsink_destroy(us_memsink_s *sink) { @@ -176,6 +175,7 @@ int us_memsink_client_get(us_memsink_s *sink, us_frame_s *frame, bool *const key } int retval = -2; // Not updated + if (sink->mem->magic == US_MEMSINK_MAGIC) { if (sink->mem->version != US_MEMSINK_VERSION) { US_LOG_ERROR("%s-sink: Protocol version mismatch: sink=%u, required=%u", @@ -196,10 +196,10 @@ int us_memsink_client_get(us_memsink_s *sink, us_frame_s *frame, bool *const key } } - done: - if (flock(sink->fd, LOCK_UN) < 0) { - US_LOG_PERROR("%s-sink: Can't unlock memory", sink->name); - return -1; - } - return retval; +done: + if (flock(sink->fd, LOCK_UN) < 0) { + US_LOG_PERROR("%s-sink: Can't unlock memory", sink->name); + retval = -1; + } + return retval; } diff --git a/src/libs/tools.h b/src/libs/tools.h index 59a5c6c..df01b6b 100644 --- a/src/libs/tools.h +++ b/src/libs/tools.h @@ -59,7 +59,8 @@ #define US_CALLOC(x_dest, x_nmemb) assert(((x_dest) = calloc((x_nmemb), sizeof(*(x_dest)))) != NULL) #define US_REALLOC(x_dest, x_nmemb) assert(((x_dest) = realloc((x_dest), (x_nmemb) * sizeof(*(x_dest)))) != NULL) -#define US_DELETE(x_dest, x_free) { if (x_dest) { x_free(x_dest); } } +#define US_DELETE(x_dest, x_free) { if (x_dest) { x_free(x_dest); x_dest = NULL; } } +#define US_CLOSE_FD(x_dest, x_close) { if (x_dest >= 0) { x_close(x_dest); x_dest = -1; } } #define US_MEMSET_ZERO(x_obj) memset(&(x_obj), 0, sizeof(x_obj)) #define US_SNPRINTF(x_dest, x_size, x_fmt, ...) assert(snprintf((x_dest), (x_size), (x_fmt), ##__VA_ARGS__) > 0) diff --git a/src/libs/unjpeg.c b/src/libs/unjpeg.c index a235872..b8d927e 100644 --- a/src/libs/unjpeg.c +++ b/src/libs/unjpeg.c @@ -77,9 +77,9 @@ int us_unjpeg(const us_frame_s *src, us_frame_s *dest, bool decode) { jpeg_finish_decompress(&jpeg); } - done: - jpeg_destroy_decompress(&jpeg); - return retval; +done: + jpeg_destroy_decompress(&jpeg); + return retval; } static void _jpeg_error_handler(j_common_ptr jpeg) { diff --git a/src/ustreamer/blank.c b/src/ustreamer/blank.c index c55a3fe..af11e45 100644 --- a/src/ustreamer/blank.c +++ b/src/ustreamer/blank.c @@ -63,16 +63,16 @@ static us_frame_s *_init_external(const char *path) { goto error; } -# define CHUNK_SIZE ((size_t)(100 * 1024)) + const size_t chunk_size = 100 * 1024; while (true) { - if (blank->used + CHUNK_SIZE >= blank->allocated) { - us_frame_realloc_data(blank, blank->used + CHUNK_SIZE * 2); + if (blank->used + chunk_size >= blank->allocated) { + us_frame_realloc_data(blank, blank->used + chunk_size * 2); } - const size_t readed = fread(blank->data + blank->used, 1, CHUNK_SIZE, fp); + const size_t readed = fread(blank->data + blank->used, 1, chunk_size, fp); blank->used += readed; - if (readed < CHUNK_SIZE) { + if (readed < chunk_size) { if (feof(fp)) { break; } else { @@ -81,7 +81,6 @@ static us_frame_s *_init_external(const char *path) { } } } -# undef CHUNK_SIZE us_frame_s *const decoded = us_frame_init(); if (us_unjpeg(blank, decoded, false) < 0) { @@ -94,12 +93,10 @@ static us_frame_s *_init_external(const char *path) { goto ok; - error: - us_frame_destroy(blank); - blank = NULL; - - ok: - US_DELETE(fp, fclose); +error: + US_DELETE(blank, us_frame_destroy); +ok: + US_DELETE(fp, fclose); return blank; } diff --git a/src/ustreamer/encoder.h b/src/ustreamer/encoder.h index 1408846..fedb188 100644 --- a/src/ustreamer/encoder.h +++ b/src/ustreamer/encoder.h @@ -35,8 +35,8 @@ #include "../libs/threading.h" #include "../libs/logging.h" #include "../libs/frame.h" +#include "../libs/device.h" -#include "device.h" #include "workers.h" #include "m2m.h" diff --git a/src/ustreamer/http/bev.c b/src/ustreamer/http/bev.c index 1ee2850..11b9137 100644 --- a/src/ustreamer/http/bev.c +++ b/src/ustreamer/http/bev.c @@ -34,7 +34,6 @@ char *us_bufferevent_format_reason(short what) { strncat(reason, perror_str, 1023); free(perror_str); strcat(reason, " ("); - # define FILL_REASON(x_bev, x_name) { \ if (what & x_bev) { \ if (first) { \ @@ -51,7 +50,6 @@ char *us_bufferevent_format_reason(short what) { FILL_REASON(BEV_EVENT_ERROR, "error"); FILL_REASON(BEV_EVENT_TIMEOUT, "timeout"); FILL_REASON(BEV_EVENT_EOF, "eof"); // cppcheck-suppress unreadVariable - # undef FILL_REASON strcat(reason, ")"); diff --git a/src/ustreamer/http/server.c b/src/ustreamer/http/server.c index ad53ba4..8e1e1e4 100644 --- a/src/ustreamer/http/server.c +++ b/src/ustreamer/http/server.c @@ -51,10 +51,8 @@ static char *_http_get_client_hostport(struct evhttp_request *request); #define _A_EVBUFFER_ADD(x_buf, x_data, x_size) assert(!evbuffer_add(x_buf, x_data, x_size)) #define _A_EVBUFFER_ADD_PRINTF(x_buf, x_fmt, ...) assert(evbuffer_add_printf(x_buf, x_fmt, ##__VA_ARGS__) >= 0) -#define _RUN(x_next) server->run->x_next -#define _STREAM(x_next) _RUN(stream->x_next) -#define _VID(x_next) _STREAM(run->video->x_next) -#define _EX(x_next) _RUN(exposed->x_next) +#define _VID(x_next) server->run->stream->run->video->x_next +#define _EX(x_next) server->run->exposed->x_next us_server_s *us_server_init(us_stream_s *stream) { @@ -64,6 +62,7 @@ us_server_s *us_server_init(us_stream_s *stream) { us_server_runtime_s *run; US_CALLOC(run, 1); + run->ext_fd = -1; run->stream = stream; run->exposed = exposed; @@ -88,78 +87,81 @@ us_server_s *us_server_init(us_stream_s *stream) { } void us_server_destroy(us_server_s *server) { - if (_RUN(refresher) != NULL) { - event_del(_RUN(refresher)); - event_free(_RUN(refresher)); + us_server_runtime_s *const run = server->run; + + if (run->refresher != NULL) { + event_del(run->refresher); + event_free(run->refresher); } - if (_RUN(request_watcher) != NULL) { - event_del(_RUN(request_watcher)); - event_free(_RUN(request_watcher)); + if (run->request_watcher != NULL) { + event_del(run->request_watcher); + event_free(run->request_watcher); } - evhttp_free(_RUN(http)); - if (_RUN(ext_fd) >= 0) { - close(_RUN(ext_fd)); - } - event_base_free(_RUN(base)); + evhttp_free(run->http); + US_CLOSE_FD(run->ext_fd, close); + event_base_free(run->base); # if LIBEVENT_VERSION_NUMBER >= 0x02010100 libevent_global_shutdown(); # endif - US_LIST_ITERATE(_RUN(stream_clients), client, { + US_LIST_ITERATE(run->stream_clients, client, { // cppcheck-suppress constStatement free(client->key); free(client->hostport); free(client); }); - US_DELETE(_RUN(auth_token), free); + US_DELETE(run->auth_token, free); - us_frame_destroy(_EX(frame)); - free(_RUN(exposed)); + us_frame_destroy(run->exposed->frame); + free(run->exposed); free(server->run); free(server); } int us_server_listen(us_server_s *server) { + us_server_runtime_s *const run = server->run; + us_stream_s *const stream = run->stream; + { if (server->static_path[0] != '\0') { US_LOG_INFO("Enabling HTTP file server: %s", server->static_path); - evhttp_set_gencb(_RUN(http), _http_callback_static, (void *)server); + evhttp_set_gencb(run->http, _http_callback_static, (void *)server); } else { - assert(!evhttp_set_cb(_RUN(http), "/", _http_callback_root, (void *)server)); - assert(!evhttp_set_cb(_RUN(http), "/favicon.ico", _http_callback_favicon, (void *)server)); + assert(!evhttp_set_cb(run->http, "/", _http_callback_root, (void *)server)); + assert(!evhttp_set_cb(run->http, "/favicon.ico", _http_callback_favicon, (void *)server)); } - assert(!evhttp_set_cb(_RUN(http), "/state", _http_callback_state, (void *)server)); - assert(!evhttp_set_cb(_RUN(http), "/snapshot", _http_callback_snapshot, (void *)server)); - assert(!evhttp_set_cb(_RUN(http), "/stream", _http_callback_stream, (void *)server)); + assert(!evhttp_set_cb(run->http, "/state", _http_callback_state, (void *)server)); + assert(!evhttp_set_cb(run->http, "/snapshot", _http_callback_snapshot, (void *)server)); + assert(!evhttp_set_cb(run->http, "/stream", _http_callback_stream, (void *)server)); } - us_frame_copy(_STREAM(blank), _EX(frame)); + us_frame_copy(stream->blank, _EX(frame)); _EX(notify_last_width) = _EX(frame->width); _EX(notify_last_height) = _EX(frame->height); if (server->exit_on_no_clients > 0) { - _RUN(last_request_ts) = us_get_now_monotonic(); + run->last_request_ts = us_get_now_monotonic(); struct timeval interval = {0}; interval.tv_usec = 100000; - assert((_RUN(request_watcher) = event_new(_RUN(base), -1, EV_PERSIST, _http_request_watcher, server)) != NULL); - assert(!event_add(_RUN(request_watcher), &interval)); + assert((run->request_watcher = event_new(run->base, -1, EV_PERSIST, _http_request_watcher, server)) != NULL); + assert(!event_add(run->request_watcher, &interval)); } { struct timeval interval = {0}; - if (_STREAM(dev->desired_fps) > 0) { - interval.tv_usec = 1000000 / (_STREAM(dev->desired_fps) * 2); + if (stream->dev->desired_fps > 0) { + interval.tv_usec = 1000000 / (stream->dev->desired_fps * 2); } else { interval.tv_usec = 16000; // ~60fps } - assert((_RUN(refresher) = event_new(_RUN(base), -1, EV_PERSIST, _http_refresher, server)) != NULL); - assert(!event_add(_RUN(refresher), &interval)); + assert((run->refresher = event_new(run->base, -1, EV_PERSIST, _http_refresher, server)) != NULL); + assert(!event_add(run->refresher, &interval)); } - evhttp_set_timeout(_RUN(http), server->timeout); + evhttp_set_timeout(run->http, server->timeout); if (server->user[0] != '\0') { char *encoded_token = NULL; @@ -169,7 +171,7 @@ int us_server_listen(us_server_s *server) { us_base64_encode((uint8_t *)raw_token, strlen(raw_token), &encoded_token, NULL); free(raw_token); - US_ASPRINTF(_RUN(auth_token), "Basic %s", encoded_token); + US_ASPRINTF(run->auth_token, "Basic %s", encoded_token); free(encoded_token); US_LOG_INFO("Using HTTP basic auth"); @@ -177,8 +179,8 @@ int us_server_listen(us_server_s *server) { if (server->unix_path[0] != '\0') { US_LOG_DEBUG("Binding HTTP to UNIX socket '%s' ...", server->unix_path); - if ((_RUN(ext_fd) = us_evhttp_bind_unix( - _RUN(http), + if ((run->ext_fd = us_evhttp_bind_unix( + run->http, server->unix_path, server->unix_rm, server->unix_mode)) < 0 @@ -190,7 +192,7 @@ int us_server_listen(us_server_s *server) { # ifdef WITH_SYSTEMD } else if (server->systemd) { US_LOG_DEBUG("Binding HTTP to systemd socket ..."); - if ((_RUN(ext_fd) = us_evhttp_bind_systemd(_RUN(http))) < 0) { + if ((run->ext_fd = us_evhttp_bind_systemd(run->http)) < 0) { return -1; } US_LOG_INFO("Listening systemd socket ..."); @@ -198,7 +200,7 @@ int us_server_listen(us_server_s *server) { } else { US_LOG_DEBUG("Binding HTTP to [%s]:%u ...", server->host, server->port); - if (evhttp_bind_socket(_RUN(http), server->host, server->port) < 0) { + if (evhttp_bind_socket(run->http, server->host, server->port) < 0) { US_LOG_PERROR("Can't bind HTTP on [%s]:%u", server->host, server->port) return -1; } @@ -210,18 +212,20 @@ int us_server_listen(us_server_s *server) { void us_server_loop(us_server_s *server) { US_LOG_INFO("Starting HTTP eventloop ..."); - event_base_dispatch(_RUN(base)); + event_base_dispatch(server->run->base); US_LOG_INFO("HTTP eventloop stopped"); } void us_server_loop_break(us_server_s *server) { - event_base_loopbreak(_RUN(base)); + event_base_loopbreak(server->run->base); } #define ADD_HEADER(x_key, x_value) assert(!evhttp_add_header(evhttp_request_get_output_headers(request), x_key, x_value)) static int _http_preprocess_request(struct evhttp_request *request, us_server_s *server) { - _RUN(last_request_ts) = us_get_now_monotonic(); + us_server_runtime_s *const run = server->run; + + run->last_request_ts = us_get_now_monotonic(); if (server->allow_origin[0] != '\0') { const char *const cors_headers = _http_get_header(request, "Access-Control-Request-Headers"); @@ -242,10 +246,10 @@ static int _http_preprocess_request(struct evhttp_request *request, us_server_s return -1; } - if (_RUN(auth_token) != NULL) { + if (run->auth_token != NULL) { const char *const token = _http_get_header(request, "Authorization"); - if (token == NULL || strcmp(token, _RUN(auth_token)) != 0) { + if (token == NULL || strcmp(token, run->auth_token) != 0) { ADD_HEADER("WWW-Authenticate", "Basic realm=\"Restricted area\""); evhttp_send_reply(request, 401, "Unauthorized", NULL); return -1; @@ -269,24 +273,22 @@ static int _http_preprocess_request(struct evhttp_request *request, us_server_s static int _http_check_run_compat_action(struct evhttp_request *request, void *v_server) { // MJPG-Streamer compatibility layer - struct evkeyvalq params; - int error = 0; + int retval = -1; + struct evkeyvalq params; evhttp_parse_query(evhttp_request_get_uri(request), ¶ms); const char *const action = evhttp_find_header(¶ms, "action"); if (action && !strcmp(action, "snapshot")) { _http_callback_snapshot(request, v_server); - goto ok; + retval = 0; } else if (action && !strcmp(action, "stream")) { _http_callback_stream(request, v_server); - goto ok; + retval = 0; } - error = -1; - ok: - evhttp_clear_headers(¶ms); - return error; + evhttp_clear_headers(¶ms); + return retval; } #define COMPAT_REQUEST { \ @@ -338,14 +340,12 @@ static void _http_callback_static(struct evhttp_request *request, void *v_server { const char *uri_path; - if ((uri = evhttp_uri_parse(evhttp_request_get_uri(request))) == NULL) { goto bad_request; } if ((uri_path = (char *)evhttp_uri_get_path(uri)) == NULL) { uri_path = "/"; } - if ((decoded_path = evhttp_uridecode(uri_path, 0, NULL)) == NULL) { goto bad_request; } @@ -383,34 +383,34 @@ static void _http_callback_static(struct evhttp_request *request, void *v_server goto cleanup; } - bad_request: - evhttp_send_error(request, HTTP_BADREQUEST, NULL); - goto cleanup; +bad_request: + evhttp_send_error(request, HTTP_BADREQUEST, NULL); + goto cleanup; - not_found: - evhttp_send_error(request, HTTP_NOTFOUND, NULL); - goto cleanup; +not_found: + evhttp_send_error(request, HTTP_NOTFOUND, NULL); + goto cleanup; - cleanup: - if (fd >= 0) { - close(fd); - } - US_DELETE(static_path, free); - US_DELETE(buf, evbuffer_free); - US_DELETE(decoded_path, free); - US_DELETE(uri, evhttp_uri_free); +cleanup: + US_CLOSE_FD(fd, close); // cppcheck-suppress unreadVariable + US_DELETE(static_path, free); + US_DELETE(buf, evbuffer_free); + US_DELETE(decoded_path, free); + US_DELETE(uri, evhttp_uri_free); } #undef COMPAT_REQUEST static void _http_callback_state(struct evhttp_request *request, void *v_server) { us_server_s *const server = (us_server_s *)v_server; + us_server_runtime_s *const run = server->run; + us_stream_s *const stream = run->stream; PREPROCESS_REQUEST; us_encoder_type_e enc_type; unsigned enc_quality; - us_encoder_get_runtime_params(_STREAM(enc), &enc_type, &enc_quality); + us_encoder_get_runtime_params(stream->enc, &enc_type, &enc_quality); struct evbuffer *buf; _A_EVBUFFER_NEW(buf); @@ -424,28 +424,28 @@ static void _http_callback_state(struct evhttp_request *request, void *v_server) enc_quality ); - if (_STREAM(run->h264) != NULL) { + if (stream->run->h264 != NULL) { _A_EVBUFFER_ADD_PRINTF(buf, " \"h264\": {\"bitrate\": %u, \"gop\": %u, \"online\": %s},", - _STREAM(h264_bitrate), - _STREAM(h264_gop), - us_bool_to_string(atomic_load(&_STREAM(run->h264->online))) + stream->h264_bitrate, + stream->h264_gop, + us_bool_to_string(atomic_load(&stream->run->h264->online)) ); } - if (_STREAM(sink) != NULL || _STREAM(h264_sink) != NULL) { + if (stream->sink != NULL || stream->h264_sink != NULL) { _A_EVBUFFER_ADD_PRINTF(buf, " \"sinks\": {"); - if (_STREAM(sink) != NULL) { + if (stream->sink != NULL) { _A_EVBUFFER_ADD_PRINTF(buf, "\"jpeg\": {\"has_clients\": %s}", - us_bool_to_string(atomic_load(&_STREAM(sink->has_clients))) + us_bool_to_string(atomic_load(&stream->sink->has_clients)) ); } - if (_STREAM(h264_sink) != NULL) { + if (stream->h264_sink != NULL) { _A_EVBUFFER_ADD_PRINTF(buf, "%s\"h264\": {\"has_clients\": %s}", - (_STREAM(sink) ? ", " : ""), - us_bool_to_string(atomic_load(&_STREAM(h264_sink->has_clients))) + (stream->sink ? ", " : ""), + us_bool_to_string(atomic_load(&stream->h264_sink->has_clients)) ); } _A_EVBUFFER_ADD_PRINTF(buf, "},"); @@ -458,13 +458,13 @@ static void _http_callback_state(struct evhttp_request *request, void *v_server) (server->fake_width ? server->fake_width : _EX(frame->width)), (server->fake_height ? server->fake_height : _EX(frame->height)), us_bool_to_string(_EX(frame->online)), - _STREAM(dev->desired_fps), + stream->dev->desired_fps, _EX(captured_fps), _EX(queued_fps), - _RUN(stream_clients_count) + run->stream_clients_count ); - US_LIST_ITERATE(_RUN(stream_clients), client, { + US_LIST_ITERATE(run->stream_clients, client, { // cppcheck-suppress constStatement _A_EVBUFFER_ADD_PRINTF(buf, "\"%" PRIx64 "\": {\"fps\": %u, \"extra_headers\": %s, \"advance_headers\": %s," " \"dual_final_frames\": %s, \"zero_data\": %s, \"key\": \"%s\"}%s", @@ -544,6 +544,7 @@ static void _http_callback_stream(struct evhttp_request *request, void *v_server // https://github.com/libevent/libevent/blob/29cc8386a2f7911eaa9336692a2c5544d8b4734f/http.c#L1458 us_server_s *const server = (us_server_s *)v_server; + us_server_runtime_s *const run = server->run; PREPROCESS_REQUEST; @@ -570,9 +571,9 @@ static void _http_callback_stream(struct evhttp_request *request, void *v_server client->hostport = _http_get_client_hostport(request); client->id = us_get_now_id(); - US_LIST_APPEND_C(_RUN(stream_clients), client, _RUN(stream_clients_count)); + US_LIST_APPEND_C(run->stream_clients, client, run->stream_clients_count); - if (_RUN(stream_clients_count) == 1) { + if (run->stream_clients_count == 1) { atomic_store(&_VID(has_clients), true); # ifdef WITH_GPIO us_gpio_set_has_http_clients(true); @@ -580,10 +581,10 @@ static void _http_callback_stream(struct evhttp_request *request, void *v_server } US_LOG_INFO("HTTP: NEW client (now=%u): %s, id=%" PRIx64, - _RUN(stream_clients_count), client->hostport, client->id); + run->stream_clients_count, client->hostport, client->id); struct bufferevent *const buf_event = evhttp_connection_get_bufferevent(conn); - if (server->tcp_nodelay && !_RUN(ext_fd)) { + if (server->tcp_nodelay && run->ext_fd >= 0) { US_LOG_DEBUG("HTTP: Setting up TCP_NODELAY to the client %s ...", client->hostport); const evutil_socket_t fd = bufferevent_getfd(buf_event); assert(fd >= 0); @@ -602,8 +603,6 @@ static void _http_callback_stream(struct evhttp_request *request, void *v_server #undef PREPROCESS_REQUEST static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_client) { -# define BOUNDARY "boundarydonotcross" - us_stream_client_s *const client = (us_stream_client_s *)v_client; us_server_s *const server = client->server; @@ -639,6 +638,8 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c // Кроме того, advance_headers форсит отключение заголовков X-UStreamer-* // по тем же причинам, по которым у нас нет Content-Length. +# define BOUNDARY "boundarydonotcross" + # define ADD_ADVANCE_HEADERS \ _A_EVBUFFER_ADD_PRINTF(buf, \ "Content-Type: image/jpeg" RN "X-Timestamp: %.06Lf" RN RN, us_get_now_real()) @@ -753,10 +754,11 @@ static void _http_callback_stream_error(struct bufferevent *buf_event, short wha us_stream_client_s *const client = (us_stream_client_s *)v_client; us_server_s *const server = client->server; + us_server_runtime_s *const run = server->run; - US_LIST_REMOVE_C(_RUN(stream_clients), client, _RUN(stream_clients_count)); + US_LIST_REMOVE_C(run->stream_clients, client, run->stream_clients_count); - if (_RUN(stream_clients_count) == 0) { + if (run->stream_clients_count == 0) { atomic_store(&_VID(has_clients), false); # ifdef WITH_GPIO us_gpio_set_has_http_clients(false); @@ -765,10 +767,10 @@ static void _http_callback_stream_error(struct bufferevent *buf_event, short wha char *const reason = us_bufferevent_format_reason(what); US_LOG_INFO("HTTP: DEL client (now=%u): %s, id=%" PRIx64 ", %s", - _RUN(stream_clients_count), client->hostport, client->id, reason); + run->stream_clients_count, client->hostport, client->id, reason); free(reason); - struct evhttp_connection *const conn = evhttp_request_get_connection(client->request); + struct evhttp_connection *conn = evhttp_request_get_connection(client->request); US_DELETE(conn, evhttp_connection_free); free(client->key); @@ -777,10 +779,12 @@ static void _http_callback_stream_error(struct bufferevent *buf_event, short wha } static void _http_queue_send_stream(us_server_s *server, bool stream_updated, bool frame_updated) { + us_server_runtime_s *const run = server->run; + bool has_clients = false; bool queued = false; - US_LIST_ITERATE(_RUN(stream_clients), client, { + US_LIST_ITERATE(run->stream_clients, client, { // cppcheck-suppress constStatement struct evhttp_connection *const conn = evhttp_request_get_connection(client->request); if (conn != NULL) { // Фикс для бага WebKit. При включенной опции дропа одинаковых фреймов, @@ -832,16 +836,17 @@ static void _http_request_watcher(int fd, short what, void *v_server) { (void)fd; (void)what; - us_server_s *server = (us_server_s *)v_server; + us_server_s *const server = (us_server_s *)v_server; + us_server_runtime_s *const run = server->run; const long double now = us_get_now_monotonic(); - if (us_stream_has_clients(_RUN(stream))) { - _RUN(last_request_ts) = now; - } else if (_RUN(last_request_ts) + server->exit_on_no_clients < now) { + if (us_stream_has_clients(run->stream)) { + run->last_request_ts = now; + } else if (run->last_request_ts + server->exit_on_no_clients < now) { US_LOG_INFO("HTTP: No requests or HTTP/sink clients found in last %u seconds, exiting ...", server->exit_on_no_clients); us_process_suicide(); - _RUN(last_request_ts) = now; + run->last_request_ts = now; } } @@ -923,10 +928,11 @@ static bool _expose_new_frame(us_server_s *server) { _EX(frame->online), _EX(expose_end_ts) - _EX(expose_begin_ts)); updated = true; - not_updated: - atomic_store(&_VID(updated), false); - US_MUTEX_UNLOCK(_VID(mutex)); - return updated; + +not_updated: + atomic_store(&_VID(updated), false); + US_MUTEX_UNLOCK(_VID(mutex)); + return updated; } static const char *_http_get_header(struct evhttp_request *request, const char *key) { diff --git a/src/ustreamer/http/server.h b/src/ustreamer/http/server.h index cbb040f..10a206e 100644 --- a/src/ustreamer/http/server.h +++ b/src/ustreamer/http/server.h @@ -125,7 +125,7 @@ typedef struct { struct event *refresher; us_stream_s *stream; - us_exposed_s *exposed; + us_exposed_s *exposed; us_stream_client_s *stream_clients; unsigned stream_clients_count; diff --git a/src/ustreamer/http/static.c b/src/ustreamer/http/static.c index d7fe5d2..66ca07d 100644 --- a/src/ustreamer/http/static.c +++ b/src/ustreamer/http/static.c @@ -42,14 +42,12 @@ char *us_find_static_file_path(const char *root_path, const char *request_path) goto error; \ } \ } - LOAD_STAT; if (S_ISDIR(st.st_mode)) { US_LOG_VERBOSE("HTTP: Requested static path %s is a directory, trying %s/index.html", path, path); strcat(path, "/index.html"); LOAD_STAT; } - # undef LOAD_STAT if (!S_ISREG(st.st_mode)) { @@ -64,12 +62,10 @@ char *us_find_static_file_path(const char *root_path, const char *request_path) goto ok; - error: - US_DELETE(path, free); - path = NULL; - - ok: - free(simplified_path); +error: + US_DELETE(path, free); +ok: + free(simplified_path); return path; } diff --git a/src/ustreamer/http/unix.c b/src/ustreamer/http/unix.c index 492175b..bf36580 100644 --- a/src/ustreamer/http/unix.c +++ b/src/ustreamer/http/unix.c @@ -25,19 +25,16 @@ evutil_socket_t us_evhttp_bind_unix(struct evhttp *http, const char *path, bool rm, mode_t mode) { struct sockaddr_un addr = {0}; + const size_t max_sun_path = sizeof(addr.sun_path) - 1; -# define MAX_SUN_PATH (sizeof(addr.sun_path) - 1) - - if (strlen(path) > MAX_SUN_PATH) { - US_LOG_ERROR("UNIX socket path is too long; max=%zu", MAX_SUN_PATH); + if (strlen(path) > max_sun_path) { + US_LOG_ERROR("UNIX socket path is too long; max=%zu", max_sun_path); return -1; } - strncpy(addr.sun_path, path, MAX_SUN_PATH); + strncpy(addr.sun_path, path, max_sun_path); addr.sun_family = AF_UNIX; -# undef MAX_SUN_PATH - const evutil_socket_t fd = socket(AF_UNIX, SOCK_STREAM, 0); assert(fd >= 0); assert(!evutil_make_socket_nonblocking(fd)); diff --git a/src/ustreamer/main.c b/src/ustreamer/main.c index 6007b43..a70b90a 100644 --- a/src/ustreamer/main.c +++ b/src/ustreamer/main.c @@ -29,9 +29,9 @@ #include "../libs/tools.h" #include "../libs/threading.h" #include "../libs/logging.h" +#include "../libs/device.h" #include "options.h" -#include "device.h" #include "encoder.h" #include "stream.h" #include "http/server.h" diff --git a/src/ustreamer/options.h b/src/ustreamer/options.h index 21ec311..ebfbb06 100644 --- a/src/ustreamer/options.h +++ b/src/ustreamer/options.h @@ -38,8 +38,8 @@ #include "../libs/frame.h" #include "../libs/memsink.h" #include "../libs/options.h" +#include "../libs/device.h" -#include "device.h" #include "encoder.h" #include "blank.h" #include "stream.h" diff --git a/src/ustreamer/stream.h b/src/ustreamer/stream.h index 423d504..2cdaa01 100644 --- a/src/ustreamer/stream.h +++ b/src/ustreamer/stream.h @@ -37,9 +37,9 @@ #include "../libs/logging.h" #include "../libs/frame.h" #include "../libs/memsink.h" +#include "../libs/device.h" #include "blank.h" -#include "device.h" #include "encoder.h" #include "workers.h" #include "h264.h"