From b8beebbef45b5f99b53256d6c0cc30c1785f8a90 Mon Sep 17 00:00:00 2001 From: Martin Lucina Date: Sat, 30 Jan 2010 16:34:24 +0100 Subject: Add primitive frame rate limiting Doesn't work quite as well as I would like it to, but until 0MQ has queue limits implemented it's useful if you want to test a large video stream on e.g. 802.11g wifi. Also added proper option handling using getopt(). --- zmq-camera.c | 69 +++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/zmq-camera.c b/zmq-camera.c index 1dd7ce3..717eade 100644 --- a/zmq-camera.c +++ b/zmq-camera.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,7 @@ struct sender_args_t { const char *endpoint; void *ctx; + int frame_rate; }; /* @@ -65,14 +67,13 @@ void *sender_thread (void *arg) sigset_t block_set; sender_args = (struct sender_args_t *)arg; - + /* Block SIGALRM in the sender thread since it's used for timers in the main thread */ sigemptyset (&block_set); sigaddset (&block_set, SIGALRM); pthread_sigmask (SIG_BLOCK, &block_set, NULL); - /* Create a ZMQ_PUB socket for sending video data and connect it to both an inproc endpoint for the local loopback view and bind to the endpoint specified by the user. */ @@ -207,6 +208,10 @@ void *sender_thread (void *arg) rc = zmq_send (s, &msg, 0); assert (rc == 0); zmq_msg_close (&msg); + + /* Limit to maximum frame rate if requested */ + if (sender_args->frame_rate > 1) + usleep (1000000 / sender_args->frame_rate); } return NULL; @@ -216,22 +221,28 @@ void *sender_thread (void *arg) * Print usage and exit. */ -void err_usage(void) +void err_usage(char *error) { const char usage[] = \ - "Usage: zmq-camera -r | -s ENDPOINT\n" \ + "Usage: zmq-camera [OPTIONS] -r | -s ENDPOINT\n" \ "Sends or receives video using 0MQ.\n" \ "\n" \ + "Mode:\n" \ " -r receive video from ENDPOINT\n" \ " -s send video to ENDPOINT\n" \ "\n" \ "ENDPOINT is any 0MQ endpoint valid for a ZMQ_PUB/ZMQ_SUB socket.\n" "\n" \ + "Options:\n" \ + " -f RATE limit maximum frame rate to RATE\n" \ + "\n" \ "Examples:\n" \ "\n" \ " zmq-camera -s tcp://eth0:5555\n" \ " zmq-camera -r tcp://eth0:5555\n"; - + + if (error) + fprintf (stderr, "Error: %s\n", error); fprintf (stderr, "%s", usage); exit (1); } @@ -251,7 +262,7 @@ int main (int argc, char *argv []) { void *ctx, *s; int rc; - int is_sender = 0; + int opt, opt_sender, opt_receiver, opt_frame_rate, frame_rate; char *endpoint = NULL; SDL_Surface *screen = NULL; SDL_Surface *rgb_surface = NULL; @@ -265,15 +276,33 @@ int main (int argc, char *argv []) char window_title[80]; /* Parse command line. */ - if (argc != 3) - err_usage(); - if (strcmp (argv [1], "-r") == 0) - is_sender = 0; - else if (strcmp (argv [1], "-s") == 0) - is_sender = 1; - else - err_usage(); - endpoint = argv [2]; + opt_sender = opt_receiver = opt_frame_rate = frame_rate = 0; + while ((opt = getopt (argc, argv, "rsf:")) != -1) { + switch (opt) { + case 'r': + opt_receiver = 1; + break; + case 's': + opt_sender = 1; + break; + case 'f': + opt_frame_rate = 1; + frame_rate = atoi (optarg); + if (frame_rate < 1) + err_usage ("RATE must be numeric and non-zero"); + printf ("Limiting frame rate to %d fps\n", frame_rate); + break; + default: + err_usage (NULL); + } + } + if (optind >= argc) + err_usage ("Expected ENDPOINT argument after options"); + if (opt_receiver && opt_sender) + err_usage ("Please specify either the -r or -s option"); + if ((opt_receiver == 0) && (opt_sender == 0)) + err_usage ("Please specify either the -r or -s option"); + endpoint = argv [optind]; /* Initialise 0MQ infrastructure for 2 application threads and a single I/O thread */ @@ -285,7 +314,7 @@ int main (int argc, char *argv []) otherwise connect to the endpoint the user specified. */ s = zmq_socket (ctx, ZMQ_SUB); assert (s); - if (is_sender) { + if (opt_sender) { rc = zmq_bind (s, local_camera); if (rc != 0) { fprintf (stderr, "zmq_bind (\"%s\"): %s\n", local_camera, @@ -295,7 +324,7 @@ int main (int argc, char *argv []) /* Start the sender thread after binding to the inproc: endpoint since this must exist for it to connect. */ - struct sender_args_t sender_args = {endpoint, ctx}; + struct sender_args_t sender_args = {endpoint, ctx, frame_rate}; pthread_t sender; rc = pthread_create (&sender, NULL, sender_thread, (void*) &sender_args); @@ -328,7 +357,7 @@ int main (int argc, char *argv []) assert (rc == 0); /* Intial window title is the endpoint we are receiving from */ - snprintf (window_title, 80, "%s", is_sender ? local_camera : endpoint); + snprintf (window_title, 80, "%s", opt_sender ? local_camera : endpoint); /* Display video until user asks to quit. */ while (!quit) { @@ -385,6 +414,8 @@ int main (int argc, char *argv []) SDL_Quit (); exit (1); } + /* Set initial window title */ + SDL_WM_SetCaption (window_title, window_title); sdl_initialised = 1; } @@ -413,7 +444,7 @@ int main (int argc, char *argv []) if (alarm_expired) { double received_mbps = (double)received_bps * 8 / (1<<20); snprintf (window_title, 80, "%s (%llu fps, %.2lf Mbps)", - is_sender ? local_camera : endpoint, + opt_sender ? local_camera : endpoint, (long long unsigned int) received_fps, received_mbps); SDL_WM_SetCaption (window_title, window_title); received_fps = received_bps = 0; -- cgit v1.2.3