mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-04-11 00:56:13 +00:00
using frame_s as common data storage
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user