vgrabbers.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright 2007, Luigi Rizzo
  5. *
  6. * See http://www.asterisk.org for more information about
  7. * the Asterisk project. Please do not directly contact
  8. * any of the maintainers of this project for assistance;
  9. * the project provides a web site, mailing lists and IRC
  10. * channels for your use.
  11. *
  12. * This program is free software, distributed under the terms of
  13. * the GNU General Public License Version 2. See the LICENSE file
  14. * at the top of the source tree.
  15. */
  16. /*
  17. * Video grabbers used in console_video.
  18. *
  19. * $Revision$
  20. *
  21. * Each grabber is implemented through open/read/close calls,
  22. * plus an additional move() function used e.g. to change origin
  23. * for the X grabber (this may be extended in the future to support
  24. * more controls e.g. resolution changes etc.).
  25. *
  26. * open() should try to open and initialize the grabber, returning NULL on error.
  27. * On success it allocates a descriptor for its private data (including
  28. * a buffer for the video) and returns a pointer to the descriptor.
  29. * read() will return NULL on failure, or a pointer to a buffer with data
  30. * on success.
  31. * close() should release resources.
  32. * move() is optional.
  33. * For more details look at the X11 grabber below.
  34. *
  35. * NOTE: at the moment we expect uncompressed video frames in YUV format,
  36. * because this is what current sources supply and also is a convenient
  37. * format for display. It is conceivable that one might want to support
  38. * an already compressed stream, in which case we should redesign the
  39. * pipeline used for the local source, which at the moment is
  40. *
  41. * .->--[loc_dpy]
  42. * [src]-->--[enc_in]--+
  43. * `->--[enc_out]
  44. */
  45. #include "asterisk.h"
  46. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  47. #include <sys/ioctl.h>
  48. #include "asterisk/file.h"
  49. #include "asterisk/utils.h" /* ast_calloc */
  50. #include "console_video.h"
  51. #if defined(HAVE_VIDEO_CONSOLE)
  52. #ifdef HAVE_X11
  53. /* A simple X11 grabber, supporting only truecolor formats */
  54. #include <X11/Xlib.h>
  55. /*! \brief internal info used by the X11 grabber */
  56. struct grab_x11_desc {
  57. Display *dpy;
  58. XImage *image;
  59. int screen_width; /* width of X screen */
  60. int screen_height; /* height of X screen */
  61. struct fbuf_t b; /* geometry and pointer into the XImage */
  62. };
  63. static void *grab_x11_close(void *desc); /* forward declaration */
  64. /*! \brief open the grabber.
  65. * We use the special name 'X11' to indicate this grabber.
  66. */
  67. static void *grab_x11_open(const char *name, struct fbuf_t *geom, int fps)
  68. {
  69. XImage *im;
  70. int screen_num;
  71. struct grab_x11_desc *v;
  72. struct fbuf_t *b;
  73. /* all names starting with X11 identify this grabber */
  74. if (strncasecmp(name, "X11", 3))
  75. return NULL; /* not us */
  76. v = ast_calloc(1, sizeof(*v));
  77. if (v == NULL)
  78. return NULL; /* no memory */
  79. /* init the connection with the X server */
  80. v->dpy = XOpenDisplay(NULL);
  81. if (v->dpy == NULL) {
  82. ast_log(LOG_WARNING, "error opening display\n");
  83. goto error;
  84. }
  85. v->b = *geom; /* copy geometry */
  86. b = &v->b; /* shorthand */
  87. /* find width and height of the screen */
  88. screen_num = DefaultScreen(v->dpy);
  89. v->screen_width = DisplayWidth(v->dpy, screen_num);
  90. v->screen_height = DisplayHeight(v->dpy, screen_num);
  91. v->image = im = XGetImage(v->dpy,
  92. RootWindow(v->dpy, DefaultScreen(v->dpy)),
  93. b->x, b->y, b->w, b->h, AllPlanes, ZPixmap);
  94. if (v->image == NULL) {
  95. ast_log(LOG_WARNING, "error creating Ximage\n");
  96. goto error;
  97. }
  98. switch (im->bits_per_pixel) {
  99. case 32:
  100. b->pix_fmt = PIX_FMT_RGBA32;
  101. break;
  102. case 16:
  103. b->pix_fmt = (im->green_mask == 0x7e0) ? PIX_FMT_RGB565 : PIX_FMT_RGB555;
  104. break;
  105. }
  106. ast_log(LOG_NOTICE, "image: data %p %d bpp fmt %d, mask 0x%lx 0x%lx 0x%lx\n",
  107. im->data,
  108. im->bits_per_pixel,
  109. b->pix_fmt,
  110. im->red_mask, im->green_mask, im->blue_mask);
  111. /* set the pointer but not the size as this is not malloc'ed */
  112. b->data = (uint8_t *)im->data;
  113. return v;
  114. error:
  115. return grab_x11_close(v);
  116. }
  117. static struct fbuf_t *grab_x11_read(void *desc)
  118. {
  119. /* read frame from X11 */
  120. struct grab_x11_desc *v = desc;
  121. struct fbuf_t *b = &v->b;
  122. XGetSubImage(v->dpy,
  123. RootWindow(v->dpy, DefaultScreen(v->dpy)),
  124. b->x, b->y, b->w, b->h, AllPlanes, ZPixmap, v->image, 0, 0);
  125. b->data = (uint8_t *)v->image->data;
  126. return b;
  127. }
  128. static int boundary_checks(int x, int limit)
  129. {
  130. return (x <= 0) ? 0 : (x > limit ? limit : x);
  131. }
  132. /*! \brief move the origin for the grabbed area, making sure we do not
  133. * overflow the screen.
  134. */
  135. static void grab_x11_move(void *desc, int dx, int dy)
  136. {
  137. struct grab_x11_desc *v = desc;
  138. v->b.x = boundary_checks(v->b.x + dx, v->screen_width - v->b.w);
  139. v->b.y = boundary_checks(v->b.y + dy, v->screen_height - v->b.h);
  140. }
  141. /*! \brief disconnect from the server and release memory */
  142. static void *grab_x11_close(void *desc)
  143. {
  144. struct grab_x11_desc *v = desc;
  145. if (v->dpy)
  146. XCloseDisplay(v->dpy);
  147. v->dpy = NULL;
  148. v->image = NULL;
  149. ast_free(v);
  150. return NULL;
  151. }
  152. static struct grab_desc grab_x11_desc = {
  153. .name = "X11",
  154. .open = grab_x11_open,
  155. .read = grab_x11_read,
  156. .move = grab_x11_move,
  157. .close = grab_x11_close,
  158. };
  159. #endif /* HAVE_X11 */
  160. #ifdef HAVE_VIDEODEV_H
  161. #include <linux/videodev.h> /* Video4Linux stuff is only used in grab_v4l1_open() */
  162. struct grab_v4l1_desc {
  163. int fd; /* device handle */
  164. struct fbuf_t b; /* buffer (allocated) with grabbed image */
  165. };
  166. /*! \brief
  167. * Open the local video source and allocate a buffer
  168. * for storing the image.
  169. */
  170. static void *grab_v4l1_open(const char *dev, struct fbuf_t *geom, int fps)
  171. {
  172. struct video_window vw = { 0 }; /* camera attributes */
  173. struct video_picture vp;
  174. int fd, i;
  175. struct grab_v4l1_desc *v;
  176. struct fbuf_t *b;
  177. /* name should be something under /dev/ */
  178. if (strncmp(dev, "/dev/", 5))
  179. return NULL;
  180. fd = open(dev, O_RDONLY | O_NONBLOCK);
  181. if (fd < 0) {
  182. ast_log(LOG_WARNING, "error opening camera %s\n", dev);
  183. return NULL;
  184. }
  185. v = ast_calloc(1, sizeof(*v));
  186. if (v == NULL) {
  187. ast_log(LOG_WARNING, "no memory for camera %s\n", dev);
  188. close(fd);
  189. return NULL; /* no memory */
  190. }
  191. v->fd = fd;
  192. v->b = *geom;
  193. b = &v->b; /* shorthand */
  194. i = fcntl(fd, F_GETFL);
  195. if (-1 == fcntl(fd, F_SETFL, i | O_NONBLOCK)) {
  196. /* non fatal, just emit a warning */
  197. ast_log(LOG_WARNING, "error F_SETFL for %s [%s]\n",
  198. dev, strerror(errno));
  199. }
  200. /* set format for the camera.
  201. * In principle we could retry with a different format if the
  202. * one we are asking for is not supported.
  203. */
  204. vw.width = b->w;
  205. vw.height = b->h;
  206. vw.flags = fps << 16;
  207. if (ioctl(fd, VIDIOCSWIN, &vw) == -1) {
  208. ast_log(LOG_WARNING, "error setting format for %s [%s]\n",
  209. dev, strerror(errno));
  210. goto error;
  211. }
  212. if (ioctl(fd, VIDIOCGPICT, &vp) == -1) {
  213. ast_log(LOG_WARNING, "error reading picture info\n");
  214. goto error;
  215. }
  216. ast_log(LOG_WARNING,
  217. "contrast %d bright %d colour %d hue %d white %d palette %d\n",
  218. vp.contrast, vp.brightness,
  219. vp.colour, vp.hue,
  220. vp.whiteness, vp.palette);
  221. /* set the video format. Here again, we don't necessary have to
  222. * fail if the required format is not supported, but try to use
  223. * what the camera gives us.
  224. */
  225. b->pix_fmt = vp.palette;
  226. vp.palette = VIDEO_PALETTE_YUV420P;
  227. if (ioctl(v->fd, VIDIOCSPICT, &vp) == -1) {
  228. ast_log(LOG_WARNING, "error setting palette, using %d\n",
  229. b->pix_fmt);
  230. } else
  231. b->pix_fmt = vp.palette;
  232. /* allocate the source buffer.
  233. * XXX, the code here only handles yuv411, for other formats
  234. * we need to look at pix_fmt and set size accordingly
  235. */
  236. b->size = (b->w * b->h * 3)/2; /* yuv411 */
  237. ast_log(LOG_WARNING, "videodev %s opened, size %dx%d %d\n",
  238. dev, b->w, b->h, b->size);
  239. b->data = ast_calloc(1, b->size);
  240. if (!b->data) {
  241. ast_log(LOG_WARNING, "error allocating buffer %d bytes\n",
  242. b->size);
  243. goto error;
  244. }
  245. ast_log(LOG_WARNING, "success opening camera\n");
  246. return v;
  247. error:
  248. close(v->fd);
  249. fbuf_free(b);
  250. ast_free(v);
  251. return NULL;
  252. }
  253. /*! \brief read until error, no data or buffer full.
  254. * This might be blocking but no big deal since we are in the
  255. * display thread.
  256. */
  257. static struct fbuf_t *grab_v4l1_read(void *desc)
  258. {
  259. struct grab_v4l1_desc *v = desc;
  260. struct fbuf_t *b = &v->b;
  261. for (;;) {
  262. int r, l = b->size - b->used;
  263. r = read(v->fd, b->data + b->used, l);
  264. // ast_log(LOG_WARNING, "read %d of %d bytes from webcam\n", r, l);
  265. if (r < 0) /* read error */
  266. break;
  267. if (r == 0) /* no data */
  268. break;
  269. b->used += r;
  270. if (r == l) {
  271. b->used = 0; /* prepare for next frame */
  272. return b;
  273. }
  274. }
  275. return NULL;
  276. }
  277. static void *grab_v4l1_close(void *desc)
  278. {
  279. struct grab_v4l1_desc *v = desc;
  280. close(v->fd);
  281. v->fd = -1;
  282. fbuf_free(&v->b);
  283. ast_free(v);
  284. return NULL;
  285. }
  286. /*! \brief our descriptor. We don't have .move */
  287. static struct grab_desc grab_v4l1_desc = {
  288. .name = "v4l1",
  289. .open = grab_v4l1_open,
  290. .read = grab_v4l1_read,
  291. .close = grab_v4l1_close,
  292. };
  293. #endif /* HAVE_VIDEODEV_H */
  294. /*
  295. * Here you can add more grabbers, e.g. V4L2, firewire,
  296. * a file, a still image...
  297. */
  298. /*! \brief The list of grabbers supported, with a NULL at the end */
  299. struct grab_desc *console_grabbers[] = {
  300. #ifdef HAVE_X11
  301. &grab_x11_desc,
  302. #endif
  303. #ifdef HAVE_VIDEODEV_H
  304. &grab_v4l1_desc,
  305. #endif
  306. NULL
  307. };
  308. #endif /* HAVE_VIDEO_CONSOLE */