omx: disabled exif, optional ijg tables, refactoring

This commit is contained in:
Devaev Maxim
2018-09-28 03:51:49 +03:00
parent d76c5da4de
commit ea5ec96874
11 changed files with 80 additions and 35 deletions

View File

@@ -3,6 +3,8 @@ PREFIX ?= /usr/local
CFLAGS ?= -O3
LDFLAGS ?=
# =====
CC = gcc
LIBS = -lm -ljpeg -pthread -levent -levent_pthreads
override CFLAGS += -c -std=c99 -Wall -Wextra -D_GNU_SOURCE
@@ -18,6 +20,7 @@ override CFLAGS += -DOMX_ENCODER -DOMX_SKIP64BIT -I/opt/vc/include
endif
# =====
all: $(SOURCES) $(PROG)

View File

@@ -84,7 +84,6 @@ struct device_t *device_init() {
dev->standard = V4L2_STD_UNKNOWN;
dev->n_buffers = max_u(sysconf(_SC_NPROCESSORS_ONLN), 1) + 1;
dev->n_workers = dev->n_buffers;
dev->jpeg_quality = 80;
dev->timeout = 1;
dev->error_timeout = 1;
dev->run = run;

View File

@@ -70,7 +70,6 @@ struct device_t {
unsigned n_workers;
unsigned every_frame;
unsigned min_frame_size;
unsigned jpeg_quality;
unsigned timeout;
unsigned error_timeout;

View File

@@ -50,6 +50,7 @@ struct encoder_t *encoder_init() {
A_CALLOC(encoder, 1);
encoder->type = ENCODER_TYPE_CPU;
encoder->quality = 80;
return encoder;
}
@@ -60,6 +61,8 @@ void encoder_prepare(struct encoder_t *encoder) {
LOG_DEBUG("Initializing encoder ...");
}
LOG_INFO("Using JPEG quality: %d%%", encoder->quality);
# ifdef OMX_ENCODER
if (encoder->type == ENCODER_TYPE_OMX) {
if ((encoder->omx = omx_encoder_init()) == NULL) {
@@ -104,7 +107,7 @@ void encoder_prepare_for_device(struct encoder_t *encoder, struct device_t *dev)
#pragma GCC diagnostic pop
# ifdef OMX_ENCODER
if (encoder->type == ENCODER_TYPE_OMX) {
if (omx_encoder_prepare_for_device(encoder->omx, dev) < 0) {
if (omx_encoder_prepare_for_device(encoder->omx, dev, encoder->quality, encoder->omx_use_ijg) < 0) {
goto use_fallback;
}
if (dev->run->n_workers > 1) {
@@ -125,11 +128,11 @@ void encoder_prepare_for_device(struct encoder_t *encoder, struct device_t *dev)
# pragma GCC diagnostic pop
}
int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, int index) {
int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, const unsigned index) {
assert(encoder->type != ENCODER_TYPE_UNKNOWN);
if (encoder->type == ENCODER_TYPE_CPU) {
jpeg_encoder_compress_buffer(dev, index);
jpeg_encoder_compress_buffer(dev, index, encoder->quality);
}
# ifdef OMX_ENCODER
else if (encoder->type == ENCODER_TYPE_OMX) {

View File

@@ -39,17 +39,17 @@
enum encoder_type_t {
ENCODER_TYPE_UNKNOWN, // Only for encoder_parse_type() and main()
ENCODER_TYPE_CPU,
#ifdef OMX_ENCODER
ENCODER_TYPE_OMX,
#endif
};
struct encoder_t {
enum encoder_type_t type;
enum encoder_type_t type;
unsigned quality;
#ifdef OMX_ENCODER
struct omx_encoder_t *omx;
bool omx_use_ijg;
struct omx_encoder_t *omx;
#endif
};
@@ -61,4 +61,4 @@ enum encoder_type_t encoder_parse_type(const char *const str);
void encoder_prepare(struct encoder_t *encoder);
void encoder_prepare_for_device(struct encoder_t *encoder, struct device_t *dev);
int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, int index);
int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, const unsigned index);

View File

@@ -68,7 +68,7 @@ static boolean _jpeg_empty_output_buffer(j_compress_ptr jpeg);
static void _jpeg_term_destination(j_compress_ptr jpeg);
void jpeg_encoder_compress_buffer(struct device_t *dev, int index) {
void jpeg_encoder_compress_buffer(struct device_t *dev, const unsigned index, const unsigned quality) {
// This function based on compress_image_to_jpeg() from mjpg-streamer
struct jpeg_compress_struct jpeg;
@@ -89,7 +89,7 @@ void jpeg_encoder_compress_buffer(struct device_t *dev, int index) {
jpeg.in_color_space = JCS_RGB;
jpeg_set_defaults(&jpeg);
jpeg_set_quality(&jpeg, dev->jpeg_quality, TRUE);
jpeg_set_quality(&jpeg, quality, TRUE);
jpeg_start_compress(&jpeg, TRUE);

View File

@@ -24,4 +24,4 @@
#include "../device.h"
void jpeg_encoder_compress_buffer(struct device_t *dev, int index);
void jpeg_encoder_compress_buffer(struct device_t *dev, const unsigned index, const unsigned quality);

View File

@@ -52,8 +52,11 @@ static const struct option _long_opts[] = {
{"dv-timings", no_argument, NULL, 't'},
{"buffers", required_argument, NULL, 'b'},
{"workers", required_argument, NULL, 'w'},
{"jpeg-quality", required_argument, NULL, 'q'},
{"quality", required_argument, NULL, 'q'},
{"encoder", required_argument, NULL, 'c'},
# ifdef OMX_ENCODER
{"encoder-omx-use-ijg", required_argument, NULL, 500},
# endif
{"device-timeout", required_argument, NULL, 1000},
{"device-error-timeout", required_argument, NULL, 1001},
@@ -71,7 +74,7 @@ static const struct option _long_opts[] = {
{NULL, 0, NULL, 0},
};
static void _help(struct device_t *dev, struct http_server_t *server) {
static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_server_t *server) {
printf("\nuStreamer - Lightweight and fast MJPG-HTTP streamer\n");
printf("===================================================\n\n");
printf("Version: %s; license: GPLv3\n", VERSION);
@@ -94,9 +97,13 @@ static void _help(struct device_t *dev, struct http_server_t *server) {
printf(" Each buffer may processed using an intermediate thread.\n");
printf(" Default: %d (number of CPU cores + 1)\n\n", dev->n_buffers);
printf(" -w|--workers <N> -- The number of compressing threads. Default: %d (== --buffers).\n\n", dev->n_workers);
printf(" -q|--jpeg-quality <N> -- Set quality of JPEG encoding from 1 to 100 (best). Default: %d.\n\n", dev->jpeg_quality);
printf(" -q|--quality <N> -- Set quality of JPEG encoding from 1 to 100 (best). Default: %d.\n\n", encoder->quality);
printf(" --encoder <type> -- Use specified encoder. It may affects to workers number.\n");
printf(" -- Available: %s; default: CPU.\n\n", ENCODER_TYPES_STR);
# ifdef OMX_ENCODER
printf(" --encoder-omx-use-ijg -- Use the standard IJG quality tables when encoding images using OMX.\n");
printf(" Default: disabled.\n\n");
# endif
printf(" --device-timeout <seconds> -- Timeout for device querying. Default: %d\n\n", dev->timeout);
printf(" --device-error-timeout <seconds> -- Delay before trying to connect to the device again\n");
printf(" after a timeout. Default: %d\n\n", dev->error_timeout);
@@ -156,8 +163,11 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e
case 't': OPT_TRUE(dev->dv_timings);
case 'b': OPT_UNSIGNED(dev->n_buffers, "--buffers", 1, 32);
case 'w': OPT_UNSIGNED(dev->n_workers, "--workers", 1, 32);
case 'q': OPT_UNSIGNED(dev->jpeg_quality, "--jpeg-quality", 1, 100);
case 'c': OPT_PARSE(encoder->type, encoder_parse_type, ENCODER_TYPE_UNKNOWN, "encoder type")
case 'q': OPT_UNSIGNED(encoder->quality, "--quality", 1, 100);
case 'c': OPT_PARSE(encoder->type, encoder_parse_type, ENCODER_TYPE_UNKNOWN, "encoder type");
# ifdef OMX_ENCODER
case 500: encoder->omx_use_ijg = true; break;
# endif
case 1000: OPT_UNSIGNED(dev->timeout, "--timeout", 1, 60);
case 1001: OPT_UNSIGNED(dev->error_timeout, "--error-timeout", 1, 60);
@@ -172,7 +182,7 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e
case 5002: log_level = LOG_LEVEL_DEBUG; break;
case 5010: OPT_UNSIGNED(log_level, "--log-level", 0, 3);
case 0: break;
case 'h': default: _help(dev, server); return -1;
case 'h': default: _help(dev, encoder, server); return -1;
}
}
@@ -245,7 +255,7 @@ int main(int argc, char *argv[]) {
LOGGING_INIT;
dev = device_init();
encoder = encoder_init(ENCODER_TYPE_CPU);
encoder = encoder_init();
stream = stream_init(dev, encoder);
server = http_server_init(stream);

View File

@@ -19,6 +19,7 @@
*****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
@@ -28,6 +29,7 @@
#include <bcm_host.h>
#include <IL/OMX_Core.h>
#include <IL/OMX_Component.h>
#include <IL/OMX_Broadcom.h>
#include <interface/vcos/vcos_semaphore.h>
#include "../logging.h"
@@ -46,7 +48,7 @@
static int _omx_init_component(struct omx_encoder_t *omx);
static int _omx_init_disable_ports(struct omx_encoder_t *omx);
static int _omx_setup_input(struct omx_encoder_t *omx, struct device_t *dev);
static int _omx_setup_output(struct omx_encoder_t *omx, struct device_t *dev);
static int _omx_setup_output(struct omx_encoder_t *omx, const unsigned quality, const bool use_ijg);
static int _omx_encoder_clear_ports(struct omx_encoder_t *omx);
static OMX_ERRORTYPE _omx_event_handler(UNUSED OMX_HANDLETYPE encoder,
@@ -134,7 +136,7 @@ void omx_encoder_destroy(struct omx_encoder_t *omx) {
free(omx);
}
int omx_encoder_prepare_for_device(struct omx_encoder_t *omx, struct device_t *dev) {
int omx_encoder_prepare_for_device(struct omx_encoder_t *omx, struct device_t *dev, const unsigned quality, const bool use_ijg) {
if (component_set_state(&omx->encoder, OMX_StateIdle) < 0) {
return -1;
}
@@ -144,7 +146,7 @@ int omx_encoder_prepare_for_device(struct omx_encoder_t *omx, struct device_t *d
if (_omx_setup_input(omx, dev) < 0) {
return -1;
}
if (_omx_setup_output(omx, dev) < 0) {
if (_omx_setup_output(omx, quality, use_ijg) < 0) {
return -1;
}
if (component_set_state(&omx->encoder, OMX_StateExecuting) < 0) {
@@ -153,7 +155,7 @@ int omx_encoder_prepare_for_device(struct omx_encoder_t *omx, struct device_t *d
return 0;
}
int omx_encoder_compress_buffer(struct omx_encoder_t *omx, struct device_t *dev, int index) {
int omx_encoder_compress_buffer(struct omx_encoder_t *omx, struct device_t *dev, const unsigned index) {
OMX_ERRORTYPE error;
bool loaded = false;
@@ -216,6 +218,8 @@ int omx_encoder_compress_buffer(struct omx_encoder_t *omx, struct device_t *dev,
}
static int _omx_init_component(struct omx_encoder_t *omx) {
// http://home.nouwen.name/RaspberryPi/documentation/ilcomponents/image_encode.html
OMX_ERRORTYPE error;
OMX_CALLBACKTYPE callbacks;
@@ -313,10 +317,9 @@ static int _omx_setup_input(struct omx_encoder_t *omx, struct device_t *dev) {
return 0;
}
static int _omx_setup_output(struct omx_encoder_t *omx, struct device_t *dev) {
static int _omx_setup_output(struct omx_encoder_t *omx, const unsigned quality, const bool use_ijg) {
OMX_ERRORTYPE error;
OMX_PARAM_PORTDEFINITIONTYPE portdef;
OMX_IMAGE_PARAM_QFACTORTYPE quality_factor;
LOG_DEBUG("Setting up OMX JPEG output port ...");
@@ -338,13 +341,42 @@ static int _omx_setup_output(struct omx_encoder_t *omx, struct device_t *dev) {
return -1;
}
OMX_INIT_STRUCTURE(quality_factor);
quality_factor.nPortIndex = OUTPUT_PORT;
quality_factor.nQFactor = dev->jpeg_quality;
{
OMX_CONFIG_BOOLEANTYPE exif;
if ((error = OMX_SetParameter(omx->encoder, OMX_IndexParamQFactor, &quality_factor)) != OMX_ErrorNone) {
LOG_OMX_ERROR(error, "Can't set OMX JPEG quality");
return -1;
OMX_INIT_STRUCTURE(exif);
exif.bEnabled = OMX_FALSE;
if ((error = OMX_SetParameter(omx->encoder, OMX_IndexParamBrcmDisableEXIF, &exif)) != OMX_ErrorNone) {
LOG_OMX_ERROR(error, "Can't disable EXIF on OMX JPEG");
return -1;
}
}
if (use_ijg) {
OMX_PARAM_IJGSCALINGTYPE ijg;
OMX_INIT_STRUCTURE(ijg);
ijg.nPortIndex = OUTPUT_PORT;
ijg.bEnabled = OMX_TRUE;
if ((error = OMX_SetParameter(omx->encoder, OMX_IndexParamBrcmEnableIJGTableScaling, &ijg)) != OMX_ErrorNone) {
LOG_OMX_ERROR(error, "Can't set OMX JPEG IJG settings");
return -1;
}
}
{
OMX_IMAGE_PARAM_QFACTORTYPE qfactor;
OMX_INIT_STRUCTURE(qfactor);
qfactor.nPortIndex = OUTPUT_PORT;
qfactor.nQFactor = quality;
if ((error = OMX_SetParameter(omx->encoder, OMX_IndexParamQFactor, &qfactor)) != OMX_ErrorNone) {
LOG_OMX_ERROR(error, "Can't set OMX JPEG quality");
return -1;
}
}
if (component_enable_port(&omx->encoder, OUTPUT_PORT) < 0) {

View File

@@ -49,5 +49,5 @@ struct omx_encoder_t {
struct omx_encoder_t *omx_encoder_init();
void omx_encoder_destroy(struct omx_encoder_t *omx);
int omx_encoder_prepare_for_device(struct omx_encoder_t *omx, struct device_t *dev);
int omx_encoder_compress_buffer(struct omx_encoder_t *omx, struct device_t *dev, int index);
int omx_encoder_prepare_for_device(struct omx_encoder_t *omx, struct device_t *dev, const unsigned quality, const bool use_ijg);
int omx_encoder_compress_buffer(struct omx_encoder_t *omx, struct device_t *dev, const unsigned index);

View File

@@ -78,7 +78,6 @@ void stream_loop(struct stream_t *stream) {
pool.workers_stop = &workers_stop;
LOG_INFO("Using V4L2 device: %s", stream->dev->path);
LOG_INFO("Using JPEG quality: %d%%", stream->dev->jpeg_quality);
while (_stream_init_loop(stream->dev, &pool) == 0) {
struct worker_t *oldest_worker = NULL;