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