summaryrefslogtreecommitdiff
path: root/modules/snapshot
diff options
context:
space:
mode:
Diffstat (limited to 'modules/snapshot')
-rw-r--r--modules/snapshot/module.mk11
-rw-r--r--modules/snapshot/png_vf.c188
-rw-r--r--modules/snapshot/png_vf.h6
-rw-r--r--modules/snapshot/snapshot.c90
4 files changed, 295 insertions, 0 deletions
diff --git a/modules/snapshot/module.mk b/modules/snapshot/module.mk
new file mode 100644
index 0000000..1be53bd
--- /dev/null
+++ b/modules/snapshot/module.mk
@@ -0,0 +1,11 @@
+#
+# module.mk
+#
+# Copyright (C) 2010 Creytiv.com
+#
+
+MOD := snapshot
+$(MOD)_SRCS += snapshot.c png_vf.c
+$(MOD)_LFLAGS += -lpng
+
+include mk/mod.mk
diff --git a/modules/snapshot/png_vf.c b/modules/snapshot/png_vf.c
new file mode 100644
index 0000000..d7f1f8a
--- /dev/null
+++ b/modules/snapshot/png_vf.c
@@ -0,0 +1,188 @@
+/**
+ * @file png_vf.c Write vidframe to a PNG-file
+ *
+ * Author: Doug Blewett
+ * Review: Alfred E. Heggestad
+ */
+#define _BSD_SOURCE 1
+#include <string.h>
+#include <time.h>
+#include <png.h>
+#include <re.h>
+#include <rem.h>
+#include <baresip.h>
+#include "png_vf.h"
+
+
+static char *png_filename(const struct tm *tmx, const char *name,
+ char *buf, unsigned int length);
+static void png_save_free(png_structp png_ptr, png_byte **png_row_pointers,
+ int png_height);
+
+
+int png_save_vidframe(const struct vidframe *vf, const char *path)
+{
+ png_byte **png_row_pointers = NULL;
+ png_byte *row;
+ const png_byte *p;
+ png_byte red, green, blue;
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ FILE *fp = NULL;
+ size_t x, y;
+ unsigned int width = vf->size.w & ~1;
+ unsigned int height = vf->size.h & ~1;
+ unsigned int bytes_per_pixel = 3; /* RGB format */
+ time_t tnow;
+ struct tm *tmx;
+ char filename_buf[64];
+ struct vidframe *f2 = NULL;
+ int err = 0;
+
+ tnow = time(NULL);
+ tmx = localtime(&tnow);
+
+ if (vf->fmt != VID_FMT_RGB32) {
+
+ err = vidframe_alloc(&f2, VID_FMT_RGB32, &vf->size);
+ if (err)
+ goto out;
+
+ vidconv(f2, vf, NULL);
+ vf = f2;
+ }
+
+ /* Initialize the write struct. */
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+ NULL, NULL, NULL);
+ if (png_ptr == NULL) {
+ err = ENOMEM;
+ goto out;
+ }
+
+ /* Initialize the info struct. */
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL) {
+ err = ENOMEM;
+ goto out;
+ }
+
+ /* Set up error handling. */
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ err = ENOMEM;
+ goto out;
+ }
+
+ /* Set image attributes. */
+ png_set_IHDR(png_ptr,
+ info_ptr,
+ width,
+ height,
+ 8,
+ PNG_COLOR_TYPE_RGB,
+ PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+
+ /* Initialize rows of PNG
+ * bytes_per_row = width * bytes_per_pixel;
+ */
+ png_row_pointers = png_malloc(png_ptr,
+ height * sizeof(png_byte *));
+
+ for (y = 0; y < height; ++y) {
+ png_row_pointers[y] =
+ (png_byte *) png_malloc(png_ptr,
+ width * sizeof(uint8_t) *
+ bytes_per_pixel);
+ }
+
+ p = vf->data[0];
+ for (y = 0; y < height; ++y) {
+
+ row = png_row_pointers[y];
+
+ for (x = 0; x < width; ++x) {
+
+ red = *p++;
+ green = *p++;
+ blue = *p++;
+
+ *row++ = blue;
+ *row++ = green;
+ *row++ = red;
+
+ ++p; /* skip alpha */
+ }
+ }
+
+ /* Write the image data. */
+ fp = fopen(png_filename(tmx, path,
+ filename_buf, sizeof(filename_buf)), "wb");
+ if (fp == NULL) {
+ err = errno;
+ goto out;
+ }
+
+ png_init_io(png_ptr, fp);
+ png_set_rows(png_ptr, info_ptr, png_row_pointers);
+ png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
+
+ info("png: wrote %s\n", filename_buf);
+
+ out:
+ /* Finish writing. */
+ mem_deref(f2);
+ png_save_free(png_ptr, png_row_pointers, height);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ if (fp)
+ fclose(fp);
+
+ return 0;
+}
+
+
+static void png_save_free(png_structp png_ptr, png_byte **png_row_pointers,
+ int png_height)
+{
+ int y;
+
+ /* Cleanup. */
+ if (png_height == 0 || png_row_pointers == NULL)
+ return;
+
+ for (y = 0; y < png_height; y++) {
+ png_free(png_ptr, png_row_pointers[y]);
+ }
+ png_free(png_ptr, png_row_pointers);
+}
+
+
+static char *png_filename(const struct tm *tmx, const char *name,
+ char *buf, unsigned int length)
+{
+ /*
+ * -2013-03-03-15-22-56.png - 24 chars
+ */
+ if (strlen(name) + 24 >= length) {
+ buf[0] = '\0';
+ return buf;
+ }
+
+ sprintf(buf, (tmx->tm_mon < 9 ? "%s-%d-0%d" : "%s-%d-%d"), name,
+ 1900 + tmx->tm_year, tmx->tm_mon + 1);
+
+ sprintf(buf + strlen(buf), (tmx->tm_mday < 10 ? "-0%d" : "-%d"),
+ tmx->tm_mday);
+
+ sprintf(buf + strlen(buf), (tmx->tm_hour < 10 ? "-0%d" : "-%d"),
+ tmx->tm_hour);
+
+ sprintf(buf + strlen(buf), (tmx->tm_min < 10 ? "-0%d" : "-%d"),
+ tmx->tm_min);
+
+ sprintf(buf + strlen(buf), (tmx->tm_sec < 10 ? "-0%d.png" : "-%d.png"),
+ tmx->tm_sec);
+
+ return buf;
+}
diff --git a/modules/snapshot/png_vf.h b/modules/snapshot/png_vf.h
new file mode 100644
index 0000000..17660cf
--- /dev/null
+++ b/modules/snapshot/png_vf.h
@@ -0,0 +1,6 @@
+/**
+ * @file png_vf.h
+ */
+
+
+int png_save_vidframe(const struct vidframe *vf, const char *path);
diff --git a/modules/snapshot/snapshot.c b/modules/snapshot/snapshot.c
new file mode 100644
index 0000000..b8a01de
--- /dev/null
+++ b/modules/snapshot/snapshot.c
@@ -0,0 +1,90 @@
+/**
+ * @file snapshot.c Snapshot Video-Filter
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <string.h>
+#include <re.h>
+#include <rem.h>
+#include <baresip.h>
+#include "png_vf.h"
+
+
+static bool flag_enc, flag_dec;
+
+
+static int encode(struct vidfilt_enc_st *st, struct vidframe *frame)
+{
+ (void)st;
+
+ if (!frame)
+ return 0;
+
+ if (flag_enc) {
+ flag_enc = false;
+ png_save_vidframe(frame, "snapshot-send");
+ }
+
+ return 0;
+}
+
+
+static int decode(struct vidfilt_dec_st *st, struct vidframe *frame)
+{
+ (void)st;
+
+ if (!frame)
+ return 0;
+
+ if (flag_dec) {
+ flag_dec = false;
+ png_save_vidframe(frame, "snapshot-recv");
+ }
+
+ return 0;
+}
+
+
+static int do_snapshot(struct re_printf *pf, void *arg)
+{
+ (void)pf;
+ (void)arg;
+
+ /* NOTE: not re-entrant */
+ flag_enc = flag_dec = true;
+
+ return 0;
+}
+
+
+static struct vidfilt snapshot = {
+ LE_INIT, "snapshot", NULL, encode, NULL, decode,
+};
+
+
+static const struct cmd cmdv[] = {
+ {'o', 0, "Take video snapshot", do_snapshot },
+};
+
+
+static int module_init(void)
+{
+ vidfilt_register(&snapshot);
+ return cmd_register(cmdv, ARRAY_SIZE(cmdv));
+}
+
+
+static int module_close(void)
+{
+ vidfilt_unregister(&snapshot);
+ cmd_unregister(cmdv);
+ return 0;
+}
+
+
+EXPORT_SYM const struct mod_export DECL_EXPORTS(snapshot) = {
+ "snapshot",
+ "vidfilt",
+ module_init,
+ module_close
+};