videotestsrc: remove threads

Remove the threads from the element and use timerfd to schedule timeouts
Propagate live flag between node links
This commit is contained in:
Wim Taymans 2016-09-19 19:17:59 +02:00
parent 1e565a5f65
commit 4b83d6cfc8
9 changed files with 809 additions and 802 deletions

View file

@ -386,6 +386,11 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
in_flags = iinfo->flags; in_flags = iinfo->flags;
out_flags = oinfo->flags; out_flags = oinfo->flags;
if (out_flags & SPA_PORT_INFO_FLAG_LIVE) {
this->output_node->live = true;
this->input_node->live = true;
}
if (in_state == SPA_NODE_STATE_READY && out_state == SPA_NODE_STATE_READY) { if (in_state == SPA_NODE_STATE_READY && out_state == SPA_NODE_STATE_READY) {
if ((out_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) && if ((out_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) &&
(in_flags & SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS)) { (in_flags & SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS)) {

View file

@ -77,8 +77,6 @@ struct _PinosNodePrivate
guint n_used_output_links; guint n_used_output_links;
GArray *input_links; GArray *input_links;
guint n_used_input_links; guint n_used_input_links;
SpaClock *clock;
}; };
G_DEFINE_TYPE (PinosNode, pinos_node, G_TYPE_OBJECT); G_DEFINE_TYPE (PinosNode, pinos_node, G_TYPE_OBJECT);
@ -319,7 +317,6 @@ suspend_node (PinosNode *this)
static void static void
send_clock_update (PinosNode *this) send_clock_update (PinosNode *this)
{ {
PinosNodePrivate *priv = this->priv;
SpaNodeCommand cmd; SpaNodeCommand cmd;
SpaNodeCommandClockUpdate cu; SpaNodeCommandClockUpdate cu;
SpaResult res; SpaResult res;
@ -333,9 +330,9 @@ send_clock_update (PinosNode *this)
SPA_NODE_COMMAND_CLOCK_UPDATE_SCALE | SPA_NODE_COMMAND_CLOCK_UPDATE_SCALE |
SPA_NODE_COMMAND_CLOCK_UPDATE_STATE | SPA_NODE_COMMAND_CLOCK_UPDATE_STATE |
SPA_NODE_COMMAND_CLOCK_UPDATE_LATENCY; SPA_NODE_COMMAND_CLOCK_UPDATE_LATENCY;
if (priv->clock) { if (this->clock && this->live) {
cu.flags = SPA_NODE_COMMAND_CLOCK_UPDATE_FLAG_LIVE; cu.flags = SPA_NODE_COMMAND_CLOCK_UPDATE_FLAG_LIVE;
res = spa_clock_get_time (priv->clock, &cu.rate, &cu.ticks, &cu.monotonic_time); res = spa_clock_get_time (this->clock, &cu.rate, &cu.ticks, &cu.monotonic_time);
} else { } else {
cu.rate = 1; cu.rate = 1;
cu.ticks = 0; cu.ticks = 0;
@ -519,8 +516,11 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
if (pl == NULL || pl->output_node->node != node || pl->output_port != oinfo[0].port_id) if (pl == NULL || pl->output_node->node != node || pl->output_port != oinfo[0].port_id)
continue; continue;
if (pl->input_node->node->state != SPA_NODE_STATE_STREAMING) if (pl->input_node->node->state != SPA_NODE_STATE_STREAMING) {
if ((res = spa_node_port_reuse_buffer (node, oinfo[0].port_id, oinfo[0].buffer_id)) < 0)
g_warning ("node %p: error reuse buffer: %d", node, res);
continue; continue;
}
iinfo[0].port_id = pl->input_port; iinfo[0].port_id = pl->input_port;
iinfo[0].buffer_id = oinfo[0].buffer_id; iinfo[0].buffer_id = oinfo[0].buffer_id;
@ -657,7 +657,7 @@ pinos_node_set_property (GObject *_object,
void *iface; void *iface;
node->node = g_value_get_pointer (value); node->node = g_value_get_pointer (value);
if (node->node->handle->get_interface (node->node->handle, SPA_INTERFACE_ID_CLOCK, &iface) >= 0) if (node->node->handle->get_interface (node->node->handle, SPA_INTERFACE_ID_CLOCK, &iface) >= 0)
priv->clock = iface; node->clock = iface;
break; break;
} }
default: default:
@ -1274,10 +1274,11 @@ pinos_node_link (PinosNode *output_node,
else else
goto no_input_ports; goto no_input_ports;
if (output_node->priv->clock) input_node->live = output_node->live;
input_node->priv->clock = output_node->priv->clock; if (output_node->clock)
input_node->clock = output_node->clock;
g_debug ("node %p: clock %p", output_node, output_node->priv->clock); g_debug ("node %p: clock %p", output_node, output_node->clock);
pl = g_object_new (PINOS_TYPE_LINK, pl = g_object_new (PINOS_TYPE_LINK,
"daemon", priv->daemon, "daemon", priv->daemon,
"output-node", output_node, "output-node", output_node,

View file

@ -53,6 +53,9 @@ struct _PinosNode {
SpaNode *node; SpaNode *node;
bool live;
SpaClock *clock;
PinosNodePrivate *priv; PinosNodePrivate *priv;
}; };

View file

@ -39,7 +39,7 @@ struct _SpaQueue {
(q)->length = 0; \ (q)->length = 0; \
} while (0); } while (0);
#define SPA_QUEUE_PUSH_TAIL(q,t,i) \ #define SPA_QUEUE_PUSH_TAIL(q,t,next,i) \
do { \ do { \
if ((q)->tail) \ if ((q)->tail) \
((t*)(q)->tail)->next = (i); \ ((t*)(q)->tail)->next = (i); \
@ -49,7 +49,7 @@ struct _SpaQueue {
(q)->length++; \ (q)->length++; \
} while (0); } while (0);
#define SPA_QUEUE_POP_HEAD(q,t,i) \ #define SPA_QUEUE_POP_HEAD(q,t,next,i) \
do { \ do { \
if (((i) = (t*)((q)->head)) == NULL) \ if (((i) = (t*)((q)->head)) == NULL) \
break; \ break; \

View file

@ -570,7 +570,7 @@ spa_alsa_sink_node_port_push_input (SpaNode *node,
have_enough = true; have_enough = true;
continue; continue;
} }
SPA_QUEUE_PUSH_TAIL (&this->ready, SpaALSABuffer, &this->alloc_buffers[info[i].buffer_id]); SPA_QUEUE_PUSH_TAIL (&this->ready, SpaALSABuffer, next, &this->alloc_buffers[info[i].buffer_id]);
} }
info[i].status = SPA_RESULT_OK; info[i].status = SPA_RESULT_OK;
} }

View file

@ -301,7 +301,7 @@ mmap_read (SpaALSAState *state)
snd_pcm_status_get_htstamp (status, &htstamp); snd_pcm_status_get_htstamp (status, &htstamp);
now = (int64_t)htstamp.tv_sec * 1000000000ll + (int64_t)htstamp.tv_nsec; now = (int64_t)htstamp.tv_sec * 1000000000ll + (int64_t)htstamp.tv_nsec;
SPA_QUEUE_POP_HEAD (&state->free, SpaALSABuffer, b); SPA_QUEUE_POP_HEAD (&state->free, SpaALSABuffer, next, b);
if (b == NULL) { if (b == NULL) {
fprintf (stderr, "no more buffers\n"); fprintf (stderr, "no more buffers\n");
} else { } else {
@ -346,7 +346,7 @@ mmap_read (SpaALSAState *state)
d = SPA_BUFFER_DATAS (b->outbuf); d = SPA_BUFFER_DATAS (b->outbuf);
d[0].mem.size = avail * state->frame_size; d[0].mem.size = avail * state->frame_size;
SPA_QUEUE_PUSH_TAIL (&state->ready, SpaALSABuffer, b); SPA_QUEUE_PUSH_TAIL (&state->ready, SpaALSABuffer, next, b);
event.type = SPA_NODE_EVENT_TYPE_HAVE_OUTPUT; event.type = SPA_NODE_EVENT_TYPE_HAVE_OUTPUT;
event.size = sizeof (ho); event.size = sizeof (ho);

View file

@ -28,6 +28,11 @@
#include <spa/queue.h> #include <spa/queue.h>
#include <spa/audio/format.h> #include <spa/audio/format.h>
#define TIMESPEC_TO_TIME(ts) ((ts)->tv_sec * 1000000000ll + (ts)->tv_nsec)
#define SAMPLES_TO_TIME(this,s) ((s) * 1000000000ll / (this)->current_format.info.raw.rate)
#define BYTES_TO_SAMPLES(this,b) ((b)/(this)->bpf)
#define BYTES_TO_TIME(this,b) SAMPLES_TO_TIME(this, BYTES_TO_SAMPLES (this, b))
typedef struct _SpaAudioTestSrc SpaAudioTestSrc; typedef struct _SpaAudioTestSrc SpaAudioTestSrc;
typedef struct { typedef struct {
@ -56,13 +61,13 @@ struct _ATSBuffer {
struct _SpaAudioTestSrc { struct _SpaAudioTestSrc {
SpaHandle handle; SpaHandle handle;
SpaNode node; SpaNode node;
SpaClock clock;
SpaAudioTestSrcProps props[2]; SpaAudioTestSrcProps props[2];
SpaNodeEventCallback event_cb; SpaNodeEventCallback event_cb;
void *user_data; void *user_data;
SpaPollItem idle;
SpaPollItem timer; SpaPollItem timer;
SpaPollFd fds[1]; SpaPollFd fds[1];
struct itimerspec timerspec; struct itimerspec timerspec;
@ -228,6 +233,95 @@ send_have_output (SpaAudioTestSrc *this)
return SPA_RESULT_OK; return SPA_RESULT_OK;
} }
static SpaResult
fill_buffer (SpaAudioTestSrc *this, ATSBuffer *b)
{
uint8_t *p = b->ptr;
size_t i;
for (i = 0; i < b->size; i++) {
p[i] = rand();
}
this->sample_count += b->size / this->bpf;
this->elapsed_time = SAMPLES_TO_TIME (this, this->sample_count);
return SPA_RESULT_OK;
}
static int audiotestsrc_on_output (SpaPollNotifyData *data);
static SpaResult
update_poll_enabled (SpaAudioTestSrc *this, bool enabled)
{
SpaNodeEvent event;
if (this->event_cb) {
event.type = SPA_NODE_EVENT_TYPE_UPDATE_POLL;
this->timer.enabled = enabled;
if (this->props[1].live) {
if (enabled) {
uint64_t next_time = this->start_time + this->elapsed_time;
fprintf (stderr, "%"PRIu64"\n", next_time);
this->timerspec.it_value.tv_sec = next_time / 1000000000;
this->timerspec.it_value.tv_nsec = next_time % 1000000000;
}
else {
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 0;
}
timerfd_settime (this->fds[0].fd, TFD_TIMER_ABSTIME, &this->timerspec, NULL);
this->timer.fds = this->fds;
this->timer.n_fds = 1;
this->timer.idle_cb = NULL;
this->timer.after_cb = audiotestsrc_on_output;
} else {
this->timer.fds = NULL;
this->timer.n_fds = 0;
this->timer.idle_cb = audiotestsrc_on_output;
this->timer.after_cb = NULL;
}
event.data = &this->timer;
event.size = sizeof (this->timer);
this->event_cb (&this->node, &event, this->user_data);
}
return SPA_RESULT_OK;
}
static int
audiotestsrc_on_output (SpaPollNotifyData *data)
{
SpaAudioTestSrc *this = data->user_data;
ATSBuffer *b;
SPA_QUEUE_POP_HEAD (&this->empty, ATSBuffer, next, b);
fprintf (stderr, "on_output %p\n", b);
if (b == NULL) {
update_poll_enabled (this, false);
return 0;
}
fill_buffer (this, b);
if (this->props[1].live) {
uint64_t expirations, next_time;
if (read (this->fds[0].fd, &expirations, sizeof (uint64_t)) < sizeof (uint64_t))
perror ("read timerfd");
next_time = this->start_time + this->elapsed_time;
this->timerspec.it_value.tv_sec = next_time / 1000000000;
this->timerspec.it_value.tv_nsec = next_time % 1000000000;
timerfd_settime (this->fds[0].fd, TFD_TIMER_ABSTIME, &this->timerspec, NULL);
}
b->next = NULL;
SPA_QUEUE_PUSH_TAIL (&this->ready, ATSBuffer, next, b);
send_have_output (this);
return 0;
}
static void static void
update_state (SpaAudioTestSrc *this, SpaNodeState state) update_state (SpaAudioTestSrc *this, SpaNodeState state)
{ {
@ -248,37 +342,6 @@ update_state (SpaAudioTestSrc *this, SpaNodeState state)
} }
} }
static SpaResult
update_poll_enabled (SpaAudioTestSrc *this, bool enabled)
{
SpaNodeEvent event;
if (this->event_cb) {
event.type = SPA_NODE_EVENT_TYPE_UPDATE_POLL;
if (this->props[1].live) {
this->timer.enabled = enabled;
if (enabled) {
uint64_t next_time = this->start_time + this->elapsed_time;
this->timerspec.it_value.tv_sec = next_time / 1000000000;
this->timerspec.it_value.tv_nsec = next_time % 1000000000;
}
else {
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 0;
}
timerfd_settime (this->fds[0].fd, TFD_TIMER_ABSTIME, &this->timerspec, NULL);
event.data = &this->timer;
event.size = sizeof (this->timer);
} else {
this->idle.enabled = enabled;
event.data = &this->idle;
event.size = sizeof (this->idle);
}
this->event_cb (&this->node, &event, this->user_data);
}
return SPA_RESULT_OK;
}
static SpaResult static SpaResult
spa_audiotestsrc_node_send_command (SpaNode *node, spa_audiotestsrc_node_send_command (SpaNode *node,
SpaNodeCommand *command) SpaNodeCommand *command)
@ -308,7 +371,7 @@ spa_audiotestsrc_node_send_command (SpaNode *node,
return SPA_RESULT_OK; return SPA_RESULT_OK;
clock_gettime (CLOCK_MONOTONIC, &now); clock_gettime (CLOCK_MONOTONIC, &now);
this->start_time = now.tv_sec * 1000000000ll + now.tv_nsec; this->start_time = TIMESPEC_TO_TIME (&now);
this->elapsed_time = 0; this->elapsed_time = 0;
this->started = true; this->started = true;
@ -356,11 +419,8 @@ spa_audiotestsrc_node_set_event_callback (SpaNode *node,
if (event_cb == NULL && this->event_cb) { if (event_cb == NULL && this->event_cb) {
event.type = SPA_NODE_EVENT_TYPE_REMOVE_POLL; event.type = SPA_NODE_EVENT_TYPE_REMOVE_POLL;
if (this->props[1].live)
event.data = &this->timer; event.data = &this->timer;
else event.size = sizeof (this->timer);
event.data = &this->idle;
event.size = sizeof (this->idle);
this->event_cb (&this->node, &event, this->user_data); this->event_cb (&this->node, &event, this->user_data);
} }
@ -369,11 +429,8 @@ spa_audiotestsrc_node_set_event_callback (SpaNode *node,
if (this->event_cb) { if (this->event_cb) {
event.type = SPA_NODE_EVENT_TYPE_ADD_POLL; event.type = SPA_NODE_EVENT_TYPE_ADD_POLL;
if (this->props[1].live)
event.data = &this->timer; event.data = &this->timer;
else event.size = sizeof (this->timer);
event.data = &this->idle;
event.size = sizeof (this->idle);
this->event_cb (&this->node, &event, this->user_data); this->event_cb (&this->node, &event, this->user_data);
} }
return SPA_RESULT_OK; return SPA_RESULT_OK;
@ -508,14 +565,13 @@ spa_audiotestsrc_node_port_set_format (SpaNode *node,
if ((res = spa_format_audio_parse (format, &this->current_format)) < 0) if ((res = spa_format_audio_parse (format, &this->current_format)) < 0)
return res; return res;
this->bpf = (2 * this->current_format.info.raw.channels);
this->have_format = true; this->have_format = true;
} }
if (this->have_format) { if (this->have_format) {
this->info.maxbuffering = -1; this->info.maxbuffering = -1;
this->info.latency = -1; this->info.latency = BYTES_TO_TIME (this, 1024);
this->bpf = (2 * this->current_format.info.raw.channels);
this->info.n_params = 1; this->info.n_params = 1;
this->info.params = this->params; this->info.params = this->params;
@ -646,7 +702,7 @@ spa_audiotestsrc_node_port_use_buffers (SpaNode *node,
b->size = d[0].mem.size; b->size = d[0].mem.size;
b->next = NULL; b->next = NULL;
SPA_QUEUE_PUSH_TAIL (&this->empty, ATSBuffer, b); SPA_QUEUE_PUSH_TAIL (&this->empty, ATSBuffer, next, b);
} }
this->n_buffers = n_buffers; this->n_buffers = n_buffers;
this->have_buffers = true; this->have_buffers = true;
@ -716,9 +772,9 @@ spa_audiotestsrc_node_port_reuse_buffer (SpaNode *node,
b->outstanding = false; b->outstanding = false;
b->next = NULL; b->next = NULL;
SPA_QUEUE_PUSH_TAIL (&this->empty, ATSBuffer, b); SPA_QUEUE_PUSH_TAIL (&this->empty, ATSBuffer, next, b);
if (this->empty.length == 1) if (this->empty.length == 1 && !this->props[1].live)
update_poll_enabled (this, true); update_poll_enabled (this, true);
return SPA_RESULT_OK; return SPA_RESULT_OK;
@ -755,72 +811,6 @@ spa_audiotestsrc_node_port_push_input (SpaNode *node,
{ {
return SPA_RESULT_INVALID_PORT; return SPA_RESULT_INVALID_PORT;
} }
static SpaResult
fill_buffer (SpaAudioTestSrc *this, ATSBuffer *b)
{
uint8_t *p = b->ptr;
size_t i;
for (i = 0; i < b->size; i++) {
p[i] = rand();
}
this->sample_count += b->size / this->bpf;
this->elapsed_time = this->sample_count * 1000000000ll / this->current_format.info.raw.rate;
return SPA_RESULT_OK;
}
static int
audiotestsrc_idle (SpaPollNotifyData *data)
{
SpaAudioTestSrc *this = data->user_data;
ATSBuffer *empty;
SPA_QUEUE_POP_HEAD (&this->empty, ATSBuffer, empty);
if (!empty) {
update_poll_enabled (this, false);
return 0;
}
fill_buffer (this, empty);
empty->next = NULL;
SPA_QUEUE_PUSH_TAIL (&this->ready, ATSBuffer, empty);
send_have_output (this);
return 0;
}
static int
audiotestsrc_on_timer (SpaPollNotifyData *data)
{
SpaAudioTestSrc *this = data->user_data;
ATSBuffer *empty;
uint64_t expirations, next_time;
if (read (this->fds[0].fd, &expirations, sizeof (uint64_t)) < sizeof (uint64_t))
perror ("read timerfd");
SPA_QUEUE_POP_HEAD (&this->empty, ATSBuffer, empty);
if (empty == NULL)
return 0;
fill_buffer (this, empty);
next_time = this->start_time + this->elapsed_time;
this->timerspec.it_value.tv_sec = next_time / 1000000000;
this->timerspec.it_value.tv_nsec = next_time % 1000000000;
timerfd_settime (this->fds[0].fd, TFD_TIMER_ABSTIME, &this->timerspec, NULL);
empty->next = NULL;
SPA_QUEUE_PUSH_TAIL (&this->ready, ATSBuffer, empty);
send_have_output (this);
return 0;
}
static SpaResult static SpaResult
spa_audiotestsrc_node_port_pull_output (SpaNode *node, spa_audiotestsrc_node_port_pull_output (SpaNode *node,
unsigned int n_info, unsigned int n_info,
@ -850,7 +840,7 @@ spa_audiotestsrc_node_port_pull_output (SpaNode *node,
continue; continue;
} }
SPA_QUEUE_POP_HEAD (&this->ready, ATSBuffer, b); SPA_QUEUE_POP_HEAD (&this->ready, ATSBuffer, next, b);
if (b == NULL) { if (b == NULL) {
info[i].status = SPA_RESULT_UNEXPECTED; info[i].status = SPA_RESULT_UNEXPECTED;
have_error = true; have_error = true;
@ -903,6 +893,56 @@ static const SpaNode audiotestsrc_node = {
spa_audiotestsrc_node_port_push_event, spa_audiotestsrc_node_port_push_event,
}; };
static SpaResult
spa_audiotestsrc_clock_get_props (SpaClock *clock,
SpaProps **props)
{
return SPA_RESULT_NOT_IMPLEMENTED;
}
static SpaResult
spa_audiotestsrc_clock_set_props (SpaClock *clock,
const SpaProps *props)
{
return SPA_RESULT_NOT_IMPLEMENTED;
}
static SpaResult
spa_audiotestsrc_clock_get_time (SpaClock *clock,
int32_t *rate,
int64_t *ticks,
int64_t *monotonic_time)
{
struct timespec now;
uint64_t tnow;
if (clock == NULL || clock->handle == NULL)
return SPA_RESULT_INVALID_ARGUMENTS;
if (rate)
*rate = 1000000000;
clock_gettime (CLOCK_MONOTONIC, &now);
tnow = TIMESPEC_TO_TIME (&now);
if (ticks)
*ticks = tnow;
if (monotonic_time)
*monotonic_time = tnow;
return SPA_RESULT_OK;
}
static const SpaClock audiotestsrc_clock = {
NULL,
sizeof (SpaClock),
NULL,
SPA_CLOCK_STATE_STOPPED,
spa_audiotestsrc_clock_get_props,
spa_audiotestsrc_clock_set_props,
spa_audiotestsrc_clock_get_time,
};
static SpaResult static SpaResult
spa_audiotestsrc_get_interface (SpaHandle *handle, spa_audiotestsrc_get_interface (SpaHandle *handle,
uint32_t interface_id, uint32_t interface_id,
@ -919,6 +959,9 @@ spa_audiotestsrc_get_interface (SpaHandle *handle,
case SPA_INTERFACE_ID_NODE: case SPA_INTERFACE_ID_NODE:
*interface = &this->node; *interface = &this->node;
break; break;
case SPA_INTERFACE_ID_CLOCK:
*interface = &this->clock;
break;
default: default:
return SPA_RESULT_UNKNOWN_INTERFACE; return SPA_RESULT_UNKNOWN_INTERFACE;
} }
@ -928,6 +971,15 @@ spa_audiotestsrc_get_interface (SpaHandle *handle,
static SpaResult static SpaResult
audiotestsrc_clear (SpaHandle *handle) audiotestsrc_clear (SpaHandle *handle)
{ {
SpaAudioTestSrc *this;
if (handle == NULL)
return SPA_RESULT_INVALID_ARGUMENTS;
this = (SpaAudioTestSrc *) handle;
close (this->fds[0].fd);
return SPA_RESULT_OK; return SPA_RESULT_OK;
} }
@ -947,6 +999,8 @@ audiotestsrc_init (const SpaHandleFactory *factory,
this = (SpaAudioTestSrc *) handle; this = (SpaAudioTestSrc *) handle;
this->node = audiotestsrc_node; this->node = audiotestsrc_node;
this->node.handle = handle; this->node.handle = handle;
this->clock = audiotestsrc_clock;
this->clock.handle = handle;
this->props[1].props.n_prop_info = PROP_ID_LAST; this->props[1].props.n_prop_info = PROP_ID_LAST;
this->props[1].props.prop_info = prop_info; this->props[1].props.prop_info = prop_info;
reset_audiotestsrc_props (&this->props[1]); reset_audiotestsrc_props (&this->props[1]);
@ -954,15 +1008,6 @@ audiotestsrc_init (const SpaHandleFactory *factory,
SPA_QUEUE_INIT (&this->empty); SPA_QUEUE_INIT (&this->empty);
SPA_QUEUE_INIT (&this->ready); SPA_QUEUE_INIT (&this->ready);
this->idle.id = 0;
this->idle.enabled = false;
this->idle.fds = NULL;
this->idle.n_fds = 0;
this->idle.idle_cb = audiotestsrc_idle;
this->idle.before_cb = NULL;
this->idle.after_cb = NULL;
this->idle.user_data = this;
this->fds[0].fd = timerfd_create (CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); this->fds[0].fd = timerfd_create (CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
this->fds[0].events = POLLIN | POLLPRI | POLLERR; this->fds[0].events = POLLIN | POLLPRI | POLLERR;
this->fds[0].revents = 0; this->fds[0].revents = 0;
@ -973,11 +1018,9 @@ audiotestsrc_init (const SpaHandleFactory *factory,
this->timer.id = 0; this->timer.id = 0;
this->timer.enabled = false; this->timer.enabled = false;
this->timer.fds = this->fds;
this->timer.n_fds = 1;
this->timer.idle_cb = NULL; this->timer.idle_cb = NULL;
this->timer.before_cb = NULL; this->timer.before_cb = NULL;
this->timer.after_cb = audiotestsrc_on_timer; this->timer.after_cb = NULL;
this->timer.user_data = this; this->timer.user_data = this;
this->info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS | this->info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS |
@ -998,6 +1041,10 @@ static const SpaInterfaceInfo audiotestsrc_interfaces[] =
SPA_INTERFACE_ID_NODE_NAME, SPA_INTERFACE_ID_NODE_NAME,
SPA_INTERFACE_ID_NODE_DESCRIPTION, SPA_INTERFACE_ID_NODE_DESCRIPTION,
}, },
{ SPA_INTERFACE_ID_CLOCK,
SPA_INTERFACE_ID_CLOCK_NAME,
SPA_INTERFACE_ID_CLOCK_DESCRIPTION,
},
}; };
static SpaResult static SpaResult

View file

@ -0,0 +1,143 @@
/* Spa Video Test Source
* Copyright (C) 2016 Axis Communications AB
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#define PIXEL_SIZE 3
#define GET_IMAGE_WIDTH(this) this->current_format.info.raw.size.width
#define GET_IMAGE_HEIGHT(this) this->current_format.info.raw.size.height
enum
{
GRAY = 0,
YELLOW,
CYAN,
GREEN,
MAGENTA,
RED,
BLUE,
BLACK,
NEG_I,
WHITE,
POS_Q,
DARK_BLACK,
LIGHT_BLACK,
N_COLORS
};
struct pixel
{
char R;
char G;
char B;
};
static struct pixel colors[N_COLORS] =
{
{191, 191, 191}, /* GRAY */
{191, 191, 0}, /* YELLOW */
{0, 191, 191}, /* CYAN */
{0, 191, 0}, /* GREEN */
{191, 0, 191}, /* MAGENTA */
{191, 0, 0}, /* RED */
{0, 0, 191}, /* BLUE */
{19, 19, 19}, /* BLACK */
{0, 33, 76}, /* NEGATIVE I */
{255, 255, 255}, /* WHITE */
{49, 0, 107}, /* POSITIVE Q */
{9, 9, 9}, /* DARK BLACK */
{29, 29, 29}, /* LIGHT BLACK */
};
static void
draw_line (char *data, struct pixel *c, int w)
{
int i;
for (i = 0; i < w; i++) {
data[i * PIXEL_SIZE + 0] = c->R;
data[i * PIXEL_SIZE + 1] = c->G;
data[i * PIXEL_SIZE + 2] = c->B;
}
}
#define DRAW_LINE(data,line,offset,color,width) \
draw_line (data + (line * w + offset) * PIXEL_SIZE, colors + color, width);
static void
draw_smpte_snow (SpaVideoTestSrc *this, char *data)
{
int h, w;
int y1, y2;
int i, j;
w = GET_IMAGE_WIDTH (this);
h = GET_IMAGE_HEIGHT (this);
y1 = 2 * h / 3;
y2 = 3 * h / 4;
for (i = 0; i < y1; i++) {
for (j = 0; j < 7; j++) {
int x1 = j * w / 7;
int x2 = (j + 1) * w / 7;
DRAW_LINE (data, i, x1, j, x2 - x1);
}
}
for (i = y1; i < y2; i++) {
for (j = 0; j < 7; j++) {
int x1 = j * w / 7;
int x2 = (j + 1) * w / 7;
int c = (j & 1) ? BLACK : BLUE - j;
DRAW_LINE (data, i, x1, c, x2 - x1);
}
}
for (i = y2; i < h; i++) {
int x = 0;
/* negative I */
DRAW_LINE (data, i, x, NEG_I, w / 6);
x += w / 6;
/* white */
DRAW_LINE (data, i, x, WHITE, w / 6);
x += w / 6;
/* positive Q */
DRAW_LINE (data, i, x, POS_Q, w / 6);
x += w / 6;
/* pluge */
DRAW_LINE (data, i, x, DARK_BLACK, w / 12);
x += w / 12;
DRAW_LINE (data, i, x, BLACK, w / 12);
x += w / 12;
DRAW_LINE (data, i, x, LIGHT_BLACK, w / 12);
x += w / 12;
/* war of the ants (a.k.a. snow) */
for (j = x; j < w; j++) {
unsigned char r = rand ();
data[(i * w + j) * PIXEL_SIZE + 0] = r;
data[(i * w + j) * PIXEL_SIZE + 1] = r;
data[(i * w + j) * PIXEL_SIZE + 2] = r;
}
}
}

File diff suppressed because it is too large Load diff