diff options
| author | Andreas Auras <yak54@gmx.net> | 2010-03-06 21:24:22 +0100 |
|---|---|---|
| committer | Andreas Auras <yak54@gmx.net> | 2010-03-06 21:24:22 +0100 |
| commit | 05bef2bf40becc5b48713dc088c0bd939d2a84ae (patch) | |
| tree | 4916615c1ed036e286f7c2005ab22e8927cd5bbc | |
| parent | d672cfc08fbf99f94c5b19d6fd875590f581de67 (diff) | |
| download | xine-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-- | HISTORY | 10 | ||||
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | README | 25 | ||||
| -rw-r--r-- | output_driver.h | 324 | ||||
| -rw-r--r-- | xine_post_atmo.c | 365 |
5 files changed, 428 insertions, 298 deletions
@@ -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 @@ -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 @@ -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; |
