mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-19 08:16:31 +00:00
refactoring
This commit is contained in:
@@ -115,41 +115,18 @@ workers_pool_s *encoder_workers_pool_init(encoder_s *enc, device_s *dev) {
|
||||
n_workers = 1;
|
||||
|
||||
} else if (type == ENCODER_TYPE_M2M_VIDEO || type == ENCODER_TYPE_M2M_IMAGE) {
|
||||
LOG_DEBUG("Preparing M2M encoder ...");
|
||||
LOG_DEBUG("Preparing M2M-%s encoder ...", (type == ENCODER_TYPE_M2M_VIDEO ? "VIDEO" : "IMAGE"));
|
||||
if (ER(m2ms) == NULL) {
|
||||
A_CALLOC(ER(m2ms), n_workers);
|
||||
}
|
||||
|
||||
// Начинаем с нуля и доинициализируем на следующих заходах при необходимости
|
||||
if (ER(n_m2ms) < n_workers) {
|
||||
for (; ER(n_m2ms) < n_workers; ++ER(n_m2ms)) {
|
||||
// Начинаем с нуля и доинициализируем на следующих заходах при необходимости
|
||||
char name[32];
|
||||
snprintf(name, 32, "JPEG-%u", ER(n_m2ms));
|
||||
if (type == ENCODER_TYPE_M2M_VIDEO) {
|
||||
double b_min = ENCODER_M2M_BITRATE_MIN;
|
||||
double b_max = ENCODER_M2M_BITRATE_MAX;
|
||||
double step = ENCODER_M2M_BITRATE_STEP;
|
||||
double bitrate = log10(quality) * (b_max - b_min) / 2 + b_min;
|
||||
bitrate = step * round(bitrate / step);
|
||||
|
||||
for (; ER(n_m2ms) < n_workers; ++ER(n_m2ms)) {
|
||||
assert(bitrate > 0);
|
||||
char name[32];
|
||||
snprintf(name, 32, "JPEG-%u", ER(n_m2ms));
|
||||
m2m_option_s options[] = {
|
||||
{"BITRATE", true, V4L2_CID_MPEG_VIDEO_BITRATE, bitrate * 1000},
|
||||
{NULL, false, 0, 0},
|
||||
};
|
||||
ER(m2ms[ER(n_m2ms)]) = m2m_encoder_init(name, enc->m2m_path, V4L2_PIX_FMT_MJPEG, 0, options);
|
||||
}
|
||||
|
||||
ER(m2ms[ER(n_m2ms)]) = m2m_mjpeg_encoder_init(name, enc->m2m_path, quality);
|
||||
} else {
|
||||
for (; ER(n_m2ms) < n_workers; ++ER(n_m2ms)) {
|
||||
char name[32];
|
||||
snprintf(name, 32, "JPEG-%u", ER(n_m2ms));
|
||||
m2m_option_s options[] = {
|
||||
{"QUALITY", true, V4L2_CID_JPEG_COMPRESSION_QUALITY, quality},
|
||||
{NULL, false, 0, 0},
|
||||
};
|
||||
ER(m2ms[ER(n_m2ms)]) = m2m_encoder_init(name, enc->m2m_path, V4L2_PIX_FMT_JPEG, 0, options);
|
||||
}
|
||||
ER(m2ms[ER(n_m2ms)]) = m2m_jpeg_encoder_init(name, enc->m2m_path, quality);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +215,7 @@ static bool _worker_run_job(worker_s *wr) {
|
||||
hw_encoder_compress(src, dest);
|
||||
|
||||
} else if (ER(type) == ENCODER_TYPE_M2M_VIDEO || ER(type) == ENCODER_TYPE_M2M_IMAGE) {
|
||||
LOG_VERBOSE("Compressing buffer using M2M");
|
||||
LOG_VERBOSE("Compressing buffer using M2M-%s", (ER(type) == ENCODER_TYPE_M2M_VIDEO ? "VIDEO" : "IMAGE"));
|
||||
if (m2m_encoder_ensure_ready(ER(m2ms[wr->number]), src) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <strings.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <pthread.h>
|
||||
@@ -44,22 +43,6 @@
|
||||
#include "encoders/hw/encoder.h"
|
||||
|
||||
|
||||
#ifndef CFG_ENCODER_M2M_BITRATE_MIN
|
||||
# define CFG_ENCODER_M2M_BITRATE_MIN 25
|
||||
#endif
|
||||
#define ENCODER_M2M_BITRATE_MIN ((unsigned)CFG_ENCODER_M2M_BITRATE_MIN)
|
||||
|
||||
#ifndef CFG_ENCODER_M2M_BITRATE_MAX
|
||||
# define CFG_ENCODER_M2M_BITRATE_MAX 25000
|
||||
#endif
|
||||
#define ENCODER_M2M_BITRATE_MAX ((unsigned)CFG_ENCODER_M2M_BITRATE_MAX)
|
||||
|
||||
#ifndef CFG_ENCODER_M2M_BITRATE_STEP
|
||||
# define CFG_ENCODER_M2M_BITRATE_STEP 25
|
||||
#endif
|
||||
#define ENCODER_M2M_BITRATE_STEP ((unsigned)CFG_ENCODER_M2M_BITRATE_STEP)
|
||||
|
||||
|
||||
#define ENCODER_TYPES_STR "CPU, HW, M2M-VIDEO, M2M-IMAGE, NOOP"
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -30,29 +30,7 @@ h264_stream_s *h264_stream_init(memsink_s *sink, const char *path, unsigned bitr
|
||||
h264->tmp_src = frame_init();
|
||||
h264->dest = frame_init();
|
||||
atomic_init(&h264->online, false);
|
||||
|
||||
# define OPTION(_required, _key, _value) {#_key, _required, V4L2_CID_MPEG_VIDEO_##_key, _value}
|
||||
|
||||
m2m_option_s options[] = {
|
||||
OPTION(true, BITRATE, bitrate * 1000),
|
||||
OPTION(false, BITRATE_PEAK, bitrate * 1000),
|
||||
OPTION(true, H264_I_PERIOD, gop),
|
||||
OPTION(true, H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE),
|
||||
OPTION(true, H264_LEVEL, V4L2_MPEG_VIDEO_H264_LEVEL_4_0),
|
||||
OPTION(true, REPEAT_SEQ_HEADER, 1),
|
||||
OPTION(false, H264_MIN_QP, 16),
|
||||
OPTION(false, H264_MAX_QP, 32),
|
||||
{NULL, false, 0, 0},
|
||||
};
|
||||
|
||||
# undef OPTION
|
||||
|
||||
// FIXME: 30 or 0? https://github.com/6by9/yavta/blob/master/yavta.c#L2100
|
||||
// По логике вещей правильно 0, но почему-то на низких разрешениях типа 640x480
|
||||
// енкодер через несколько секунд перестает производить корректные фреймы.
|
||||
// TODO: Это было актуально для MMAL, надо проверить для V4L2.
|
||||
|
||||
h264->enc = m2m_encoder_init("H264", path, V4L2_PIX_FMT_H264, 30, options);
|
||||
h264->enc = m2m_h264_encoder_init("H264", path, bitrate, gop);
|
||||
return h264;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include "m2m.h"
|
||||
|
||||
|
||||
static m2m_encoder_s *_m2m_encoder_init(const char *name, const char *path, unsigned format, unsigned fps, m2m_option_s *options);
|
||||
|
||||
static bool _m2m_encoder_is_prepared_for(m2m_encoder_s *enc, const frame_s *frame);
|
||||
static int _m2m_encoder_prepare(m2m_encoder_s *enc, const frame_s *frame);
|
||||
|
||||
@@ -42,9 +44,57 @@ static int _m2m_encoder_compress_raw(m2m_encoder_s *enc, const frame_s *src, fra
|
||||
#define E_LOG_DEBUG(_msg, ...) LOG_DEBUG("%s: " _msg, enc->name, ##__VA_ARGS__)
|
||||
|
||||
|
||||
m2m_encoder_s *m2m_encoder_init(const char *name, const char *path, unsigned format, unsigned fps, m2m_option_s *options) {
|
||||
assert(format == V4L2_PIX_FMT_H264 || format == V4L2_PIX_FMT_JPEG || format == V4L2_PIX_FMT_MJPEG);
|
||||
m2m_encoder_s *m2m_h264_encoder_init(const char *name, const char *path, unsigned bitrate, unsigned gop) {
|
||||
# define OPTION(_required, _key, _value) {#_key, _required, V4L2_CID_MPEG_VIDEO_##_key, _value}
|
||||
|
||||
m2m_option_s options[] = {
|
||||
OPTION(true, BITRATE, bitrate * 1000),
|
||||
// OPTION(false, BITRATE_PEAK, bitrate * 1000),
|
||||
OPTION(true, H264_I_PERIOD, gop),
|
||||
OPTION(true, H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE),
|
||||
OPTION(true, H264_LEVEL, V4L2_MPEG_VIDEO_H264_LEVEL_4_0),
|
||||
OPTION(true, REPEAT_SEQ_HEADER, 1),
|
||||
OPTION(false, H264_MIN_QP, 16),
|
||||
OPTION(false, H264_MAX_QP, 32),
|
||||
{NULL, false, 0, 0},
|
||||
};
|
||||
|
||||
# undef OPTION
|
||||
|
||||
// FIXME: 30 or 0? https://github.com/6by9/yavta/blob/master/yavta.c#L2100
|
||||
// По логике вещей правильно 0, но почему-то на низких разрешениях типа 640x480
|
||||
// енкодер через несколько секунд перестает производить корректные фреймы.
|
||||
return _m2m_encoder_init(name, path, V4L2_PIX_FMT_H264, 30, options);
|
||||
}
|
||||
|
||||
m2m_encoder_s *m2m_mjpeg_encoder_init(const char *name, const char *path, unsigned quality) {
|
||||
const double b_min = 25;
|
||||
const double b_max = 25000;
|
||||
const double step = 25;
|
||||
double bitrate = log10(quality) * (b_max - b_min) / 2 + b_min;
|
||||
bitrate = step * round(bitrate / step);
|
||||
bitrate *= 1000; // From Kbps
|
||||
assert(bitrate > 0);
|
||||
|
||||
m2m_option_s options[] = {
|
||||
{"BITRATE", true, V4L2_CID_MPEG_VIDEO_BITRATE, bitrate},
|
||||
{NULL, false, 0, 0},
|
||||
};
|
||||
|
||||
// FIXME: То же самое про 30 or 0, но еще даже не проверено на низких разрешениях
|
||||
return _m2m_encoder_init(name, path, V4L2_PIX_FMT_MJPEG, 30, options);
|
||||
}
|
||||
|
||||
m2m_encoder_s *m2m_jpeg_encoder_init(const char *name, const char *path, unsigned quality) {
|
||||
m2m_option_s options[] = {
|
||||
{"QUALITY", true, V4L2_CID_JPEG_COMPRESSION_QUALITY, quality},
|
||||
{NULL, false, 0, 0},
|
||||
};
|
||||
|
||||
return _m2m_encoder_init(name, path, V4L2_PIX_FMT_JPEG, 30, options);
|
||||
}
|
||||
|
||||
static 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;
|
||||
@@ -159,8 +209,8 @@ static int _m2m_encoder_prepare(m2m_encoder_s *enc, const frame_s *frame) {
|
||||
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;
|
||||
// fmt.fmt.pix_mp.plane_fmt[0].bytesperline = 0;
|
||||
// fmt.fmt.pix_mp.plane_fmt[0].sizeimage = 512 << 10;
|
||||
E_LOG_DEBUG("Configuring OUTPUT format ...");
|
||||
E_XIOCTL(VIDIOC_S_FMT, &fmt, "Can't set OUTPUT format");
|
||||
if (fmt.fmt.pix_mp.pixelformat != enc->output_format) {
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
@@ -78,7 +79,9 @@ typedef struct {
|
||||
} m2m_encoder_s;
|
||||
|
||||
|
||||
m2m_encoder_s *m2m_encoder_init(const char *name, const char *path, unsigned format, unsigned fps, m2m_option_s *options);
|
||||
m2m_encoder_s *m2m_h264_encoder_init(const char *name, const char *path, unsigned bitrate, unsigned gop);
|
||||
m2m_encoder_s *m2m_mjpeg_encoder_init(const char *name, const char *path, unsigned quality);
|
||||
m2m_encoder_s *m2m_jpeg_encoder_init(const char *name, const char *path, unsigned quality);
|
||||
void m2m_encoder_destroy(m2m_encoder_s *enc);
|
||||
|
||||
int m2m_encoder_ensure_ready(m2m_encoder_s *enc, const frame_s *frame);
|
||||
|
||||
Reference in New Issue
Block a user