mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-19 08:16:31 +00:00
omx: disabled exif, optional ijg tables, refactoring
This commit is contained in:
3
Makefile
3
Makefile
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
24
src/main.c
24
src/main.c
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user