Open the video device at regular intervals (every 10 seconds)

This commit is contained in:
Pierre Pronchery 2014-01-06 00:18:16 -06:00
parent 968a9353be
commit 5fdad562a9

View File

@ -13,7 +13,6 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* TODO: /* TODO:
* - attempt to open the video device at regular intervals
* - display a window even if it was impossible to open a capture device * - display a window even if it was impossible to open a capture device
* - re-use code from the Camera project instead */ * - re-use code from the Camera project instead */
@ -85,6 +84,9 @@ static void _video_destroy(VideoPhonePlugin * video);
static int _video_ioctl(VideoPhonePlugin * video, unsigned long request, static int _video_ioctl(VideoPhonePlugin * video, unsigned long request,
void * data); void * data);
static void _video_start(VideoPhonePlugin * video);
static void _video_stop(VideoPhonePlugin * video);
/* callbacks */ /* callbacks */
static gboolean _video_on_can_read(GIOChannel * channel, GIOCondition condition, static gboolean _video_on_can_read(GIOChannel * channel, GIOCondition condition,
gpointer data); gpointer data);
@ -93,6 +95,7 @@ static gboolean _video_on_drawing_area_configure(GtkWidget * widget,
GdkEventConfigure * event, gpointer data); GdkEventConfigure * event, gpointer data);
static gboolean _video_on_drawing_area_expose(GtkWidget * widget, static gboolean _video_on_drawing_area_expose(GtkWidget * widget,
GdkEventExpose * event, gpointer data); GdkEventExpose * event, gpointer data);
static gboolean _video_on_open(gpointer data);
static gboolean _video_on_refresh(gpointer data); static gboolean _video_on_refresh(gpointer data);
@ -113,8 +116,6 @@ PhonePluginDefinition plugin =
/* private */ /* private */
/* functions */ /* functions */
/* video_init */ /* video_init */
static int _open_setup(VideoPhonePlugin * video);
static VideoPhonePlugin * _video_init(PhonePluginHelper * helper) static VideoPhonePlugin * _video_init(PhonePluginHelper * helper)
{ {
VideoPhonePlugin * video; VideoPhonePlugin * video;
@ -149,17 +150,11 @@ static VideoPhonePlugin * _video_init(PhonePluginHelper * helper)
video->gc = NULL; video->gc = NULL;
video->window = NULL; video->window = NULL;
/* check for errors */ /* check for errors */
if((video->device = string_new(device)) == NULL if((video->device = string_new(device)) == NULL)
|| (video->fd = open(device, O_RDWR)) < 0)
{ {
helper->error(helper->phone, helper->error(helper->phone,
"Could not open the video capture device", 1); "Could not initialize the video capture device",
_video_destroy(video); 1);
return NULL;
}
if(_open_setup(video) != 0)
{
helper->error(helper->phone, error_get(), 1);
_video_destroy(video); _video_destroy(video);
return NULL; return NULL;
} }
@ -180,11 +175,199 @@ static VideoPhonePlugin * _video_init(PhonePluginHelper * helper)
video->format.fmt.pix.height); video->format.fmt.pix.height);
gtk_container_add(GTK_CONTAINER(video->window), video->area); gtk_container_add(GTK_CONTAINER(video->window), video->area);
gtk_widget_show_all(video->window); gtk_widget_show_all(video->window);
if(_video_on_refresh(video) == TRUE) _video_start(video);
video->source = g_timeout_add(1000, _video_on_refresh, video);
return video; return video;
} }
/* video_destroy */
static void _video_destroy(VideoPhonePlugin * video)
{
_video_stop(video);
if(video->channel != NULL)
{
/* XXX we ignore errors at this point */
g_io_channel_shutdown(video->channel, TRUE, NULL);
#if 0
/* FIXME seems to cause a crash in the original code */
g_object_unref(video->channel);
#endif
}
if(video->pixmap != NULL)
g_object_unref(video->pixmap);
if(video->gc != NULL)
g_object_unref(video->gc);
if(video->window != NULL)
gtk_widget_destroy(video->window);
if(video->fd >= 0)
close(video->fd);
if((char *)video->rgb_buffer != video->raw_buffer)
free(video->rgb_buffer);
free(video->raw_buffer);
string_delete(video->device);
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;
}
/* video_start */
static void _video_start(VideoPhonePlugin * video)
{
if(video->source != 0)
return;
video->source = g_idle_add(_video_on_open, video);
}
/* video_stop */
static void _video_stop(VideoPhonePlugin * video)
{
if(video->source != 0)
g_source_remove(video->source);
video->source = 0;
}
/* callbacks */
/* video_on_can_read */
static gboolean _video_on_can_read(GIOChannel * channel, GIOCondition condition,
gpointer data)
{
VideoPhonePlugin * video = data;
PhonePluginHelper * helper = video->helper;
ssize_t s;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif
if(channel != video->channel || condition != G_IO_IN)
return FALSE;
if((s = read(video->fd, video->raw_buffer, video->raw_buffer_cnt))
<= 0)
{
/* this error can be ignored */
if(errno == EAGAIN)
return TRUE;
close(video->fd);
video->fd = -1;
helper->error(helper->phone, strerror(errno), 1);
video->source = 0;
return FALSE;
}
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() %lu %ld\n", __func__,
video->raw_buffer_cnt, s);
#endif
video->source = g_idle_add(_video_on_refresh, video);
return FALSE;
}
/* video_on_closex */
static gboolean _video_on_closex(gpointer data)
{
VideoPhonePlugin * video = data;
gtk_widget_hide(video->window);
_video_stop(video);
return TRUE;
}
/* video_on_drawing_area_configure */
static gboolean _video_on_drawing_area_configure(GtkWidget * widget,
GdkEventConfigure * event, gpointer data)
{
/* XXX this code is inspired from GQcam */
VideoPhonePlugin * video = data;
GtkAllocation * allocation = &video->area_allocation;
if(video->pixmap != NULL)
g_object_unref(video->pixmap);
/* FIXME requires Gtk+ 2.18 */
gtk_widget_get_allocation(widget, allocation);
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() %dx%d\n", __func__, allocation->width,
allocation->height);
#endif
video->pixmap = gdk_pixmap_new(widget->window, allocation->width,
allocation->height, -1);
/* FIXME is it not better to scale the previous pixmap for now? */
gdk_draw_rectangle(video->pixmap, video->gc, TRUE, 0, 0,
allocation->width, allocation->height);
return TRUE;
}
/* video_on_drawing_area_expose */
static gboolean _video_on_drawing_area_expose(GtkWidget * widget,
GdkEventExpose * event, gpointer data)
{
/* XXX this code is inspired from GQcam */
VideoPhonePlugin * video = data;
gdk_draw_pixmap(widget->window, video->gc, video->pixmap,
event->area.x, event->area.y,
event->area.x, event->area.y,
event->area.width, event->area.height);
return FALSE;
}
/* video_on_open */
static int _open_setup(VideoPhonePlugin * video);
static gboolean _video_on_open(gpointer data)
{
VideoPhonePlugin * video = data;
PhonePluginHelper * helper = video->helper;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() \"%s\"\n", __func__, video->device);
#endif
if((video->fd = open(video->device, O_RDWR)) < 0)
{
error_set_code(1, "%s: %s (%s)", video->device,
"Could not open the video capture device",
strerror(errno));
helper->error(helper->phone, error_get(), 1);
video->source = g_timeout_add(10000, _video_on_open, video);
return FALSE;
}
if(_open_setup(video) != 0)
{
helper->error(helper->phone, error_get(), 1);
close(video->fd);
video->fd = -1;
video->source = g_timeout_add(10000, _video_on_open, video);
return FALSE;
}
video->source = 0;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() %dx%d\n", __func__,
video->format.fmt.pix.width,
video->format.fmt.pix.height);
#endif
/* FIXME allow the window to be smaller */
gtk_widget_set_size_request(video->area, video->format.fmt.pix.width,
video->format.fmt.pix.height);
return FALSE;
}
static int _open_setup(VideoPhonePlugin * video) static int _open_setup(VideoPhonePlugin * video)
{ {
struct v4l2_cropcap cropcap; struct v4l2_cropcap cropcap;
@ -256,139 +439,6 @@ static int _open_setup(VideoPhonePlugin * video)
} }
/* video_destroy */
static void _video_destroy(VideoPhonePlugin * video)
{
if(video->source != 0)
g_source_remove(video->source);
if(video->channel != NULL)
{
/* XXX we ignore errors at this point */
g_io_channel_shutdown(video->channel, TRUE, NULL);
#if 0
/* FIXME seems to cause a crash in the original code */
g_object_unref(video->channel);
#endif
}
if(video->pixmap != NULL)
g_object_unref(video->pixmap);
if(video->gc != NULL)
g_object_unref(video->gc);
if(video->window != NULL)
gtk_widget_destroy(video->window);
if(video->fd >= 0)
close(video->fd);
if((char *)video->rgb_buffer != video->raw_buffer)
free(video->rgb_buffer);
free(video->raw_buffer);
string_delete(video->device);
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_can_read */
static gboolean _video_on_can_read(GIOChannel * channel, GIOCondition condition,
gpointer data)
{
VideoPhonePlugin * video = data;
PhonePluginHelper * helper = video->helper;
ssize_t s;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif
if(channel != video->channel || condition != G_IO_IN)
return FALSE;
if((s = read(video->fd, video->raw_buffer, video->raw_buffer_cnt))
<= 0)
{
/* this error can be ignored */
if(errno == EAGAIN)
return TRUE;
close(video->fd);
video->fd = -1;
helper->error(helper->phone, strerror(errno), 1);
video->source = 0;
return FALSE;
}
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() %lu %ld\n", __func__,
video->raw_buffer_cnt, s);
#endif
video->source = g_idle_add(_video_on_refresh, video);
return FALSE;
}
/* 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_drawing_area_configure */
static gboolean _video_on_drawing_area_configure(GtkWidget * widget,
GdkEventConfigure * event, gpointer data)
{
/* XXX this code is inspired from GQcam */
VideoPhonePlugin * video = data;
GtkAllocation * allocation = &video->area_allocation;
if(video->pixmap != NULL)
g_object_unref(video->pixmap);
/* FIXME requires Gtk+ 2.18 */
gtk_widget_get_allocation(widget, allocation);
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() %dx%d\n", __func__, allocation->width,
allocation->height);
#endif
video->pixmap = gdk_pixmap_new(widget->window, allocation->width,
allocation->height, -1);
/* FIXME is it not better to scale the previous pixmap for now? */
gdk_draw_rectangle(video->pixmap, video->gc, TRUE, 0, 0,
allocation->width, allocation->height);
return TRUE;
}
/* video_on_drawing_area_expose */
static gboolean _video_on_drawing_area_expose(GtkWidget * widget,
GdkEventExpose * event, gpointer data)
{
/* XXX this code is inspired from GQcam */
VideoPhonePlugin * video = data;
gdk_draw_pixmap(widget->window, video->gc, video->pixmap,
event->area.x, event->area.y,
event->area.x, event->area.y,
event->area.width, event->area.height);
return FALSE;
}
/* video_on_refresh */ /* video_on_refresh */
static void _refresh_convert(VideoPhonePlugin * video); static void _refresh_convert(VideoPhonePlugin * video);
static void _refresh_convert_yuv(int amp, uint8_t y, uint8_t u, uint8_t v, static void _refresh_convert_yuv(int amp, uint8_t y, uint8_t u, uint8_t v,