summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Auras <yak54@gmx.net>2010-03-06 21:24:22 +0100
committerAndreas Auras <yak54@gmx.net>2010-03-06 21:24:22 +0100
commit05bef2bf40becc5b48713dc088c0bd939d2a84ae (patch)
tree4916615c1ed036e286f7c2005ab22e8927cd5bbc
parentd672cfc08fbf99f94c5b19d6fd875590f581de67 (diff)
downloadxine-lib-atmolight-05bef2bf40becc5b48713dc088c0bd939d2a84ae.tar.gz
xine-lib-atmolight-05bef2bf40becc5b48713dc088c0bd939d2a84ae.tar.bz2
Improved calculation of weights for border area
Improved calculation of average brightness Add support for DF10CH config version 2 (overscan, edge weighting, analyze size are now read from controller) Improved DF10CH driver error logging Added 'hue_threshold' parameter. Modify 'edge weighting' parameter. Value is now divided by 10 to reach more fine control Changed darkness limit default from 10 to 1
-rw-r--r--HISTORY10
-rw-r--r--Makefile2
-rw-r--r--README25
-rw-r--r--output_driver.h324
-rw-r--r--xine_post_atmo.c365
5 files changed, 428 insertions, 298 deletions
diff --git a/HISTORY b/HISTORY
index 4cd4c05..741289e 100644
--- a/HISTORY
+++ b/HISTORY
@@ -5,8 +5,14 @@ Added support for "on the fly" parameter changes.
Added 'start_delay' plugin parameter for individual adjustment of start delay after start of new stream.
Changed start delay default from 1000ms to 250ms
Added 'enable' plugin parameter for switching the atmolight on/off on the fly.
-DF10CH channel layout configuration parameters are now mandatory.
-Changed calculation of weights for border area
+DF10CH configuration parameters are now mandatory.
+Improved calculation of weights for border area
+Improved calculation of average brightness
+Add support for DF10CH config version 2 (overscan, edge weighting, analyze size are now read from controller)
+Improved DF10CH driver error logging
+Added 'hue_threshold' parameter.
+Modify 'edge weighting' parameter. Value is now divided by 10 to reach more fine control
+Changed darkness limit default from 10 to 1
--- Version 0.4
diff --git a/Makefile b/Makefile
index 44db1ba..e878305 100644
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@ install: all
clean:
@-rm -f *.so* *.o
-xine_post_atmo.o: xine_post_atmo.c output_driver.h
+xine_post_atmo.o: xine_post_atmo.c output_driver.h df10ch_usb_proto.h
$(CC) $(CFLAGS) $(CFLAGS_XINE) $(CFLAGS_USB) -c -o $@ $<
$(XINEPOSTATMO): xine_post_atmo.o
diff --git a/README b/README
index ba11683..65a4fc5 100644
--- a/README
+++ b/README
@@ -131,20 +131,37 @@ analyze_size 1 Size of analyze window. The window width is
analyze window.
Valid values: 0 ... 3
+ For DF10CH controller you do not have to specify this parameter here because it is read
+ from the controller configuration data. Use the DF10CH setup program to configure your
+ desired analyze size.
+
overscan 30 Ignored overscan border of grabbed video frame.
Unit is percentage of 1000. e.g. 30 -> 3%
Valid values: 0 ... 200
-darkness_limit 10 Minimum brightness of pixel. Value's below are interpreted as black pixel.
+ For DF10CH controller you do not have to specify this parameter here because it is read
+ from the controller configuration data. Use the DF10CH setup program to configure your
+ desired overscan.
+
+edge_weighting 80 Power of edge weighting.
+ Value is divided by 10 e.g. 80 -> power of 8
+ Valid values 10 ... 200
+
+ For DF10CH controller you do not have to specify this parameter here because it is read
+ from the controller configuration data. Use the DF10CH setup program to configure your
+ desired edge weighting.
+
+darkness_limit 1 Minimum brightness of pixel. Value's below are interpreted as black pixel.
Used to detect and skip "black borders" in video.
Valid values are 0 ... 100
-edge_weighting 8 Power of edge weighting. Valid values 1 ... 30
-
hue_win_size 3 Windowing size for HUE. Valid values 0 ... 5
sat_win_size 3 Windowing size for saturation. Valid values 0 ... 5
+hue_treshold 93 Threshold limit for change of color.
+ Unit percentage of 100. Valid values 1 ... 100
+
filter combined Select's smoothness filter. Currently there are two filters
supported: percentage and combined.
Valid values: off, percentage, combined
@@ -185,5 +202,5 @@ gamma 0 Gamma correction factor for red, green and b
start_delay 250 Delay after stream start before first output is send [ms].
Valid values 0 ... 5000.
-enable 1 Enable/Disable output of color values to atmolight controller
+enable 1 Enable/Disable output of color values to atmolight controller.
\ No newline at end of file
diff --git a/output_driver.h b/output_driver.h
index e050e6f..2885858 100644
--- a/output_driver.h
+++ b/output_driver.h
@@ -22,13 +22,6 @@
#include <termios.h>
#include <regex.h>
#include <fcntl.h>
-#include <math.h>
-
-#define NUM_AREAS 9 /* Number of different areas (top, bottom ...) */
-
-typedef struct { int sum, top, bottom, left, right, center, top_left, top_right, bottom_left, bottom_right; } num_channels_t;
-
-extern long int lround(double); /* Missing in math.h? */
/*
@@ -37,13 +30,13 @@ extern long int lround(double); /* Missing in math.h? */
typedef struct output_driver_s output_driver_t;
struct output_driver_s {
/* open device and configure for number of channels */
- int (*open)(output_driver_t *this, const char *param, num_channels_t *channels);
+ int (*open)(output_driver_t *this, atmo_parameters_t *param);
/* configure device for number of channels */
- int (*configure)(output_driver_t *this, num_channels_t *channels);
+ int (*configure)(output_driver_t *this, atmo_parameters_t *param);
/* close device */
- void (*close)(output_driver_t *this);
+ int (*close)(output_driver_t *this);
/*
* send RGB color values to device
@@ -64,20 +57,20 @@ struct output_driver_s {
typedef struct {
output_driver_t output_driver;
- num_channels_t num_channels;
+ atmo_parameters_t param;
FILE *fd;
int id;
} file_output_driver_t;
-static int file_driver_open(output_driver_t *this_gen, const char *param, num_channels_t *n) {
+static int file_driver_open(output_driver_t *this_gen, atmo_parameters_t *p) {
file_output_driver_t *this = (file_output_driver_t *) this_gen;
- this->num_channels = *n;
+ this->param = *p;
this->id = 0;
- if (param && strlen(param))
- this->fd = fopen(param, "a");
+ if (this->param.driver_param && strlen(this->param.driver_param))
+ this->fd = fopen(this->param.driver_param, "a");
else
this->fd = fopen("xine_atmo_data.out", "a");
@@ -88,19 +81,20 @@ static int file_driver_open(output_driver_t *this_gen, const char *param, num_ch
return 0;
}
-static int file_driver_configure(output_driver_t *this_gen, num_channels_t *n) {
+static int file_driver_configure(output_driver_t *this_gen, atmo_parameters_t *p) {
file_output_driver_t *this = (file_output_driver_t *) this_gen;
- this->num_channels = *n;
+ this->param = *p;
return 0;
}
-static void file_driver_close(output_driver_t *this_gen) {
+static int file_driver_close(output_driver_t *this_gen) {
file_output_driver_t *this = (file_output_driver_t *) this_gen;
if (this->fd) {
fclose(this->fd);
this->fd = NULL;
}
+ return 0;
}
@@ -114,35 +108,35 @@ static void file_driver_output_colors(output_driver_t *this_gen, rgb_color_t *co
gettimeofday(&tvnow, NULL);
fprintf(fd, "%d: %ld.%03ld ---\n", this->id++, tvnow.tv_sec, tvnow.tv_usec / 1000);
- for (c = 1; c <= this->num_channels.top; ++c, ++colors)
+ for (c = 1; c <= this->param.top; ++c, ++colors)
fprintf(fd," top %2d: %3d %3d %3d\n", c, colors->r, colors->g, colors->b);
- for (c = 1; c <= this->num_channels.bottom; ++c, ++colors)
+ for (c = 1; c <= this->param.bottom; ++c, ++colors)
fprintf(fd," bottom %2d: %3d %3d %3d\n", c, colors->r, colors->g, colors->b);
- for (c = 1; c <= this->num_channels.left; ++c, ++colors)
+ for (c = 1; c <= this->param.left; ++c, ++colors)
fprintf(fd," left %2d: %3d %3d %3d\n", c, colors->r, colors->g, colors->b);
- for (c = 1; c <= this->num_channels.right; ++c, ++colors)
+ for (c = 1; c <= this->param.right; ++c, ++colors)
fprintf(fd," right %2d: %3d %3d %3d\n", c, colors->r, colors->g, colors->b);
- if (this->num_channels.center) {
+ if (this->param.center) {
fprintf(fd," center: %3d %3d %3d\n", colors->r, colors->g, colors->b);
++colors;
}
- if (this->num_channels.top_left) {
+ if (this->param.top_left) {
fprintf(fd," top left: %3d %3d %3d\n", colors->r, colors->g, colors->b);
++colors;
}
- if (this->num_channels.top_right) {
+ if (this->param.top_right) {
fprintf(fd," top right: %3d %3d %3d\n", colors->r, colors->g, colors->b);
++colors;
}
- if (this->num_channels.bottom_left) {
+ if (this->param.bottom_left) {
fprintf(fd," bottom left: %3d %3d %3d\n", colors->r, colors->g, colors->b);
++colors;
}
- if (this->num_channels.bottom_right) {
+ if (this->param.bottom_right) {
fprintf(fd," bottom right: %3d %3d %3d\n", colors->r, colors->g, colors->b);
}
fflush(fd);
@@ -157,33 +151,33 @@ static void file_driver_output_colors(output_driver_t *this_gen, rgb_color_t *co
typedef struct {
output_driver_t output_driver;
- num_channels_t num_channels;
+ atmo_parameters_t param;
int devfd;
} serial_output_driver_t;
-static int serial_driver_open(output_driver_t *this_gen, const char *param, num_channels_t *n) {
+static int serial_driver_open(output_driver_t *this_gen, atmo_parameters_t *p) {
serial_output_driver_t *this = (serial_output_driver_t *) this_gen;
char buf[256], buf1[64], *s;
const char *devname = NULL;
regex_t preg;
int rc;
- this->num_channels = *n;
+ this->param = *p;
this->devfd = -1;
- if (!param || !strlen(param))
+ if (!this->param.driver_param || !strlen(this->param.driver_param))
{
strcpy(this->output_driver.errmsg, "no device parameter");
return -1;
}
- if (strncmp(param, "usb:", 4) == 0) {
+ if (strncmp(this->param.driver_param, "usb:", 4) == 0) {
/* Lookup serial USB device name */
- rc = regcomp(&preg, param + 4, REG_EXTENDED | REG_NOSUB);
+ rc = regcomp(&preg, this->param.driver_param + 4, REG_EXTENDED | REG_NOSUB);
if (rc) {
regerror(rc, &preg, buf, sizeof(buf));
- snprintf(this->output_driver.errmsg, sizeof(this->output_driver.errmsg), "illegal device identification pattern '%s': %s", param + 4, buf);
+ snprintf(this->output_driver.errmsg, sizeof(this->output_driver.errmsg), "illegal device identification pattern '%s': %s", this->param.driver_param + 4, buf);
regfree(&preg);
return -1;
}
@@ -210,9 +204,9 @@ static int serial_driver_open(output_driver_t *this_gen, const char *param, num_
strcpy(this->output_driver.errmsg, "could not find usb device in /proc/tty/driver/usbserial");
return -1;
}
- llprintf(LOG_1, "USB tty device for '%s' is '%s'\n", param + 4, devname);
+ llprintf(LOG_1, "USB tty device for '%s' is '%s'\n", this->param.driver_param + 4, devname);
} else {
- devname = param;
+ devname = this->param.driver_param;
}
/* open serial port */
@@ -245,21 +239,21 @@ static int serial_driver_open(output_driver_t *this_gen, const char *param, num_
}
-static int serial_driver_configure(output_driver_t *this_gen, num_channels_t *n) {
+static int serial_driver_configure(output_driver_t *this_gen, atmo_parameters_t *p) {
serial_output_driver_t *this = (serial_output_driver_t *) this_gen;
- this->num_channels = *n;
+ this->param = *p;
return 0;
}
-static void serial_driver_close(output_driver_t *this_gen) {
+static int serial_driver_close(output_driver_t *this_gen) {
serial_output_driver_t *this = (serial_output_driver_t *) this_gen;
- if (this->devfd < 0)
- return;
-
- close(this->devfd);
- this->devfd = -1;
+ if (this->devfd >= 0) {
+ close(this->devfd);
+ this->devfd = -1;
+ }
+ return 0;
}
@@ -282,43 +276,43 @@ static void classic_driver_output_colors(output_driver_t *this_gen, rgb_color_t
msg[3] = 15; /* number of channels (5 * RGB) */
/* top channel */
- if (this->num_channels.top)
+ if (this->param.top)
{
msg[13] = colors->r;
msg[14] = colors->g;
msg[15] = colors->b;
- colors += this->num_channels.top;
+ colors += this->param.top;
}
/* bottom channel */
- if (this->num_channels.bottom)
+ if (this->param.bottom)
{
msg[16] = colors->r;
msg[17] = colors->g;
msg[18] = colors->b;
- colors += this->num_channels.bottom;
+ colors += this->param.bottom;
}
/* left channel */
- if (this->num_channels.left)
+ if (this->param.left)
{
msg[7] = colors->r;
msg[8] = colors->g;
msg[9] = colors->b;
- colors += this->num_channels.left;
+ colors += this->param.left;
}
/* right channel */
- if (this->num_channels.right)
+ if (this->param.right)
{
msg[10] = colors->r;
msg[11] = colors->g;
msg[12] = colors->b;
- colors += this->num_channels.right;
+ colors += this->param.right;
}
/* center channel */
- if (this->num_channels.center)
+ if (this->param.center)
{
msg[4] = colors->r;
msg[5] = colors->g;
@@ -350,34 +344,34 @@ static void df4ch_driver_output_colors(output_driver_t *this_gen, rgb_color_t *c
msg[2] = 12; /* number of channels (4 * RGB) */
/* top channel */
- if (this->num_channels.top)
+ if (this->param.top)
{
msg[9] = colors->r;
msg[10] = colors->g;
msg[11] = colors->b;
- colors += this->num_channels.top;
+ colors += this->param.top;
}
/* bottom channel */
- if (this->num_channels.bottom)
+ if (this->param.bottom)
{
msg[12] = colors->r;
msg[13] = colors->g;
msg[14] = colors->b;
- colors += this->num_channels.bottom;
+ colors += this->param.bottom;
}
/* left channel */
- if (this->num_channels.left)
+ if (this->param.left)
{
msg[3] = colors->r;
msg[4] = colors->g;
msg[5] = colors->b;
- colors += this->num_channels.left;
+ colors += this->param.left;
}
/* right channel */
- if (this->num_channels.right)
+ if (this->param.right)
{
msg[6] = colors->r;
msg[7] = colors->g;
@@ -406,7 +400,7 @@ static void df4ch_driver_output_colors(output_driver_t *this_gen, rgb_color_t *c
#define DF10CH_USB_DEFAULT_TIMEOUT 100
#define DF10CH_MAX_CHANNELS 30
-#define DF10CH_SIZE_CONFIG (14 + DF10CH_MAX_CHANNELS * 6)
+#define DF10CH_SIZE_CONFIG (17 + DF10CH_MAX_CHANNELS * 6)
#define DF10CH_CONFIG_VALID_ID 0xA0A1
enum { DF10CH_AREA_TOP, DF10CH_AREA_BOTTOM, DF10CH_AREA_LEFT, DF10CH_AREA_RIGHT, DF10CH_AREA_CENTER, DF10CH_AREA_TOP_LEFT, DF10CH_AREA_TOP_RIGHT, DF10CH_AREA_BOTTOM_LEFT, DF10CH_AREA_BOTTOM_RIGHT };
@@ -426,29 +420,35 @@ typedef struct {
df10ch_gamma_tab_t *gamma_tab; // Corresponding gamma table
} df10ch_channel_config_t;
+typedef struct df10ch_output_driver_s df10ch_output_driver_t;
+
typedef struct df10ch_ctrl_s {
struct df10ch_ctrl_s *next;
+ df10ch_output_driver_t *driver;
libusb_device_handle *dev;
- int idx_serial_number;
+ int idx_serial_number; // USB string index of serial number
uint16_t config_version; // Version number of configuration data
uint16_t pwm_res; // PWM resolution
int num_req_channels; // Number of channels in request
df10ch_channel_config_t *channel_config; // List of channel configurations
char id[32]; // ID of Controller
- struct libusb_transfer *transfer;
- uint8_t *transfer_data;
- int pending_submit;
+ struct libusb_transfer *transfer; // Prepared set brightness request for asynchrony submitting
+ uint8_t *transfer_data; // Data of set brightness request
+ int pending_submit; // Is true if a asynchrony transfer is pending
+ int transfer_error;
} df10ch_ctrl_t;
-typedef struct {
+struct df10ch_output_driver_s {
output_driver_t output_driver;
libusb_context *ctx;
- num_channels_t num_channels; // Global channel layout
- df10ch_ctrl_t *ctrls; // List of found controllers
- df10ch_gamma_tab_t *gamma_tabs; // List of calculated gamma tables
+ atmo_parameters_t param; // Global channel layout
+ df10ch_ctrl_t *ctrls; // List of found controllers
+ df10ch_gamma_tab_t *gamma_tabs; // List of calculated gamma tables
+ uint16_t config_version; // (Maximum) Version number of configuration data
int max_transmit_latency;
int avg_transmit_latency;
-} df10ch_output_driver_t;
+ int transfer_err_cnt; // Number of transfer errors
+};
static const char *df10ch_usb_errmsg(int rc) {
@@ -507,6 +507,30 @@ static const char * df10ch_usb_transfer_errmsg(int s) {
}
+static void df10ch_comm_errmsg(int stat, char *rc) {
+ if (stat == 0)
+ strcpy(rc, "OK");
+ else
+ *rc = 0;
+ if (stat & (1<<COMM_ERR_OVERRUN))
+ strcat(rc, " OVERRUN");
+ if (stat & (1<<COMM_ERR_FRAME))
+ strcat(rc, " FRAME");
+ if (stat & (1<<COMM_ERR_TIMEOUT))
+ strcat(rc, " TIMEOUT");
+ if (stat & (1<<COMM_ERR_START))
+ strcat(rc, " START");
+ if (stat & (1<<COMM_ERR_OVERFLOW))
+ strcat(rc, " OVERFLOW");
+ if (stat & (1<<COMM_ERR_CRC))
+ strcat(rc, " CRC");
+ if (stat & (1<<COMM_ERR_DUPLICATE))
+ strcat(rc, " DUPLICATE");
+ if (stat & (1<<COMM_ERR_DEBUG))
+ strcat(rc, " DEBUG");
+}
+
+
static int df10ch_control_in_transfer(df10ch_ctrl_t *ctrl, uint8_t req, uint16_t val, uint16_t index, unsigned int timeout, uint8_t *buf, uint16_t buflen)
{
// Use a return buffer always so that the controller is able to send a USB reply status
@@ -526,9 +550,12 @@ static int df10ch_control_in_transfer(df10ch_ctrl_t *ctrl, uint8_t req, uint16_t
n = libusb_control_transfer(ctrl->dev, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, req, val, index, buf, len, timeout);
if (n != LIBUSB_ERROR_INTERRUPTED)
{
+ if (n < 0)
+ ++ctrl->driver->transfer_err_cnt;
if (n >= 0 || n != LIBUSB_ERROR_PIPE)
break;
++retrys;
+ llprintf(LOG_1, "%s: sending USB control transfer message %d failed (pipe error): retry %d\n", ctrl->id, req, retrys);
}
}
@@ -595,20 +622,46 @@ static void df10ch_wait_for_replys(df10ch_output_driver_t *this) {
else
ctrl = ctrl->next;
}
+
+ ctrl = this->ctrls;
+ while (ctrl) {
+ if (ctrl->transfer_error) {
+ char reply_errmsg[128], request_errmsg[128];
+ uint8_t data[1];
+ if (df10ch_control_in_transfer(ctrl, REQ_GET_REPLY_ERR_STATUS, 0, 0, DF10CH_USB_DEFAULT_TIMEOUT, data, 1))
+ strcpy(reply_errmsg, "N/A");
+ else
+ df10ch_comm_errmsg(data[0], reply_errmsg);
+ if (df10ch_control_in_transfer(ctrl, PWM_REQ_GET_REQUEST_ERR_STATUS, 0, 0, DF10CH_USB_DEFAULT_TIMEOUT, data, 1))
+ strcpy(request_errmsg, "N/A");
+ else
+ df10ch_comm_errmsg(data[0], request_errmsg);
+ llprintf(LOG_1, "%s: comm error USB: %s, PWM: %s\n", ctrl->id, reply_errmsg, request_errmsg);
+ }
+ ctrl = ctrl->next;
+ }
}
static void df10ch_reply_cb(struct libusb_transfer *transfer) {
df10ch_ctrl_t *ctrl = (df10ch_ctrl_t *) transfer->user_data;
ctrl->pending_submit = 0;
- if (transfer->status != LIBUSB_TRANSFER_COMPLETED && transfer->status != LIBUSB_TRANSFER_CANCELLED)
+ if (transfer->status != LIBUSB_TRANSFER_COMPLETED && transfer->status != LIBUSB_TRANSFER_CANCELLED) {
+ ++ctrl->driver->transfer_err_cnt;
+ ctrl->transfer_error = 1;
llprintf(LOG_1, "%s: submitting USB control transfer message failed: %s\n", ctrl->id, df10ch_usb_transfer_errmsg(transfer->status));
+ }
}
-static int df10ch_driver_open(output_driver_t *this_gen, const char *param, num_channels_t *num_channels) {
+static int df10ch_driver_open(output_driver_t *this_gen, atmo_parameters_t *param) {
df10ch_output_driver_t *this = (df10ch_output_driver_t *) this_gen;
+ this->config_version = 0;
+ this->max_transmit_latency = 0;
+ this->avg_transmit_latency = 0;
+ this->transfer_err_cnt = 0;
+
if (libusb_init(&this->ctx) < 0) {
strcpy(this->output_driver.errmsg, "can't initialize USB library");
return -1;
@@ -664,6 +717,7 @@ static int df10ch_driver_open(output_driver_t *this_gen, const char *param, num_
df10ch_ctrl_t *ctrl = (df10ch_ctrl_t *) calloc(1, sizeof(df10ch_ctrl_t));
ctrl->next = this->ctrls;
this->ctrls = ctrl;
+ ctrl->driver = this;
ctrl->dev = hdl;
ctrl->idx_serial_number = desc.iSerialNumber;
strcpy(ctrl->id, id);
@@ -687,7 +741,15 @@ static int df10ch_driver_open(output_driver_t *this_gen, const char *param, num_
}
// Ignore channel configuration defined by plugin parameters
- memset(num_channels, 0, sizeof(num_channels_t));
+ param->top = 0;
+ param->bottom = 0;
+ param->left = 0;
+ param->right = 0;
+ param->center = 0;
+ param->top_left = 0;
+ param->top_right = 0;
+ param->bottom_left = 0;
+ param->bottom_right = 0;
// Read controller configuration
df10ch_ctrl_t *ctrl = this->ctrls;
@@ -737,42 +799,51 @@ static int df10ch_driver_open(output_driver_t *this_gen, const char *param, num_
}
ctrl->config_version = eedata[2] + (eedata[3] << 8);
+ if (ctrl->config_version > this->config_version)
+ this->config_version = ctrl->config_version;
// Determine channel layout
int n;
n = eedata[4 + DF10CH_AREA_TOP];
- if (n > num_channels->top)
- num_channels->top = n;
+ if (n > param->top)
+ param->top = n;
n = eedata[4 + DF10CH_AREA_BOTTOM];
- if (n > num_channels->bottom)
- num_channels->bottom = n;
+ if (n > param->bottom)
+ param->bottom = n;
n = eedata[4 + DF10CH_AREA_LEFT];
- if (n > num_channels->left)
- num_channels->left = n;
+ if (n > param->left)
+ param->left = n;
n = eedata[4 + DF10CH_AREA_RIGHT];
- if (n > num_channels->right)
- num_channels->right = n;
+ if (n > param->right)
+ param->right = n;
n = eedata[4 + DF10CH_AREA_CENTER];
- if (n > num_channels->center)
- num_channels->center = n;
+ if (n > param->center)
+ param->center = n;
n = eedata[4 + DF10CH_AREA_TOP_LEFT];
- if (n > num_channels->top_left)
- num_channels->top_left = n;
+ if (n > param->top_left)
+ param->top_left = n;
n = eedata[4 + DF10CH_AREA_TOP_RIGHT];
- if (n > num_channels->top_right)
- num_channels->top_right = n;
+ if (n > param->top_right)
+ param->top_right = n;
n = eedata[4 + DF10CH_AREA_BOTTOM_LEFT];
- if (n > num_channels->bottom_left)
- num_channels->bottom_left = n;
+ if (n > param->bottom_left)
+ param->bottom_left = n;
n = eedata[4 + DF10CH_AREA_BOTTOM_RIGHT];
- if (n > num_channels->bottom_right)
- num_channels->bottom_right = n;
+ if (n > param->bottom_right)
+ param->bottom_right = n;
ctrl->num_req_channels = eedata[13];
if (ctrl->num_req_channels > DF10CH_MAX_CHANNELS)
ctrl->num_req_channels = DF10CH_MAX_CHANNELS;
- // Read PWM resolution
+ if (ctrl->config_version > 1) {
+ int eei = 14 + ctrl->num_req_channels * 6;
+ param->overscan = eedata[eei];
+ param->analyze_size = eedata[eei + 1];
+ param->edge_weighting = eedata[eei + 2];
+ }
+
+ // Read PWM resolution
if (df10ch_control_in_transfer(ctrl, PWM_REQ_GET_MAX_PWM, 0, 0, DF10CH_USB_DEFAULT_TIMEOUT, data, 2)) {
snprintf(this->output_driver.errmsg, sizeof(this->output_driver.errmsg), "%s: reading PWM resolution data fails!", ctrl->id);
df10ch_dispose(this);
@@ -806,11 +877,11 @@ static int df10ch_driver_open(output_driver_t *this_gen, const char *param, num_
this->gamma_tabs = gt;
gt->gamma = gamma;
gt->white_cal = white_cal;
- double dgamma = gamma / 10.0;
- double dwhite_cal = white_cal;
+ const double dgamma = gamma / 10.0;
+ const double dwhite_cal = white_cal;
int v;
for (v = 0; v < 256; ++v) {
- gt->tab[v] = (uint16_t) (lround(pow((v / 255.0), dgamma) * dwhite_cal));
+ gt->tab[v] = (uint16_t) (lround(pow(((double)v / 255.0), dgamma) * dwhite_cal));
if (gt->tab[v] > ctrl->pwm_res)
gt->tab[v] = ctrl->pwm_res;
}
@@ -832,37 +903,39 @@ static int df10ch_driver_open(output_driver_t *this_gen, const char *param, num_
ctrl = ctrl->next;
}
- this->num_channels = *num_channels;
- this->max_transmit_latency = 0;
- this->avg_transmit_latency = 0;
+ this->param = *param;
return 0;
}
-static int df10ch_driver_configure(output_driver_t *this_gen, num_channels_t *num_channels) {
+static int df10ch_driver_configure(output_driver_t *this_gen, atmo_parameters_t *param) {
df10ch_output_driver_t *this = (df10ch_output_driver_t *) this_gen;
// Ignore channel configuration defined by plugin parameters
- num_channels->top = this->num_channels.top;
- num_channels->bottom = this->num_channels.bottom;
- num_channels->left = this->num_channels.left;
- num_channels->right = this->num_channels.right;
- num_channels->center = this->num_channels.center;
- num_channels->top_left = this->num_channels.top_left;
- num_channels->top_right = this->num_channels.top_right;
- num_channels->bottom_left = this->num_channels.bottom_left;
- num_channels->bottom_right = this->num_channels.bottom_right;
-
- this->num_channels = *num_channels;
+ param->top = this->param.top;
+ param->bottom = this->param.bottom;
+ param->left = this->param.left;
+ param->right = this->param.right;
+ param->center = this->param.center;
+ param->top_left = this->param.top_left;
+ param->top_right = this->param.top_right;
+ param->bottom_left = this->param.bottom_left;
+ param->bottom_right = this->param.bottom_right;
+
+ if (this->config_version > 1) {
+ param->overscan = this->param.overscan;
+ param->analyze_size = this->param.analyze_size;
+ param->edge_weighting = this->param.edge_weighting;
+ }
+
+ this->param = *param;
return 0;
}
-static void df10ch_driver_close(output_driver_t *this_gen) {
+static int df10ch_driver_close(output_driver_t *this_gen) {
df10ch_output_driver_t *this = (df10ch_output_driver_t *) this_gen;
- llprintf(LOG_1, "average transmit latency: %d [us]\n", this->avg_transmit_latency);
-
// Cancel all pending requests
df10ch_ctrl_t *ctrl = this->ctrls;
while (ctrl) {
@@ -873,6 +946,14 @@ static void df10ch_driver_close(output_driver_t *this_gen) {
df10ch_wait_for_replys(this);
df10ch_dispose(this);
+
+ llprintf(LOG_1, "average transmit latency: %d [us]\n", this->avg_transmit_latency);
+
+ if (this->transfer_err_cnt) {
+ snprintf(this->output_driver.errmsg, sizeof(this->output_driver.errmsg), "%d transfer errors happen", this->transfer_err_cnt);
+ return -1;
+ }
+ return 0;
}
@@ -884,21 +965,21 @@ static void df10ch_driver_output_colors(output_driver_t *this_gen, rgb_color_t *
rgb_color_t *area_map[9];
rgb_color_t *c = colors;
area_map[DF10CH_AREA_TOP] = c;
- c += this->num_channels.top;
+ c += this->param.top;
area_map[DF10CH_AREA_BOTTOM] = c;
- c += this->num_channels.bottom;
+ c += this->param.bottom;
area_map[DF10CH_AREA_LEFT] = c;
- c += this->num_channels.left;
+ c += this->param.left;
area_map[DF10CH_AREA_RIGHT] = c;
- c += this->num_channels.right;
+ c += this->param.right;
area_map[DF10CH_AREA_CENTER] = c;
- c += this->num_channels.center;
+ c += this->param.center;
area_map[DF10CH_AREA_TOP_LEFT] = c;
- c += this->num_channels.top_left;
+ c += this->param.top_left;
area_map[DF10CH_AREA_TOP_RIGHT] = c;
- c += this->num_channels.top_right;
+ c += this->param.top_right;
area_map[DF10CH_AREA_BOTTOM_LEFT] = c;
- c += this->num_channels.bottom_left;
+ c += this->param.bottom_left;
area_map[DF10CH_AREA_BOTTOM_RIGHT] = c;
if (LOG_1)
@@ -944,6 +1025,7 @@ static void df10ch_driver_output_colors(output_driver_t *this_gen, rgb_color_t *
// initiate asynchron data transfer to controller
if (do_submit) {
+ ctrl->transfer_error = 0;
int rc = libusb_submit_transfer(ctrl->transfer);
if (rc)
llprintf(LOG_1, "%s: submitting USB control transfer message failed: %s\n", ctrl->id, df10ch_usb_errmsg(rc));
diff --git a/xine_post_atmo.c b/xine_post_atmo.c
index a9b6480..1bc7486 100644
--- a/xine_post_atmo.c
+++ b/xine_post_atmo.c
@@ -36,6 +36,8 @@
#include <xine/post.h>
+extern long int lround(double); /* Missing in math.h? */
+
#undef LOG_MODULE
#define LOG_MODULE "atmo"
#define LOG_1 1
@@ -46,6 +48,7 @@
#define GRAB_TIMEOUT 100 /* max. time waiting for next grab image [ms] */
#define THREAD_TERMINATION_WAIT_TIME 150 /* time waiting for thread termination [ms] */
+#define NUM_AREAS 9 /* Number of different areas (top, bottom ...) */
/* accuracy of color calculation */
#define h_MAX 255
@@ -62,8 +65,6 @@ typedef struct { uint8_t h, s, v; } hsv_color_t;
typedef struct { uint8_t r, g, b; } rgb_color_t;
typedef struct { uint64_t r, g, b; } rgb_color_sum_t;
-#include "output_driver.h"
-
/*
* Plugin
*/
@@ -88,6 +89,7 @@ typedef struct {
int edge_weighting;
int hue_win_size;
int sat_win_size;
+ int hue_threshold;
int brightness;
int filter;
int filter_smoothness;
@@ -101,6 +103,9 @@ typedef struct {
} atmo_parameters_t;
+#include "output_driver.h"
+
+
#define NUM_FILTERS 2
static char *filter_enum[NUM_FILTERS+1] = { "off", "percentage", "combined" };
@@ -138,12 +143,14 @@ PARAM_ITEM(POST_PARAM_TYPE_INT, overscan, NULL, 0, 200, 0,
"ignored overscan border of grabbed image [%1000]")
PARAM_ITEM(POST_PARAM_TYPE_INT, darkness_limit, NULL, 0, 100, 0,
"limit for black pixel")
-PARAM_ITEM(POST_PARAM_TYPE_INT, edge_weighting, NULL, 1, 30, 0,
+PARAM_ITEM(POST_PARAM_TYPE_INT, edge_weighting, NULL, 10, 200, 0,
"power of edge weighting")
PARAM_ITEM(POST_PARAM_TYPE_INT, hue_win_size, NULL, 0, 5, 0,
"hue windowing size")
PARAM_ITEM(POST_PARAM_TYPE_INT, sat_win_size, NULL, 0, 5, 0,
"saturation windowing size")
+PARAM_ITEM(POST_PARAM_TYPE_INT, hue_threshold, NULL, 0, 100, 0,
+ "hue threshold [%]")
PARAM_ITEM(POST_PARAM_TYPE_INT, brightness, NULL, 50, 300, 0,
"brightness [%]")
PARAM_ITEM(POST_PARAM_TYPE_INT, filter, filter_enum, 0, NUM_FILTERS, 0,
@@ -184,7 +191,8 @@ typedef struct atmo_post_plugin_s
pthread_mutex_t port_lock;
/* channel configuration related */
- num_channels_t num_channels;
+ atmo_parameters_t active_parm;
+ int sum_channels;
/* thread related */
int *grab_running, *output_running;
@@ -196,14 +204,13 @@ typedef struct atmo_post_plugin_s
output_driver_t *output_driver;
output_drivers_t output_drivers;
int driver_opened;
- int driver;
- char driver_param[256];
rgb_color_t *output_colors, *last_output_colors;
/* analyze related */
uint64_t *hue_hist, *sat_hist;
uint64_t *w_hue_hist, *w_sat_hist;
- int *most_used_hue, *last_most_used_hue, *most_used_sat;
+ uint64_t *avg_bright;
+ int *most_used_hue, *last_most_used_hue, *most_used_sat, *avg_cnt;
rgb_color_t *analyzed_colors;
/* filter related */
@@ -399,82 +406,89 @@ static void calc_hsv_image(hsv_color_t *hsv, uint8_t *rgb, int img_size) {
}
-static void calc_weight(atmo_post_plugin_t *this, int *weight, const int width, const int height, const double edge_weighting) {
+static void calc_weight(atmo_post_plugin_t *this, uint8_t *weight, const int width, const int height, const int edge_weighting) {
int row, col, c;
- const int top_channels = this->num_channels.top;
- const int bottom_channels = this->num_channels.bottom;
- const int left_channels = this->num_channels.left;
- const int right_channels = this->num_channels.right;
- const int center_channel = this->num_channels.center;
- const int top_left_channel = this->num_channels.top_left;
- const int top_right_channel = this->num_channels.top_right;
- const int bottom_left_channel = this->num_channels.bottom_left;
- const int bottom_right_channel = this->num_channels.bottom_right;
+ const double w = edge_weighting > 10 ? (double)edge_weighting / 10.0: 10.0;
- c = top_channels + top_left_channel + top_right_channel;
- const int top_chunk = c ? width / c: 0;
+ const int top_channels = this->active_parm.top;
+ const int bottom_channels = this->active_parm.bottom;
+ const int left_channels = this->active_parm.left;
+ const int right_channels = this->active_parm.right;
+ const int center_channel = this->active_parm.center;
+ const int top_left_channel = this->active_parm.top_left;
+ const int top_right_channel = this->active_parm.top_right;
+ const int bottom_left_channel = this->active_parm.bottom_left;
+ const int bottom_right_channel = this->active_parm.bottom_right;
- c = bottom_channels + bottom_left_channel + bottom_right_channel;
- const int bottom_chunk = c ? width / c: 0;
+ const int sum_top_channels = top_channels + top_left_channel + top_right_channel;
+ const int sum_bottom_channels = bottom_channels + bottom_left_channel + bottom_right_channel;
+ const int sum_left_channels = left_channels + bottom_left_channel + top_left_channel;
+ const int sum_right_channels = right_channels + bottom_right_channel + top_right_channel;
- c = left_channels + bottom_left_channel + top_left_channel;
- const int left_chunk = c ? height / c: 0;
+ const int center_y = height / 2;
+ const int center_x = width / 2;
- c = right_channels + bottom_right_channel + top_right_channel;
- const int right_chunk = c ? height / c: 0;
+ const double fheight = height - 1;
+ const double fwidth = width - 1;
for (row = 0; row < height; ++row)
{
- double row_norm = (double)row / (double)(height - 1);
- int top = (int) (255.0 * pow(1.0 - row_norm, edge_weighting));
- int bottom = (int) (255.0 * pow(row_norm, edge_weighting));
+ double row_norm = (double)row / fheight;
+ int top = (int)(255.0 * pow(1.0 - row_norm, w));
+ int bottom = (int)(255.0 * pow(row_norm, w));
for (col = 0; col < width; ++col)
{
- double col_norm = (double)col / (double)(width - 1);
- int left = (int) (255.0 * pow((1.0 - col_norm), edge_weighting));
- int right = (int) (255.0 * pow(col_norm, edge_weighting));
+ double col_norm = (double)col / fwidth;
+ int left = (int)(255.0 * pow((1.0 - col_norm), w));
+ int right = (int)(255.0 * pow(col_norm, w));
for (c = top_left_channel; c < (top_channels + top_left_channel); ++c)
- *weight++ = (col >= (c * top_chunk) && col < ((c + 1) * top_chunk)) ? top: 0;
+ *weight++ = (col >= ((width * c) / sum_top_channels) && col < ((width * (c + 1)) / sum_top_channels) && row < center_y) ? top: 0;
+
for (c = bottom_left_channel; c < (bottom_channels + bottom_left_channel); ++c)
- *weight++ = (col >= (c * bottom_chunk) && col < ((c + 1) * bottom_chunk)) ? bottom: 0;
+ *weight++ = (col >= ((width * c) / sum_bottom_channels) && col < ((width * (c + 1)) / sum_bottom_channels) && row >= center_y) ? bottom: 0;
+
for (c = top_left_channel; c < (left_channels + top_left_channel); ++c)
- *weight++ = (row >= (c * left_chunk) && row < ((c + 1) * left_chunk)) ? left: 0;
+ *weight++ = (row >= ((height * c) / sum_left_channels) && row < ((height * (c + 1)) / sum_left_channels) && col < center_x) ? left: 0;
+
for (c = top_right_channel; c < (right_channels + top_right_channel); ++c)
- *weight++ = (row >= (c * right_chunk) && row < ((c + 1) * right_chunk)) ? right: 0;
+ *weight++ = (row >= ((height * c) / sum_right_channels) && row < ((height * (c + 1)) / sum_right_channels) && col >= center_x) ? right: 0;
+
if (center_channel)
*weight++ = 255;
+
if (top_left_channel)
- *weight++ = (top > left) ? top: left;
+ *weight++ = (col < center_x && row < center_y) ? ((top > left) ? top: left) : 0;
+
if (top_right_channel)
- *weight++ = (top > right) ? top: right;
+ *weight++ = (col >= center_x && row < center_y) ? ((top > right) ? top: right): 0;
+
if (bottom_left_channel)
- *weight++ = (bottom > left) ? bottom: left;
+ *weight++ = (col < center_x && row >= center_y) ? ((bottom > left) ? bottom: left): 0;
+
if (bottom_right_channel)
- *weight++ = (bottom > right) ? bottom: right;
+ *weight++ = (col >= center_x && row >= center_y) ? ((bottom > right) ? bottom: right): 0;
}
}
}
-static void calc_hue_hist(atmo_post_plugin_t *this, hsv_color_t *hsv, int *weight, int img_size) {
- const int n = this->num_channels.sum;
+static void calc_hue_hist(atmo_post_plugin_t *this, hsv_color_t *hsv, uint8_t *weight, int img_size) {
+ const int n = this->sum_channels;
uint64_t * const hue_hist = this->hue_hist;
- const int darkness_limit = this->parm.darkness_limit;
+ const int darkness_limit = this->active_parm.darkness_limit;
memset(hue_hist, 0, (n * (h_MAX+1) * sizeof(uint64_t)));
while (img_size--) {
- if (hsv->v > darkness_limit) {
+ if (hsv->v >= darkness_limit) {
int c;
- for (c = 0; c < n; ++c) {
- hue_hist[c * (h_MAX+1) + hsv->h] += *weight * hsv->v;
- ++weight;
- }
- } else
- weight += n;
+ for (c = 0; c < n; ++c)
+ hue_hist[c * (h_MAX+1) + hsv->h] += weight[c] * hsv->v;
+ }
+ weight += n;
++hsv;
}
}
@@ -482,10 +496,10 @@ static void calc_hue_hist(atmo_post_plugin_t *this, hsv_color_t *hsv, int *weigh
static void calc_windowed_hue_hist(atmo_post_plugin_t *this) {
int i, c, w;
- const int n = this->num_channels.sum;
+ const int n = this->sum_channels;
uint64_t * const hue_hist = this->hue_hist;
uint64_t * const w_hue_hist = this->w_hue_hist;
- const int hue_win_size = this->parm.hue_win_size;
+ const int hue_win_size = this->active_parm.hue_win_size;
memset(w_hue_hist, 0, (n * (h_MAX+1) * sizeof(uint64_t)));
@@ -512,10 +526,11 @@ static void calc_windowed_hue_hist(atmo_post_plugin_t *this) {
static void calc_most_used_hue(atmo_post_plugin_t *this) {
int i, c;
- const int n = this->num_channels.sum;
+ const int n = this->sum_channels;
uint64_t * const w_hue_hist = this->w_hue_hist;
int * const most_used_hue = this->most_used_hue;
int * const last_most_used_hue = this->last_most_used_hue;
+ const double hue_threshold = (double)this->active_parm.hue_threshold / 100.0;
memset(most_used_hue, 0, (n * sizeof(int)));
@@ -527,7 +542,7 @@ static void calc_most_used_hue(atmo_post_plugin_t *this) {
most_used_hue[c] = i;
}
}
- if (((double) w_hue_hist[c * (h_MAX+1) + last_most_used_hue[c]] / (double) v) > 0.93)
+ if (((double) w_hue_hist[c * (h_MAX+1) + last_most_used_hue[c]] / (double) v) > hue_threshold)
most_used_hue[c] = last_most_used_hue[c];
else
last_most_used_hue[c] = most_used_hue[c];
@@ -535,26 +550,25 @@ static void calc_most_used_hue(atmo_post_plugin_t *this) {
}
-static void calc_sat_hist(atmo_post_plugin_t *this, hsv_color_t *hsv, int *weight, int img_size) {
- const int n = this->num_channels.sum;
+static void calc_sat_hist(atmo_post_plugin_t *this, hsv_color_t *hsv, uint8_t *weight, int img_size) {
+ const int n = this->sum_channels;
uint64_t * const sat_hist = this->sat_hist;
int * const most_used_hue = this->most_used_hue;
- const int darkness_limit = this->parm.darkness_limit;
- const int hue_win_size = this->parm.hue_win_size;
+ const int darkness_limit = this->active_parm.darkness_limit;
+ const int hue_win_size = this->active_parm.hue_win_size;
memset(sat_hist, 0, (n * (s_MAX+1) * sizeof(uint64_t)));
while (img_size--) {
- if (hsv->v > darkness_limit) {
+ if (hsv->v >= darkness_limit) {
int h = hsv->h;
int c;
for (c = 0; c < n; ++c) {
if (h > (most_used_hue[c] - hue_win_size) && h < (most_used_hue[c] + hue_win_size))
- sat_hist[c * (s_MAX+1) + hsv->s] += *weight * hsv->v;
- ++weight;
+ sat_hist[c * (s_MAX+1) + hsv->s] += weight[c] * hsv->v;
}
- } else
- weight += n;
+ }
+ weight += n;
++hsv;
}
}
@@ -562,10 +576,10 @@ static void calc_sat_hist(atmo_post_plugin_t *this, hsv_color_t *hsv, int *weigh
static void calc_windowed_sat_hist(atmo_post_plugin_t *this) {
int i, c, w;
- const int n = this->num_channels.sum;
+ const int n = this->sum_channels;
uint64_t * const sat_hist = this->sat_hist;
uint64_t * const w_sat_hist = this->w_sat_hist;
- const int sat_win_size = this->parm.sat_win_size;
+ const int sat_win_size = this->active_parm.sat_win_size;
memset(w_sat_hist, 0, (n * (s_MAX+1) * sizeof(uint64_t)));
@@ -591,7 +605,7 @@ static void calc_windowed_sat_hist(atmo_post_plugin_t *this) {
static void calc_most_used_sat(atmo_post_plugin_t *this) {
int i, c;
- const int n = this->num_channels.sum;
+ const int n = this->sum_channels;
uint64_t * const w_sat_hist = this->w_sat_hist;
int * const most_used_sat = this->most_used_sat;
@@ -609,18 +623,36 @@ static void calc_most_used_sat(atmo_post_plugin_t *this) {
}
-static int calc_average_brightness(hsv_color_t *hsv, int img_size, const int darkness_limit) {
- int n = 0;
- uint64_t v_avg = 0;
+static void calc_average_brightness(atmo_post_plugin_t *this, hsv_color_t *hsv, uint8_t *weight, int img_size) {
+ int c;
+ const int n = this->sum_channels;
+ const int darkness_limit = this->active_parm.darkness_limit;
+ const uint64_t bright = this->active_parm.brightness;
+ uint64_t * const avg_bright = this->avg_bright;
+ int * const avg_cnt = this->avg_cnt;
+
+ memset(avg_bright, 0, (n * sizeof(uint64_t)));
+ memset(avg_cnt, 0, (n * sizeof(int)));
while (img_size--) {
- if (hsv->v > darkness_limit)
- v_avg += hsv->v;
- ++n;
+ const int v = hsv->v;
+ if (v >= darkness_limit) {
+ for (c = 0; c < n; ++c) {
+ avg_bright[c] += v * weight[c];
+ avg_cnt[c] += weight[c];
+ }
+ }
+ weight += n;
++hsv;
}
- return (int)(v_avg / n);
+ for (c = 0; c < n; ++c) {
+ if (avg_cnt[c]) {
+ avg_bright[c] = (avg_bright[c] * bright) / (avg_cnt[c] * ((uint64_t)100));
+ if (avg_bright[c] > v_MAX)
+ avg_bright[c] = v_MAX;
+ }
+ }
}
@@ -675,16 +707,13 @@ static void hsv_to_rgb(rgb_color_t *rgb, double h, double s, double v) {
}
-static void calc_rgb_values(atmo_post_plugin_t *this, int v_avg)
+static void calc_rgb_values(atmo_post_plugin_t *this)
{
int c;
- const int n = this->num_channels.sum;
- double v = (v_avg * this->parm.brightness) / 100.0;
- if (v > 255.0)
- v = 255.0;
+ const int n = this->sum_channels;
for (c = 0; c < n; ++c)
- hsv_to_rgb(&this->analyzed_colors[c], this->most_used_hue[c], this->most_used_sat[c], v);
+ hsv_to_rgb(&this->analyzed_colors[c], this->most_used_hue[c], this->most_used_sat[c], this->avg_bright[c]);
}
@@ -701,7 +730,7 @@ static void *atmo_grab_loop (void *this_gen) {
int edge_weighting = 0;
int running = 1;
hsv_color_t *hsv_img = NULL;
- int *weight = NULL;
+ uint8_t *weight = NULL;
struct timeval tvnow, tvlast, tvdiff;
useconds_t analyze_rate;
@@ -744,11 +773,11 @@ static void *atmo_grab_loop (void *this_gen) {
if (grab_width > 0 && grab_height > 0) {
/* calculate size of analyze image */
- analyze_width = (this->parm.analyze_size + 1) * 64;
+ analyze_width = (this->active_parm.analyze_size + 1) * 64;
analyze_height = (analyze_width * grab_height) / grab_width;
/* calculate size of grab (sub) window */
- overscan = this->parm.overscan;
+ overscan = this->active_parm.overscan;
if (overscan) {
frame->crop_left = frame->crop_right = grab_width * overscan / 1000;
frame->crop_top = frame->crop_bottom = grab_height * overscan / 1000;
@@ -775,7 +804,7 @@ static void *atmo_grab_loop (void *this_gen) {
free(weight);
alloc_img_size = img_size;
hsv_img = (hsv_color_t *) malloc(img_size * sizeof(hsv_color_t));
- weight = (int *) malloc(img_size * this->num_channels.sum * sizeof(int));
+ weight = (uint8_t *) malloc(img_size * this->sum_channels * sizeof(uint8_t));
if (!hsv_img || !weight)
break;
last_analyze_width = 0;
@@ -784,8 +813,8 @@ static void *atmo_grab_loop (void *this_gen) {
}
/* calculate weight image */
- if (analyze_width != last_analyze_width || analyze_height != last_analyze_height || edge_weighting != this->parm.edge_weighting) {
- edge_weighting = this->parm.edge_weighting;
+ if (analyze_width != last_analyze_width || analyze_height != last_analyze_height || edge_weighting != this->active_parm.edge_weighting) {
+ edge_weighting = this->active_parm.edge_weighting;
last_analyze_width = analyze_width;
last_analyze_height = analyze_height;
calc_weight(this, weight, analyze_width, analyze_height, edge_weighting);
@@ -800,9 +829,9 @@ static void *atmo_grab_loop (void *this_gen) {
calc_sat_hist(this, hsv_img, weight, img_size);
calc_windowed_sat_hist(this);
calc_most_used_sat(this);
- int v_avg = calc_average_brightness(hsv_img, img_size, this->parm.darkness_limit);
+ calc_average_brightness(this, hsv_img, weight, img_size);
pthread_mutex_lock(&this->lock);
- calc_rgb_values(this, v_avg);
+ calc_rgb_values(this);
pthread_mutex_unlock(&this->lock);
llprintf(LOG_2, "grab %ld.%03ld: vpts=%ld\n", tvlast.tv_sec, tvlast.tv_usec / 1000, frame->vpts);
@@ -816,7 +845,7 @@ static void *atmo_grab_loop (void *this_gen) {
}
/* loop with analyze rate duration */
- analyze_rate = this->parm.analyze_rate * 1000;
+ analyze_rate = this->active_parm.analyze_rate * 1000;
gettimeofday(&tvnow, NULL);
timersub(&tvnow, &tvlast, &tvdiff);
if (tvdiff.tv_sec == 0 && tvdiff.tv_usec < analyze_rate)
@@ -852,9 +881,9 @@ static void reset_filters(atmo_post_plugin_t *this) {
static void percent_filter(atmo_post_plugin_t *this) {
rgb_color_t *act = this->analyzed_colors;
rgb_color_t *out = this->filtered_colors;
- const int old_p = this->parm.filter_smoothness;
+ const int old_p = this->active_parm.filter_smoothness;
const int new_p = 100 - old_p;
- int n = this->num_channels.sum;
+ int n = this->sum_channels;
while (n--) {
out->r = (act->r * new_p + out->r * old_p) / 100;
@@ -871,11 +900,11 @@ static void mean_filter(atmo_post_plugin_t *this) {
rgb_color_t *out = this->filtered_colors;
rgb_color_t *mean_values = this->mean_filter_values;
rgb_color_sum_t *mean_sums = this->mean_filter_sum_values;
- const int64_t mean_threshold = (int64_t) ((double) this->parm.filter_threshold * 3.6);
- const int old_p = this->parm.filter_smoothness;
+ const int64_t mean_threshold = (int64_t) ((double) this->active_parm.filter_threshold * 3.6);
+ const int old_p = this->active_parm.filter_smoothness;
const int new_p = 100 - old_p;
- int n = this->num_channels.sum;
- const int filter_length = this->parm.filter_length;
+ int n = this->sum_channels;
+ const int filter_length = this->active_parm.filter_length;
const int64_t mean_length = (filter_length < OUTPUT_RATE) ? 1: filter_length / OUTPUT_RATE;
const int reinitialize = ((int)mean_length != this->old_mean_length);
this->old_mean_length = (int)mean_length;
@@ -926,14 +955,14 @@ static void mean_filter(atmo_post_plugin_t *this) {
static void apply_white_calibration(atmo_post_plugin_t *this) {
- const int wc_red = this->parm.wc_red;
- const int wc_green = this->parm.wc_green;
- const int wc_blue = this->parm.wc_blue;
+ const int wc_red = this->active_parm.wc_red;
+ const int wc_green = this->active_parm.wc_green;
+ const int wc_blue = this->active_parm.wc_blue;
if (wc_red == 255 && wc_green == 255 && wc_blue == 255)
return;
rgb_color_t *out = this->output_colors;
- int n = this->num_channels.sum;
+ int n = this->sum_channels;
while (n--) {
out->r = (uint8_t)((int)out->r * wc_red / 255);
out->g = (uint8_t)((int)out->g * wc_green / 255);
@@ -944,13 +973,13 @@ static void apply_white_calibration(atmo_post_plugin_t *this) {
static void apply_gamma_correction(atmo_post_plugin_t *this) {
- const int igamma = this->parm.gamma;
+ const int igamma = this->active_parm.gamma;
if (igamma <= 10)
return;
const double gamma = (double)igamma / 10.0;
rgb_color_t *out = this->output_colors;
- int n = this->num_channels.sum;
+ int n = this->sum_channels;
while (n--) {
out->r = (uint8_t)(pow((double)out->r / 255.0, gamma) * 255.0);
out->g = (uint8_t)(pow((double)out->g / 255.0, gamma) * 255.0);
@@ -965,7 +994,7 @@ static void *atmo_output_loop (void *this_gen) {
post_video_port_t *port = this->port;
xine_ticket_t *ticket = this->post_plugin.running_ticket;
output_driver_t *output_driver = this->output_driver;
- int colors_size = this->num_channels.sum * sizeof(rgb_color_t);
+ int colors_size = this->sum_channels * sizeof(rgb_color_t);
int running = 1;
struct timeval tvnow, tvlast, tvdiff, tvfirst;
@@ -997,7 +1026,7 @@ static void *atmo_output_loop (void *this_gen) {
/* Transfer analyzed colors into filtered colors */
pthread_mutex_lock(&this->lock);
- switch (this->parm.filter) {
+ switch (this->active_parm.filter) {
case 1:
percent_filter(this);
break;
@@ -1018,7 +1047,7 @@ static void *atmo_output_loop (void *this_gen) {
/* Output colors */
gettimeofday(&tvnow, NULL);
timersub(&tvnow, &tvfirst, &tvdiff);
- if ((tvdiff.tv_sec * 1000 + tvdiff.tv_usec / 1000) >= this->parm.start_delay) {
+ if ((tvdiff.tv_sec * 1000 + tvdiff.tv_usec / 1000) >= this->active_parm.start_delay) {
if (memcmp(this->output_colors, this->last_output_colors, colors_size)) {
output_driver->output_colors(output_driver, this->output_colors, this->last_output_colors);
memcpy(this->last_output_colors, this->output_colors, colors_size);
@@ -1056,10 +1085,10 @@ static void *atmo_output_loop (void *this_gen) {
static void config_channels(atmo_post_plugin_t *this) {
- int n = this->num_channels.top + this->num_channels.bottom + this->num_channels.left + this->num_channels.right +
- this->num_channels.center +
- this->num_channels.top_left + this->num_channels.top_right + this->num_channels.bottom_left + this->num_channels.bottom_right;
- this->num_channels.sum = n;
+ int n = this->parm.top + this->parm.bottom + this->parm.left + this->parm.right +
+ this->parm.center +
+ this->parm.top_left + this->parm.top_right + this->parm.bottom_left + this->parm.bottom_right;
+ this->sum_channels = n;
if (n)
{
@@ -1072,6 +1101,9 @@ static void config_channels(atmo_post_plugin_t *this) {
this->w_sat_hist = (uint64_t *) calloc(n * (s_MAX + 1), sizeof(uint64_t));
this->most_used_sat = (int *) calloc(n, sizeof(int));
+ this->avg_cnt = (int *) calloc(n, sizeof(int));
+ this->avg_bright = (uint64_t *) calloc(n, sizeof(uint64_t));
+
this->analyzed_colors = (rgb_color_t *) calloc(n, sizeof(rgb_color_t));
this->filtered_colors = (rgb_color_t *) calloc(n, sizeof(rgb_color_t));
this->output_colors = (rgb_color_t *) calloc(n, sizeof(rgb_color_t));
@@ -1081,13 +1113,13 @@ static void config_channels(atmo_post_plugin_t *this) {
}
llprintf(LOG_1, "configure channels top %d, bottom %d, left %d, right %d, center %d, topLeft %d, topRight %d, bottomLeft %d, bottomRight %d\n",
- this->num_channels.top, this->num_channels.bottom, this->num_channels.left, this->num_channels.right, this->num_channels.center,
- this->num_channels.top_left, this->num_channels.top_right, this->num_channels.bottom_left, this->num_channels.bottom_right);
+ this->parm.top, this->parm.bottom, this->parm.left, this->parm.right, this->parm.center,
+ this->parm.top_left, this->parm.top_right, this->parm.bottom_left, this->parm.bottom_right);
}
static void free_channels(atmo_post_plugin_t *this) {
- if (this->num_channels.sum)
+ if (this->sum_channels)
{
free(this->hue_hist);
free(this->w_hue_hist);
@@ -1098,6 +1130,9 @@ static void free_channels(atmo_post_plugin_t *this) {
free(this->w_sat_hist);
free(this->most_used_sat);
+ free(this->avg_bright);
+ free(this->avg_cnt);
+
free(this->analyzed_colors);
free(this->filtered_colors);
free(this->output_colors);
@@ -1160,12 +1195,13 @@ static void close_output_driver(atmo_post_plugin_t *this) {
if (this->driver_opened) {
/* Switch all channels off */
- int colors_size = this->num_channels.sum * sizeof(rgb_color_t);
+ int colors_size = this->sum_channels * sizeof(rgb_color_t);
memset(this->output_colors, 0, colors_size);
if (memcmp(this->output_colors, this->last_output_colors, colors_size))
this->output_driver->output_colors(this->output_driver, this->output_colors, this->last_output_colors);
- this->output_driver->close(this->output_driver);
+ if (this->output_driver->close(this->output_driver))
+ xine_log(this->post_plugin.xine, XINE_LOG_PLUGIN, "atmo: output driver: %s!\n", this->output_driver->errmsg);
this->driver_opened = 0;
llprintf(LOG_1, "output driver closed\n");
}
@@ -1174,82 +1210,54 @@ static void close_output_driver(atmo_post_plugin_t *this) {
static void open_output_driver(atmo_post_plugin_t *this) {
- if (!this->parm.enabled || this->driver != this->parm.driver || strcmp(this->driver_param, this->parm.driver_param))
+ if (!this->parm.enabled || this->active_parm.driver != this->parm.driver || strcmp(this->active_parm.driver_param, this->parm.driver_param))
close_output_driver(this);
if (this->parm.enabled) {
- num_channels_t num_channels;
- int start = 1, configure = 0;
-
- if (this->num_channels.top != this->parm.top ||
- this->num_channels.bottom != this->parm.bottom ||
- this->num_channels.left != this->parm.left ||
- this->num_channels.right != this->parm.right ||
- this->num_channels.center != this->parm.center ||
- this->num_channels.top_left != this->parm.top_left ||
- this->num_channels.top_right != this->parm.top_right ||
- this->num_channels.bottom_left != this->parm.bottom_left ||
- this->num_channels.bottom_right != this->parm.bottom_right) {
- configure = 1;
- }
-
- num_channels.top = this->parm.top;
- num_channels.bottom = this->parm.bottom;
- num_channels.left = this->parm.left;
- num_channels.right = this->parm.right;
- num_channels.center = this->parm.center;
- num_channels.top_left = this->parm.top_left;
- num_channels.top_right = this->parm.top_right;
- num_channels.bottom_left = this->parm.bottom_left;
- num_channels.bottom_right = this->parm.bottom_right;
+ int start = 1;
+ atmo_parameters_t parm = this->parm;
/* open output driver */
if (!this->driver_opened) {
- this->driver = this->parm.driver;
- strcpy(this->driver_param, this->parm.driver_param);
-
- if ((this->output_driver = get_output_driver(&this->output_drivers, this->driver)) == NULL) {
+ if ((this->output_driver = get_output_driver(&this->output_drivers, this->parm.driver)) == NULL) {
xine_log(this->post_plugin.xine, XINE_LOG_PLUGIN, "atmo: no valid output driver selected!\n");
start = 0;
- } else if (this->output_driver->open(this->output_driver, this->driver_param, &num_channels)) {
+ } else if (this->output_driver->open(this->output_driver, &this->parm)) {
xine_log(this->post_plugin.xine, XINE_LOG_PLUGIN, "atmo: can't open output driver: %s!\n", this->output_driver->errmsg);
start = 0;
} else {
this->driver_opened = 1;
llprintf(LOG_1, "output driver opened\n");
}
- } else if (configure) {
- if (this->output_driver->configure(this->output_driver, &num_channels)) {
+ } else {
+ if (this->output_driver->configure(this->output_driver, &this->parm)) {
xine_log(this->post_plugin.xine, XINE_LOG_PLUGIN, "atmo: can't configure output driver: %s!\n", this->output_driver->errmsg);
start = 0;
}
}
- if (this->num_channels.top != num_channels.top ||
- this->num_channels.bottom != num_channels.bottom ||
- this->num_channels.left != num_channels.left ||
- this->num_channels.right != num_channels.right ||
- this->num_channels.center != num_channels.center ||
- this->num_channels.top_left != num_channels.top_left ||
- this->num_channels.top_right != num_channels.top_right ||
- this->num_channels.bottom_left != num_channels.bottom_left ||
- this->num_channels.bottom_right != num_channels.bottom_right) {
+ if (join_post_api_parameters(&atmo_param_descr, &parm, &this->parm)) {
+ char buf[512];
+ build_post_api_parameter_string(buf, sizeof(buf), &atmo_param_descr, &this->parm, &this->default_parm);
+ this->post_plugin.xine->config->update_string(this->post_plugin.xine->config, "post.atmo.parameters", buf);
+ }
+
+ if (this->active_parm.top != this->parm.top ||
+ this->active_parm.bottom != this->parm.bottom ||
+ this->active_parm.left != this->parm.left ||
+ this->active_parm.right != this->parm.right ||
+ this->active_parm.center != this->parm.center ||
+ this->active_parm.top_left != this->parm.top_left ||
+ this->active_parm.top_right != this->parm.top_right ||
+ this->active_parm.bottom_left != this->parm.bottom_left ||
+ this->active_parm.bottom_right != this->parm.bottom_right) {
free_channels(this);
- this->num_channels = num_channels;
config_channels(this);
}
- this->parm.top = num_channels.top;
- this->parm.bottom = num_channels.bottom;
- this->parm.left = num_channels.left;
- this->parm.right = num_channels.right;
- this->parm.center = num_channels.center;
- this->parm.top_left = num_channels.top_left;
- this->parm.top_right = num_channels.top_right;
- this->parm.bottom_left = num_channels.bottom_left;
- this->parm.bottom_right = num_channels.bottom_right;
-
- if (!this->num_channels.sum)
+ this->active_parm = this->parm;
+
+ if (!this->sum_channels)
start = 0;
if (start) {
@@ -1310,7 +1318,6 @@ static xine_post_api_descr_t *atmo_get_param_descr(void)
static int atmo_set_parameters(xine_post_t *this_gen, void *parm_gen)
{
atmo_post_plugin_t *this = (atmo_post_plugin_t *)this_gen;
- int enabled = this->parm.enabled;
if (join_post_api_parameters(&atmo_param_descr, &this->parm, parm_gen)) {
char buf[512];
@@ -1321,14 +1328,32 @@ static int atmo_set_parameters(xine_post_t *this_gen, void *parm_gen)
pthread_mutex_lock(&this->port_lock);
if (this->port) {
if (this->parm.enabled) {
- if (!enabled)
+ if (!this->active_parm.enabled)
open_output_driver(this);
+ else {
+ this->active_parm.analyze_rate = this->parm.analyze_rate;
+ this->active_parm.brightness = this->parm.brightness;
+ this->active_parm.darkness_limit = this->parm.darkness_limit;
+ this->active_parm.filter = this->parm.filter;
+ this->active_parm.filter_length = this->parm.filter_length;
+ this->active_parm.filter_smoothness = this->parm.filter_smoothness;
+ this->active_parm.filter_threshold = this->parm.filter_threshold;
+ this->active_parm.gamma = this->parm.gamma;
+ this->active_parm.hue_win_size = this->parm.hue_win_size;
+ this->active_parm.sat_win_size = this->parm.sat_win_size;
+ this->active_parm.hue_threshold = this->parm.hue_threshold;
+ this->active_parm.start_delay = this->parm.start_delay;
+ this->active_parm.wc_blue = this->parm.wc_blue;
+ this->active_parm.wc_green = this->parm.wc_green;
+ this->active_parm.wc_red = this->parm.wc_red;
+ }
} else {
- if (enabled) {
+ if (this->active_parm.enabled) {
stop_threads(this, 1);
close_output_driver(this);
}
}
+ this->active_parm.enabled = this->parm.enabled;
}
pthread_mutex_unlock(&this->port_lock);
}
@@ -1417,7 +1442,6 @@ static post_plugin_t *atmo_open_plugin(post_class_t *class_gen,
input_param->data = &post_api;
xine_list_push_back(this->post_plugin.input, input_param);
- this->driver = -1;
pthread_mutex_init(&this->lock, NULL);
pthread_mutex_init(&this->port_lock, NULL);
pthread_cond_init(&this->thread_started, NULL);
@@ -1428,14 +1452,15 @@ static post_plugin_t *atmo_open_plugin(post_class_t *class_gen,
this->parm.analyze_rate = 40;
this->parm.analyze_size = 1;
this->parm.brightness = 100;
- this->parm.darkness_limit = 10;
- this->parm.edge_weighting = 8;
+ this->parm.darkness_limit = 1;
+ this->parm.edge_weighting = 80;
this->parm.filter = 2;
this->parm.filter_length = 500;
this->parm.filter_smoothness = 50;
this->parm.filter_threshold = 40;
this->parm.hue_win_size = 3;
this->parm.sat_win_size = 3;
+ this->parm.hue_threshold = 93;
this->parm.wc_red = 255;
this->parm.wc_green = 255;
this->parm.wc_blue = 255;