diff --git a/src/common/frame.c b/src/common/frame.c index c4f64a4..f9faeac 100644 --- a/src/common/frame.c +++ b/src/common/frame.c @@ -28,11 +28,13 @@ frame_s *frame_init(const char *role) { A_CALLOC(frame, 1); frame->role = role; + frame->managed = true; frame_realloc_data(frame, 500 * 1024); return frame; } void frame_destroy(frame_s *frame) { + assert(frame->managed); if (frame->data) { free(frame->data); } @@ -40,6 +42,7 @@ void frame_destroy(frame_s *frame) { } void frame_realloc_data(frame_s *frame, size_t size) { + assert(frame->managed); if (frame->allocated < size) { LOG_DEBUG("Increasing frame buffer '%s': %zu -> %zu (+%zu)", frame->role, frame->allocated, size, size - frame->allocated); @@ -49,12 +52,15 @@ void frame_realloc_data(frame_s *frame, size_t size) { } void frame_set_data(frame_s *frame, const uint8_t *data, size_t size) { + assert(frame->managed); frame_realloc_data(frame, size); memcpy(frame->data, data, size); frame->used = size; } void frame_append_data(frame_s *frame, const uint8_t *data, size_t size) { + assert(frame->managed); + size_t new_used = frame->used + size; frame_realloc_data(frame, new_used); @@ -63,6 +69,8 @@ void frame_append_data(frame_s *frame, const uint8_t *data, size_t size) { } void frame_copy(const frame_s *src, frame_s *dest) { + assert(dest->managed); + frame_set_data(dest, src->data, src->used); # define COPY(_field) dest->_field = src->_field @@ -72,6 +80,7 @@ void frame_copy(const frame_s *src, frame_s *dest) { COPY(width); COPY(height); + COPY(format); COPY(grab_ts); COPY(encode_begin_ts); diff --git a/src/common/frame.h b/src/common/frame.h index ca727c5..e083385 100644 --- a/src/common/frame.h +++ b/src/common/frame.h @@ -35,14 +35,19 @@ typedef struct { const char *role; + uint8_t *data; size_t used; size_t allocated; unsigned width; unsigned height; + unsigned format; + long double grab_ts; long double encode_begin_ts; long double encode_end_ts; + + bool managed; } frame_s; diff --git a/src/ustreamer/device.c b/src/ustreamer/device.c index 4f2c54c..ceaaa25 100644 --- a/src/ustreamer/device.c +++ b/src/ustreamer/device.c @@ -178,14 +178,14 @@ void device_close(device_s *dev) { # define HW(_next) RUN(hw_buffers)[index]._next if (dev->io_method == V4L2_MEMORY_MMAP) { - if (HW(allocated) > 0 && HW(data) != MAP_FAILED) { - if (munmap(HW(data), HW(allocated)) < 0) { + if (HW(raw.allocated) > 0 && HW(raw.data) != MAP_FAILED) { + if (munmap(HW(raw.data), HW(raw.allocated)) < 0) { LOG_PERROR("Can't unmap device buffer %u", index); } } } else { // V4L2_MEMORY_USERPTR - if (HW(data)) { - free(HW(data)); + if (HW(raw.data)) { + free(HW(raw.data)); } } A_MUTEX_DESTROY(&HW(grabbed_mutex)); @@ -321,12 +321,12 @@ int device_grab_buffer(device_s *dev) { HW(grabbed) = true; A_MUTEX_UNLOCK(&HW(grabbed_mutex)); - HW(used) = buf_info.bytesused; - HW(width) = RUN(width); - HW(height) = RUN(height); - HW(format) = RUN(format); + HW(raw.used) = buf_info.bytesused; + HW(raw.width) = RUN(width); + HW(raw.height) = RUN(height); + HW(raw.format) = RUN(format); memcpy(&HW(buf_info), &buf_info, sizeof(struct v4l2_buffer)); - HW(grab_ts) = get_now_monotonic(); + HW(raw.grab_ts) = get_now_monotonic(); # undef HW return buf_info.index; @@ -625,7 +625,7 @@ static int _device_open_io_method_mmap(device_s *dev) { A_MUTEX_INIT(&HW(grabbed_mutex)); LOG_DEBUG("Mapping device buffer %u ...", RUN(n_buffers)); - if ((HW(data) = mmap( + if ((HW(raw.data) = mmap( NULL, buf_info.length, PROT_READ | PROT_WRITE, @@ -636,7 +636,7 @@ static int _device_open_io_method_mmap(device_s *dev) { LOG_PERROR("Can't map device buffer %u", RUN(n_buffers)); return -1; } - HW(allocated) = buf_info.length; + HW(raw.allocated) = buf_info.length; # undef HW } @@ -672,9 +672,9 @@ static int _device_open_io_method_userptr(device_s *dev) { for (RUN(n_buffers) = 0; RUN(n_buffers) < req.count; ++RUN(n_buffers)) { # define HW(_next) RUN(hw_buffers)[RUN(n_buffers)]._next - assert(HW(data) = aligned_alloc(page_size, buf_size)); - memset(HW(data), 0, buf_size); - HW(allocated) = buf_size; + assert(HW(raw.data) = aligned_alloc(page_size, buf_size)); + memset(HW(raw.data), 0, buf_size); + HW(raw.allocated) = buf_size; # undef HW } @@ -690,8 +690,8 @@ static int _device_open_queue_buffers(device_s *dev) { buf_info.memory = dev->io_method; buf_info.index = index; if (dev->io_method == V4L2_MEMORY_USERPTR) { - buf_info.m.userptr = (unsigned long)RUN(hw_buffers)[index].data; - buf_info.length = RUN(hw_buffers)[index].allocated; + buf_info.m.userptr = (unsigned long)RUN(hw_buffers)[index].raw.data; + buf_info.length = RUN(hw_buffers)[index].raw.allocated; } LOG_DEBUG("Calling ioctl(VIDIOC_QBUF) for buffer %u ...", index); diff --git a/src/ustreamer/device.h b/src/ustreamer/device.h index f627038..54b0141 100644 --- a/src/ustreamer/device.h +++ b/src/ustreamer/device.h @@ -44,6 +44,7 @@ #include "../common/tools.h" #include "../common/logging.h" #include "../common/threading.h" +#include "../common/frame.h" #include "xioctl.h" @@ -71,13 +72,7 @@ typedef struct { - uint8_t *data; - size_t used; - size_t allocated; - unsigned width; - unsigned height; - unsigned format; - long double grab_ts; + frame_s raw; struct v4l2_buffer buf_info; diff --git a/src/ustreamer/encoder.c b/src/ustreamer/encoder.c index cd1cfb6..7901ca4 100644 --- a/src/ustreamer/encoder.c +++ b/src/ustreamer/encoder.c @@ -207,26 +207,26 @@ void encoder_get_runtime_params(encoder_s *encoder, encoder_type_e *type, unsign #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic push -int encoder_compress_buffer(encoder_s *encoder, unsigned worker_number, hw_buffer_s *hw, frame_s *frame) { +int encoder_compress_buffer(encoder_s *encoder, unsigned worker_number, frame_s *raw, frame_s *frame) { #pragma GCC diagnostic pop assert(ER(type) != ENCODER_TYPE_UNKNOWN); - assert(hw->used > 0); + assert(raw->used > 0); - frame->grab_ts = hw->grab_ts; + frame->grab_ts = raw->grab_ts; frame->encode_begin_ts = get_now_monotonic(); if (ER(type) == ENCODER_TYPE_CPU) { LOG_VERBOSE("Compressing buffer using CPU"); - cpu_encoder_compress_buffer(hw, frame, ER(quality)); + cpu_encoder_compress_buffer(raw, frame, ER(quality)); } else if (ER(type) == ENCODER_TYPE_HW) { LOG_VERBOSE("Compressing buffer using HW (just copying)"); - hw_encoder_compress_buffer(hw, frame); + hw_encoder_compress_buffer(raw, frame); } # ifdef WITH_OMX else if (ER(type) == ENCODER_TYPE_OMX) { LOG_VERBOSE("Compressing buffer using OMX"); - if (omx_encoder_compress_buffer(ER(omxs[worker_number]), hw, frame) < 0) { + if (omx_encoder_compress_buffer(ER(omxs[worker_number]), raw, frame) < 0) { goto error; } } @@ -240,8 +240,9 @@ int encoder_compress_buffer(encoder_s *encoder, unsigned worker_number, hw_buffe frame->encode_end_ts = get_now_monotonic(); - frame->width = hw->width; - frame->height = hw->height; + frame->width = raw->width; + frame->height = raw->height; + // frame->format = V4L2_PIX_FMT_JPEG; return 0; diff --git a/src/ustreamer/encoder.h b/src/ustreamer/encoder.h index 2c58e7e..c5e974d 100644 --- a/src/ustreamer/encoder.h +++ b/src/ustreamer/encoder.h @@ -111,4 +111,4 @@ const char *encoder_type_to_string(encoder_type_e type); void encoder_prepare(encoder_s *encoder, device_s *dev); void encoder_get_runtime_params(encoder_s *encoder, encoder_type_e *type, unsigned *quality); -int encoder_compress_buffer(encoder_s *encoder, unsigned worker_number, hw_buffer_s *hw, frame_s *frame); +int encoder_compress_buffer(encoder_s *encoder, unsigned worker_number, frame_s *raw, frame_s *frame); diff --git a/src/ustreamer/encoders/cpu/encoder.c b/src/ustreamer/encoders/cpu/encoder.c index 52ce3b5..8e9c168 100644 --- a/src/ustreamer/encoders/cpu/encoder.c +++ b/src/ustreamer/encoders/cpu/encoder.c @@ -58,7 +58,7 @@ static boolean _jpeg_empty_output_buffer(j_compress_ptr jpeg); static void _jpeg_term_destination(j_compress_ptr jpeg); -void cpu_encoder_compress_buffer(hw_buffer_s *hw, frame_s *frame, unsigned quality) { +void cpu_encoder_compress_buffer(frame_s *raw, frame_s *frame, unsigned quality) { // This function based on compress_image_to_jpeg() from mjpg-streamer struct jpeg_compress_struct jpeg; @@ -69,8 +69,8 @@ void cpu_encoder_compress_buffer(hw_buffer_s *hw, frame_s *frame, unsigned quali _jpeg_set_picture(&jpeg, frame); - jpeg.image_width = hw->width; - jpeg.image_height = hw->height; + jpeg.image_width = raw->width; + jpeg.image_height = raw->height; jpeg.input_components = 3; jpeg.in_color_space = JCS_RGB; @@ -80,9 +80,9 @@ void cpu_encoder_compress_buffer(hw_buffer_s *hw, frame_s *frame, unsigned quali jpeg_start_compress(&jpeg, TRUE); # define WRITE_SCANLINES(_format, _func) \ - case _format: { _func(&jpeg, hw->data, hw->width, hw->height); break; } + case _format: { _func(&jpeg, raw->data, raw->width, raw->height); break; } - switch (hw->format) { + switch (raw->format) { // https://www.fourcc.org/yuv.php WRITE_SCANLINES(V4L2_PIX_FMT_YUYV, _jpeg_write_scanlines_yuyv); WRITE_SCANLINES(V4L2_PIX_FMT_UYVY, _jpeg_write_scanlines_uyvy); diff --git a/src/ustreamer/encoders/cpu/encoder.h b/src/ustreamer/encoders/cpu/encoder.h index 72a18c4..c28a3dc 100644 --- a/src/ustreamer/encoders/cpu/encoder.h +++ b/src/ustreamer/encoders/cpu/encoder.h @@ -33,7 +33,6 @@ #include "../../../common/tools.h" #include "../../../common/frame.h" -#include "../../device.h" -void cpu_encoder_compress_buffer(hw_buffer_s *hw, frame_s *frame, unsigned quality); +void cpu_encoder_compress_buffer(frame_s *raw, frame_s *frame, unsigned quality); diff --git a/src/ustreamer/encoders/hw/encoder.c b/src/ustreamer/encoders/hw/encoder.c index 19a507a..ec13319 100644 --- a/src/ustreamer/encoders/hw/encoder.c +++ b/src/ustreamer/encoders/hw/encoder.c @@ -28,7 +28,7 @@ #include "encoder.h" -void _copy_plus_huffman(const hw_buffer_s *src, frame_s *dest); +void _copy_plus_huffman(const frame_s *src, frame_s *dest); static bool _is_huffman(const uint8_t *data); @@ -49,14 +49,14 @@ int hw_encoder_prepare(device_s *dev, unsigned quality) { return 0; } -void hw_encoder_compress_buffer(hw_buffer_s *hw, frame_s *frame) { - if (hw->format != V4L2_PIX_FMT_MJPEG && hw->format != V4L2_PIX_FMT_JPEG) { +void hw_encoder_compress_buffer(frame_s *raw, frame_s *frame) { + if (raw->format != V4L2_PIX_FMT_MJPEG && raw->format != V4L2_PIX_FMT_JPEG) { assert(0 && "Unsupported input format for HW encoder"); } - _copy_plus_huffman(hw, frame); + _copy_plus_huffman(raw, frame); } -void _copy_plus_huffman(const hw_buffer_s *src, frame_s *dest) { +void _copy_plus_huffman(const frame_s *src, frame_s *dest) { if (!_is_huffman(src->data)) { const uint8_t *src_ptr = src->data; const uint8_t *src_end = src->data + src->used; diff --git a/src/ustreamer/encoders/hw/encoder.h b/src/ustreamer/encoders/hw/encoder.h index 33c856f..7303a8e 100644 --- a/src/ustreamer/encoders/hw/encoder.h +++ b/src/ustreamer/encoders/hw/encoder.h @@ -39,4 +39,4 @@ int hw_encoder_prepare(device_s *dev, unsigned quality); -void hw_encoder_compress_buffer(hw_buffer_s *hw, frame_s *frame); +void hw_encoder_compress_buffer(frame_s *raw, frame_s *frame); diff --git a/src/ustreamer/encoders/omx/encoder.c b/src/ustreamer/encoders/omx/encoder.c index ec4be3c..7e5e769 100644 --- a/src/ustreamer/encoders/omx/encoder.c +++ b/src/ustreamer/encoders/omx/encoder.c @@ -154,12 +154,12 @@ int omx_encoder_prepare(omx_encoder_s *omx, device_s *dev, unsigned quality) { return 0; } -int omx_encoder_compress_buffer(omx_encoder_s *omx, hw_buffer_s *hw, frame_s *frame) { +int omx_encoder_compress_buffer(omx_encoder_s *omx, frame_s *raw, frame_s *frame) { # define IN(_next) omx->input_buffer->_next # define OUT(_next) omx->output_buffer->_next OMX_ERRORTYPE error; - size_t slice_size = (IN(nAllocLen) < hw->used ? IN(nAllocLen) : hw->used); + size_t slice_size = (IN(nAllocLen) < raw->used ? IN(nAllocLen) : raw->used); size_t pos = 0; if ((error = OMX_FillThisBuffer(omx->encoder, omx->output_buffer)) != OMX_ErrorNone) { @@ -195,18 +195,18 @@ int omx_encoder_compress_buffer(omx_encoder_s *omx, hw_buffer_s *hw, frame_s *fr if (omx->input_required) { omx->input_required = false; - if (pos == hw->used) { + if (pos == raw->used) { continue; } - memcpy(IN(pBuffer), hw->data + pos, slice_size); + memcpy(IN(pBuffer), raw->data + pos, slice_size); IN(nOffset) = 0; IN(nFilledLen) = slice_size; pos += slice_size; - if (pos + slice_size > hw->used) { - slice_size = hw->used - pos; + if (pos + slice_size > raw->used) { + slice_size = raw->used - pos; } if ((error = OMX_EmptyThisBuffer(omx->encoder, omx->input_buffer)) != OMX_ErrorNone) { diff --git a/src/ustreamer/encoders/omx/encoder.h b/src/ustreamer/encoders/omx/encoder.h index 71e7fd0..8177517 100644 --- a/src/ustreamer/encoders/omx/encoder.h +++ b/src/ustreamer/encoders/omx/encoder.h @@ -71,4 +71,4 @@ omx_encoder_s *omx_encoder_init(void); void omx_encoder_destroy(omx_encoder_s *omx); int omx_encoder_prepare(omx_encoder_s *omx, device_s *dev, unsigned quality); -int omx_encoder_compress_buffer(omx_encoder_s *omx, hw_buffer_s *hw, frame_s *frame); +int omx_encoder_compress_buffer(omx_encoder_s *omx, frame_s *raw, frame_s *frame); diff --git a/src/ustreamer/stream.c b/src/ustreamer/stream.c index 36de92e..4be1a84 100644 --- a/src/ustreamer/stream.c +++ b/src/ustreamer/stream.c @@ -209,15 +209,15 @@ void stream_loop(stream_s *stream) { LOG_VERBOSE("Fluency: delay=%.03Lf, grab_after=%.03Lf", fluency_delay, grab_after); # ifdef WITH_RAWSINK -# define HW(_next) DEV(run->hw_buffers[buf_index]._next) +# define RAW(_next) DEV(run->hw_buffers[buf_index].raw._next) if (stream->rawsink && rawsink_server_put( - stream->rawsink, HW(data), HW(used), HW(format), - HW(width), HW(height), HW(grab_ts), true + stream->rawsink, RAW(data), RAW(used), RAW(format), + RAW(width), RAW(height), RAW(grab_ts), true ) < 0) { stream->rawsink = NULL; LOG_ERROR("RAW sink completely disabled due error"); } -# undef HW +# undef RAW # endif _workers_pool_assign(pool, ready_wr, buf_index); @@ -484,7 +484,7 @@ static void *_worker_thread(void *v_worker) { wr->job_failed = (bool)encoder_compress_buffer( wr->stream->encoder, wr->number, - &wr->stream->dev->run->hw_buffers[wr->buf_index], + &wr->stream->dev->run->hw_buffers[wr->buf_index].raw, wr->frame );