From 3511430f841a5bdc2745b81165222522d24dfd1e Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 12 Oct 2012 01:13:17 +0000 Subject: [PATCH] Introducing the "video" plug-in (not functional yet) --- Makefile | 1 + src/plugins/Makefile | 16 ++- src/plugins/project.conf | 9 +- src/plugins/video.c | 206 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 228 insertions(+), 4 deletions(-) create mode 100644 src/plugins/video.c diff --git a/Makefile b/Makefile index 1da3422..62cf8d9 100644 --- a/Makefile +++ b/Makefile @@ -105,6 +105,7 @@ dist: $(PACKAGE)-$(VERSION)/src/plugins/systray.c \ $(PACKAGE)-$(VERSION)/src/plugins/template.c \ $(PACKAGE)-$(VERSION)/src/plugins/ussd.c \ + $(PACKAGE)-$(VERSION)/src/plugins/video.c \ $(PACKAGE)-$(VERSION)/src/plugins/Makefile \ $(PACKAGE)-$(VERSION)/src/plugins/project.conf \ $(PACKAGE)-$(VERSION)/src/plugins/16x16/Makefile \ diff --git a/src/plugins/Makefile b/src/plugins/Makefile index 76bda5f..7705e5b 100644 --- a/src/plugins/Makefile +++ b/src/plugins/Makefile @@ -1,5 +1,5 @@ SUBDIRS = 16x16 24x24 32x32 48x48 -TARGETS = blacklist.so debug.so engineering.so gprs.so gps.so locker.so n900.so openmoko.so oss.so panel.so profiles.so smscrypt.so systray.so template.so ussd.so +TARGETS = blacklist.so debug.so engineering.so gprs.so gps.so locker.so n900.so openmoko.so oss.so panel.so profiles.so smscrypt.so systray.so template.so ussd.so video.so PREFIX = /usr/local DESTDIR = LIBDIR = $(PREFIX)/lib @@ -127,6 +127,13 @@ ussd_LDFLAGS = $(LDFLAGSF) $(LDFLAGS) ussd.so: $(ussd_OBJS) $(CCSHARED) -o ussd.so $(ussd_OBJS) $(ussd_LDFLAGS) +video_OBJS = video.o +video_CFLAGS = $(CPPFLAGSF) $(CPPFLAGS) $(CFLAGSF) $(CFLAGS) +video_LDFLAGS = $(LDFLAGSF) $(LDFLAGS) + +video.so: $(video_OBJS) + $(CCSHARED) -o video.so $(video_OBJS) $(video_LDFLAGS) + blacklist.o: blacklist.c ../../include/Phone.h $(CC) $(blacklist_CFLAGS) -c blacklist.c @@ -172,13 +179,16 @@ template.o: template.c ../../include/Phone.h ussd.o: ussd.c ../../include/Phone.h $(CC) $(ussd_CFLAGS) -c ussd.c +video.o: video.c ../../include/Phone.h + $(CC) $(video_CFLAGS) -c video.c + clean: @for i in $(SUBDIRS); do (cd $$i && $(MAKE) clean) || exit; done - $(RM) -- $(blacklist_OBJS) $(debug_OBJS) $(engineering_OBJS) $(gprs_OBJS) $(gps_OBJS) $(locker_OBJS) $(n900_OBJS) $(openmoko_OBJS) $(oss_OBJS) $(panel_OBJS) $(profiles_OBJS) $(smscrypt_OBJS) $(systray_OBJS) $(template_OBJS) $(ussd_OBJS) + $(RM) -- $(blacklist_OBJS) $(debug_OBJS) $(engineering_OBJS) $(gprs_OBJS) $(gps_OBJS) $(locker_OBJS) $(n900_OBJS) $(openmoko_OBJS) $(oss_OBJS) $(panel_OBJS) $(profiles_OBJS) $(smscrypt_OBJS) $(systray_OBJS) $(template_OBJS) $(ussd_OBJS) $(video_OBJS) distclean: @for i in $(SUBDIRS); do (cd $$i && $(MAKE) distclean) || exit; done - $(RM) -- $(blacklist_OBJS) $(debug_OBJS) $(engineering_OBJS) $(gprs_OBJS) $(gps_OBJS) $(locker_OBJS) $(n900_OBJS) $(openmoko_OBJS) $(oss_OBJS) $(panel_OBJS) $(profiles_OBJS) $(smscrypt_OBJS) $(systray_OBJS) $(template_OBJS) $(ussd_OBJS) + $(RM) -- $(blacklist_OBJS) $(debug_OBJS) $(engineering_OBJS) $(gprs_OBJS) $(gps_OBJS) $(locker_OBJS) $(n900_OBJS) $(openmoko_OBJS) $(oss_OBJS) $(panel_OBJS) $(profiles_OBJS) $(smscrypt_OBJS) $(systray_OBJS) $(template_OBJS) $(ussd_OBJS) $(video_OBJS) $(RM) -- $(TARGETS) install: $(TARGETS) diff --git a/src/plugins/project.conf b/src/plugins/project.conf index c298ea3..03c2408 100644 --- a/src/plugins/project.conf +++ b/src/plugins/project.conf @@ -1,5 +1,5 @@ subdirs=16x16,24x24,32x32,48x48 -targets=blacklist,debug,engineering,gprs,gps,locker,n900,openmoko,oss,panel,profiles,smscrypt,systray,template,ussd +targets=blacklist,debug,engineering,gprs,gps,locker,n900,openmoko,oss,panel,profiles,smscrypt,systray,template,ussd,video cppflags_force=-I ../../include cppflags= cflags_force=-W `pkg-config --cflags libSystem gtk+-2.0` @@ -133,3 +133,10 @@ install=$(LIBDIR)/Phone/plugins [ussd.c] depends=../../include/Phone.h + +[video] +type=plugin +sources=video.c + +[video.c] +depends=../../include/Phone.h diff --git a/src/plugins/video.c b/src/plugins/video.c new file mode 100644 index 0000000..15d2bbe --- /dev/null +++ b/src/plugins/video.c @@ -0,0 +1,206 @@ +/* $Id$ */ +/* Copyright (c) 2012 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Phone */ +/* This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ +/* TODO: + * - attempt to open the video device at regular intervals + * - display a window even if it was impossible to open a capture device */ + + + +#include +#ifdef __NetBSD__ +# include +#else +# include +#endif +#include +#include +#include +#include +#include +#include +#include "Phone.h" + + +/* Video */ +/* private */ +/* types */ +typedef struct _PhonePlugin +{ + PhonePluginHelper * helper; + + int fd; + guint source; + Buffer * buffer; + + /* widgets */ + GtkWidget * window; + GtkWidget * area; +} VideoPhonePlugin; + + +/* prototypes */ +/* plug-in */ +static VideoPhonePlugin * _video_init(PhonePluginHelper * helper); +static void _video_destroy(VideoPhonePlugin * video); + +/* useful */ +static int _video_ioctl(VideoPhonePlugin * video, unsigned long request, + void * data); + +/* callbacks */ +static gboolean _video_on_closex(gpointer data); +static gboolean _video_on_refresh(gpointer data); + + +/* public */ +/* variables */ +PhonePluginDefinition plugin = +{ + "Video", + "camera-video", + NULL, + _video_init, + _video_destroy, + NULL, + NULL +}; + + +/* private */ +/* functions */ +/* video_init */ +static VideoPhonePlugin * _video_init(PhonePluginHelper * helper) +{ + VideoPhonePlugin * video; + struct v4l2_capability cap; + struct v4l2_cropcap cropcap; + struct v4l2_crop crop; + struct v4l2_format format; + + if((video = object_new(sizeof(*video))) == NULL) + return NULL; + video->helper = helper; + /* FIXME let this be configurable */ + video->fd = open("/dev/video0", O_RDWR); + video->buffer = buffer_new(0, NULL); + video->source = 0; + video->window = NULL; + /* check for errors */ + if(video->buffer == NULL + || video->fd < 0 + || _video_ioctl(video, VIDIOC_QUERYCAP, &cap) == -1 + || (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0 + /* FIXME also implement mmap() and streaming */ + || (cap.capabilities & V4L2_CAP_READWRITE) == 0) + { + _video_destroy(video); + return NULL; + } + /* reset cropping */ + memset(&cropcap, 0, sizeof(cropcap)); + cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if(_video_ioctl(video, VIDIOC_CROPCAP, &cropcap) == 0) + { + /* reset to default */ + crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + crop.c = cropcap.defrect; + if(_video_ioctl(video, VIDIOC_S_CROP, &crop) == -1 + && errno == EINVAL) + helper->error(helper->phone, "Cropping not supported", + 0); + } + /* obtain the current format */ + if(_video_ioctl(video, VIDIOC_G_FMT, &format) == -1 + || buffer_set_size(video->buffer, + format.fmt.pix.sizeimage) != 0) + { + _video_destroy(video); + return NULL; + } + /* create the window */ + video->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size(GTK_WINDOW(video->window), + format.fmt.pix.width, format.fmt.pix.height); + gtk_window_set_resizable(GTK_WINDOW(video->window), FALSE); + g_signal_connect_swapped(video->window, "delete-event", G_CALLBACK( + _video_on_closex), video); + video->area = gtk_drawing_area_new(); + gtk_container_add(GTK_CONTAINER(video->window), video->area); + video->source = g_timeout_add(1000, _video_on_refresh, video); + return video; +} + + +/* video_destroy */ +static void _video_destroy(VideoPhonePlugin * video) +{ + if(video->window != NULL) + gtk_widget_destroy(video->window); + if(video->source != 0) + g_source_remove(video->source); + if(video->fd >= 0) + close(video->fd); + buffer_delete(video->buffer); + object_delete(video); +} + + +/* useful */ +/* video_ioctl */ +static int _video_ioctl(VideoPhonePlugin * video, unsigned long request, + void * data) +{ + int ret; + + for(;;) + if((ret = ioctl(video->fd, request, data)) != -1 + || errno != EINTR) + break; + return ret; +} + + +/* callbacks */ +/* video_on_closex */ +static gboolean _video_on_closex(gpointer data) +{ + VideoPhonePlugin * video = data; + + gtk_widget_hide(video->window); + if(video->source != 0) + g_source_remove(video->source); + video->source = 0; + return TRUE; +} + + +/* video_on_refresh */ +static gboolean _video_on_refresh(gpointer data) +{ + VideoPhonePlugin * video = data; + + /* FIXME no longer block on read() */ + if(read(video->fd, buffer_get_data(video->buffer), + buffer_get_size(video->buffer)) <= 0) + { + /* this error can be ignored */ + if(errno == EAGAIN) + return TRUE; + close(video->fd); + video->fd = -1; + return FALSE; + } + return TRUE; +}