mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-03-13 02:53:42 +00:00
omx prototype
This commit is contained in:
9
Makefile
9
Makefile
@@ -13,6 +13,13 @@ PROG = ustreamer
|
|||||||
all: $(SOURCES) $(PROG)
|
all: $(SOURCES) $(PROG)
|
||||||
|
|
||||||
|
|
||||||
|
rpi:
|
||||||
|
make all \
|
||||||
|
SOURCES="$(SOURCES) $(shell ls src/omx/*.c)" \
|
||||||
|
LIBS="$(LIBS) -lbcm_host -lvcos -lopenmaxil -L/opt/vc/lib" \
|
||||||
|
CFLAGS="$(CFLAGS) -DOMX_ENCODER -DOMX_SKIP64BIT -I/opt/vc/include"
|
||||||
|
|
||||||
|
|
||||||
install: $(PROG)
|
install: $(PROG)
|
||||||
install -Dm755 $(PROG) $(DESTDIR)$(PREFIX)/bin/$(PROG)
|
install -Dm755 $(PROG) $(DESTDIR)$(PREFIX)/bin/$(PROG)
|
||||||
|
|
||||||
@@ -30,4 +37,4 @@ $(PROG): $(OBJECTS)
|
|||||||
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f src/*.o vgcore.* $(PROG)
|
rm -f src/*.o src/{jpeg,omx}/*.o vgcore.* $(PROG)
|
||||||
|
|||||||
@@ -138,6 +138,8 @@ int device_open(struct device_t *dev) {
|
|||||||
}
|
}
|
||||||
_device_open_alloc_picbufs(dev);
|
_device_open_alloc_picbufs(dev);
|
||||||
|
|
||||||
|
dev->run->n_workers = dev->n_workers;
|
||||||
|
|
||||||
LOG_DEBUG("Device fd=%d initialized", dev->run->fd);
|
LOG_DEBUG("Device fd=%d initialized", dev->run->fd);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ struct device_runtime_t {
|
|||||||
unsigned height;
|
unsigned height;
|
||||||
unsigned format;
|
unsigned format;
|
||||||
unsigned n_buffers;
|
unsigned n_buffers;
|
||||||
|
unsigned n_workers;
|
||||||
struct hw_buffer_t *hw_buffers;
|
struct hw_buffer_t *hw_buffers;
|
||||||
struct picture_t *pictures;
|
struct picture_t *pictures;
|
||||||
unsigned long max_picture_size;
|
unsigned long max_picture_size;
|
||||||
|
|||||||
105
src/encoder.c
Normal file
105
src/encoder.c
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||||
|
# #
|
||||||
|
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||||
|
# #
|
||||||
|
# This program is free software: you can redistribute it and/or modify #
|
||||||
|
# it under the terms of the GNU General Public License as published by #
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or #
|
||||||
|
# (at your option) any later version. #
|
||||||
|
# #
|
||||||
|
# This program is distributed in the hope that it will be useful, #
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||||
|
# GNU General Public License for more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the GNU General Public License #
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||||
|
# #
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "tools.h"
|
||||||
|
#include "device.h"
|
||||||
|
#include "encoder.h"
|
||||||
|
|
||||||
|
#include "jpeg/encoder.h"
|
||||||
|
|
||||||
|
#ifdef OMX_ENCODER
|
||||||
|
# include "omx/encoder.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct encoder_t *encoder_init(enum encoder_type_t type) {
|
||||||
|
struct encoder_t *encoder;
|
||||||
|
|
||||||
|
A_CALLOC(encoder, 1);
|
||||||
|
encoder->type = type;
|
||||||
|
|
||||||
|
# ifdef OMX_ENCODER
|
||||||
|
if (type == ENCODER_TYPE_OMX) {
|
||||||
|
if ((encoder->omx = omx_encoder_init()) == NULL) {
|
||||||
|
goto use_fallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
return encoder;
|
||||||
|
|
||||||
|
# pragma GCC diagnostic ignored "-Wunused-label"
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
use_fallback:
|
||||||
|
LOG_ERROR("Can't initialize selected encoder, using CPU instead it");
|
||||||
|
encoder->type = ENCODER_TYPE_CPU;
|
||||||
|
return encoder;
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
}
|
||||||
|
|
||||||
|
void encoder_destroy(struct encoder_t *encoder) {
|
||||||
|
# ifdef OMX_ENCODER
|
||||||
|
if (encoder->omx) {
|
||||||
|
omx_encoder_destroy(encoder->omx);
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
free(encoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
void encoder_prepare(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(encoder->omx, dev) < 0) {
|
||||||
|
goto use_fallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dev->run->n_workers > 1) {
|
||||||
|
LOG_INFO("OMX encoder can only work with one worker thread; forcing n_workers to 1");
|
||||||
|
dev->run->n_workers = 1;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
# pragma GCC diagnostic ignored "-Wunused-label"
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
use_fallback:
|
||||||
|
LOG_ERROR("Can't prepare selected encoder, falling back to CPU");
|
||||||
|
encoder->type = ENCODER_TYPE_CPU;
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
}
|
||||||
|
|
||||||
|
void encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, int index) {
|
||||||
|
# ifdef OMX_ENCODER
|
||||||
|
if (encoder->type == ENCODER_TYPE_OMX) {
|
||||||
|
if (omx_encoder_compress_buffer(encoder->omx, dev, index) < 0) {
|
||||||
|
LOG_INFO("OMX compressor error, falling back to CPU method");
|
||||||
|
encoder->type = ENCODER_TYPE_CPU;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
if (encoder->type == ENCODER_TYPE_CPU) {
|
||||||
|
jpeg_encoder_compress_buffer(dev, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/encoder.h
Normal file
53
src/encoder.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||||
|
# #
|
||||||
|
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||||
|
# #
|
||||||
|
# This program is free software: you can redistribute it and/or modify #
|
||||||
|
# it under the terms of the GNU General Public License as published by #
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or #
|
||||||
|
# (at your option) any later version. #
|
||||||
|
# #
|
||||||
|
# This program is distributed in the hope that it will be useful, #
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||||
|
# GNU General Public License for more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the GNU General Public License #
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||||
|
# #
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "tools.h"
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
#ifdef OMX_ENCODER
|
||||||
|
# include "omx/encoder.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
enum encoder_type_t {
|
||||||
|
ENCODER_TYPE_CPU,
|
||||||
|
|
||||||
|
#ifdef OMX_ENCODER
|
||||||
|
ENCODER_TYPE_OMX,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct encoder_t {
|
||||||
|
enum encoder_type_t type;
|
||||||
|
|
||||||
|
#ifdef OMX_ENCODER
|
||||||
|
struct omx_encoder_t *omx;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct encoder_t *encoder_init(enum encoder_type_t type);
|
||||||
|
void encoder_destroy(struct encoder_t *encoder);
|
||||||
|
|
||||||
|
void encoder_prepare(struct encoder_t *encoder, struct device_t *dev);
|
||||||
|
void encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, int index);
|
||||||
@@ -68,7 +68,7 @@ static boolean _jpeg_empty_output_buffer(j_compress_ptr jpeg);
|
|||||||
static void _jpeg_term_destination(j_compress_ptr jpeg);
|
static void _jpeg_term_destination(j_compress_ptr jpeg);
|
||||||
|
|
||||||
|
|
||||||
int jpeg_compress_buffer(struct device_t *dev, int index) {
|
void jpeg_encoder_compress_buffer(struct device_t *dev, int index) {
|
||||||
// This function based on compress_image_to_jpeg() from mjpg-streamer
|
// This function based on compress_image_to_jpeg() from mjpg-streamer
|
||||||
|
|
||||||
struct jpeg_compress_struct jpeg;
|
struct jpeg_compress_struct jpeg;
|
||||||
@@ -110,7 +110,6 @@ int jpeg_compress_buffer(struct device_t *dev, int index) {
|
|||||||
jpeg_destroy_compress(&jpeg);
|
jpeg_destroy_compress(&jpeg);
|
||||||
free(line_buffer);
|
free(line_buffer);
|
||||||
assert(dev->run->pictures[index].size > 0);
|
assert(dev->run->pictures[index].size > 0);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _jpeg_set_dest_picture(j_compress_ptr jpeg, unsigned char *picture, unsigned long *written) {
|
static void _jpeg_set_dest_picture(j_compress_ptr jpeg, unsigned char *picture, unsigned long *written) {
|
||||||
|
|||||||
@@ -27,4 +27,4 @@
|
|||||||
#include "../device.h"
|
#include "../device.h"
|
||||||
|
|
||||||
|
|
||||||
int jpeg_compress_buffer(struct device_t *dev, int index);
|
void jpeg_encoder_compress_buffer(struct device_t *dev, int index);
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
#include "encoder.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include "http.h"
|
#include "http.h"
|
||||||
|
|
||||||
@@ -218,6 +219,7 @@ static void _install_signal_handlers() {
|
|||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
struct device_t *dev;
|
struct device_t *dev;
|
||||||
|
struct encoder_t *encoder;
|
||||||
struct stream_t *stream;
|
struct stream_t *stream;
|
||||||
struct http_server_t *server;
|
struct http_server_t *server;
|
||||||
int exit_code = 0;
|
int exit_code = 0;
|
||||||
@@ -225,7 +227,8 @@ int main(int argc, char *argv[]) {
|
|||||||
LOGGING_INIT;
|
LOGGING_INIT;
|
||||||
|
|
||||||
dev = device_init();
|
dev = device_init();
|
||||||
stream = stream_init(dev);
|
encoder = encoder_init(ENCODER_TYPE_CPU);
|
||||||
|
stream = stream_init(dev, encoder);
|
||||||
server = http_server_init(stream);
|
server = http_server_init(stream);
|
||||||
|
|
||||||
if ((exit_code = _parse_options(argc, argv, dev, server)) == 0) {
|
if ((exit_code = _parse_options(argc, argv, dev, server)) == 0) {
|
||||||
@@ -249,6 +252,7 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
http_server_destroy(server);
|
http_server_destroy(server);
|
||||||
stream_destroy(stream);
|
stream_destroy(stream);
|
||||||
|
encoder_destroy(encoder);
|
||||||
device_destroy(dev);
|
device_destroy(dev);
|
||||||
|
|
||||||
LOGGING_DESTROY;
|
LOGGING_DESTROY;
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ int component_get_portdef(OMX_HANDLETYPE *component, OMX_PARAM_PORTDEFINITIONTYP
|
|||||||
int component_set_portdef(OMX_HANDLETYPE *component, OMX_PARAM_PORTDEFINITIONTYPE *portdef) {
|
int component_set_portdef(OMX_HANDLETYPE *component, OMX_PARAM_PORTDEFINITIONTYPE *portdef) {
|
||||||
OMX_ERRORTYPE error;
|
OMX_ERRORTYPE error;
|
||||||
|
|
||||||
LOG_DEBUG("Writing OMX port %u definition ...", port);
|
LOG_DEBUG("Writing OMX port %u definition ...", portdef->nPortIndex);
|
||||||
if ((error = OMX_SetParameter(*component, OMX_IndexParamPortDefinition, portdef)) != OMX_ErrorNone) {
|
if ((error = OMX_SetParameter(*component, OMX_IndexParamPortDefinition, portdef)) != OMX_ErrorNone) {
|
||||||
LOG_OMX_ERROR(error, "Can't set OMX port %u definition", portdef->nPortIndex);
|
LOG_OMX_ERROR(error, "Can't set OMX port %u definition", portdef->nPortIndex);
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ void omx_encoder_destroy(struct omx_encoder_t *omx) {
|
|||||||
free(omx);
|
free(omx);
|
||||||
}
|
}
|
||||||
|
|
||||||
int omx_encoder_set_device(struct omx_encoder_t *omx, struct device_t *dev) {
|
int omx_encoder_prepare(struct omx_encoder_t *omx, struct device_t *dev) {
|
||||||
if (component_set_state(&omx->encoder, OMX_StateIdle) < 0) {
|
if (component_set_state(&omx->encoder, OMX_StateIdle) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -132,13 +132,13 @@ int omx_encoder_set_device(struct omx_encoder_t *omx, struct device_t *dev) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void 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, int index) {
|
||||||
OMX_ERRORTYPE error;
|
OMX_ERRORTYPE error;
|
||||||
bool loaded = false;
|
bool loaded = false;
|
||||||
|
|
||||||
if ((error = OMX_FillThisBuffer(omx->encoder, omx->output_buffer)) != OMX_ErrorNone) {
|
if ((error = OMX_FillThisBuffer(omx->encoder, omx->output_buffer)) != OMX_ErrorNone) {
|
||||||
LOG_OMX_ERROR(error, "Failed to request filling of the output buffer on encoder");
|
LOG_OMX_ERROR(error, "Failed to request filling of the output buffer on encoder");
|
||||||
assert(0); // TODO
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->run->pictures[index].size = 0;
|
dev->run->pictures[index].size = 0;
|
||||||
@@ -146,7 +146,9 @@ void omx_encoder_compress_buffer(struct omx_encoder_t *omx, struct device_t *dev
|
|||||||
omx->input_required = true;
|
omx->input_required = true;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
assert(!omx->failed); // FIXME
|
if (omx->failed) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (omx->output_available) {
|
if (omx->output_available) {
|
||||||
omx->output_available = false;
|
omx->output_available = false;
|
||||||
@@ -165,7 +167,7 @@ void omx_encoder_compress_buffer(struct omx_encoder_t *omx, struct device_t *dev
|
|||||||
|
|
||||||
if ((error = OMX_FillThisBuffer(omx->encoder, omx->output_buffer)) != OMX_ErrorNone) {
|
if ((error = OMX_FillThisBuffer(omx->encoder, omx->output_buffer)) != OMX_ErrorNone) {
|
||||||
LOG_OMX_ERROR(error, "Failed to request filling of the output buffer on encoder");
|
LOG_OMX_ERROR(error, "Failed to request filling of the output buffer on encoder");
|
||||||
assert(0); // TODO
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,12 +184,13 @@ void omx_encoder_compress_buffer(struct omx_encoder_t *omx, struct device_t *dev
|
|||||||
|
|
||||||
if ((error = OMX_EmptyThisBuffer(omx->encoder, omx->input_buffer)) != OMX_ErrorNone) {
|
if ((error = OMX_EmptyThisBuffer(omx->encoder, omx->input_buffer)) != OMX_ErrorNone) {
|
||||||
LOG_OMX_ERROR(error, "Failed to request emptying of the input buffer on encoder");
|
LOG_OMX_ERROR(error, "Failed to request emptying of the input buffer on encoder");
|
||||||
assert(0); // TODO
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vcos_semaphore_wait(&omx->handler_lock);
|
vcos_semaphore_wait(&omx->handler_lock);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _omx_init_component(struct omx_encoder_t *omx) {
|
static int _omx_init_component(struct omx_encoder_t *omx) {
|
||||||
|
|||||||
@@ -28,5 +28,5 @@ struct omx_encoder_t {
|
|||||||
struct omx_encoder_t *omx_encoder_init();
|
struct omx_encoder_t *omx_encoder_init();
|
||||||
void omx_encoder_destroy(struct omx_encoder_t *omx);
|
void omx_encoder_destroy(struct omx_encoder_t *omx);
|
||||||
|
|
||||||
int omx_encoder_set_device(struct omx_encoder_t *omx, struct device_t *dev);
|
int omx_encoder_prepare(struct omx_encoder_t *omx, struct device_t *dev);
|
||||||
void 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, int index);
|
||||||
|
|||||||
26
src/stream.c
26
src/stream.c
@@ -32,6 +32,7 @@
|
|||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
#include "encoder.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
|
|
||||||
#include "jpeg/encoder.h"
|
#include "jpeg/encoder.h"
|
||||||
@@ -53,11 +54,12 @@ static int _stream_release_buffer(struct device_t *dev, struct v4l2_buffer *buf_
|
|||||||
static int _stream_handle_event(struct device_t *dev);
|
static int _stream_handle_event(struct device_t *dev);
|
||||||
|
|
||||||
|
|
||||||
struct stream_t *stream_init(struct device_t *dev) {
|
struct stream_t *stream_init(struct device_t *dev, struct encoder_t *encoder) {
|
||||||
struct stream_t *stream;
|
struct stream_t *stream;
|
||||||
|
|
||||||
A_CALLOC(stream, 1);
|
A_CALLOC(stream, 1);
|
||||||
stream->dev = dev;
|
stream->dev = dev;
|
||||||
|
stream->encoder = encoder;
|
||||||
A_PTHREAD_M_INIT(&stream->mutex);
|
A_PTHREAD_M_INIT(&stream->mutex);
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
@@ -72,6 +74,7 @@ void stream_loop(struct stream_t *stream) {
|
|||||||
bool workers_stop;
|
bool workers_stop;
|
||||||
|
|
||||||
MEMSET_ZERO(pool);
|
MEMSET_ZERO(pool);
|
||||||
|
pool.encoder = stream->encoder;
|
||||||
pool.workers_stop = &workers_stop;
|
pool.workers_stop = &workers_stop;
|
||||||
|
|
||||||
LOG_INFO("Using V4L2 device: %s", stream->dev->path);
|
LOG_INFO("Using V4L2 device: %s", stream->dev->path);
|
||||||
@@ -111,7 +114,7 @@ void stream_loop(struct stream_t *stream) {
|
|||||||
|
|
||||||
LOG_PERF("##### ACCEPT : %u", free_worker_number);
|
LOG_PERF("##### ACCEPT : %u", free_worker_number);
|
||||||
} else {
|
} else {
|
||||||
for (unsigned number = 0; number < stream->dev->n_workers; ++number) {
|
for (unsigned number = 0; number < stream->dev->run->n_workers; ++number) {
|
||||||
if (!pool.workers[number].has_job && (free_worker_number == -1
|
if (!pool.workers[number].has_job && (free_worker_number == -1
|
||||||
|| pool.workers[free_worker_number].job_start_time < pool.workers[number].job_start_time
|
|| pool.workers[free_worker_number].job_start_time < pool.workers[number].job_start_time
|
||||||
)) {
|
)) {
|
||||||
@@ -301,7 +304,7 @@ static void _stream_expose_picture(struct stream_t *stream, unsigned buf_index)
|
|||||||
static long double _stream_get_fluency_delay(struct device_t *dev, struct workers_pool_t *pool) {
|
static long double _stream_get_fluency_delay(struct device_t *dev, struct workers_pool_t *pool) {
|
||||||
long double delay = 0;
|
long double delay = 0;
|
||||||
|
|
||||||
for (unsigned number = 0; number < dev->n_workers; ++number) {
|
for (unsigned number = 0; number < dev->run->n_workers; ++number) {
|
||||||
A_PTHREAD_M_LOCK(&pool->workers[number].last_comp_time_mutex);
|
A_PTHREAD_M_LOCK(&pool->workers[number].last_comp_time_mutex);
|
||||||
if (pool->workers[number].last_comp_time > 0) {
|
if (pool->workers[number].last_comp_time > 0) {
|
||||||
delay += pool->workers[number].last_comp_time;
|
delay += pool->workers[number].last_comp_time;
|
||||||
@@ -309,7 +312,7 @@ static long double _stream_get_fluency_delay(struct device_t *dev, struct worker
|
|||||||
A_PTHREAD_M_UNLOCK(&pool->workers[number].last_comp_time_mutex);
|
A_PTHREAD_M_UNLOCK(&pool->workers[number].last_comp_time_mutex);
|
||||||
}
|
}
|
||||||
// Среднее арифметическое деленное на количество воркеров
|
// Среднее арифметическое деленное на количество воркеров
|
||||||
return delay / dev->n_workers / dev->n_workers;
|
return delay / dev->run->n_workers / dev->run->n_workers;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _stream_init_loop(struct device_t *dev, struct workers_pool_t *pool) {
|
static int _stream_init_loop(struct device_t *dev, struct workers_pool_t *pool) {
|
||||||
@@ -340,6 +343,9 @@ static int _stream_init(struct device_t *dev, struct workers_pool_t *pool) {
|
|||||||
if (_stream_control(dev, true) < 0) {
|
if (_stream_control(dev, true) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
encoder_prepare(pool->encoder, dev);
|
||||||
|
|
||||||
_stream_init_workers(dev, pool);
|
_stream_init_workers(dev, pool);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -350,15 +356,15 @@ static int _stream_init(struct device_t *dev, struct workers_pool_t *pool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void _stream_init_workers(struct device_t *dev, struct workers_pool_t *pool) {
|
static void _stream_init_workers(struct device_t *dev, struct workers_pool_t *pool) {
|
||||||
LOG_INFO("Spawning %d workers ...", dev->n_workers);
|
LOG_INFO("Spawning %d workers ...", dev->run->n_workers);
|
||||||
|
|
||||||
*pool->workers_stop = false;
|
*pool->workers_stop = false;
|
||||||
A_CALLOC(pool->workers, dev->n_workers);
|
A_CALLOC(pool->workers, dev->run->n_workers);
|
||||||
|
|
||||||
A_PTHREAD_M_INIT(&pool->free_workers_mutex);
|
A_PTHREAD_M_INIT(&pool->free_workers_mutex);
|
||||||
A_PTHREAD_C_INIT(&pool->free_workers_cond);
|
A_PTHREAD_C_INIT(&pool->free_workers_cond);
|
||||||
|
|
||||||
for (unsigned number = 0; number < dev->n_workers; ++number) {
|
for (unsigned number = 0; number < dev->run->n_workers; ++number) {
|
||||||
pool->free_workers += 1;
|
pool->free_workers += 1;
|
||||||
|
|
||||||
A_PTHREAD_M_INIT(&pool->workers[number].has_job_mutex);
|
A_PTHREAD_M_INIT(&pool->workers[number].has_job_mutex);
|
||||||
@@ -369,6 +375,8 @@ static void _stream_init_workers(struct device_t *dev, struct workers_pool_t *po
|
|||||||
pool->workers[number].ctx.dev_stop = (sig_atomic_t *volatile)&dev->stop;
|
pool->workers[number].ctx.dev_stop = (sig_atomic_t *volatile)&dev->stop;
|
||||||
pool->workers[number].ctx.workers_stop = pool->workers_stop;
|
pool->workers[number].ctx.workers_stop = pool->workers_stop;
|
||||||
|
|
||||||
|
pool->workers[number].ctx.encoder = pool->encoder;
|
||||||
|
|
||||||
pool->workers[number].ctx.last_comp_time_mutex = &pool->workers[number].last_comp_time_mutex;
|
pool->workers[number].ctx.last_comp_time_mutex = &pool->workers[number].last_comp_time_mutex;
|
||||||
pool->workers[number].ctx.last_comp_time = &pool->workers[number].last_comp_time;
|
pool->workers[number].ctx.last_comp_time = &pool->workers[number].last_comp_time;
|
||||||
|
|
||||||
@@ -405,7 +413,7 @@ static void *_stream_worker_thread(void *v_ctx) {
|
|||||||
|
|
||||||
LOG_DEBUG("Worker %u compressing JPEG from buffer %d ...", ctx->number, ctx->buf_index);
|
LOG_DEBUG("Worker %u compressing JPEG from buffer %d ...", ctx->number, ctx->buf_index);
|
||||||
|
|
||||||
jpeg_compress_buffer(ctx->dev, ctx->buf_index);
|
encoder_compress_buffer(ctx->encoder, ctx->dev, ctx->buf_index);
|
||||||
|
|
||||||
if (_stream_release_buffer(ctx->dev, &ctx->buf_info) == 0) {
|
if (_stream_release_buffer(ctx->dev, &ctx->buf_info) == 0) {
|
||||||
*ctx->job_start_time = start_time;
|
*ctx->job_start_time = start_time;
|
||||||
@@ -442,7 +450,7 @@ static void _stream_destroy_workers(struct device_t *dev, struct workers_pool_t
|
|||||||
LOG_INFO("Destroying workers ...");
|
LOG_INFO("Destroying workers ...");
|
||||||
|
|
||||||
*pool->workers_stop = true;
|
*pool->workers_stop = true;
|
||||||
for (unsigned number = 0; number < dev->n_workers; ++number) {
|
for (unsigned number = 0; number < dev->run->n_workers; ++number) {
|
||||||
A_PTHREAD_M_LOCK(&pool->workers[number].has_job_mutex);
|
A_PTHREAD_M_LOCK(&pool->workers[number].has_job_mutex);
|
||||||
pool->workers[number].has_job = true; // Final job: die
|
pool->workers[number].has_job = true; // Final job: die
|
||||||
A_PTHREAD_M_UNLOCK(&pool->workers[number].has_job_mutex);
|
A_PTHREAD_M_UNLOCK(&pool->workers[number].has_job_mutex);
|
||||||
|
|||||||
18
src/stream.h
18
src/stream.h
@@ -27,6 +27,7 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
#include "encoder.h"
|
||||||
|
|
||||||
|
|
||||||
struct worker_context_t {
|
struct worker_context_t {
|
||||||
@@ -37,6 +38,8 @@ struct worker_context_t {
|
|||||||
sig_atomic_t *volatile dev_stop;
|
sig_atomic_t *volatile dev_stop;
|
||||||
bool *workers_stop;
|
bool *workers_stop;
|
||||||
|
|
||||||
|
struct encoder_t *encoder;
|
||||||
|
|
||||||
pthread_mutex_t *last_comp_time_mutex;
|
pthread_mutex_t *last_comp_time_mutex;
|
||||||
long double *last_comp_time;
|
long double *last_comp_time;
|
||||||
|
|
||||||
@@ -69,12 +72,14 @@ struct worker_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct workers_pool_t {
|
struct workers_pool_t {
|
||||||
struct worker_t *workers;
|
struct worker_t*workers;
|
||||||
bool *workers_stop;
|
bool *workers_stop;
|
||||||
|
|
||||||
pthread_mutex_t free_workers_mutex;
|
pthread_mutex_t free_workers_mutex;
|
||||||
unsigned free_workers;
|
unsigned free_workers;
|
||||||
pthread_cond_t free_workers_cond;
|
pthread_cond_t free_workers_cond;
|
||||||
|
|
||||||
|
struct encoder_t *encoder;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct stream_t {
|
struct stream_t {
|
||||||
@@ -84,10 +89,11 @@ struct stream_t {
|
|||||||
bool updated;
|
bool updated;
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
struct device_t *dev;
|
struct device_t *dev;
|
||||||
|
struct encoder_t *encoder;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct stream_t *stream_init(struct device_t *dev);
|
struct stream_t *stream_init(struct device_t *dev, struct encoder_t *encoder);
|
||||||
void stream_destroy(struct stream_t *stream);
|
void stream_destroy(struct stream_t *stream);
|
||||||
|
|
||||||
void stream_loop(struct stream_t *stream);
|
void stream_loop(struct stream_t *stream);
|
||||||
|
|||||||
Reference in New Issue
Block a user