From 10aa33d89938ffa3bcd1a1fc0d9589efa7da495a Mon Sep 17 00:00:00 2001 From: Maxim Devaev Date: Thu, 18 Nov 2021 18:47:03 +0300 Subject: [PATCH] common m2m code, fixed non-dma dq --- src/ustreamer/h264/stream.c | 30 ++- src/ustreamer/h264/stream.h | 6 +- src/ustreamer/{h264/encoder.c => m2m.c} | 231 ++++++++++++------------ src/ustreamer/{h264/encoder.h => m2m.h} | 43 +++-- 4 files changed, 169 insertions(+), 141 deletions(-) rename src/ustreamer/{h264/encoder.c => m2m.c} (55%) rename src/ustreamer/{h264/encoder.h => m2m.h} (70%) diff --git a/src/ustreamer/h264/stream.c b/src/ustreamer/h264/stream.c index 53d1059..f6a962c 100644 --- a/src/ustreamer/h264/stream.c +++ b/src/ustreamer/h264/stream.c @@ -35,14 +35,30 @@ h264_stream_s *h264_stream_init(memsink_s *sink, const char *path, unsigned bitr // По логике вещей правильно 0, но почему-то на низких разрешениях типа 640x480 // енкодер через несколько секунд перестает производить корректные фреймы. // TODO: Это было актуально для MMAL, надо проверить для V4L2. - h264->enc = h264_encoder_init(path, bitrate, gop, 30); + +# define ADD_OPTION(_index, _required, _key, _value) { \ + h264->options[_index] = (m2m_option_s){#_key, _required, V4L2_CID_MPEG_VIDEO_##_key, _value}; \ + } + + A_CALLOC(h264->options, 8); + ADD_OPTION(0, true, BITRATE, bitrate * 1000); + ADD_OPTION(1, true, H264_I_PERIOD, gop); + ADD_OPTION(2, true, H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE); + ADD_OPTION(3, true, H264_LEVEL, V4L2_MPEG_VIDEO_H264_LEVEL_4_0); + ADD_OPTION(4, true, REPEAT_SEQ_HEADER, 1); + ADD_OPTION(5, false, H264_MIN_QP, 16); + ADD_OPTION(6, false, H264_MAX_QP, 32); + h264->options[7] = (m2m_option_s){NULL, false, 0, 0}; + +# undef ADD_OPTION + + h264->enc = m2m_encoder_init("H264", path, V4L2_PIX_FMT_H264, 30, h264->options); return h264; } void h264_stream_destroy(h264_stream_s *h264) { - if (h264->enc) { - h264_encoder_destroy(h264->enc); - } + m2m_encoder_destroy(h264->enc); + free(h264->options); frame_destroy(h264->dest); frame_destroy(h264->tmp_src); free(h264); @@ -76,12 +92,12 @@ void h264_stream_process(h264_stream_s *h264, const frame_s *frame, int dma_fd, bool online = false; - if (!h264_encoder_is_prepared_for(h264->enc, frame, dma)) { - h264_encoder_prepare(h264->enc, frame, dma); + if (!m2m_encoder_is_prepared_for(h264->enc, frame, dma)) { + m2m_encoder_prepare(h264->enc, frame, dma); } if (h264->enc->ready) { - if (h264_encoder_compress(h264->enc, frame, dma_fd, h264->dest, force_key) == 0) { + if (m2m_encoder_compress(h264->enc, frame, dma_fd, h264->dest, force_key) == 0) { online = !memsink_server_put(h264->sink, h264->dest); } } diff --git a/src/ustreamer/h264/stream.h b/src/ustreamer/h264/stream.h index dd1eb3b..d2592b3 100644 --- a/src/ustreamer/h264/stream.h +++ b/src/ustreamer/h264/stream.h @@ -31,15 +31,15 @@ #include "../../libs/frame.h" #include "../../libs/memsink.h" #include "../../libs/unjpeg.h" - -#include "encoder.h" +#include "../m2m.h" typedef struct { memsink_s *sink; frame_s *tmp_src; frame_s *dest; - h264_encoder_s *enc; + m2m_option_s *options; + m2m_encoder_s *enc; atomic_bool online; } h264_stream_s; diff --git a/src/ustreamer/h264/encoder.c b/src/ustreamer/m2m.c similarity index 55% rename from src/ustreamer/h264/encoder.c rename to src/ustreamer/m2m.c index 4f0a99b..01256e8 100644 --- a/src/ustreamer/h264/encoder.c +++ b/src/ustreamer/m2m.c @@ -20,59 +20,65 @@ *****************************************************************************/ -#include "encoder.h" +#include "m2m.h" -static int _h264_encoder_init_buffers( - h264_encoder_s *enc, const char *name, enum v4l2_buf_type type, - h264_buffer_s **bufs_ptr, unsigned *n_bufs_ptr, bool dma); +static int _m2m_encoder_init_buffers( + m2m_encoder_s *enc, const char *name, enum v4l2_buf_type type, + m2m_buffer_s **bufs_ptr, unsigned *n_bufs_ptr, bool dma); -static void _h264_encoder_cleanup(h264_encoder_s *enc); +static void _m2m_encoder_cleanup(m2m_encoder_s *enc); -static int _h264_encoder_compress_raw( - h264_encoder_s *enc, const frame_s *src, int src_dma_fd, +static int _m2m_encoder_compress_raw( + m2m_encoder_s *enc, const frame_s *src, int src_dma_fd, frame_s *dest, bool force_key); -h264_encoder_s *h264_encoder_init(const char *path, unsigned bitrate, unsigned gop, unsigned fps) { - LOG_INFO("H264: Initializing V4L2 encoder ..."); - LOG_INFO("H264: Using bitrate: %u Kbps", bitrate); - LOG_INFO("H264: Using GOP: %u", gop); +#define E_LOG_ERROR(_msg, ...) LOG_ERROR("%s: " _msg, enc->name, ##__VA_ARGS__) +#define E_LOG_PERROR(_msg, ...) LOG_PERROR("%s: " _msg, enc->name, ##__VA_ARGS__) +#define E_LOG_INFO(_msg, ...) LOG_INFO("%s: " _msg, enc->name, ##__VA_ARGS__) +#define E_LOG_VERBOSE(_msg, ...) LOG_VERBOSE("%s: " _msg, enc->name, ##__VA_ARGS__) +#define E_LOG_DEBUG(_msg, ...) LOG_DEBUG("%s: " _msg, enc->name, ##__VA_ARGS__) - h264_encoder_s *enc; + +m2m_encoder_s *m2m_encoder_init(const char *name, const char *path, unsigned format, unsigned fps, m2m_option_s *options) { + LOG_INFO("%s: Initializing encoder ...", name); + m2m_encoder_s *enc; A_CALLOC(enc, 1); + assert(enc->name = strdup(name)); assert(enc->path = strdup(path)); - enc->bitrate = bitrate; // Kbps - enc->gop = gop; // Interval between keyframes + enc->output_format = format; enc->fps = fps; + enc->options = options; enc->last_online = -1; return enc; } -void h264_encoder_destroy(h264_encoder_s *enc) { - LOG_INFO("H264: Destroying encoder ..."); - _h264_encoder_cleanup(enc); +void m2m_encoder_destroy(m2m_encoder_s *enc) { + E_LOG_INFO("Destroying encoder ..."); + _m2m_encoder_cleanup(enc); free(enc->path); + free(enc->name); free(enc); } -bool h264_encoder_is_prepared_for(h264_encoder_s *enc, const frame_s *frame, bool dma) { +bool m2m_encoder_is_prepared_for(m2m_encoder_s *enc, const frame_s *frame, bool dma) { # define EQ(_field) (enc->_field == frame->_field) return (EQ(width) && EQ(height) && EQ(format) && EQ(stride) && (enc->dma == dma)); # undef EQ } -#define ENCODER_XIOCTL(_request, _value, _msg, ...) { \ +#define E_XIOCTL(_request, _value, _msg, ...) { \ if (xioctl(enc->fd, _request, _value) < 0) { \ - LOG_PERROR(_msg, ##__VA_ARGS__); \ + E_LOG_PERROR(_msg, ##__VA_ARGS__); \ goto error; \ } \ } -int h264_encoder_prepare(h264_encoder_s *enc, const frame_s *frame, bool dma) { - LOG_INFO("H264: Configuring encoder: DMA=%d ...", dma); +int m2m_encoder_prepare(m2m_encoder_s *enc, const frame_s *frame, bool dma) { + E_LOG_INFO("Configuring encoder: DMA=%d ...", dma); - _h264_encoder_cleanup(enc); + _m2m_encoder_cleanup(enc); enc->width = frame->width; enc->height = frame->height; @@ -81,38 +87,27 @@ int h264_encoder_prepare(h264_encoder_s *enc, const frame_s *frame, bool dma) { enc->dma = dma; if ((enc->fd = open(enc->path, O_RDWR)) < 0) { - LOG_PERROR("H264: Can't open encoder device"); + E_LOG_PERROR("Can't open encoder device"); goto error; } - { -# define SET_OPTION(_required, _key, _value) { \ - struct v4l2_control _ctl = {0}; \ - _ctl.id = V4L2_CID_MPEG_VIDEO_##_key; \ - _ctl.value = _value; \ - LOG_DEBUG("H264: Configuring option %s ...", #_key); \ - if (_required) { \ - ENCODER_XIOCTL(VIDIOC_S_CTRL, &_ctl, "H264: Can't set option " #_key); \ - } else { \ - if (xioctl(enc->fd, VIDIOC_S_CTRL, &_ctl) < 0) { \ - if (errno == EINVAL) { \ - LOG_ERROR("H264: Can't set option " #_key ": Unsupported by encoder"); \ - } else { \ - LOG_PERROR("H264: Can't set option " #_key); \ - } \ - } \ - } \ + for (m2m_option_s *option = enc->options; option->name != NULL; ++option) { + struct v4l2_control ctl = {0}; + ctl.id = option->id; + ctl.value = option->value; + + E_LOG_DEBUG("Configuring option %s ...", option->name); + if (option->required) { + E_XIOCTL(VIDIOC_S_CTRL, &ctl, "Can't set option %s", option->name); + } else { + if (xioctl(enc->fd, VIDIOC_S_CTRL, &ctl) < 0) { + if (errno == EINVAL) { + E_LOG_ERROR("Can't set option %s: Unsupported by encoder", option->name); + } else { + E_LOG_PERROR("Can't set option %s", option->name); + } } - - SET_OPTION(true, BITRATE, enc->bitrate * 1000); - SET_OPTION(true, H264_I_PERIOD, enc->gop); - SET_OPTION(true, H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE); - SET_OPTION(true, H264_LEVEL, V4L2_MPEG_VIDEO_H264_LEVEL_4_0); - SET_OPTION(true, REPEAT_SEQ_HEADER, 1); - SET_OPTION(false, H264_MIN_QP, 16); - SET_OPTION(false, H264_MAX_QP, 32); - -# undef SET_OPTION + } } { @@ -124,8 +119,8 @@ int h264_encoder_prepare(h264_encoder_s *enc, const frame_s *frame, bool dma) { fmt.fmt.pix_mp.field = V4L2_FIELD_ANY; fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_JPEG; // libcamera currently has no means to request the right colour space fmt.fmt.pix_mp.num_planes = 1; - LOG_DEBUG("H264: Configuring INPUT format ..."); - ENCODER_XIOCTL(VIDIOC_S_FMT, &fmt, "H264: Can't set INPUT format"); + E_LOG_DEBUG("Configuring INPUT format ..."); + E_XIOCTL(VIDIOC_S_FMT, &fmt, "Can't set INPUT format"); } { @@ -133,14 +128,14 @@ int h264_encoder_prepare(h264_encoder_s *enc, const frame_s *frame, bool dma) { fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; fmt.fmt.pix_mp.width = frame->width; fmt.fmt.pix_mp.height = frame->height; - fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; + fmt.fmt.pix_mp.pixelformat = enc->output_format; fmt.fmt.pix_mp.field = V4L2_FIELD_ANY; fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT; fmt.fmt.pix_mp.num_planes = 1; fmt.fmt.pix_mp.plane_fmt[0].bytesperline = 0; fmt.fmt.pix_mp.plane_fmt[0].sizeimage = 512 << 10; - LOG_DEBUG("H264: Configuring OUTPUT format ..."); - ENCODER_XIOCTL(VIDIOC_S_FMT, &fmt, "H264: Can't set OUTPUT format"); + E_LOG_DEBUG("Configuring OUTPUT format ..."); + E_XIOCTL(VIDIOC_S_FMT, &fmt, "Can't set OUTPUT format"); } { @@ -148,57 +143,57 @@ int h264_encoder_prepare(h264_encoder_s *enc, const frame_s *frame, bool dma) { setfps.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; setfps.parm.output.timeperframe.numerator = 1; setfps.parm.output.timeperframe.denominator = enc->fps; - LOG_DEBUG("H264: Configuring INPUT FPS ..."); - ENCODER_XIOCTL(VIDIOC_S_PARM, &setfps, "H264: Can't set INPUT FPS"); + E_LOG_DEBUG("Configuring INPUT FPS ..."); + E_XIOCTL(VIDIOC_S_PARM, &setfps, "Can't set INPUT FPS"); } - if (_h264_encoder_init_buffers(enc, (dma ? "INPUT-DMA" : "INPUT"), V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + if (_m2m_encoder_init_buffers(enc, (dma ? "INPUT-DMA" : "INPUT"), V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, &enc->input_bufs, &enc->n_input_bufs, dma) < 0) { goto error; } - if (_h264_encoder_init_buffers(enc, "OUTPUT", V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + if (_m2m_encoder_init_buffers(enc, "OUTPUT", V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, &enc->output_bufs, &enc->n_output_bufs, false) < 0) { goto error; } { enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - LOG_DEBUG("H264: Starting INPUT ..."); - ENCODER_XIOCTL(VIDIOC_STREAMON, &type, "H264: Can't start INPUT"); + E_LOG_DEBUG("Starting INPUT ..."); + E_XIOCTL(VIDIOC_STREAMON, &type, "Can't start INPUT"); type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - LOG_DEBUG("H264: Starting OUTPUT ..."); - ENCODER_XIOCTL(VIDIOC_STREAMON, &type, "H264: Can't start OUTPUT"); + E_LOG_DEBUG("Starting OUTPUT ..."); + E_XIOCTL(VIDIOC_STREAMON, &type, "Can't start OUTPUT"); } enc->ready = true; - LOG_DEBUG("H264: Encoder state: *** READY ***"); + E_LOG_DEBUG("Encoder state: *** READY ***"); return 0; error: - _h264_encoder_cleanup(enc); - LOG_ERROR("H264: Encoder destroyed due an error (prepare)"); + _m2m_encoder_cleanup(enc); + E_LOG_ERROR("Encoder destroyed due an error (prepare)"); return -1; } -static int _h264_encoder_init_buffers( - h264_encoder_s *enc, const char *name, enum v4l2_buf_type type, - h264_buffer_s **bufs_ptr, unsigned *n_bufs_ptr, bool dma) { +static int _m2m_encoder_init_buffers( + m2m_encoder_s *enc, const char *name, enum v4l2_buf_type type, + m2m_buffer_s **bufs_ptr, unsigned *n_bufs_ptr, bool dma) { - LOG_DEBUG("H264: Initializing %s buffers: ...", name); + E_LOG_DEBUG("Initializing %s buffers ...", name); struct v4l2_requestbuffers req = {0}; req.count = 1; req.type = type; req.memory = (dma ? V4L2_MEMORY_DMABUF : V4L2_MEMORY_MMAP); - LOG_DEBUG("H264: Requesting %u %s buffers ...", req.count, name); - ENCODER_XIOCTL(VIDIOC_REQBUFS, &req, "H264: Can't request %s buffers", name); + E_LOG_DEBUG("Requesting %u %s buffers ...", req.count, name); + E_XIOCTL(VIDIOC_REQBUFS, &req, "Can't request %s buffers", name); if (req.count < 1) { - LOG_ERROR("H264: Insufficient %s buffer memory: %u", name, req.count); + E_LOG_ERROR("Insufficient %s buffer memory: %u", name, req.count); goto error; } - LOG_DEBUG("H264: Got %u %s buffers", req.count, name); + E_LOG_DEBUG("Got %u %s buffers", req.count, name); if (dma) { *n_bufs_ptr = req.count; @@ -213,10 +208,10 @@ static int _h264_encoder_init_buffers( buf.length = 1; buf.m.planes = &plane; - LOG_DEBUG("H264: Querying %s buffer index=%u ...", name, *n_bufs_ptr); - ENCODER_XIOCTL(VIDIOC_QUERYBUF, &buf, "H264: Can't query %s buffer index=%u", name, *n_bufs_ptr); + E_LOG_DEBUG("Querying %s buffer index=%u ...", name, *n_bufs_ptr); + E_XIOCTL(VIDIOC_QUERYBUF, &buf, "Can't query %s buffer index=%u", name, *n_bufs_ptr); - LOG_DEBUG("H264: Mapping %s buffer index=%u ...", name, *n_bufs_ptr); + E_LOG_DEBUG("Mapping %s buffer index=%u ...", name, *n_bufs_ptr); if (((*bufs_ptr)[*n_bufs_ptr].data = mmap( NULL, plane.length, @@ -225,13 +220,13 @@ static int _h264_encoder_init_buffers( enc->fd, plane.m.mem_offset )) == MAP_FAILED) { - LOG_PERROR("H264: Can't map %s buffer index=%u", name, *n_bufs_ptr); + E_LOG_PERROR("Can't map %s buffer index=%u", name, *n_bufs_ptr); goto error; } (*bufs_ptr)[*n_bufs_ptr].allocated = plane.length; - LOG_DEBUG("H264: Queuing %s buffer index=%u ...", name, *n_bufs_ptr); - ENCODER_XIOCTL(VIDIOC_QBUF, &buf, "H264: Can't queue %s buffer index=%u", name, *n_bufs_ptr); + E_LOG_DEBUG("Queuing %s buffer index=%u ...", name, *n_bufs_ptr); + E_XIOCTL(VIDIOC_QBUF, &buf, "Can't queue %s buffer index=%u", name, *n_bufs_ptr); } } @@ -240,13 +235,13 @@ static int _h264_encoder_init_buffers( return -1; } -static void _h264_encoder_cleanup(h264_encoder_s *enc) { +static void _m2m_encoder_cleanup(m2m_encoder_s *enc) { if (enc->ready) { # define STOP_STREAM(_name, _type) { \ enum v4l2_buf_type _type_var = _type; \ - LOG_DEBUG("H264: Stopping %s ...", _name); \ + E_LOG_DEBUG("Stopping %s ...", _name); \ if (xioctl(enc->fd, VIDIOC_STREAMOFF, &_type_var) < 0) { \ - LOG_PERROR("H264: Can't stop %s", _name); \ + E_LOG_PERROR("Can't stop %s", _name); \ } \ } @@ -261,7 +256,7 @@ static void _h264_encoder_cleanup(h264_encoder_s *enc) { for (unsigned index = 0; index < enc->n_##_target##_bufs; ++index) { \ if (enc->_target##_bufs[index].allocated > 0 && enc->_target##_bufs[index].data != MAP_FAILED) { \ if (munmap(enc->_target##_bufs[index].data, enc->_target##_bufs[index].allocated) < 0) { \ - LOG_PERROR("H264: Can't unmap %s buffer index=%u", #_name, index); \ + E_LOG_PERROR("Can't unmap %s buffer index=%u", #_name, index); \ } \ } \ } \ @@ -278,7 +273,7 @@ static void _h264_encoder_cleanup(h264_encoder_s *enc) { if (enc->fd >= 0) { if (close(enc->fd) < 0) { - LOG_PERROR("H264: Can't close encoder device"); + E_LOG_PERROR("Can't close encoder device"); } enc->fd = -1; } @@ -286,10 +281,10 @@ static void _h264_encoder_cleanup(h264_encoder_s *enc) { enc->last_online = -1; enc->ready = false; - LOG_DEBUG("H264: Encoder state: ~~~ NOT READY ~~~"); + E_LOG_DEBUG("Encoder state: ~~~ NOT READY ~~~"); } -int h264_encoder_compress(h264_encoder_s *enc, const frame_s *src, int src_dma_fd, frame_s *dest, bool force_key) { +int m2m_encoder_compress(m2m_encoder_s *enc, const frame_s *src, int src_dma_fd, frame_s *dest, bool force_key) { assert(enc->ready); assert(src->used > 0); assert(enc->width == src->width); @@ -304,37 +299,37 @@ int h264_encoder_compress(h264_encoder_s *enc, const frame_s *src, int src_dma_f frame_copy_meta(src, dest); dest->encode_begin_ts = get_now_monotonic(); - dest->format = V4L2_PIX_FMT_H264; + dest->format = enc->output_format; dest->stride = 0; force_key = (force_key || enc->last_online != src->online); - if (_h264_encoder_compress_raw(enc, src, src_dma_fd, dest, force_key) < 0) { - _h264_encoder_cleanup(enc); - LOG_ERROR("H264: Encoder destroyed due an error (compress)"); + if (_m2m_encoder_compress_raw(enc, src, src_dma_fd, dest, force_key) < 0) { + _m2m_encoder_cleanup(enc); + E_LOG_ERROR("Encoder destroyed due an error (compress)"); return -1; } dest->encode_end_ts = get_now_monotonic(); - LOG_VERBOSE("H264: Compressed new frame: size=%zu, time=%0.3Lf, force_key=%d", + E_LOG_VERBOSE("Compressed new frame: size=%zu, time=%0.3Lf, force_key=%d", dest->used, dest->encode_end_ts - dest->encode_begin_ts, force_key); enc->last_online = src->online; return 0; } -static int _h264_encoder_compress_raw( - h264_encoder_s *enc, const frame_s *src, int src_dma_fd, +static int _m2m_encoder_compress_raw( + m2m_encoder_s *enc, const frame_s *src, int src_dma_fd, frame_s *dest, bool force_key) { - LOG_DEBUG("H264: Compressing new frame; force_key=%d ...", force_key); + E_LOG_DEBUG("Compressing new frame; force_key=%d ...", force_key); if (force_key) { struct v4l2_control ctl = {0}; ctl.id = V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME; ctl.value = 1; - LOG_DEBUG("H264: Forcing keyframe ...") - ENCODER_XIOCTL(VIDIOC_S_CTRL, &ctl, "H264: Can't force keyframe"); + E_LOG_DEBUG("Forcing keyframe ...") + E_XIOCTL(VIDIOC_S_CTRL, &ctl, "Can't force keyframe"); } struct v4l2_buffer input_buf = {0}; @@ -349,18 +344,18 @@ static int _h264_encoder_compress_raw( input_buf.memory = V4L2_MEMORY_DMABUF; input_buf.field = V4L2_FIELD_NONE; input_plane.m.fd = src_dma_fd; - LOG_DEBUG("H264: Using INPUT-DMA buffer index=%u", input_buf.index); + E_LOG_DEBUG("Using INPUT-DMA buffer index=%u", input_buf.index); } else { assert(src_dma_fd < 0); input_buf.memory = V4L2_MEMORY_MMAP; - LOG_DEBUG("H264: Grabbing INPUT buffer ..."); - ENCODER_XIOCTL(VIDIOC_DQBUF, &input_buf, "H264: Can't grab INPUT buffer"); + E_LOG_DEBUG("Grabbing INPUT buffer ..."); + E_XIOCTL(VIDIOC_DQBUF, &input_buf, "Can't grab INPUT buffer"); if (input_buf.index >= enc->n_input_bufs) { - LOG_ERROR("H264: V4L2 error: grabbed invalid INPUT buffer: index=%u, n_bufs=%u", + E_LOG_ERROR("V4L2 error: grabbed invalid INPUT buffer: index=%u, n_bufs=%u", input_buf.index, enc->n_input_bufs); goto error; } - LOG_DEBUG("H264: Grabbed INPUT buffer index=%u", input_buf.index); + E_LOG_DEBUG("Grabbed INPUT buffer index=%u", input_buf.index); } uint64_t now = get_now_monotonic_u64(); @@ -374,22 +369,24 @@ static int _h264_encoder_compress_raw( const char *input_name = (enc->dma ? "INPUT-DMA" : "INPUT"); - LOG_DEBUG("H264: Sending %s buffer ...", input_name); - ENCODER_XIOCTL(VIDIOC_QBUF, &input_buf, "H264: Can't send %s buffer", input_name); + E_LOG_DEBUG("Sending%s %s buffer ...", (!enc->dma ? " (releasing)" : ""), input_name); + E_XIOCTL(VIDIOC_QBUF, &input_buf, "Can't send %s buffer", input_name); + + // Для не-DMA отправка буфера по факту являтся освобождением этого буфера + bool input_released = !enc->dma; - bool input_released = false; while (true) { struct pollfd enc_poll = {enc->fd, POLLIN, 0}; if (poll(&enc_poll, 1, 200) < 0 && errno != EINTR) { - LOG_PERROR("H264: Can't poll encoder"); + E_LOG_PERROR("Can't poll encoder"); goto error; } if (enc_poll.revents & POLLIN) { if (!input_released) { - LOG_DEBUG("H264: Releasing %s buffer index=%u ...", input_name, input_buf.index); - ENCODER_XIOCTL(VIDIOC_DQBUF, &input_buf, "H264: Can't release %s buffer index=%u", + E_LOG_DEBUG("Releasing %s buffer index=%u ...", input_name, input_buf.index); + E_XIOCTL(VIDIOC_DQBUF, &input_buf, "Can't release %s buffer index=%u", input_name, input_buf.index); input_released = true; } @@ -400,14 +397,14 @@ static int _h264_encoder_compress_raw( output_buf.memory = V4L2_MEMORY_MMAP; output_buf.length = 1; output_buf.m.planes = &output_plane; - LOG_DEBUG("H264: Fetching OUTPUT buffer ..."); - ENCODER_XIOCTL(VIDIOC_DQBUF, &output_buf, "H264: Can't fetch OUTPUT buffer"); + E_LOG_DEBUG("Fetching OUTPUT buffer ..."); + E_XIOCTL(VIDIOC_DQBUF, &output_buf, "Can't fetch OUTPUT buffer"); frame_set_data(dest, enc->output_bufs[output_buf.index].data, output_plane.bytesused); dest->key = output_buf.flags & V4L2_BUF_FLAG_KEYFRAME; - LOG_DEBUG("H264: Releasing OUTPUT buffer index=%u ...", output_buf.index); - ENCODER_XIOCTL(VIDIOC_QBUF, &output_buf, "H264: Can't release OUTPUT buffer index=%u", output_buf.index); + E_LOG_DEBUG("Releasing OUTPUT buffer index=%u ...", output_buf.index); + E_XIOCTL(VIDIOC_QBUF, &output_buf, "Can't release OUTPUT buffer index=%u", output_buf.index); break; } } @@ -417,4 +414,10 @@ static int _h264_encoder_compress_raw( return -1; } -#undef ENCODER_XIOCTL +#undef E_XIOCTL + +#undef E_LOG_DEBUG +#undef E_LOG_VERBOSE +#undef E_LOG_INFO +#undef E_LOG_PERROR +#undef E_LOG_ERROR diff --git a/src/ustreamer/h264/encoder.h b/src/ustreamer/m2m.h similarity index 70% rename from src/ustreamer/h264/encoder.h rename to src/ustreamer/m2m.h index edc1520..53ccde7 100644 --- a/src/ustreamer/h264/encoder.h +++ b/src/ustreamer/m2m.h @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -34,28 +35,36 @@ #include -#include "../../libs/tools.h" -#include "../../libs/logging.h" -#include "../../libs/frame.h" +#include "../libs/tools.h" +#include "../libs/logging.h" +#include "../libs/frame.h" -#include "../xioctl.h" +#include "xioctl.h" typedef struct { uint8_t *data; size_t allocated; -} h264_buffer_s; +} m2m_buffer_s; typedef struct { - char *path; - unsigned bitrate; // Kbit-per-sec - unsigned gop; // Interval between keyframes - unsigned fps; + char *name; + bool required; + uint32_t id; + int32_t value; +} m2m_option_s; + +typedef struct { + char *name; + char *path; + unsigned output_format; + unsigned fps; + m2m_option_s *options; int fd; - h264_buffer_s *input_bufs; + m2m_buffer_s *input_bufs; unsigned n_input_bufs; - h264_buffer_s *output_bufs; + m2m_buffer_s *output_bufs; unsigned n_output_bufs; int last_online; @@ -66,12 +75,12 @@ typedef struct { unsigned stride; bool dma; bool ready; -} h264_encoder_s; +} m2m_encoder_s; -h264_encoder_s *h264_encoder_init(const char *path, unsigned bitrate, unsigned gop, unsigned fps); -void h264_encoder_destroy(h264_encoder_s *enc); +m2m_encoder_s *m2m_encoder_init(const char *name, const char *path, unsigned format, unsigned fps, m2m_option_s *options); +void m2m_encoder_destroy(m2m_encoder_s *enc); -bool h264_encoder_is_prepared_for(h264_encoder_s *enc, const frame_s *frame, bool dma); -int h264_encoder_prepare(h264_encoder_s *enc, const frame_s *frame, bool dma); -int h264_encoder_compress(h264_encoder_s *enc, const frame_s *src, int src_dma_fd, frame_s *dest, bool force_key); +bool m2m_encoder_is_prepared_for(m2m_encoder_s *enc, const frame_s *frame, bool dma); +int m2m_encoder_prepare(m2m_encoder_s *enc, const frame_s *frame, bool dma); +int m2m_encoder_compress(m2m_encoder_s *enc, const frame_s *src, int src_dma_fd, frame_s *dest, bool force_key);