vgrabbers.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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. /*** MODULEINFO
  46. <support_level>extended</support_level>
  47. ***/
  48. #include "asterisk.h"
  49. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  50. #include <sys/ioctl.h>
  51. #include "asterisk/file.h"
  52. #include "asterisk/utils.h" /* ast_calloc */
  53. #include "console_video.h"
  54. #if defined(HAVE_VIDEO_CONSOLE)
  55. #ifdef HAVE_X11
  56. /* A simple X11 grabber, supporting only truecolor formats */
  57. #include <X11/Xlib.h>
  58. /*! \brief internal info used by the X11 grabber */
  59. struct grab_x11_desc {
  60. Display *dpy;
  61. XImage *image;
  62. int screen_width; /* width of X screen */
  63. int screen_height; /* height of X screen */
  64. struct fbuf_t b; /* geometry and pointer into the XImage */
  65. };
  66. static void *grab_x11_close(void *desc); /* forward declaration */
  67. /*! \brief open the grabber.
  68. * We use the special name 'X11' to indicate this grabber.
  69. */
  70. static void *grab_x11_open(const char *name, struct fbuf_t *geom, int fps)
  71. {
  72. XImage *im;
  73. int screen_num;
  74. struct grab_x11_desc *v;
  75. struct fbuf_t *b;
  76. /* all names starting with X11 identify this grabber */
  77. if (strncasecmp(name, "X11", 3))
  78. return NULL; /* not us */
  79. v = ast_calloc(1, sizeof(*v));
  80. if (v == NULL)
  81. return NULL; /* no memory */
  82. /* init the connection with the X server */
  83. v->dpy = XOpenDisplay(NULL);
  84. if (v->dpy == NULL) {
  85. ast_log(LOG_WARNING, "error opening display\n");
  86. goto error;
  87. }
  88. v->b = *geom; /* copy geometry */
  89. b = &v->b; /* shorthand */
  90. /* find width and height of the screen */
  91. screen_num = DefaultScreen(v->dpy);
  92. v->screen_width = DisplayWidth(v->dpy, screen_num);
  93. v->screen_height = DisplayHeight(v->dpy, screen_num);
  94. v->image = im = XGetImage(v->dpy,
  95. RootWindow(v->dpy, DefaultScreen(v->dpy)),
  96. b->x, b->y, b->w, b->h, AllPlanes, ZPixmap);
  97. if (v->image == NULL) {
  98. ast_log(LOG_WARNING, "error creating Ximage\n");
  99. goto error;
  100. }
  101. switch (im->bits_per_pixel) {
  102. case 32:
  103. b->pix_fmt = PIX_FMT_RGBA32;
  104. break;
  105. case 16:
  106. b->pix_fmt = (im->green_mask == 0x7e0) ? PIX_FMT_RGB565 : PIX_FMT_RGB555;
  107. break;
  108. }
  109. ast_log(LOG_NOTICE, "image: data %p %d bpp fmt %d, mask 0x%lx 0x%lx 0x%lx\n",
  110. im->data,
  111. im->bits_per_pixel,
  112. b->pix_fmt,
  113. im->red_mask, im->green_mask, im->blue_mask);
  114. /* set the pointer but not the size as this is not malloc'ed */
  115. b->data = (uint8_t *)im->data;
  116. return v;
  117. error:
  118. return grab_x11_close(v);
  119. }
  120. static struct fbuf_t *grab_x11_read(void *desc)
  121. {
  122. /* read frame from X11 */
  123. struct grab_x11_desc *v = desc;
  124. struct fbuf_t *b = &v->b;
  125. XGetSubImage(v->dpy,
  126. RootWindow(v->dpy, DefaultScreen(v->dpy)),
  127. b->x, b->y, b->w, b->h, AllPlanes, ZPixmap, v->image, 0, 0);
  128. b->data = (uint8_t *)v->image->data;
  129. return b;
  130. }
  131. static int boundary_checks(int x, int limit)
  132. {
  133. return (x <= 0) ? 0 : (x > limit ? limit : x);
  134. }
  135. /*! \brief move the origin for the grabbed area, making sure we do not
  136. * overflow the screen.
  137. */
  138. static void grab_x11_move(void *desc, int dx, int dy)
  139. {
  140. struct grab_x11_desc *v = desc;
  141. v->b.x = boundary_checks(v->b.x + dx, v->screen_width - v->b.w);
  142. v->b.y = boundary_checks(v->b.y + dy, v->screen_height - v->b.h);
  143. }
  144. /*! \brief disconnect from the server and release memory */
  145. static void *grab_x11_close(void *desc)
  146. {
  147. struct grab_x11_desc *v = desc;
  148. if (v->dpy)
  149. XCloseDisplay(v->dpy);
  150. v->dpy = NULL;
  151. v->image = NULL;
  152. ast_free(v);
  153. return NULL;
  154. }
  155. static struct grab_desc grab_x11_desc = {
  156. .name = "X11",
  157. .open = grab_x11_open,
  158. .read = grab_x11_read,
  159. .move = grab_x11_move,
  160. .close = grab_x11_close,
  161. };
  162. #endif /* HAVE_X11 */
  163. #ifdef HAVE_VIDEODEV_H
  164. #include <linux/videodev.h> /* Video4Linux stuff is only used in grab_v4l1_open() */
  165. struct grab_v4l1_desc {
  166. int fd; /* device handle */
  167. struct fbuf_t b; /* buffer (allocated) with grabbed image */
  168. };
  169. /*! \brief
  170. * Open the local video source and allocate a buffer
  171. * for storing the image.
  172. */
  173. static void *grab_v4l1_open(const char *dev, struct fbuf_t *geom, int fps)
  174. {
  175. struct video_window vw = { 0 }; /* camera attributes */
  176. struct video_picture vp;
  177. int fd, i;
  178. struct grab_v4l1_desc *v;
  179. struct fbuf_t *b;
  180. /* name should be something under /dev/ */
  181. if (strncmp(dev, "/dev/", 5))
  182. return NULL;
  183. fd = open(dev, O_RDONLY | O_NONBLOCK);
  184. if (fd < 0) {
  185. ast_log(LOG_WARNING, "error opening camera %s\n", dev);
  186. return NULL;
  187. }
  188. v = ast_calloc(1, sizeof(*v));
  189. if (v == NULL) {
  190. ast_log(LOG_WARNING, "no memory for camera %s\n", dev);
  191. close(fd);
  192. return NULL; /* no memory */
  193. }
  194. v->fd = fd;
  195. v->b = *geom;
  196. b = &v->b; /* shorthand */
  197. ast_fd_set_flags(fd, O_NONBLOCK);
  198. /* set format for the camera.
  199. * In principle we could retry with a different format if the
  200. * one we are asking for is not supported.
  201. */
  202. vw.width = b->w;
  203. vw.height = b->h;
  204. vw.flags = fps << 16;
  205. if (ioctl(fd, VIDIOCSWIN, &vw) == -1) {
  206. ast_log(LOG_WARNING, "error setting format for %s [%s]\n",
  207. dev, strerror(errno));
  208. goto error;
  209. }
  210. if (ioctl(fd, VIDIOCGPICT, &vp) == -1) {
  211. ast_log(LOG_WARNING, "error reading picture info\n");
  212. goto error;
  213. }
  214. ast_log(LOG_WARNING,
  215. "contrast %d bright %d colour %d hue %d white %d palette %d\n",
  216. vp.contrast, vp.brightness,
  217. vp.colour, vp.hue,
  218. vp.whiteness, vp.palette);
  219. /* set the video format. Here again, we don't necessary have to
  220. * fail if the required format is not supported, but try to use
  221. * what the camera gives us.
  222. */
  223. b->pix_fmt = vp.palette;
  224. vp.palette = VIDEO_PALETTE_YUV420P;
  225. if (ioctl(v->fd, VIDIOCSPICT, &vp) == -1) {
  226. ast_log(LOG_WARNING, "error setting palette, using %d\n",
  227. b->pix_fmt);
  228. } else
  229. b->pix_fmt = vp.palette;
  230. /* allocate the source buffer.
  231. * XXX, the code here only handles yuv411, for other formats
  232. * we need to look at pix_fmt and set size accordingly
  233. */
  234. b->size = (b->w * b->h * 3)/2; /* yuv411 */
  235. ast_log(LOG_WARNING, "videodev %s opened, size %dx%d %d\n",
  236. dev, b->w, b->h, b->size);
  237. b->data = ast_calloc(1, b->size);
  238. if (!b->data) {
  239. ast_log(LOG_WARNING, "error allocating buffer %d bytes\n",
  240. b->size);
  241. goto error;
  242. }
  243. ast_log(LOG_WARNING, "success opening camera\n");
  244. return v;
  245. error:
  246. close(v->fd);
  247. fbuf_free(b);
  248. ast_free(v);
  249. return NULL;
  250. }
  251. /*! \brief read until error, no data or buffer full.
  252. * This might be blocking but no big deal since we are in the
  253. * display thread.
  254. */
  255. static struct fbuf_t *grab_v4l1_read(void *desc)
  256. {
  257. struct grab_v4l1_desc *v = desc;
  258. struct fbuf_t *b = &v->b;
  259. for (;;) {
  260. int r, l = b->size - b->used;
  261. r = read(v->fd, b->data + b->used, l);
  262. // ast_log(LOG_WARNING, "read %d of %d bytes from webcam\n", r, l);
  263. if (r < 0) /* read error */
  264. break;
  265. if (r == 0) /* no data */
  266. break;
  267. b->used += r;
  268. if (r == l) {
  269. b->used = 0; /* prepare for next frame */
  270. return b;
  271. }
  272. }
  273. return NULL;
  274. }
  275. static void *grab_v4l1_close(void *desc)
  276. {
  277. struct grab_v4l1_desc *v = desc;
  278. close(v->fd);
  279. v->fd = -1;
  280. fbuf_free(&v->b);
  281. ast_free(v);
  282. return NULL;
  283. }
  284. /*! \brief our descriptor. We don't have .move */
  285. static struct grab_desc grab_v4l1_desc = {
  286. .name = "v4l1",
  287. .open = grab_v4l1_open,
  288. .read = grab_v4l1_read,
  289. .close = grab_v4l1_close,
  290. };
  291. #endif /* HAVE_VIDEODEV_H */
  292. /*
  293. * Here you can add more grabbers, e.g. V4L2, firewire,
  294. * a file, a still image...
  295. */
  296. /*! \brief The list of grabbers supported, with a NULL at the end */
  297. struct grab_desc *console_grabbers[] = {
  298. #ifdef HAVE_X11
  299. &grab_x11_desc,
  300. #endif
  301. #ifdef HAVE_VIDEODEV_H
  302. &grab_v4l1_desc,
  303. #endif
  304. NULL
  305. };
  306. #endif /* HAVE_VIDEO_CONSOLE */