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