diff options
-rw-r--r-- | src/cameras/dummy.c | 248 | ||||
-rw-r--r-- | src/uca-cam.h | 35 | ||||
-rw-r--r-- | test/CMakeLists.txt | 2 | ||||
-rw-r--r-- | test/grab-async.c | 46 |
4 files changed, 240 insertions, 91 deletions
diff --git a/src/cameras/dummy.c b/src/cameras/dummy.c index ba95a67..0177c6a 100644 --- a/src/cameras/dummy.c +++ b/src/cameras/dummy.c @@ -1,19 +1,144 @@ - #include <stdlib.h> #include <string.h> +#define __USE_BSD +#include <unistd.h> +#undef __USE_BSD + +#include "config.h" #include "uca.h" #include "uca-cam.h" #include "uca-grabber.h" +#ifdef HAVE_PTHREADS +#include <pthread.h> +#endif + +/** + * User structure for the dummy camera. + */ typedef struct dummy_cam { uint32_t bitdepth; - uint32_t framerate; - char* buffer; + uint32_t frame_rate; +#ifdef HAVE_PTHREADS + pthread_t grab_thread; + bool thread_running; + char *buffer; +#endif } dummy_cam_t; + +static const char digits[10][20] = { + /* 0 */ + { 0x00, 0xff, 0xff, 0x00, + 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0x00 }, + /* 1 */ + { 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, + 0x00, 0x00, 0xff, 0x00, + 0x00, 0x00, 0xff, 0x00, + 0x00, 0x00, 0xff, 0x00 }, + /* 2 */ + { 0x00, 0xff, 0xff, 0x00, + 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff }, + /* 3 */ + { 0x00, 0xff, 0xff, 0x00, + 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0x00, + 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0x00 }, + /* 4 */ + { 0xff, 0x00, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff }, + /* 5 */ + { 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0x00 }, + /* 6 */ + { 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x00, + 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0x00 }, + /* 7 */ + { 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00 }, + /* 8 */ + { 0x00, 0xff, 0xff, 0x00, + 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0x00, + 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0x00 }, + /* 9 */ + { 0x00, 0xff, 0xff, 0x00, + 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0x00 } +}; + +const int DIGIT_WIDTH = 4; +const int DIGIT_HEIGHT = 5; + #define GET_DUMMY(uca) ((struct dummy_cam *)(uca->user)) #define set_void(p, type, value) { *((type *) p) = value; } +static void uca_dummy_print_number(char *buffer, int number, int x, int y, int width) +{ + for (int i = 0; i < DIGIT_WIDTH; i++) { + for (int j = 0; j < DIGIT_HEIGHT; j++) { + buffer[(y+j)*width + (x+i)] = digits[number][j*DIGIT_WIDTH+i]; + } + } +} + +static void uca_dummy_memcpy(struct uca_camera *cam, char *buffer) +{ + /* print current frame number */ + unsigned int number = cam->current_frame; + unsigned int divisor = 100000000; + int x = 10; + while (divisor > 1) { + uca_dummy_print_number(buffer, number / divisor, x, 10, cam->frame_width); + number = number % divisor; + divisor = divisor / 10; + x += 5; + } +} + +static void *uca_dummy_grab_thread(void *arg) +{ + struct uca_camera *cam = ((struct uca_camera *) arg); + struct dummy_cam *dc = GET_DUMMY(cam); + + const __useconds_t sleep_time = (unsigned int) 1000000.0f / dc->frame_rate; + + while (dc->thread_running) { + uca_dummy_memcpy(cam, dc->buffer); + cam->callback(cam->current_frame, dc->buffer); + cam->current_frame++; + usleep(sleep_time); + } + return NULL; +} + + +/* + * --- interface implementations ---------------------------------------------- + */ static uint32_t uca_dummy_set_property(struct uca_camera *cam, enum uca_property_ids property, void *data) { if (cam->state == UCA_CAM_RECORDING) @@ -28,6 +153,10 @@ static uint32_t uca_dummy_set_property(struct uca_camera *cam, enum uca_property cam->frame_height = *((uint32_t *) data); break; + case UCA_PROP_FRAMERATE: + GET_DUMMY(cam)->frame_rate = *((uint32_t *) data); + break; + default: return UCA_ERR_PROP_INVALID; } @@ -78,6 +207,15 @@ static uint32_t uca_dummy_get_property(struct uca_camera *cam, enum uca_property uint32_t uca_dummy_start_recording(struct uca_camera *cam) { + if (cam->callback != NULL) { +#ifdef HAVE_PTHREADS + struct dummy_cam *dc = GET_DUMMY(cam); + /* FIXME: handle return value */ + dc->thread_running = true; + dc->buffer = (char *) malloc(cam->frame_width * cam->frame_height); + pthread_create(&dc->grab_thread, NULL, &uca_dummy_grab_thread, cam); +#endif + } cam->current_frame = 0; cam->state = UCA_CAM_RECORDING; return UCA_NO_ERROR; @@ -85,106 +223,37 @@ uint32_t uca_dummy_start_recording(struct uca_camera *cam) uint32_t uca_dummy_stop_recording(struct uca_camera *cam) { + if (cam->callback != NULL) { + GET_DUMMY(cam)->thread_running = false; + free(GET_DUMMY(cam)->buffer); + } cam->state = UCA_CAM_ARMED; return UCA_NO_ERROR; } -static const char digits[10][20] = { - /* 0 */ - { 0x00, 0xff, 0xff, 0x00, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00 }, - /* 1 */ - { 0x00, 0x00, 0xff, 0x00, - 0x00, 0xff, 0xff, 0x00, - 0x00, 0x00, 0xff, 0x00, - 0x00, 0x00, 0xff, 0x00, - 0x00, 0x00, 0xff, 0x00 }, - /* 2 */ - { 0x00, 0xff, 0xff, 0x00, - 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, - 0x00, 0xff, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff }, - /* 3 */ - { 0x00, 0xff, 0xff, 0x00, - 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, - 0xff, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00 }, - /* 4 */ - { 0xff, 0x00, 0x00, 0x00, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff }, - /* 5 */ - { 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x00, - 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0x00 }, - /* 6 */ - { 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0x00, - 0xff, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00 }, - /* 7 */ - { 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, - 0x00, 0xff, 0x00, 0x00, - 0xff, 0x00, 0x00, 0x00 }, - /* 8 */ - { 0x00, 0xff, 0xff, 0x00, - 0xff, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00, - 0xff, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00 }, - /* 9 */ - { 0x00, 0xff, 0xff, 0x00, - 0xff, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0x00 } -}; - -static void uca_dummy_print_number(struct dummy_cam *dummy, int number, int x, int y, int width) +uint32_t uca_dummy_register_callback(struct uca_camera *cam, uca_cam_grab_callback cb) { - const int digit_width = 4; - const int digit_height = 5; - char *buffer = dummy->buffer; - for (int i = 0; i < digit_width; i++) { - for (int j = 0; j < digit_height; j++) { - buffer[(y+j)*width + (x+i)] = digits[number][j*digit_width+i]; - } - } + if (cam->callback == NULL) + cam->callback = cb; + else + return UCA_ERR_GRABBER_CALLBACK_ALREADY_REGISTERED; + + return UCA_NO_ERROR; } uint32_t uca_dummy_grab(struct uca_camera *cam, char *buffer) { - struct dummy_cam *dummy = GET_DUMMY(cam); - dummy->buffer = buffer; + if (cam->callback != NULL) + return UCA_ERR_GRABBER_CALLBACK_ALREADY_REGISTERED; - /* print current frame number */ - unsigned int number = cam->current_frame; - unsigned int divisor = 100000000; - int x = 10; - while (divisor > 1) { - uca_dummy_print_number(dummy, number / divisor, x, 10, cam->frame_width); - number = number % divisor; - divisor = divisor / 10; - x += 5; - } + uca_dummy_memcpy(cam, buffer); cam->current_frame++; return UCA_NO_ERROR; } static uint32_t uca_dummy_destroy(struct uca_camera *cam) { + free(GET_DUMMY(cam)); return UCA_NO_ERROR; } @@ -198,6 +267,8 @@ uint32_t uca_dummy_init(struct uca_camera **cam, struct uca_grabber *grabber) uca->start_recording = &uca_dummy_start_recording; uca->stop_recording = &uca_dummy_stop_recording; uca->grab = &uca_dummy_grab; + uca->register_callback = &uca_dummy_register_callback; + uca->state = UCA_CAM_CONFIGURABLE; uca->frame_width = 320; uca->frame_height = 240; @@ -205,8 +276,7 @@ uint32_t uca_dummy_init(struct uca_camera **cam, struct uca_grabber *grabber) struct dummy_cam *dummy_cam = (struct dummy_cam *) malloc(sizeof(struct dummy_cam)); dummy_cam->bitdepth = 8; - dummy_cam->framerate = 100; - dummy_cam->buffer = NULL; + dummy_cam->frame_rate = 100; uca->user = dummy_cam; *cam = uca; diff --git a/src/uca-cam.h b/src/uca-cam.h index 822f011..ca80ec9 100644 --- a/src/uca-cam.h +++ b/src/uca-cam.h @@ -129,6 +129,28 @@ typedef uint32_t (*uca_cam_start_recording) (struct uca_camera *cam); typedef uint32_t (*uca_cam_stop_recording) (struct uca_camera *cam); /** + * Function pointer to a grab callback. + * + * Register such a callback function with uca_cam_register_callback() to + * receive data as soon as it is delivered. + * + * \param[in] image_number Current frame number + * + * \param[in] buffer Image data + */ +typedef void (*uca_cam_grab_callback) (uint32_t image_number, void *buffer); + +/** + * Register callback for given frame grabber. To actually start receiving + * frames, call uca_grabber_acquire(). + * + * \param[in] grabber The grabber for which the callback should be installed + * + * \param[in] cb Callback function for when a frame arrived + */ +typedef uint32_t (*uca_cam_register_callback) (struct uca_camera *cam, uca_cam_grab_callback cb); + +/** * \brief Grab one image from the camera * * The grabbing involves a memory copy because we might have to decode the image @@ -182,6 +204,13 @@ typedef struct uca_camera { */ uca_cam_grab grab; + /** + * Method to register an frame acquisition callback. + * + * \see uca_cam_register_callback + */ + uca_cam_register_callback register_callback; + /* Private */ /** * Method to close the camera. @@ -189,11 +218,13 @@ typedef struct uca_camera { */ uca_cam_destroy destroy; - struct uca_grabber *grabber; /**< grabber associated with this camera */ - enum uca_cam_state state; /**< camera state */ + /* private */ + struct uca_grabber *grabber; /**< grabber associated with this camera */ + enum uca_cam_state state; /**< camera state */ uint32_t frame_width; /**< current frame width */ uint32_t frame_height; /**< current frame height */ uint32_t current_frame; /**< last grabbed frame number */ + uca_cam_grab_callback callback; void *user; /**< private user data to be used by the camera driver */ } uca_camera_t; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3ea7414..287f9ea 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -15,9 +15,11 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/control.glade # --- Build targets ----------------------------------------------------------- add_executable(enum enum.c) add_executable(grab grab.c) +add_executable(grab-async grab-async.c) target_link_libraries(enum uca) target_link_libraries(grab uca) +target_link_libraries(grab-async uca) if (GTK2_FOUND) include_directories(${GTK2_INCLUDE_DIRS}) diff --git a/test/grab-async.c b/test/grab-async.c new file mode 100644 index 0000000..8086d92 --- /dev/null +++ b/test/grab-async.c @@ -0,0 +1,46 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "uca.h" +#include "uca-cam.h" + +void grab_callback(uint32_t image_number, void *buffer) +{ + printf("got picture number %i\n", image_number); +} + +int main(int argc, char *argv[]) +{ + struct uca *u = uca_init(NULL); + if (u == NULL) { + printf("Couldn't find a camera\n"); + return 1; + } + + /* take first camera */ + struct uca_camera *cam = u->cameras; + + uint32_t val = 1; + cam->set_property(cam, UCA_PROP_EXPOSURE, &val); + val = 0; + cam->set_property(cam, UCA_PROP_DELAY, &val); + val = 10; + cam->set_property(cam, UCA_PROP_FRAMERATE, &val); + + uint32_t width, height, bits; + cam->get_property(cam, UCA_PROP_WIDTH, &width, 0); + cam->get_property(cam, UCA_PROP_HEIGHT, &height, 0); + cam->get_property(cam, UCA_PROP_BITDEPTH, &bits, 0); + + uca_cam_alloc(cam, 10); + + cam->register_callback(cam, &grab_callback); + cam->start_recording(cam); + printf("waiting for 10 seconds\n"); + sleep(10); + cam->stop_recording(cam); + + uca_destroy(u); + return 0; +} |