Open the video device at regular intervals (every 10 seconds)
This commit is contained in:
parent
968a9353be
commit
5fdad562a9
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user