fix: not displaying non-4 aligned video
[platform/adaptation/xf86-video-emulfb.git] / src / xv / i386 / fbdev_video_v4l2.c
1 /**************************************************************************
2
3 xserver-xorg-video-emulfb
4
5 Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: Boram Park <boram1288.park@samsung.com>
8
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sub license, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
16
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial portions
19 of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
24 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29 **************************************************************************/
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <sys/mman.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <X11/extensions/Xv.h>
40 #include <X11/extensions/Xvproto.h>
41
42 #include "fbdev_util.h"
43 #include "fbdev_video_v4l2.h"
44
45 #include "fbdev.h"
46 #include "fbdev_fb.h"
47 #include "fbdev_util.h"
48 #include "fbdev_video.h"
49 #include "fbdev_video_fourcc.h"
50 #include "fbdev_pixman.h"
51
52 #define BUF_NUM     1
53
54 typedef struct _DeviceInfo
55 {
56         char *video;     /* video */
57         int   bOpened;
58 } DeviceInfo;
59
60 typedef struct _FormatInfo
61 {
62         int           id;
63         int           type;
64         uint          pixelformat;
65         FBDevV4l2Memory memory;
66 } FormatInfo;
67
68 typedef struct
69 {
70         int index;
71
72         ScreenPtr pScreen;
73
74         int       video_fd;
75
76         struct
77         {
78                 int init;
79                 xRectangle img;
80                 xRectangle crop;
81                 xRectangle dst;
82                 int id;
83                 int hw_rotate;
84                 int scn_rotate;
85                 int hflip;
86                 int vflip;
87                 int streamon;
88                 int cur_idx;
89
90                 void* last_buffer;
91                 int   queued_index;
92
93                 void* backup;
94                 Bool  sync;
95         } status;
96
97         int size;
98         unsigned int pixfmt;
99         FBDevV4l2FimcBuffer fimcbuf;
100         FBDevV4l2SrcBuffer *src_buf;
101         FBDevV4l2DstBuffer *dst_buf;
102         FBDevV4l2Memory     memory;
103
104         int offset_x;
105         int offset_y;
106
107         int re_setting;
108
109     void *aligned_buffer;
110     int   aligned_width;
111 } FBDevDispHandle;
112
113 enum
114 {
115         TYPE_RGB,
116         TYPE_YUV444,
117         TYPE_YUV422,
118         TYPE_YUV420,
119 };
120
121 static FormatInfo format_infos [] =
122 {
123         { FOURCC_RGB565,    TYPE_RGB,       V4L2_PIX_FMT_RGB565,    V4L2_MEMORY_MMAP },
124         { FOURCC_RGB32,     TYPE_RGB,       V4L2_PIX_FMT_RGB32,     V4L2_MEMORY_MMAP },
125         { FOURCC_I420,      TYPE_YUV420,    V4L2_PIX_FMT_YUV420,    V4L2_MEMORY_MMAP },
126         { FOURCC_YUY2,      TYPE_YUV422,    V4L2_PIX_FMT_YUYV,      V4L2_MEMORY_MMAP },
127         { FOURCC_YV12,      TYPE_YUV420,    V4L2_PIX_FMT_YVU420,    V4L2_MEMORY_MMAP },
128
129 };
130
131 static XF86ImageRec Images[] =
132 {
133         XVIMAGE_I420,
134         XVIMAGE_YV12,
135         XVIMAGE_YUY2,
136         XVIMAGE_RGB32,
137         XVIMAGE_RGB565,
138 };
139
140 static DeviceInfo device_infos[] =
141 {
142         { "/dev/video1", FALSE },
143         { "/dev/video2", FALSE },
144 };
145
146 #define NUM_IMAGES        (sizeof(Images) / sizeof(XF86ImageRec))
147 #define DEVICE_NUMS (sizeof (device_infos) / sizeof (DeviceInfo))
148
149 static Bool
150 _fbdevVideoV4l2SetDst (int fd, int offset_x, int offset_y, xRectangle *rect)
151 {
152         struct v4l2_format      format = {0,};
153         int caps;
154
155         return_val_if_fail (fd >= 0, FALSE);
156
157         DRVLOG ("[SetDst] offset(%d,%d) win(%d,%d %dx%d) \n", offset_x, offset_y,
158                 rect->x, rect->y, rect->width, rect->height);
159
160         caps = V4L2_CAP_VIDEO_OVERLAY;
161         if (!fbdev_v4l2_querycap (fd, caps))
162                 return FALSE;
163
164         /* set format */
165         CLEAR (format);
166         format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
167         if (!fbdev_v4l2_g_fmt (fd, &format))
168                 return FALSE;
169
170         format.fmt.win.w.left   = rect->x + offset_x;
171         format.fmt.win.w.top    = rect->y + offset_y;
172         format.fmt.win.w.width  = rect->width;
173         format.fmt.win.w.height = rect->height;
174         if (!fbdev_v4l2_s_fmt (fd, &format))
175                 return FALSE;
176
177         return TRUE;
178 }
179
180 static Bool
181 _fbdevVideoV4l2SetBuffer (int fd,
182                           FBDevV4l2BufType type,
183                           FBDevV4l2Memory memory,
184                           int num_buf,
185                           FBDevV4l2DstBuffer **mem_buf)
186 {
187         struct v4l2_requestbuffers      req = {0,};
188
189         return_val_if_fail (fd >= 0, FALSE);
190
191         DRVLOG ("[SetBuffer] num_buf(%d) mem_buf(%p) memory(%d)\n",
192                 num_buf, mem_buf, memory);
193
194         CLEAR (req);
195         req.count  = num_buf;
196         req.type   = type;
197         req.memory = memory;
198         if (!fbdev_v4l2_reqbuf (fd, &req))
199                 return FALSE;
200
201         if (memory == V4L2_MEMORY_MMAP)
202         {
203                 FBDevV4l2DstBuffer *out_buf;
204                 int i;
205
206                 return_val_if_fail (mem_buf != NULL, FALSE);
207
208                 out_buf = calloc (req.count, sizeof (FBDevV4l2DstBuffer));
209                 return_val_if_fail (out_buf != NULL, FALSE);
210
211                 for (i = 0; i < num_buf; i++)
212                 {
213                         struct v4l2_buffer buffer = {0,};
214
215                         CLEAR (buffer);
216                         buffer.index  = i;
217                         buffer.type   = type;
218                         buffer.memory = V4L2_MEMORY_MMAP;
219                         if (!fbdev_v4l2_querybuf (fd, &buffer))
220                         {
221                                 free (out_buf);
222                                 return FALSE;
223                         }
224
225                         out_buf[i].index  = buffer.index;
226                         out_buf[i].size   = buffer.length;
227                         out_buf[i].buf    = mmap (NULL, buffer.length,
228                                                   PROT_READ | PROT_WRITE , \
229                                                   MAP_SHARED , fd, buffer.m.offset & ~(PAGE_SIZE - 1));
230                         out_buf[i].buf    += buffer.m.offset & (PAGE_SIZE - 1);
231
232                         if (out_buf[i].buf == MAP_FAILED)
233                         {
234                                 xf86DrvMsg (0, X_ERROR, "[SetBuffer] mmap failed. index(%d)\n", i);
235                                 free (out_buf);
236                                 return FALSE;
237                         }
238                 }
239
240                 *mem_buf = out_buf;
241         }
242
243         return TRUE;
244 }
245
246 static Bool
247 _fbdevVideoV4l2ClearBuffer (int fd,
248                             FBDevV4l2BufType type,
249                             FBDevV4l2Memory memory,
250                             int num_buf,
251                             FBDevV4l2DstBuffer *mem_buf)
252 {
253         struct v4l2_requestbuffers req = {0,};
254
255         return_val_if_fail (fd >= 0, FALSE);
256
257         DRVLOG ("[ClearBuffer] memory(%d) num_buf(%d) mem_buf(%p)\n",
258                 num_buf, mem_buf, memory);
259
260         if (memory == V4L2_MEMORY_MMAP && mem_buf)
261         {
262                 int i;
263
264                 for (i = 0; i < num_buf; i++)
265                         if (mem_buf[i].buf)
266                                 if (munmap (mem_buf[i].buf, mem_buf[i].size) == -1)
267                                         xf86DrvMsg (0, X_WARNING, "[ClearBuffer] Failed to unmap v4l2 buffer at index %d\n", i);
268
269                 free (mem_buf);
270         }
271
272         CLEAR (req);
273         req.count  = 0;
274         req.type   = type;
275         req.memory = memory;
276         if (!fbdev_v4l2_reqbuf (fd, &req))
277                 return FALSE;
278
279         return TRUE;
280 }
281
282 static Bool
283 _fbdevVideoV4l2StreamOn (int fd)
284 {
285         return_val_if_fail (fd >= 0, FALSE);
286
287         DRVLOG ("[StreamOn] \n");
288
289         if (!fbdev_v4l2_start_overlay (fd))
290                 return FALSE;
291
292         return TRUE;
293 }
294
295
296 static Bool
297 _fbdevVideoV4l2StreamOff (int fd)
298 {
299         return_val_if_fail (fd >= 0, FALSE);
300
301         DRVLOG ("[StreamOff] \n");
302
303         if (!fbdev_v4l2_stop_overlay (fd))
304                 return FALSE;
305
306         return TRUE;
307 }
308
309 static int
310 _open_device (char *device)
311 {
312         int fd;
313
314         return_val_if_fail (device != NULL, -1);
315
316         fd = open (device, O_RDWR);
317         if (fd < 0)
318         {
319                 xf86DrvMsg (0, X_ERROR, "Cannot open '%s'. fd(%d)\n", device, fd);
320                 return -1;
321         }
322
323         DRVLOG ("'%s' opened. fd(%d) \n", device, fd);
324
325         return fd;
326 }
327
328 static void
329 _close_device (int fd)
330 {
331         int ret;
332
333         return_if_fail (fd >= 0);
334
335         ret = close (fd);
336         if (ret < 0)
337         {
338                 xf86DrvMsg (0, X_ERROR, "Cannot close fd(%d)\n", fd);
339                 return;
340         }
341
342         DRVLOG ("fd(%d) closed. \n", fd);
343 }
344
345 static Bool
346 _fbdevVideoV4l2EnsureStreamOff (FBDevDispHandle *hdisp)
347 {
348         if (!hdisp->status.streamon)
349                 return TRUE;
350
351         if (!_fbdevVideoV4l2StreamOff (hdisp->video_fd))
352                 return FALSE;
353
354         hdisp->status.streamon = FALSE;
355
356         return TRUE;
357 }
358
359 static Bool
360 _fbdevVideoV4l2OpenDevice (FBDevDispHandle *hdisp, int index)
361 {
362         if (device_infos[index].bOpened)
363         {
364                 DRVLOG ("[OpenDevice, %p] Already opened : %s\n", hdisp, device_infos[index].video);
365                 return FALSE;
366         }
367
368         hdisp->video_fd = _open_device (device_infos[index].video);
369         if (hdisp->video_fd < 0)
370                 return FALSE;
371
372         device_infos[index].bOpened = TRUE;
373
374         return TRUE;
375 }
376
377 /* This function never failed.
378  * If failed, it means kernel has some problems.
379  * Then a device should be rebooted.
380  */
381 static void
382 _fbdevVideoV4l2CloseDevice (FBDevDispHandle *hdisp)
383 {
384         if (!_fbdevVideoV4l2EnsureStreamOff (hdisp)) // We will consider this as a LCD Off case.
385                 xf86DrvMsg (0, X_WARNING, "[CloseDevice, %p] Warning : Cannot stream off!! \n", hdisp);
386
387         if (hdisp->video_fd >= 0)
388                 if (!_fbdevVideoV4l2ClearBuffer (hdisp->video_fd,
389                                                  V4L2_BUF_TYPE_VIDEO_OVERLAY,
390                                                  hdisp->memory,
391                                                  BUF_NUM,
392                                                  hdisp->dst_buf))
393                         xf86DrvMsg (0, X_WARNING, "[CloseDevice, %p] Warning : Cannot clear buffer!! \n", hdisp);
394
395         hdisp->dst_buf = NULL;
396
397         if (hdisp->video_fd >= 0)
398         {
399                 _close_device (hdisp->video_fd);
400                 hdisp->video_fd = -1;
401         }
402
403     if (hdisp->aligned_buffer)
404     {
405         free (hdisp->aligned_buffer);
406         hdisp->aligned_buffer = NULL;
407         hdisp->aligned_width = 0;
408     }
409
410         device_infos[hdisp->index].bOpened = FALSE;
411 }
412
413 int
414 fbdevVideoV4l2GetHandleNums (void)
415 {
416         return DEVICE_NUMS;
417 }
418
419 Bool
420 fbdevVideoV4l2HandleOpened (int index)
421 {
422         return_val_if_fail (index < DEVICE_NUMS, FALSE);
423
424         return device_infos[index].bOpened;
425 }
426
427 void *
428 fbdevVideoV4l2OpenHandle (ScreenPtr pScreen, int index, int requestbuffer)
429 {
430         FBDevDispHandle *handle;
431
432         return_val_if_fail (pScreen != NULL, NULL);
433         return_val_if_fail (index < DEVICE_NUMS, NULL);
434
435         handle = (FBDevDispHandle*)calloc (sizeof (FBDevDispHandle), 1);
436
437         return_val_if_fail (handle != NULL, NULL);
438
439         handle->pScreen = pScreen;
440         handle->index = index;
441         handle->status.hw_rotate = -1;
442         handle->status.id     = 0;
443         handle->status.cur_idx = -1;
444         handle->status.init = 0;
445         handle->memory = V4L2_MEMORY_MMAP;
446         handle->video_fd = -1;
447
448         if (!_fbdevVideoV4l2OpenDevice (handle, index))
449         {
450                 free (handle);
451                 return NULL;
452         }
453
454         DRVLOG ("[OpenHandle, %p] Handle(%d) opened. \n", handle, index);
455
456         return handle;
457 }
458
459 void
460 fbdevVideoV4l2CloseHandle (void *handle)
461 {
462         FBDevDispHandle *hdisp = (FBDevDispHandle*)handle;
463
464         return_if_fail (handle != NULL);
465
466         _fbdevVideoV4l2CloseDevice ((FBDevDispHandle*)handle);
467
468         if (hdisp->status.backup)
469         {
470                 free (hdisp->status.backup);
471                 hdisp->status.backup = NULL;
472         }
473
474         DRVLOG ("[CloseHandle, %p] Handle(%d) closed. \n", hdisp, hdisp->index);
475
476         free (handle);
477 }
478
479 Bool
480 fbdevVideoV4l2StreamOn (void *handle)
481 {
482         FBDevDispHandle *hdisp = (FBDevDispHandle*)handle;
483         uint phy_addrs[3];
484
485         return_val_if_fail (hdisp != NULL, FALSE);
486
487         hdisp->re_setting = TRUE;
488
489         if (!_fbdevVideoV4l2OpenDevice (hdisp, hdisp->index))
490                 return FALSE;
491
492         fbdevVideoV4l2SetFormat (handle,
493                                  &hdisp->status.img,
494                                  &hdisp->status.crop,
495                                  &hdisp->status.dst,
496                                  hdisp->status.id,
497                                  hdisp->status.scn_rotate,
498                                  hdisp->status.hw_rotate,
499                                  hdisp->status.hflip,
500                                  hdisp->status.vflip,
501                                  BUF_NUM,
502                                  hdisp->status.sync);
503
504         phy_addrs[0] = hdisp->fimcbuf.base[0];
505         phy_addrs[1] = hdisp->fimcbuf.base[1];
506         phy_addrs[2] = hdisp->fimcbuf.base[2];
507
508         if (hdisp->status.backup)
509         {
510                 int size;
511
512                 size = fbdevVideoQueryImageAttributes (NULL, FOURCC_RGB32,
513                                                        (unsigned short*)&hdisp->status.dst.width,
514                                                        (unsigned short*)&hdisp->status.dst.height,
515                                                        NULL, NULL, NULL);
516
517                 memcpy (hdisp->dst_buf[0].buf, hdisp->status.backup, size);
518
519                 free (hdisp->status.backup);
520                 hdisp->status.backup = NULL;
521         }
522
523         hdisp->re_setting = FALSE;
524
525         DRVLOG ("%s \n", __FUNCTION__);
526
527         return TRUE;
528 }
529
530 void
531 fbdevVideoV4l2StreamOff (void *handle)
532 {
533         FBDevDispHandle *hdisp = (FBDevDispHandle*)handle;
534
535         return_if_fail (hdisp != NULL);
536
537         if (hdisp->memory == V4L2_MEMORY_MMAP)
538         {
539                 int size;
540
541                 if (hdisp->status.backup)
542                 {
543                         free (hdisp->status.backup);
544                         hdisp->status.backup = NULL;
545                 }
546
547                 size = fbdevVideoQueryImageAttributes (NULL, FOURCC_RGB32,
548                                                        (unsigned short*)&hdisp->status.dst.width,
549                                                        (unsigned short*)&hdisp->status.dst.height,
550                                                        NULL, NULL, NULL);
551
552                 if (size > 0)
553                         hdisp->status.backup = malloc (size);
554
555                 if (hdisp->status.backup &&
556                         hdisp->dst_buf &&
557                         hdisp->dst_buf[hdisp->status.queued_index].buf)
558                 {
559                         memcpy (hdisp->status.backup,
560                                 hdisp->dst_buf[hdisp->status.queued_index].buf,
561                                 size);
562                 }
563         }
564
565         _fbdevVideoV4l2CloseDevice (hdisp);
566
567         DRVLOG ("%s \n", __FUNCTION__);
568 }
569
570 void
571 fbdevVideoV4l2VideoOffset (void *handle, int x, int y)
572 {
573         FBDevDispHandle *hdisp = (FBDevDispHandle*)handle;
574
575         return_if_fail (handle != NULL);
576
577         DRVLOG ("[VideoOffset, %p] to %d,%d\n", hdisp, x, y);
578
579         if (hdisp->offset_x == x && hdisp->offset_y == y)
580                 return;
581
582         if (!_fbdevVideoV4l2SetDst (hdisp->video_fd, x, y, &hdisp->status.dst))
583         {
584                 xf86DrvMsg (0, X_ERROR, "[VideoOffset, %p] _fbdevVideoV4l2SetDst is failed. \n", hdisp);
585                 return;
586         }
587
588         hdisp->offset_x = x;
589         hdisp->offset_y = y;
590 }
591
592 /* img->x, img->y : not used. */
593 Bool
594 fbdevVideoV4l2SetFormat (void *handle,
595                          xRectangle *img, xRectangle *crop, xRectangle *dst,
596                          uint id,
597                          int  scn_rotate,
598                          int  hw_rotate,
599                          int  hflip,
600                          int  vflip,
601                          int  requestbuffer,
602                          Bool sync)
603 {
604         FBDevDispHandle *hdisp = (FBDevDispHandle*)handle;
605         Bool src_changed = FALSE;
606         Bool dst_changed = FALSE;
607         Bool buf_changed = FALSE;
608
609         return_val_if_fail (handle != NULL, FALSE);
610         return_val_if_fail (img != NULL, FALSE);
611         return_val_if_fail (crop != NULL, FALSE);
612         return_val_if_fail (dst != NULL, FALSE);
613
614         DRVLOG ("[SetFormat, %p] try to set : img(%d,%d %dx%d) crop(%d,%d %dx%d) dst(%d,%d %dx%d) id(%x), rot(%d), flip(%d,%d) req(%d)\n", hdisp,
615                 img->x, img->y, img->width, img->height,
616                 crop->x, crop->y, crop->width, crop->height,
617                 dst->x, dst->y, dst->width, dst->height,
618                 id, hw_rotate, hflip, vflip, requestbuffer);
619
620         if (memcmp (&hdisp->status.img, img, sizeof (xRectangle)) ||
621                 memcmp (&hdisp->status.crop, crop, sizeof (xRectangle)) ||
622                 hdisp->status.id != id)
623                 src_changed = TRUE;
624
625         if (memcmp (&hdisp->status.dst, dst, sizeof (xRectangle)) ||
626                 hdisp->status.hw_rotate != hw_rotate ||
627                 hdisp->status.hflip != hflip ||
628                 hdisp->status.vflip != vflip)
629                 dst_changed = TRUE;
630
631         if (hdisp->status.init && (src_changed || dst_changed || buf_changed))
632         {
633                 _fbdevVideoV4l2CloseDevice (hdisp);
634                 _fbdevVideoV4l2OpenDevice (hdisp, hdisp->index);
635
636                 DRVLOG ("[SetFormat, %p] changed : img(%d) dst(%d) buf(%d) \n", hdisp,
637                         src_changed, dst_changed, buf_changed);
638
639                 /* After close device, below all steps should be done. */
640                 src_changed = dst_changed = buf_changed = TRUE;
641                 hdisp->status.init = 0;
642         }
643
644         if (hdisp->re_setting)
645                 src_changed = dst_changed = buf_changed = TRUE;
646
647         if (src_changed || dst_changed || buf_changed)
648         {
649                 fbdevVideoV4l2GetFormatInfo (id, NULL, &hdisp->pixfmt, &hdisp->memory);
650
651                 DRVLOG ("[SetFormat, %p] id(%c%c%c%c) => pixfmt(%d) memory(%d) \n", hdisp,
652                         id & 0xFF, (id & 0xFF00) >> 8, (id & 0xFF0000) >> 16,  (id & 0xFF000000) >> 24,
653                         hdisp->pixfmt, hdisp->memory);
654
655                 hdisp->status.img  = *img;
656                 hdisp->status.crop = *crop;
657                 hdisp->status.id   = id;
658                 hdisp->status.sync = sync;
659                 hdisp->status.init = 1;
660
661                 hdisp->status.cur_idx = 0;
662                 hdisp->status.hw_rotate = hw_rotate;
663                 hdisp->status.scn_rotate = scn_rotate;
664                 hdisp->status.hflip = hflip;
665                 hdisp->status.vflip = vflip;
666                 hdisp->status.dst = *dst;
667
668                 if (!_fbdevVideoV4l2SetDst (hdisp->video_fd, hdisp->offset_x, hdisp->offset_y, dst))
669                 {
670                         xf86DrvMsg (0, X_ERROR, "[SetFormat, %p] _fbdevVideoV4l2SetDst is failed. \n", hdisp);
671                         return FALSE;
672                 }
673
674                 if (!_fbdevVideoV4l2SetBuffer (hdisp->video_fd,
675                                                V4L2_BUF_TYPE_VIDEO_OVERLAY,
676                                                hdisp->memory,
677                                                BUF_NUM,
678                                                &hdisp->dst_buf))
679                 {
680                         xf86DrvMsg (0, X_ERROR, "[SetFormat, %p] _fbdevVideoV4l2SetBuffer is failed. \n", hdisp);
681                         return FALSE;
682                 }
683
684                 hdisp->status.cur_idx = 0;
685         }
686
687         if (!hdisp->status.streamon)
688         {
689                 _fbdevVideoV4l2StreamOn (hdisp->video_fd);
690                 hdisp->status.streamon = TRUE;
691         }
692
693         return TRUE;
694 }
695
696 XF86ImagePtr
697 fbdevVideoV4l2SupportImages (int *count)
698 {
699         if (count)
700                 *count = NUM_IMAGES;
701
702         return Images;
703 }
704
705 int
706 fbdevVideoV4l2Draw (void *handle, uchar *buf, uint *phy_addrs)
707 {
708         FBDevDispHandle *hdisp = (FBDevDispHandle*)handle;
709         pixman_format_code_t src_format, dst_format;
710         xRectangle img = hdisp->status.img;
711         xRectangle src = hdisp->status.crop;
712         xRectangle pxm = hdisp->status.dst;
713         xRectangle dst = hdisp->status.dst;
714
715         pxm.x = pxm.y = dst.x = dst.y = 0;
716
717         switch (hdisp->pixfmt)
718         {
719         case V4L2_PIX_FMT_YUV420:
720         case V4L2_PIX_FMT_YVU420:
721                 src_format = PIXMAN_yv12;
722                 break;
723         case V4L2_PIX_FMT_YUYV:
724                 src_format = PIXMAN_yuy2;
725                 break;
726         case V4L2_PIX_FMT_RGB565:
727                 src_format = PIXMAN_r5g6b5;
728                 break;
729         case V4L2_PIX_FMT_RGB24:
730                 src_format = PIXMAN_r8g8b8;
731                 break;
732         case V4L2_PIX_FMT_RGB32:
733                 src_format = PIXMAN_a8r8g8b8;
734                 break;
735         default:
736                 return FALSE;
737         }
738
739         switch (hdisp->pixfmt)
740         {
741         case V4L2_PIX_FMT_YUV420:
742                 dst_format = PIXMAN_x8b8g8r8;
743                 break;
744         default:
745                 dst_format = PIXMAN_x8r8g8b8;
746                 break;
747         }
748
749     if (src_format == PIXMAN_yv12 && img.width % 16)
750     {
751         int src_p[3] = {0,}, src_o[3] = {0,}, src_l[3] = {0,};
752         int dst_p[3] = {0,}, dst_o[3] = {0,}, dst_l[3] = {0,};
753         unsigned short src_w, src_h, dst_w, dst_h;
754         int size;
755
756         src_w = img.width;
757         src_h = img.height;
758         fbdevVideoQueryImageAttributes (NULL, FOURCC_I420, &src_w, &src_h,
759                                         src_p, src_o, src_l);
760
761         dst_w = (img.width + 15) & ~15;
762         dst_h = img.height;
763         size = fbdevVideoQueryImageAttributes (NULL, FOURCC_I420, &dst_w, &dst_h,
764                                                dst_p, dst_o, dst_l);
765
766         if (!hdisp->aligned_buffer)
767         {
768             hdisp->aligned_buffer = malloc (size);
769             if (!hdisp->aligned_buffer)
770                 return FALSE;
771         }
772
773         fbdev_util_copy_image (src_w, src_h,
774                                (char*)buf, src_w, src_h,
775                                src_p, src_o, src_l,
776                                (char*)hdisp->aligned_buffer, dst_w, dst_h,
777                                dst_p, dst_o, dst_l,
778                                3, 2, 2);
779
780         hdisp->aligned_width = dst_w;
781         img.width = dst_w;
782         buf = hdisp->aligned_buffer;
783     }
784
785         /* support only RGB  */
786         fbdev_pixman_convert_image (PIXMAN_OP_SRC,
787                                     buf, hdisp->dst_buf[0].buf,
788                                     src_format, dst_format,
789                                     &img, &pxm, &src, &dst,
790                                     NULL, (hdisp->status.hw_rotate + (360 - hdisp->status.scn_rotate)) % 360,
791                                     hdisp->status.hflip, hdisp->status.vflip);
792
793         return TRUE;
794 }
795
796 Bool
797 fbdevVideoV4l2GetFormatInfo (int id, int *type, uint *pixelformat, FBDevV4l2Memory *memory)
798 {
799         int i;
800
801         for (i = 0; i < sizeof (format_infos) / sizeof (FormatInfo); i++)
802                 if (format_infos[i].id == id)
803                 {
804                         if (type)
805                                 *type = format_infos[i].type;
806                         if (pixelformat)
807                                 *pixelformat = format_infos[i].pixelformat;
808                         if (memory)
809                                 *memory = format_infos[i].memory;
810                         return TRUE;
811                 }
812
813         return FALSE;
814 }
815
816 /*  img : original src size
817  *  src : real src size (cropped area inside img)
818  *  dst : real dst size
819  *        original dst size (in case that image is drawn on opened framebuffer)
820  */
821 Bool
822 fbdevVideoV4l2CheckSize (void *handle, uint pixelformat,
823                          xRectangle *img, xRectangle *src, xRectangle *dst,
824                          int type, int memory)
825 {
826         /* img */
827         if (img)
828         {
829                 if (img->width % 16)
830                         xf86DrvMsg (0, X_WARNING, "img's width(%d) is not multiple of 16!!!\n", img->width);
831
832                 if (type == TYPE_YUV420 && img->height % 2)
833                         xf86DrvMsg (0, X_WARNING, "img's height(%d) is not multiple of 2!!!\n", img->height);
834
835                 return_val_if_fail (img->width >= 16, FALSE);
836                 return_val_if_fail (img->height >= 16, FALSE);
837         }
838
839         /* src */
840         if (src)
841         {
842                 if (type == TYPE_YUV420 || type == TYPE_YUV422)
843                 {
844                         src->x = src->x & (~0x1);
845                         src->width = src->width & (~0x1);
846                 }
847
848                 if (type == TYPE_YUV420)
849                         src->height = src->height & (~0x1);
850
851                 return_val_if_fail (src->width >= 16, FALSE);
852                 return_val_if_fail (src->height >= 16, FALSE);
853         }
854
855         /* dst */
856         if (dst)
857         {
858                 dst->width = dst->width & (~0x1);
859                 dst->height = dst->height & (~0x1);
860
861                 return_val_if_fail (dst->width >= 8, FALSE);
862                 return_val_if_fail (dst->height >= 8, FALSE);
863         }
864
865         return TRUE;
866 }
867
868 void
869 fbdevVideoGetFBInfo (void *handle, void **base, xRectangle *pos)
870 {
871         FBDevDispHandle *hdisp = (FBDevDispHandle*)handle;
872
873         if (!hdisp)
874                 return;
875
876         if (pos)
877                 *pos = hdisp->status.dst;
878         if (base)
879                 *base = hdisp->dst_buf[0].buf;
880 }