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