/* Copyright (C) 2011, 2012 Matthias Vogelgesang (Karlsruhe Institute of Technology) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA */ #include "config.h" #include #include #include #include "uca-plugin-manager.h" #include "uca-camera.h" #include "uca-ring-buffer.h" #include "common.h" #ifdef HAVE_LIBTIFF #include #endif typedef struct { gint n_frames; gdouble duration; gchar *filename; #ifdef HAVE_LIBTIFF gboolean write_tiff; #endif } Options; static guint get_bytes_per_pixel (guint bits_per_pixel) { return bits_per_pixel > 8 ? 2 : 1; } #ifdef HAVE_LIBTIFF static void write_tiff (UcaRingBuffer *buffer, Options *opts, guint width, guint height, guint bits_per_pixel) { TIFF *tif; guint32 rows_per_strip; guint n_frames; guint bits_per_sample; gsize bytes_per_pixel; if (opts->filename) tif = TIFFOpen (opts->filename, "w"); else tif = TIFFOpen ("frames.tif", "w"); n_frames = uca_ring_buffer_get_num_blocks (buffer); rows_per_strip = TIFFDefaultStripSize (tif, (guint32) - 1); bytes_per_pixel = get_bytes_per_pixel (bits_per_pixel); bits_per_sample = bits_per_pixel > 8 ? 16 : 8; /* Write multi page TIFF file */ TIFFSetField (tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE); for (guint i = 0; i < n_frames; i++) { gpointer data; gsize offset = 0; data = uca_ring_buffer_get_read_pointer (buffer); TIFFSetField (tif, TIFFTAG_IMAGEWIDTH, width); TIFFSetField (tif, TIFFTAG_IMAGELENGTH, height); TIFFSetField (tif, TIFFTAG_BITSPERSAMPLE, bits_per_sample); TIFFSetField (tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); TIFFSetField (tif, TIFFTAG_SAMPLESPERPIXEL, 1); TIFFSetField (tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField (tif, TIFFTAG_ROWSPERSTRIP, rows_per_strip); TIFFSetField (tif, TIFFTAG_PAGENUMBER, i, n_frames); for (guint y = 0; y < height; y++, offset += width * bytes_per_pixel) TIFFWriteScanline (tif, data + offset, y, 0); TIFFWriteDirectory (tif); } TIFFClose (tif); } #endif static void write_raw (UcaRingBuffer *buffer, Options *opts) { guint n_frames; gsize size; size = uca_ring_buffer_get_block_size (buffer); n_frames = uca_ring_buffer_get_num_blocks (buffer); for (gint i = 0; i < n_frames; i++) { FILE *fp; gchar *filename; gpointer data; if (opts->filename) filename = g_strdup_printf ("%s-%08i.raw", opts->filename, i); else filename = g_strdup_printf ("frame-%08i.raw", i); fp = fopen(filename, "wb"); data = uca_ring_buffer_get_read_pointer (buffer); fwrite (data, size, 1, fp); fclose (fp); g_free (filename); } } static GError * record_frames (UcaCamera *camera, Options *opts) { guint roi_width; guint roi_height; guint bits; guint pixel_size; gsize size; gint n_frames; guint n_allocated; GTimer *timer; UcaRingBuffer *buffer; GError *error = NULL; gdouble last_printed; g_object_get (G_OBJECT (camera), "roi-width", &roi_width, "roi-height", &roi_height, "sensor-bitdepth", &bits, NULL); pixel_size = get_bytes_per_pixel (bits); size = roi_width * roi_height * pixel_size; n_allocated = opts->n_frames > 0 ? opts->n_frames : 256; buffer = uca_ring_buffer_new (size, n_allocated); timer = g_timer_new(); g_print("Start recording: %ix%i at %i bits/pixel\n", roi_width, roi_height, bits); uca_camera_start_recording(camera, &error); if (error != NULL) return error; n_frames = 0; g_timer_start(timer); last_printed = 0.0; while (1) { gdouble elapsed; uca_camera_grab (camera, uca_ring_buffer_get_write_pointer (buffer), &error); uca_ring_buffer_write_advance (buffer); if (error != NULL) return error; n_frames++; elapsed = g_timer_elapsed (timer, NULL); if (n_frames == opts->n_frames || (opts->duration > 0.0 && elapsed >= opts->duration)) break; if (elapsed - last_printed >= 1.0) { g_print ("Recorded %i frames at %.2f frames/s\n", n_frames, n_frames / elapsed); last_printed = elapsed; } } g_print ("Stop recording: %3.2f frames/s\n", n_frames / g_timer_elapsed (timer, NULL)); uca_camera_stop_recording (camera, &error); #ifdef HAVE_LIBTIFF if (opts->write_tiff) write_tiff (buffer, opts, roi_width, roi_height, bits); else write_raw (buffer, opts); #else write_raw (buffer, opts); #endif g_object_unref (buffer); g_timer_destroy (timer); return error; } int main (int argc, char *argv[]) { GOptionContext *context; UcaPluginManager *manager; UcaCamera *camera; GError *error = NULL; static Options opts = { .n_frames = -1, .duration = -1.0, .filename = NULL, #ifdef HAVE_LIBTIFF .write_tiff = FALSE, #endif }; static GOptionEntry entries[] = { { "num-frames", 'n', 0, G_OPTION_ARG_INT, &opts.n_frames, "Number of frames to acquire", "N" }, { "duration", 'd', 0, G_OPTION_ARG_DOUBLE, &opts.duration, "Duration in seconds", NULL }, { "output", 'o', 0, G_OPTION_ARG_STRING, &opts.filename, "Output file name", "FILE" }, #ifdef HAVE_LIBTIFF { "write-tiff", 't', 0, G_OPTION_ARG_NONE, &opts.write_tiff, "Write as TIFF", NULL }, #endif { NULL } }; #if !(GLIB_CHECK_VERSION (2, 36, 0)) g_type_init(); #endif manager = uca_plugin_manager_new (); context = uca_common_context_new (manager); g_option_context_add_main_entries (context, entries, NULL); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_print ("Failed parsing arguments: %s\n", error->message); goto cleanup_manager; } if (argc < 2) { g_print ("%s\n", g_option_context_get_help (context, TRUE, NULL)); goto cleanup_manager; } if (opts.n_frames < 0 && opts.duration < 0.0) { g_print ("You must specify at least one of --num-frames and --output.\n"); goto cleanup_manager; } camera = uca_common_get_camera (manager, argv[argc - 1], &error); if (camera == NULL) { g_print ("Error during initialization: %s\n", error->message); goto cleanup_manager; } error = record_frames (camera, &opts); if (error != NULL) g_print ("Error: %s\n", error->message); g_option_context_free (context); g_object_unref (camera); cleanup_manager: g_object_unref (manager); return error != NULL ? 1 : 0; }