Tell the user why video capture is failing
[ffmpeg.git] / libavformat / grab.c
1 /*
2  * Linux video grab interface
3  * Copyright (c) 2000,2001 Fabrice Bellard.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library 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 GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 #include "avformat.h"
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <sys/ioctl.h>
23 #include <sys/mman.h>
24 #include <sys/time.h>
25 #define _LINUX_TIME_H 1
26 #include <linux/videodev.h>
27 #include <time.h>
28
29 typedef struct {
30     int fd;
31     int frame_format; /* see VIDEO_PALETTE_xxx */
32     int use_mmap;
33     int width, height;
34     int frame_rate;
35     int frame_rate_base;
36     int64_t time_frame;
37     int frame_size;
38     struct video_capability video_cap;
39     struct video_audio audio_saved;
40     uint8_t *video_buf;
41     struct video_mbuf gb_buffers;
42     struct video_mmap gb_buf;
43     int gb_frame;
44
45     /* ATI All In Wonder specific stuff */
46     /* XXX: remove and merge in libavcodec/imgconvert.c */
47     int aiw_enabled;
48     int deint;
49     int halfw;
50     uint8_t *src_mem;
51     uint8_t *lum_m4_mem;
52 } VideoData;
53
54 static int aiw_init(VideoData *s);
55 static int aiw_read_picture(VideoData *s, uint8_t *data);
56 static int aiw_close(VideoData *s);
57
58 static int grab_read_header(AVFormatContext *s1, AVFormatParameters *ap)
59 {
60     VideoData *s = s1->priv_data;
61     AVStream *st;
62     int width, height;
63     int video_fd, frame_size;
64     int ret, frame_rate, frame_rate_base;
65     int desired_palette;
66     struct video_tuner tuner;
67     struct video_audio audio;
68     const char *video_device;
69     int j;
70
71     if (ap->width <= 0 || ap->height <= 0 || ap->time_base.den <= 0) {
72         av_log(s1, AV_LOG_ERROR, "Bad capture size (%dx%d) or wrong time base (%d)\n",
73             ap->width, ap->height, ap->time_base.den);
74
75         return -1;
76     }
77
78     width = ap->width;
79     height = ap->height;
80     frame_rate      = ap->time_base.den;
81     frame_rate_base = ap->time_base.num;
82
83     if((unsigned)width > 32767 || (unsigned)height > 32767) {
84         av_log(s1, AV_LOG_ERROR, "Capture size is out of range: %dx%d\n",
85             width, height);
86
87         return -1;
88     }
89
90     st = av_new_stream(s1, 0);
91     if (!st)
92         return -ENOMEM;
93     av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
94
95     s->width = width;
96     s->height = height;
97     s->frame_rate      = frame_rate;
98     s->frame_rate_base = frame_rate_base;
99
100     video_device = ap->device;
101     if (!video_device)
102         video_device = "/dev/video";
103     video_fd = open(video_device, O_RDWR);
104     if (video_fd < 0) {
105         perror(video_device);
106         goto fail;
107     }
108
109     if (ioctl(video_fd,VIDIOCGCAP, &s->video_cap) < 0) {
110         perror("VIDIOCGCAP");
111         goto fail;
112     }
113
114     if (!(s->video_cap.type & VID_TYPE_CAPTURE)) {
115         av_log(s1, AV_LOG_ERROR, "Fatal: grab device does not handle capture\n");
116         goto fail;
117     }
118
119     desired_palette = -1;
120     if (st->codec->pix_fmt == PIX_FMT_YUV420P) {
121         desired_palette = VIDEO_PALETTE_YUV420P;
122     } else if (st->codec->pix_fmt == PIX_FMT_YUV422) {
123         desired_palette = VIDEO_PALETTE_YUV422;
124     } else if (st->codec->pix_fmt == PIX_FMT_BGR24) {
125         desired_palette = VIDEO_PALETTE_RGB24;
126     }
127
128     /* set tv standard */
129     if (ap->standard && !ioctl(video_fd, VIDIOCGTUNER, &tuner)) {
130         if (!strcasecmp(ap->standard, "pal"))
131             tuner.mode = VIDEO_MODE_PAL;
132         else if (!strcasecmp(ap->standard, "secam"))
133             tuner.mode = VIDEO_MODE_SECAM;
134         else
135             tuner.mode = VIDEO_MODE_NTSC;
136         ioctl(video_fd, VIDIOCSTUNER, &tuner);
137     }
138
139     /* unmute audio */
140     audio.audio = 0;
141     ioctl(video_fd, VIDIOCGAUDIO, &audio);
142     memcpy(&s->audio_saved, &audio, sizeof(audio));
143     audio.flags &= ~VIDEO_AUDIO_MUTE;
144     ioctl(video_fd, VIDIOCSAUDIO, &audio);
145
146     ret = ioctl(video_fd,VIDIOCGMBUF,&s->gb_buffers);
147     if (ret < 0) {
148         /* try to use read based access */
149         struct video_window win;
150         struct video_picture pict;
151         int val;
152
153         win.x = 0;
154         win.y = 0;
155         win.width = width;
156         win.height = height;
157         win.chromakey = -1;
158         win.flags = 0;
159
160         ioctl(video_fd, VIDIOCSWIN, &win);
161
162         ioctl(video_fd, VIDIOCGPICT, &pict);
163 #if 0
164         printf("v4l: colour=%d hue=%d brightness=%d constrast=%d whiteness=%d\n",
165                pict.colour,
166                pict.hue,
167                pict.brightness,
168                pict.contrast,
169                pict.whiteness);
170 #endif
171         /* try to choose a suitable video format */
172         pict.palette = desired_palette;
173         if (desired_palette == -1 || (ret = ioctl(video_fd, VIDIOCSPICT, &pict)) < 0) {
174             pict.palette=VIDEO_PALETTE_YUV420P;
175             ret = ioctl(video_fd, VIDIOCSPICT, &pict);
176             if (ret < 0) {
177                 pict.palette=VIDEO_PALETTE_YUV422;
178                 ret = ioctl(video_fd, VIDIOCSPICT, &pict);
179                 if (ret < 0) {
180                     pict.palette=VIDEO_PALETTE_RGB24;
181                     ret = ioctl(video_fd, VIDIOCSPICT, &pict);
182                     if (ret < 0)
183                         goto fail1;
184                 }
185             }
186         }
187
188         s->frame_format = pict.palette;
189
190         val = 1;
191         ioctl(video_fd, VIDIOCCAPTURE, &val);
192
193         s->time_frame = av_gettime() * s->frame_rate / s->frame_rate_base;
194         s->use_mmap = 0;
195
196         /* ATI All In Wonder automatic activation */
197         if (!strcmp(s->video_cap.name, "Km")) {
198             if (aiw_init(s) < 0)
199                 goto fail;
200             s->aiw_enabled = 1;
201             /* force 420P format because convertion from YUV422 to YUV420P
202                is done in this driver (ugly) */
203             s->frame_format = VIDEO_PALETTE_YUV420P;
204         }
205     } else {
206         s->video_buf = mmap(0,s->gb_buffers.size,PROT_READ|PROT_WRITE,MAP_SHARED,video_fd,0);
207         if ((unsigned char*)-1 == s->video_buf) {
208             perror("mmap");
209             goto fail;
210         }
211         s->gb_frame = 0;
212         s->time_frame = av_gettime() * s->frame_rate / s->frame_rate_base;
213
214         /* start to grab the first frame */
215         s->gb_buf.frame = s->gb_frame % s->gb_buffers.frames;
216         s->gb_buf.height = height;
217         s->gb_buf.width = width;
218         s->gb_buf.format = desired_palette;
219
220         if (desired_palette == -1 || (ret = ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf)) < 0) {
221             s->gb_buf.format = VIDEO_PALETTE_YUV420P;
222
223             ret = ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf);
224             if (ret < 0 && errno != EAGAIN) {
225                 /* try YUV422 */
226                 s->gb_buf.format = VIDEO_PALETTE_YUV422;
227
228                 ret = ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf);
229                 if (ret < 0 && errno != EAGAIN) {
230                     /* try RGB24 */
231                     s->gb_buf.format = VIDEO_PALETTE_RGB24;
232                     ret = ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf);
233                 }
234             }
235         }
236         if (ret < 0) {
237             if (errno != EAGAIN) {
238             fail1:
239                 av_log(s1, AV_LOG_ERROR, "Fatal: grab device does not support suitable format\n");
240             } else {
241                 av_log(s1, AV_LOG_ERROR,"Fatal: grab device does not receive any video signal\n");
242             }
243             goto fail;
244         }
245         for (j = 1; j < s->gb_buffers.frames; j++) {
246           s->gb_buf.frame = j;
247           ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf);
248         }
249         s->frame_format = s->gb_buf.format;
250         s->use_mmap = 1;
251     }
252
253     switch(s->frame_format) {
254     case VIDEO_PALETTE_YUV420P:
255         frame_size = (width * height * 3) / 2;
256         st->codec->pix_fmt = PIX_FMT_YUV420P;
257         break;
258     case VIDEO_PALETTE_YUV422:
259         frame_size = width * height * 2;
260         st->codec->pix_fmt = PIX_FMT_YUV422;
261         break;
262     case VIDEO_PALETTE_RGB24:
263         frame_size = width * height * 3;
264         st->codec->pix_fmt = PIX_FMT_BGR24; /* NOTE: v4l uses BGR24, not RGB24 ! */
265         break;
266     default:
267         goto fail;
268     }
269     s->fd = video_fd;
270     s->frame_size = frame_size;
271
272     st->codec->codec_type = CODEC_TYPE_VIDEO;
273     st->codec->codec_id = CODEC_ID_RAWVIDEO;
274     st->codec->width = width;
275     st->codec->height = height;
276     st->codec->time_base.den      = frame_rate;
277     st->codec->time_base.num = frame_rate_base;
278     st->codec->bit_rate = frame_size * 1/av_q2d(st->codec->time_base) * 8;
279
280     return 0;
281  fail:
282     if (video_fd >= 0)
283         close(video_fd);
284     av_free(st);
285     return AVERROR_IO;
286 }
287
288 static int v4l_mm_read_picture(VideoData *s, uint8_t *buf)
289 {
290     uint8_t *ptr;
291
292     while (ioctl(s->fd, VIDIOCSYNC, &s->gb_frame) < 0 &&
293            (errno == EAGAIN || errno == EINTR));
294
295     ptr = s->video_buf + s->gb_buffers.offsets[s->gb_frame];
296     memcpy(buf, ptr, s->frame_size);
297
298     /* Setup to capture the next frame */
299     s->gb_buf.frame = s->gb_frame;
300     if (ioctl(s->fd, VIDIOCMCAPTURE, &s->gb_buf) < 0) {
301         if (errno == EAGAIN)
302             av_log(NULL, AV_LOG_ERROR, "Cannot Sync\n");
303         else
304             perror("VIDIOCMCAPTURE");
305         return AVERROR_IO;
306     }
307
308     /* This is now the grabbing frame */
309     s->gb_frame = (s->gb_frame + 1) % s->gb_buffers.frames;
310
311     return s->frame_size;
312 }
313
314 static int grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
315 {
316     VideoData *s = s1->priv_data;
317     int64_t curtime, delay;
318     struct timespec ts;
319
320     /* Calculate the time of the next frame */
321     s->time_frame += int64_t_C(1000000);
322
323     /* wait based on the frame rate */
324     for(;;) {
325         curtime = av_gettime();
326         delay = s->time_frame  * s->frame_rate_base / s->frame_rate - curtime;
327         if (delay <= 0) {
328             if (delay < int64_t_C(-1000000) * s->frame_rate_base / s->frame_rate) {
329                 /* printf("grabbing is %d frames late (dropping)\n", (int) -(delay / 16666)); */
330                 s->time_frame += int64_t_C(1000000);
331             }
332             break;
333         }
334         ts.tv_sec = delay / 1000000;
335         ts.tv_nsec = (delay % 1000000) * 1000;
336         nanosleep(&ts, NULL);
337     }
338
339     if (av_new_packet(pkt, s->frame_size) < 0)
340         return AVERROR_IO;
341
342     pkt->pts = curtime;
343
344     /* read one frame */
345     if (s->aiw_enabled) {
346         return aiw_read_picture(s, pkt->data);
347     } else if (s->use_mmap) {
348         return v4l_mm_read_picture(s, pkt->data);
349     } else {
350         if (read(s->fd, pkt->data, pkt->size) != pkt->size)
351             return AVERROR_IO;
352         return s->frame_size;
353     }
354 }
355
356 static int grab_read_close(AVFormatContext *s1)
357 {
358     VideoData *s = s1->priv_data;
359
360     if (s->aiw_enabled)
361         aiw_close(s);
362
363     if (s->use_mmap)
364         munmap(s->video_buf, s->gb_buffers.size);
365
366     /* mute audio. we must force it because the BTTV driver does not
367        return its state correctly */
368     s->audio_saved.flags |= VIDEO_AUDIO_MUTE;
369     ioctl(s->fd, VIDIOCSAUDIO, &s->audio_saved);
370
371     close(s->fd);
372     return 0;
373 }
374
375 static AVInputFormat video_grab_device_format = {
376     "video4linux",
377     "video grab",
378     sizeof(VideoData),
379     NULL,
380     grab_read_header,
381     grab_read_packet,
382     grab_read_close,
383     .flags = AVFMT_NOFILE,
384 };
385
386 /* All in Wonder specific stuff */
387 /* XXX: remove and merge in libavcodec/imgconvert.c */
388
389 static int aiw_init(VideoData *s)
390 {
391     int width, height;
392
393     width = s->width;
394     height = s->height;
395
396     if ((width == s->video_cap.maxwidth && height == s->video_cap.maxheight) ||
397         (width == s->video_cap.maxwidth && height == s->video_cap.maxheight*2) ||
398         (width == s->video_cap.maxwidth/2 && height == s->video_cap.maxheight)) {
399
400         s->deint=0;
401         s->halfw=0;
402         if (height == s->video_cap.maxheight*2) s->deint=1;
403         if (width == s->video_cap.maxwidth/2) s->halfw=1;
404     } else {
405         av_log(NULL, AV_LOG_ERROR, "\nIncorrect Grab Size Supplied - Supported Sizes Are:\n");
406         av_log(NULL, AV_LOG_ERROR, " %dx%d  %dx%d %dx%d\n\n",
407                 s->video_cap.maxwidth,s->video_cap.maxheight,
408                 s->video_cap.maxwidth,s->video_cap.maxheight*2,
409                 s->video_cap.maxwidth/2,s->video_cap.maxheight);
410         goto fail;
411     }
412
413     if (s->halfw == 0) {
414         s->src_mem = av_malloc(s->width*2);
415     } else {
416         s->src_mem = av_malloc(s->width*4);
417     }
418     if (!s->src_mem) goto fail;
419
420     s->lum_m4_mem = av_malloc(s->width);
421     if (!s->lum_m4_mem)
422         goto fail;
423     return 0;
424  fail:
425     av_freep(&s->src_mem);
426     av_freep(&s->lum_m4_mem);
427     return -1;
428 }
429
430 #ifdef HAVE_MMX
431 #include "libavcodec/i386/mmx.h"
432
433 #define LINE_WITH_UV \
434                     movq_m2r(ptr[0],mm0); \
435                     movq_m2r(ptr[8],mm1);  \
436                     movq_r2r(mm0, mm4); \
437                     punpcklbw_r2r(mm1,mm0); \
438                     punpckhbw_r2r(mm1,mm4); \
439                     movq_r2r(mm0,mm5); \
440                     punpcklbw_r2r(mm4,mm0); \
441                     punpckhbw_r2r(mm4,mm5); \
442                     movq_r2r(mm0,mm1); \
443                     punpcklbw_r2r(mm5,mm1); \
444                     movq_r2m(mm1,lum[0]); \
445                     movq_m2r(ptr[16],mm2); \
446                     movq_m2r(ptr[24],mm1); \
447                     movq_r2r(mm2,mm4); \
448                     punpcklbw_r2r(mm1,mm2); \
449                     punpckhbw_r2r(mm1,mm4); \
450                     movq_r2r(mm2,mm3); \
451                     punpcklbw_r2r(mm4,mm2); \
452                     punpckhbw_r2r(mm4,mm3); \
453                     movq_r2r(mm2,mm1); \
454                     punpcklbw_r2r(mm3,mm1); \
455                     movq_r2m(mm1,lum[8]); \
456                     punpckhdq_r2r(mm2,mm0); \
457                     punpckhdq_r2r(mm3,mm5); \
458                     movq_r2m(mm0,cb[0]); \
459                     movq_r2m(mm5,cr[0]);
460
461 #define LINE_NO_UV \
462                     movq_m2r(ptr[0],mm0);\
463                     movq_m2r(ptr[8],mm1);\
464                     movq_r2r(mm0, mm4);\
465                     punpcklbw_r2r(mm1,mm0); \
466                     punpckhbw_r2r(mm1,mm4);\
467                     movq_r2r(mm0,mm5);\
468                     punpcklbw_r2r(mm4,mm0);\
469                     punpckhbw_r2r(mm4,mm5);\
470                     movq_r2r(mm0,mm1);\
471                     punpcklbw_r2r(mm5,mm1);\
472                     movq_r2m(mm1,lum[0]);\
473                     movq_m2r(ptr[16],mm2);\
474                     movq_m2r(ptr[24],mm1);\
475                     movq_r2r(mm2,mm4);\
476                     punpcklbw_r2r(mm1,mm2);\
477                     punpckhbw_r2r(mm1,mm4);\
478                     movq_r2r(mm2,mm3);\
479                     punpcklbw_r2r(mm4,mm2);\
480                     punpckhbw_r2r(mm4,mm3);\
481                     movq_r2r(mm2,mm1);\
482                     punpcklbw_r2r(mm3,mm1);\
483                     movq_r2m(mm1,lum[8]);
484
485 #define LINE_WITHUV_AVG \
486                     movq_m2r(ptr[0], mm0);\
487                     movq_m2r(ptr[8], mm1);\
488                     movq_r2r(mm0, mm4);\
489                     punpcklbw_r2r(mm1,mm0);\
490                     punpckhbw_r2r(mm1,mm4);\
491                     movq_r2r(mm0,mm5);\
492                     punpcklbw_r2r(mm4,mm0);\
493                     punpckhbw_r2r(mm4,mm5);\
494                     movq_r2r(mm0,mm1);\
495                     movq_r2r(mm5,mm2);\
496                     punpcklbw_r2r(mm7,mm1);\
497                     punpcklbw_r2r(mm7,mm2);\
498                     paddw_r2r(mm6,mm1);\
499                     paddw_r2r(mm2,mm1);\
500                     psraw_i2r(1,mm1);\
501                     packuswb_r2r(mm7,mm1);\
502                     movd_r2m(mm1,lum[0]);\
503                     movq_m2r(ptr[16],mm2);\
504                     movq_m2r(ptr[24],mm1);\
505                     movq_r2r(mm2,mm4);\
506                     punpcklbw_r2r(mm1,mm2);\
507                     punpckhbw_r2r(mm1,mm4);\
508                     movq_r2r(mm2,mm3);\
509                     punpcklbw_r2r(mm4,mm2);\
510                     punpckhbw_r2r(mm4,mm3);\
511                     movq_r2r(mm2,mm1);\
512                     movq_r2r(mm3,mm4);\
513                     punpcklbw_r2r(mm7,mm1);\
514                     punpcklbw_r2r(mm7,mm4);\
515                     paddw_r2r(mm6,mm1);\
516                     paddw_r2r(mm4,mm1);\
517                     psraw_i2r(1,mm1);\
518                     packuswb_r2r(mm7,mm1);\
519                     movd_r2m(mm1,lum[4]);\
520                     punpckhbw_r2r(mm7,mm0);\
521                     punpckhbw_r2r(mm7,mm2);\
522                     paddw_r2r(mm6,mm0);\
523                     paddw_r2r(mm2,mm0);\
524                     psraw_i2r(1,mm0);\
525                     packuswb_r2r(mm7,mm0);\
526                     punpckhbw_r2r(mm7,mm5);\
527                     punpckhbw_r2r(mm7,mm3);\
528                     paddw_r2r(mm6,mm5);\
529                     paddw_r2r(mm3,mm5);\
530                     psraw_i2r(1,mm5);\
531                     packuswb_r2r(mm7,mm5);\
532                     movd_r2m(mm0,cb[0]);\
533                     movd_r2m(mm5,cr[0]);
534
535 #define LINE_NOUV_AVG \
536                     movq_m2r(ptr[0],mm0);\
537                     movq_m2r(ptr[8],mm1);\
538                     pand_r2r(mm5,mm0);\
539                     pand_r2r(mm5,mm1);\
540                     pmaddwd_r2r(mm6,mm0);\
541                     pmaddwd_r2r(mm6,mm1);\
542                     packssdw_r2r(mm1,mm0);\
543                     paddw_r2r(mm6,mm0);\
544                     psraw_i2r(1,mm0);\
545                     movq_m2r(ptr[16],mm2);\
546                     movq_m2r(ptr[24],mm3);\
547                     pand_r2r(mm5,mm2);\
548                     pand_r2r(mm5,mm3);\
549                     pmaddwd_r2r(mm6,mm2);\
550                     pmaddwd_r2r(mm6,mm3);\
551                     packssdw_r2r(mm3,mm2);\
552                     paddw_r2r(mm6,mm2);\
553                     psraw_i2r(1,mm2);\
554                     packuswb_r2r(mm2,mm0);\
555                     movq_r2m(mm0,lum[0]);
556
557 #define DEINT_LINE_LUM(ptroff) \
558                     movd_m2r(lum_m4[(ptroff)],mm0);\
559                     movd_m2r(lum_m3[(ptroff)],mm1);\
560                     movd_m2r(lum_m2[(ptroff)],mm2);\
561                     movd_m2r(lum_m1[(ptroff)],mm3);\
562                     movd_m2r(lum[(ptroff)],mm4);\
563                     punpcklbw_r2r(mm7,mm0);\
564                     movd_r2m(mm2,lum_m4[(ptroff)]);\
565                     punpcklbw_r2r(mm7,mm1);\
566                     punpcklbw_r2r(mm7,mm2);\
567                     punpcklbw_r2r(mm7,mm3);\
568                     punpcklbw_r2r(mm7,mm4);\
569                     psllw_i2r(2,mm1);\
570                     psllw_i2r(1,mm2);\
571                     paddw_r2r(mm6,mm1);\
572                     psllw_i2r(2,mm3);\
573                     paddw_r2r(mm2,mm1);\
574                     paddw_r2r(mm4,mm0);\
575                     paddw_r2r(mm3,mm1);\
576                     psubusw_r2r(mm0,mm1);\
577                     psrlw_i2r(3,mm1);\
578                     packuswb_r2r(mm7,mm1);\
579                     movd_r2m(mm1,lum_m2[(ptroff)]);
580
581 #else
582 #include "libavcodec/dsputil.h"
583
584 #define LINE_WITH_UV \
585                     lum[0]=ptr[0];lum[1]=ptr[2];lum[2]=ptr[4];lum[3]=ptr[6];\
586                     cb[0]=ptr[1];cb[1]=ptr[5];\
587                     cr[0]=ptr[3];cr[1]=ptr[7];\
588                     lum[4]=ptr[8];lum[5]=ptr[10];lum[6]=ptr[12];lum[7]=ptr[14];\
589                     cb[2]=ptr[9];cb[3]=ptr[13];\
590                     cr[2]=ptr[11];cr[3]=ptr[15];\
591                     lum[8]=ptr[16];lum[9]=ptr[18];lum[10]=ptr[20];lum[11]=ptr[22];\
592                     cb[4]=ptr[17];cb[5]=ptr[21];\
593                     cr[4]=ptr[19];cr[5]=ptr[23];\
594                     lum[12]=ptr[24];lum[13]=ptr[26];lum[14]=ptr[28];lum[15]=ptr[30];\
595                     cb[6]=ptr[25];cb[7]=ptr[29];\
596                     cr[6]=ptr[27];cr[7]=ptr[31];
597
598 #define LINE_NO_UV \
599                     lum[0]=ptr[0];lum[1]=ptr[2];lum[2]=ptr[4];lum[3]=ptr[6];\
600                     lum[4]=ptr[8];lum[5]=ptr[10];lum[6]=ptr[12];lum[7]=ptr[14];\
601                     lum[8]=ptr[16];lum[9]=ptr[18];lum[10]=ptr[20];lum[11]=ptr[22];\
602                     lum[12]=ptr[24];lum[13]=ptr[26];lum[14]=ptr[28];lum[15]=ptr[30];
603
604 #define LINE_WITHUV_AVG \
605                     sum=(ptr[0]+ptr[2]+1) >> 1;lum[0]=sum; \
606                     sum=(ptr[4]+ptr[6]+1) >> 1;lum[1]=sum; \
607                     sum=(ptr[1]+ptr[5]+1) >> 1;cb[0]=sum; \
608                     sum=(ptr[3]+ptr[7]+1) >> 1;cr[0]=sum; \
609                     sum=(ptr[8]+ptr[10]+1) >> 1;lum[2]=sum; \
610                     sum=(ptr[12]+ptr[14]+1) >> 1;lum[3]=sum; \
611                     sum=(ptr[9]+ptr[13]+1) >> 1;cb[1]=sum; \
612                     sum=(ptr[11]+ptr[15]+1) >> 1;cr[1]=sum; \
613                     sum=(ptr[16]+ptr[18]+1) >> 1;lum[4]=sum; \
614                     sum=(ptr[20]+ptr[22]+1) >> 1;lum[5]=sum; \
615                     sum=(ptr[17]+ptr[21]+1) >> 1;cb[2]=sum; \
616                     sum=(ptr[19]+ptr[23]+1) >> 1;cr[2]=sum; \
617                     sum=(ptr[24]+ptr[26]+1) >> 1;lum[6]=sum; \
618                     sum=(ptr[28]+ptr[30]+1) >> 1;lum[7]=sum; \
619                     sum=(ptr[25]+ptr[29]+1) >> 1;cb[3]=sum; \
620                     sum=(ptr[27]+ptr[31]+1) >> 1;cr[3]=sum;
621
622 #define LINE_NOUV_AVG \
623                     sum=(ptr[0]+ptr[2]+1) >> 1;lum[0]=sum; \
624                     sum=(ptr[4]+ptr[6]+1) >> 1;lum[1]=sum; \
625                     sum=(ptr[8]+ptr[10]+1) >> 1;lum[2]=sum; \
626                     sum=(ptr[12]+ptr[14]+1) >> 1;lum[3]=sum; \
627                     sum=(ptr[16]+ptr[18]+1) >> 1;lum[4]=sum; \
628                     sum=(ptr[20]+ptr[22]+1) >> 1;lum[5]=sum; \
629                     sum=(ptr[24]+ptr[26]+1) >> 1;lum[6]=sum; \
630                     sum=(ptr[28]+ptr[30]+1) >> 1;lum[7]=sum;
631
632 #define DEINT_LINE_LUM(ptroff) \
633                     sum=(-lum_m4[(ptroff)]+(lum_m3[(ptroff)]<<2)+(lum_m2[(ptroff)]<<1)+(lum_m1[(ptroff)]<<2)-lum[(ptroff)]); \
634                     lum_m4[(ptroff)]=lum_m2[(ptroff)];\
635                     lum_m2[(ptroff)]=cm[(sum+4)>>3];\
636                     sum=(-lum_m4[(ptroff)+1]+(lum_m3[(ptroff)+1]<<2)+(lum_m2[(ptroff)+1]<<1)+(lum_m1[(ptroff)+1]<<2)-lum[(ptroff)+1]); \
637                     lum_m4[(ptroff)+1]=lum_m2[(ptroff)+1];\
638                     lum_m2[(ptroff)+1]=cm[(sum+4)>>3];\
639                     sum=(-lum_m4[(ptroff)+2]+(lum_m3[(ptroff)+2]<<2)+(lum_m2[(ptroff)+2]<<1)+(lum_m1[(ptroff)+2]<<2)-lum[(ptroff)+2]); \
640                     lum_m4[(ptroff)+2]=lum_m2[(ptroff)+2];\
641                     lum_m2[(ptroff)+2]=cm[(sum+4)>>3];\
642                     sum=(-lum_m4[(ptroff)+3]+(lum_m3[(ptroff)+3]<<2)+(lum_m2[(ptroff)+3]<<1)+(lum_m1[(ptroff)+3]<<2)-lum[(ptroff)+3]); \
643                     lum_m4[(ptroff)+3]=lum_m2[(ptroff)+3];\
644                     lum_m2[(ptroff)+3]=cm[(sum+4)>>3];
645
646 #endif
647
648
649 /* Read two fields separately. */
650 static int aiw_read_picture(VideoData *s, uint8_t *data)
651 {
652     uint8_t *ptr, *lum, *cb, *cr;
653     int h;
654 #ifndef HAVE_MMX
655     int sum;
656 #endif
657     uint8_t* src = s->src_mem;
658     uint8_t *ptrend = &src[s->width*2];
659     lum=data;
660     cb=&lum[s->width*s->height];
661     cr=&cb[(s->width*s->height)/4];
662     if (s->deint == 0 && s->halfw == 0) {
663         while (read(s->fd,src,s->width*2) < 0) {
664             usleep(100);
665         }
666         for (h = 0; h < s->height-2; h+=2) {
667             for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) {
668                 LINE_WITH_UV
669                     }
670             read(s->fd,src,s->width*2);
671             for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16) {
672                 LINE_NO_UV
673                     }
674             read(s->fd,src,s->width*2);
675         }
676         /*
677          * Do last two lines
678          */
679         for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) {
680             LINE_WITH_UV
681                 }
682         read(s->fd,src,s->width*2);
683         for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16) {
684             LINE_NO_UV
685                 }
686         /* drop second field */
687         while (read(s->fd,src,s->width*2) < 0) {
688             usleep(100);
689         }
690         for (h = 0; h < s->height - 1; h++) {
691             read(s->fd,src,s->width*2);
692         }
693     } else if (s->halfw == 1) {
694 #ifdef HAVE_MMX
695         mmx_t rounder;
696         mmx_t masker;
697         rounder.uw[0]=1;
698         rounder.uw[1]=1;
699         rounder.uw[2]=1;
700         rounder.uw[3]=1;
701         masker.ub[0]=0xff;
702         masker.ub[1]=0;
703         masker.ub[2]=0xff;
704         masker.ub[3]=0;
705         masker.ub[4]=0xff;
706         masker.ub[5]=0;
707         masker.ub[6]=0xff;
708         masker.ub[7]=0;
709         pxor_r2r(mm7,mm7);
710         movq_m2r(rounder,mm6);
711 #endif
712         while (read(s->fd,src,s->width*4) < 0) {
713             usleep(100);
714         }
715         ptrend = &src[s->width*4];
716         for (h = 0; h < s->height-2; h+=2) {
717             for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=8, cb+=4, cr+=4) {
718                 LINE_WITHUV_AVG
719                     }
720             read(s->fd,src,s->width*4);
721 #ifdef HAVE_MMX
722             movq_m2r(masker,mm5);
723 #endif
724             for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=8) {
725                 LINE_NOUV_AVG
726                     }
727             read(s->fd,src,s->width*4);
728         }
729         /*
730  * Do last two lines
731  */
732         for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=8, cb+=4, cr+=4) {
733             LINE_WITHUV_AVG
734                 }
735         read(s->fd,src,s->width*4);
736 #ifdef HAVE_MMX
737         movq_m2r(masker,mm5);
738 #endif
739         for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=8) {
740             LINE_NOUV_AVG
741                 }
742         /* drop second field */
743         while (read(s->fd,src,s->width*4) < 0) {
744             usleep(100);
745         }
746         for (h = 0; h < s->height - 1; h++) {
747             read(s->fd,src,s->width*4);
748         }
749     } else {
750         uint8_t *lum_m1, *lum_m2, *lum_m3, *lum_m4;
751 #ifdef HAVE_MMX
752         mmx_t rounder;
753         rounder.uw[0]=4;
754         rounder.uw[1]=4;
755         rounder.uw[2]=4;
756         rounder.uw[3]=4;
757         movq_m2r(rounder,mm6);
758         pxor_r2r(mm7,mm7);
759 #else
760         uint8_t *cm = cropTbl + MAX_NEG_CROP;
761 #endif
762
763         /* read two fields and deinterlace them */
764         while (read(s->fd,src,s->width*2) < 0) {
765             usleep(100);
766         }
767         for (h = 0; h < (s->height/2)-2; h+=2) {
768             for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) {
769                 LINE_WITH_UV
770                     }
771             read(s->fd,src,s->width*2);
772             /* skip a luminance line - will be filled in later */
773             lum += s->width;
774             for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) {
775                 LINE_WITH_UV
776                     }
777             /* skip a luminance line - will be filled in later */
778             lum += s->width;
779             read(s->fd,src,s->width*2);
780         }
781         /*
782  * Do last two lines
783  */
784         for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) {
785             LINE_WITH_UV
786                 }
787         /* skip a luminance line - will be filled in later */
788         lum += s->width;
789         read(s->fd,src,s->width*2);
790         for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) {
791             LINE_WITH_UV
792                 }
793         /*
794  *
795  * SECOND FIELD
796  *
797  */
798         lum=&data[s->width];
799         while (read(s->fd,src,s->width*2) < 0) {
800             usleep(10);
801         }
802         /* First (and last) two lines not interlaced */
803         for (h = 0; h < 2; h++) {
804             for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16) {
805                 LINE_NO_UV
806                     }
807             read(s->fd,src,s->width*2);
808             /* skip a luminance line */
809             lum += s->width;
810         }
811         lum_m1=&lum[-s->width];
812         lum_m2=&lum_m1[-s->width];
813         lum_m3=&lum_m2[-s->width];
814         memmove(s->lum_m4_mem,&lum_m3[-s->width],s->width);
815         for (; h < (s->height/2)-1; h++) {
816             lum_m4=s->lum_m4_mem;
817             for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16,lum_m1+=16,lum_m2+=16,lum_m3+=16,lum_m4+=16) {
818                 LINE_NO_UV
819
820                     DEINT_LINE_LUM(0)
821                     DEINT_LINE_LUM(4)
822                     DEINT_LINE_LUM(8)
823                     DEINT_LINE_LUM(12)
824                     }
825             read(s->fd,src,s->width*2);
826             /* skip a luminance line */
827             lum += s->width;
828             lum_m1 += s->width;
829             lum_m2 += s->width;
830             lum_m3 += s->width;
831             //                lum_m4 += s->width;
832         }
833         /*
834  * Do last line
835  */
836         lum_m4=s->lum_m4_mem;
837         for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, lum_m1+=16, lum_m2+=16, lum_m3+=16, lum_m4+=16) {
838             LINE_NO_UV
839
840                 DEINT_LINE_LUM(0)
841                 DEINT_LINE_LUM(4)
842                 DEINT_LINE_LUM(8)
843                 DEINT_LINE_LUM(12)
844                 }
845     }
846 #ifdef HAVE_MMX
847     emms();
848 #endif
849     return s->frame_size;
850 }
851
852 static int aiw_close(VideoData *s)
853 {
854     av_freep(&s->lum_m4_mem);
855     av_freep(&s->src_mem);
856     return 0;
857 }
858
859 int video_grab_init(void)
860 {
861     av_register_input_format(&video_grab_device_format);
862     return 0;
863 }