You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

302 lines
7.8KB

  1. /*
  2. * Linux video grab interface
  3. * Copyright (c) 2000,2001 Gerard Lantau.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19. #include "avformat.h"
  20. #include <linux/videodev.h>
  21. #include <unistd.h>
  22. #include <fcntl.h>
  23. #include <sys/ioctl.h>
  24. #include <sys/mman.h>
  25. #include <sys/time.h>
  26. typedef struct {
  27. int fd;
  28. int frame_format; /* see VIDEO_PALETTE_xxx */
  29. int use_mmap;
  30. int width, height;
  31. int frame_rate;
  32. INT64 time_frame;
  33. int frame_size;
  34. } VideoData;
  35. const char *v4l_device = "/dev/video";
  36. /* XXX: move all that to the context */
  37. static struct video_capability video_cap;
  38. static UINT8 *video_buf;
  39. static struct video_mbuf gb_buffers;
  40. static struct video_mmap gb_buf;
  41. static struct video_audio audio, audio_saved;
  42. static int gb_frame = 0;
  43. static int grab_read_header(AVFormatContext *s1, AVFormatParameters *ap)
  44. {
  45. VideoData *s;
  46. AVStream *st;
  47. int width, height;
  48. int video_fd, frame_size;
  49. int ret, frame_rate;
  50. if (!ap || ap->width <= 0 || ap->height <= 0 || ap->frame_rate <= 0)
  51. return -1;
  52. width = ap->width;
  53. height = ap->height;
  54. frame_rate = ap->frame_rate;
  55. s = av_mallocz(sizeof(VideoData));
  56. if (!s)
  57. return -ENOMEM;
  58. st = av_mallocz(sizeof(AVStream));
  59. if (!st) {
  60. free(s);
  61. return -ENOMEM;
  62. }
  63. s1->priv_data = s;
  64. s1->nb_streams = 1;
  65. s1->streams[0] = st;
  66. s->width = width;
  67. s->height = height;
  68. s->frame_rate = frame_rate;
  69. video_fd = open(v4l_device, O_RDWR);
  70. if (video_fd < 0) {
  71. perror(v4l_device);
  72. goto fail;
  73. }
  74. if (ioctl(video_fd,VIDIOCGCAP,&video_cap) < 0) {
  75. perror("VIDIOCGCAP");
  76. goto fail;
  77. }
  78. if (!(video_cap.type & VID_TYPE_CAPTURE)) {
  79. fprintf(stderr, "Fatal: grab device does not handle capture\n");
  80. goto fail;
  81. }
  82. /* unmute audio */
  83. ioctl(video_fd, VIDIOCGAUDIO, &audio);
  84. memcpy(&audio_saved, &audio, sizeof(audio));
  85. audio.flags &= ~VIDEO_AUDIO_MUTE;
  86. ioctl(video_fd, VIDIOCSAUDIO, &audio);
  87. ret = ioctl(video_fd,VIDIOCGMBUF,&gb_buffers);
  88. if (ret < 0) {
  89. /* try to use read based access */
  90. struct video_window win;
  91. struct video_picture pict;
  92. int val;
  93. win.x = 0;
  94. win.y = 0;
  95. win.width = width;
  96. win.height = height;
  97. win.chromakey = -1;
  98. win.flags = 0;
  99. ioctl(video_fd, VIDIOCSWIN, &win);
  100. ioctl(video_fd, VIDIOCGPICT, &pict);
  101. #if 0
  102. printf("v4l: colour=%d hue=%d brightness=%d constrast=%d whiteness=%d\n",
  103. pict.colour,
  104. pict.hue,
  105. pict.brightness,
  106. pict.contrast,
  107. pict.whiteness);
  108. #endif
  109. /* try to choose a suitable video format */
  110. pict.palette=VIDEO_PALETTE_YUV420P;
  111. ret = ioctl(video_fd, VIDIOCSPICT, &pict);
  112. if (ret < 0) {
  113. pict.palette=VIDEO_PALETTE_YUV422;
  114. ret = ioctl(video_fd, VIDIOCSPICT, &pict);
  115. if (ret < 0) {
  116. pict.palette=VIDEO_PALETTE_RGB24;
  117. ret = ioctl(video_fd, VIDIOCSPICT, &pict);
  118. if (ret < 0)
  119. goto fail1;
  120. }
  121. }
  122. s->frame_format = pict.palette;
  123. val = 1;
  124. ioctl(video_fd, VIDIOCCAPTURE, &val);
  125. s->time_frame = gettime();
  126. s->use_mmap = 0;
  127. } else {
  128. video_buf = mmap(0,gb_buffers.size,PROT_READ|PROT_WRITE,MAP_SHARED,video_fd,0);
  129. if ((unsigned char*)-1 == video_buf) {
  130. perror("mmap");
  131. goto fail;
  132. }
  133. gb_frame = 0;
  134. s->time_frame = gettime();
  135. /* start to grab the first frame */
  136. gb_buf.frame = (gb_frame + 1) % gb_buffers.frames;
  137. gb_buf.height = height;
  138. gb_buf.width = width;
  139. gb_buf.format = VIDEO_PALETTE_YUV420P;
  140. ret = ioctl(video_fd, VIDIOCMCAPTURE, &gb_buf);
  141. if (ret < 0 && errno != EAGAIN) {
  142. /* try YUV422 */
  143. gb_buf.format = VIDEO_PALETTE_YUV422;
  144. ret = ioctl(video_fd, VIDIOCMCAPTURE, &gb_buf);
  145. if (ret < 0 && errno != EAGAIN) {
  146. /* try RGB24 */
  147. gb_buf.format = VIDEO_PALETTE_RGB24;
  148. ret = ioctl(video_fd, VIDIOCMCAPTURE, &gb_buf);
  149. }
  150. }
  151. if (ret < 0) {
  152. if (errno != EAGAIN) {
  153. fail1:
  154. fprintf(stderr, "Fatal: grab device does not support suitable format\n");
  155. } else {
  156. fprintf(stderr,"Fatal: grab device does not receive any video signal\n");
  157. }
  158. goto fail;
  159. }
  160. s->frame_format = gb_buf.format;
  161. s->use_mmap = 1;
  162. }
  163. switch(s->frame_format) {
  164. case VIDEO_PALETTE_YUV420P:
  165. frame_size = (width * height * 3) / 2;
  166. st->codec.pix_fmt = PIX_FMT_YUV420P;
  167. break;
  168. case VIDEO_PALETTE_YUV422:
  169. frame_size = width * height * 2;
  170. st->codec.pix_fmt = PIX_FMT_YUV422;
  171. break;
  172. case VIDEO_PALETTE_RGB24:
  173. frame_size = width * height * 3;
  174. st->codec.pix_fmt = PIX_FMT_BGR24; /* NOTE: v4l uses BGR24, not RGB24 ! */
  175. break;
  176. default:
  177. goto fail;
  178. }
  179. s->fd = video_fd;
  180. s->frame_size = frame_size;
  181. st->codec.codec_id = CODEC_ID_RAWVIDEO;
  182. st->codec.width = width;
  183. st->codec.height = height;
  184. st->codec.frame_rate = frame_rate;
  185. return 0;
  186. fail:
  187. if (video_fd >= 0)
  188. close(video_fd);
  189. free(st);
  190. free(s);
  191. return -EIO;
  192. }
  193. static int v4l_mm_read_picture(VideoData *s, UINT8 *buf)
  194. {
  195. UINT8 *ptr;
  196. gb_buf.frame = gb_frame;
  197. if (ioctl(s->fd, VIDIOCMCAPTURE, &gb_buf) < 0) {
  198. if (errno == EAGAIN)
  199. fprintf(stderr,"Cannot Sync\n");
  200. else
  201. perror("VIDIOCMCAPTURE");
  202. return -EIO;
  203. }
  204. gb_frame = (gb_frame + 1) % gb_buffers.frames;
  205. while (ioctl(s->fd, VIDIOCSYNC, &gb_frame) < 0 &&
  206. (errno == EAGAIN || errno == EINTR));
  207. ptr = video_buf + gb_buffers.offsets[gb_frame];
  208. memcpy(buf, ptr, s->frame_size);
  209. return s->frame_size;
  210. }
  211. static int grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
  212. {
  213. VideoData *s = s1->priv_data;
  214. INT64 curtime, delay;
  215. struct timespec ts;
  216. /* wait based on the frame rate */
  217. s->time_frame += (INT64_C(1000000) * FRAME_RATE_BASE) / s->frame_rate;
  218. for(;;) {
  219. curtime = gettime();
  220. delay = s->time_frame - curtime;
  221. if (delay <= 0)
  222. break;
  223. ts.tv_sec = delay / 1000000;
  224. ts.tv_nsec = (delay % 1000000) * 1000;
  225. nanosleep(&ts, NULL);
  226. }
  227. if (av_new_packet(pkt, s->frame_size) < 0)
  228. return -EIO;
  229. /* read one frame */
  230. if (s->use_mmap) {
  231. return v4l_mm_read_picture(s, pkt->data);
  232. } else {
  233. if (read(s->fd, pkt->data, pkt->size) != pkt->size)
  234. return -EIO;
  235. return s->frame_size;
  236. }
  237. }
  238. static int grab_read_close(AVFormatContext *s1)
  239. {
  240. VideoData *s = s1->priv_data;
  241. /* restore audio settings */
  242. ioctl(s->fd, VIDIOCSAUDIO, &audio_saved);
  243. close(s->fd);
  244. free(s);
  245. return 0;
  246. }
  247. AVFormat video_grab_device_format = {
  248. "video_grab_device",
  249. "video grab",
  250. "",
  251. "",
  252. CODEC_ID_NONE,
  253. CODEC_ID_NONE,
  254. NULL,
  255. NULL,
  256. NULL,
  257. grab_read_header,
  258. grab_read_packet,
  259. grab_read_close,
  260. NULL,
  261. AVFMT_NOFILE,
  262. };