1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 * Copyright@ Samsung Electronics Co. LTD
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 /*!
19 * \file libscaler-v4l2.cpp
20 * \brief source file for Scaler HAL
21 * \author Cho KyongHo <pullip.cho@samsung.com>
22 * \date 2014/05/12
23 *
24 * <b>Revision History: </b>
25 * - 2014.05.12 : Cho KyongHo (pullip.cho@samsung.com) \n
26 * Create
27 */
28
29 #include <cstring>
30 #include <cstdlib>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <sys/ioctl.h>
34 #include <sys/mman.h>
35
36 #include "libscaler-v4l2.h"
37 #include "libscaler-swscaler.h"
38
39
40 #define V4L2_CID_EXYNOS_BASE (V4L2_CTRL_CLASS_USER | 0x2000)
41 #define V4L2_CID_CSC_EQ_MODE (V4L2_CID_EXYNOS_BASE + 100)
42 #define V4L2_CID_CSC_EQ (V4L2_CID_EXYNOS_BASE + 101)
43 #define V4L2_CID_CSC_RANGE (V4L2_CID_EXYNOS_BASE + 102)
44 #define V4L2_CID_CONTENT_PROTECTION (V4L2_CID_EXYNOS_BASE + 201)
45
Initialize(int instance)46 void CScalerV4L2::Initialize(int instance)
47 {
48 snprintf(m_cszNode, SC_MAX_NODENAME, SC_DEV_NODE "%d", SC_NODE(instance));
49
50 m_fdScaler = open(m_cszNode, O_RDWR);
51 if (m_fdScaler < 0) {
52 SC_LOGERR("Failed to open '%s'", m_cszNode);
53 return;
54 }
55
56 m_fdValidate = -m_fdScaler;
57 }
58
CScalerV4L2(int instance,int allow_drm)59 CScalerV4L2::CScalerV4L2(int instance, int allow_drm)
60 {
61 m_fdScaler = -1;
62 m_iInstance = instance;
63 m_nRotDegree = 0;
64 m_fStatus = 0;
65 m_filter = 0;
66
67 memset(&m_frmSrc, 0, sizeof(m_frmSrc));
68 memset(&m_frmDst, 0, sizeof(m_frmDst));
69
70 m_frmSrc.fdAcquireFence = -1;
71 m_frmDst.fdAcquireFence = -1;
72
73 m_frmSrc.name = "output";
74 m_frmDst.name = "capture";
75
76 m_frmSrc.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
77 m_frmDst.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
78
79 m_frameRate = 0;
80
81 Initialize(instance);
82
83 if(Valid()) {
84 if (allow_drm)
85 SetFlag(m_fStatus, SCF_ALLOW_DRM);
86 SC_LOGD("Successfully opened '%s'; returned fd %d; drmmode %s",
87 m_cszNode, m_fdScaler, allow_drm ? "enabled" : "disabled");
88 }
89 }
90
~CScalerV4L2()91 CScalerV4L2::~CScalerV4L2()
92 {
93 if (m_fdScaler >= 0)
94 close(m_fdScaler);
95
96 m_fdScaler = -1;
97 }
98
Stop()99 bool CScalerV4L2::Stop()
100 {
101 if (!ResetDevice(m_frmSrc)) {
102 SC_LOGE("Failed to stop Scaler for the output frame");
103 return false;
104 }
105
106 if (!ResetDevice(m_frmDst)) {
107 SC_LOGE("Failed to stop Scaler for the cature frame");
108 return false;
109 }
110
111 return true;
112 }
113
Run()114 bool CScalerV4L2::Run()
115 {
116 if (LibScaler::UnderOne16thScaling(
117 m_frmSrc.crop.width, m_frmSrc.crop.height,
118 m_frmDst.crop.width, m_frmDst.crop.height,
119 m_nRotDegree))
120 return RunSWScaling();
121
122 if (!DevSetCtrl())
123 return false;
124
125 if (!DevSetFormat())
126 return false;
127
128 if (!ReqBufs())
129 return false;
130
131 if (!StreamOn())
132 return false;
133
134 if (!QBuf()) {
135 Stop();
136 return false;
137 }
138
139 return DQBuf();
140 }
141
SetCtrl()142 bool CScalerV4L2::SetCtrl()
143 {
144 struct v4l2_control ctrl;
145
146 if (TestFlag(m_fStatus, SCF_DRM_FRESH)) {
147 if (!Stop())
148 return false;
149
150 ctrl.id = V4L2_CID_CONTENT_PROTECTION;
151 ctrl.value = TestFlag(m_fStatus, SCF_DRM);
152 if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) {
153 SC_LOGERR("Failed configure V4L2_CID_CONTENT_PROTECTION to %d", TestFlag(m_fStatus, SCF_DRM));
154 return false;
155 }
156
157 ClearFlag(m_fStatus, SCF_DRM_FRESH);
158 } else {
159 SC_LOGD("Skipping DRM configuration");
160 }
161
162 if (TestFlag(m_fStatus, SCF_ROTATION_FRESH)) {
163 if (!Stop())
164 return false;
165
166 ctrl.id = V4L2_CID_ROTATE;
167 ctrl.value = m_nRotDegree;
168 if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) {
169 SC_LOGERR("Failed V4L2_CID_ROTATE with degree %d", m_nRotDegree);
170 return false;
171 }
172
173 ctrl.id = V4L2_CID_VFLIP;
174 ctrl.value = TestFlag(m_fStatus, SCF_HFLIP);
175 if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) {
176 SC_LOGERR("Failed V4L2_CID_VFLIP - %d", TestFlag(m_fStatus, SCF_VFLIP));
177 return false;
178 }
179
180 ctrl.id = V4L2_CID_HFLIP;
181 ctrl.value = TestFlag(m_fStatus, SCF_VFLIP);
182 if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) {
183 SC_LOGERR("Failed V4L2_CID_HFLIP - %d", TestFlag(m_fStatus, SCF_HFLIP));
184 return false;
185 }
186
187 SC_LOGD("Successfully set CID_ROTATE(%d), CID_VFLIP(%d) and CID_HFLIP(%d)",
188 m_nRotDegree, TestFlag(m_fStatus, SCF_VFLIP), TestFlag(m_fStatus, SCF_HFLIP));
189 ClearFlag(m_fStatus, SCF_ROTATION_FRESH);
190 } else {
191 SC_LOGD("Skipping rotation and flip setting due to no change");
192 }
193
194 if (m_filter > 0) {
195 if (!Stop())
196 return false;
197
198 ctrl.id = LIBSC_V4L2_CID_DNOISE_FT;
199 ctrl.value = m_filter;
200 if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) {
201 SC_LOGERR("Failed LIBSC_V4L2_CID_DNOISE_FT to %d", m_filter);
202 return false;
203 }
204 }
205
206 if (TestFlag(m_fStatus, SCF_CSC_FRESH)) {
207 if (!Stop())
208 return false;
209
210 ctrl.id = V4L2_CID_CSC_RANGE;
211 ctrl.value = TestFlag(m_fStatus, SCF_CSC_WIDE) ? 1 : 0;
212 if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) {
213 SC_LOGERR("Failed V4L2_CID_CSC_RANGE to %d", TestFlag(m_fStatus, SCF_CSC_WIDE));
214 return false;
215 }
216
217 ctrl.id = V4L2_CID_CSC_EQ;
218 ctrl.value = m_colorspace;
219 if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) {
220 SC_LOGERR("Failed V4L2_CID_CSC_EQ to %d", m_colorspace);
221 }
222 ClearFlag(m_fStatus, SCF_CSC_FRESH);
223 }
224
225 /* This is optional, so we don't return failure. */
226 if (TestFlag(m_fStatus, SCF_FRAMERATE)) {
227 if (!Stop())
228 return false;
229
230 ctrl.id = SC_CID_FRAMERATE;
231 ctrl.value = m_frameRate;
232 if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) {
233 SC_LOGD("Failed SC_CID_FRAMERATE to %d", m_frameRate);
234 }
235 ClearFlag(m_fStatus, SCF_FRAMERATE);
236 }
237
238 return true;
239 }
240
DevSetCtrl()241 bool CScalerV4L2::DevSetCtrl()
242 {
243 return SetCtrl();
244 }
245
ResetDevice(FrameInfo & frm)246 bool CScalerV4L2::ResetDevice(FrameInfo &frm)
247 {
248 DQBuf(frm);
249
250 if (TestFlag(frm.flags, SCFF_STREAMING)) {
251 if (ioctl(m_fdScaler, VIDIOC_STREAMOFF, &frm.type) < 0) {
252 SC_LOGERR("Failed STREAMOFF for the %s", frm.name);
253 }
254 ClearFlag(frm.flags, SCFF_STREAMING);
255 }
256
257 SC_LOGD("VIDIC_STREAMOFF is successful for the %s", frm.name);
258
259 if (TestFlag(frm.flags, SCFF_REQBUFS)) {
260 v4l2_requestbuffers reqbufs;
261 memset(&reqbufs, 0, sizeof(reqbufs));
262 reqbufs.type = frm.type;
263 reqbufs.memory = frm.memory;
264 if (ioctl(m_fdScaler, VIDIOC_REQBUFS, &reqbufs) < 0 ) {
265 SC_LOGERR("Failed to REQBUFS(0) for the %s", frm.name);
266 }
267
268 ClearFlag(frm.flags, SCFF_REQBUFS);
269 }
270
271 SC_LOGD("VIDIC_REQBUFS(0) is successful for the %s", frm.name);
272
273 return true;
274 }
275
DevSetFormat(FrameInfo & frm)276 bool CScalerV4L2::DevSetFormat(FrameInfo &frm)
277 {
278
279 if (!TestFlag(frm.flags, SCFF_BUF_FRESH)) {
280 SC_LOGD("Skipping S_FMT for the %s since it is already done", frm.name);
281 return true;
282 }
283
284 if (!ResetDevice(frm)) {
285 SC_LOGE("Failed to VIDIOC_S_FMT for the %s", frm.name);
286 return false;
287 }
288
289 v4l2_format fmt;
290 memset(&fmt, 0, sizeof(fmt));
291 fmt.type = frm.type;
292 fmt.fmt.pix_mp.pixelformat = frm.color_format;
293 fmt.fmt.pix_mp.width = frm.width;
294 fmt.fmt.pix_mp.height = frm.height;
295
296 if (TestFlag(frm.flags, SCFF_PREMULTIPLIED)) {
297 #ifdef SCALER_USE_PREMUL_FMT
298 fmt.fmt.pix_mp.flags = V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
299 #else
300 fmt.fmt.pix_mp.reserved[1] = SC_V4L2_FMT_PREMULTI_FLAG;
301 #endif
302 }
303
304 if (ioctl(m_fdScaler, VIDIOC_S_FMT, &fmt) < 0) {
305 SC_LOGERR("Failed S_FMT(fmt: %d, w:%d, h:%d) for the %s",
306 fmt.fmt.pix_mp.pixelformat, fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
307 frm.name);
308 return false;
309 }
310
311 // returned fmt.fmt.pix_mp.num_planes and fmt.fmt.pix_mp.plane_fmt[i].sizeimage
312 frm.out_num_planes = fmt.fmt.pix_mp.num_planes;
313
314 for (int i = 0; i < frm.out_num_planes; i++)
315 frm.out_plane_size[i] = fmt.fmt.pix_mp.plane_fmt[i].sizeimage;
316
317 v4l2_crop crop;
318 crop.type = frm.type;
319 crop.c = frm.crop;
320
321 if (ioctl(m_fdScaler, VIDIOC_S_CROP, &crop) < 0) {
322 SC_LOGERR("Failed S_CROP(fmt: %d, l:%d, t:%d, w:%d, h:%d) for the %s",
323 crop.type, crop.c.left, crop.c.top, crop.c.width, crop.c.height,
324 frm.name);
325 return false;
326 }
327
328 if (frm.out_num_planes > SC_MAX_PLANES) {
329 SC_LOGE("Number of planes exceeds %d of %s", frm.out_num_planes, frm.name);
330 return false;
331 }
332
333 ClearFlag(frm.flags, SCFF_BUF_FRESH);
334
335 SC_LOGD("Successfully S_FMT and S_CROP for the %s", frm.name);
336
337 return true;
338 }
339
DevSetFormat()340 bool CScalerV4L2::DevSetFormat()
341 {
342 if (!DevSetFormat(m_frmSrc))
343 return false;
344
345 return DevSetFormat(m_frmDst);
346 }
347
QBuf(FrameInfo & frm,int * pfdReleaseFence)348 bool CScalerV4L2::QBuf(FrameInfo &frm, int *pfdReleaseFence)
349 {
350 v4l2_buffer buffer;
351 v4l2_plane planes[SC_MAX_PLANES];
352
353 if (!TestFlag(frm.flags, SCFF_REQBUFS)) {
354 SC_LOGE("Trying to QBUF without REQBUFS for %s is not allowed",
355 frm.name);
356 return false;
357 }
358
359 if (!DQBuf(frm))
360 return false;
361
362 memset(&buffer, 0, sizeof(buffer));
363 memset(&planes, 0, sizeof(planes));
364
365 buffer.type = frm.type;
366 buffer.memory = frm.memory;
367 buffer.index = 0;
368 buffer.length = frm.out_num_planes;
369
370 if (pfdReleaseFence) {
371 buffer.flags = V4L2_BUF_FLAG_USE_SYNC;
372 buffer.reserved = frm.fdAcquireFence;
373 }
374
375 buffer.m.planes = planes;
376 for (unsigned long i = 0; i < buffer.length; i++) {
377 planes[i].length = frm.out_plane_size[i];
378 if (V4L2_TYPE_IS_OUTPUT(buffer.type))
379 planes[i].bytesused = planes[i].length;
380 if (buffer.memory == V4L2_MEMORY_DMABUF)
381 planes[i].m.fd = static_cast<__s32>(reinterpret_cast<long>(frm.addr[i]));
382 else
383 planes[i].m.userptr = reinterpret_cast<unsigned long>(frm.addr[i]);
384 }
385
386
387 if (ioctl(m_fdScaler, VIDIOC_QBUF, &buffer) < 0) {
388 SC_LOGERR("Failed to QBUF for the %s", frm.name);
389 return false;
390 }
391
392 SetFlag(frm.flags, SCFF_QBUF);
393
394 if (pfdReleaseFence) {
395 if (frm.fdAcquireFence >= 0)
396 close(frm.fdAcquireFence);
397 frm.fdAcquireFence = -1;
398
399 *pfdReleaseFence = static_cast<int>(buffer.reserved);
400 }
401
402 SC_LOGD("Successfully QBUF for the %s", frm.name);
403
404 return true;
405 }
406
ReqBufs(FrameInfo & frm)407 bool CScalerV4L2::ReqBufs(FrameInfo &frm)
408 {
409 v4l2_requestbuffers reqbufs;
410
411 if (TestFlag(frm.flags, SCFF_REQBUFS)) {
412 SC_LOGD("Skipping REQBUFS for the %s since it is already done", frm.name);
413 return true;
414 }
415
416 memset(&reqbufs, 0, sizeof(reqbufs));
417
418 reqbufs.type = frm.type;
419 reqbufs.memory = frm.memory;
420 reqbufs.count = 1;
421
422 if (ioctl(m_fdScaler, VIDIOC_REQBUFS, &reqbufs) < 0) {
423 SC_LOGERR("Failed to REQBUFS for the %s", frm.name);
424 return false;
425 }
426
427 SetFlag(frm.flags, SCFF_REQBUFS);
428
429 SC_LOGD("Successfully REQBUFS for the %s", frm.name);
430
431 return true;
432 }
433
SetRotate(int rot,int flip_h,int flip_v)434 bool CScalerV4L2::SetRotate(int rot, int flip_h, int flip_v)
435 {
436 if ((rot % 90) != 0) {
437 SC_LOGE("Rotation of %d degree is not supported", rot);
438 return false;
439 }
440
441 SetRotDegree(rot);
442
443 if (flip_h)
444 SetFlag(m_fStatus, SCF_VFLIP);
445 else
446 ClearFlag(m_fStatus, SCF_VFLIP);
447
448 if (flip_v)
449 SetFlag(m_fStatus, SCF_HFLIP);
450 else
451 ClearFlag(m_fStatus, SCF_HFLIP);
452
453 SetFlag(m_fStatus, SCF_ROTATION_FRESH);
454
455 return true;
456 }
457
StreamOn(FrameInfo & frm)458 bool CScalerV4L2::StreamOn(FrameInfo &frm)
459 {
460 if (!TestFlag(frm.flags, SCFF_REQBUFS)) {
461 SC_LOGE("Trying to STREAMON without REQBUFS for %s is not allowed",
462 frm.name);
463 return false;
464 }
465
466 if (!TestFlag(frm.flags, SCFF_STREAMING)) {
467 if (ioctl(m_fdScaler, VIDIOC_STREAMON, &frm.type) < 0 ) {
468 SC_LOGERR("Failed StreamOn for the %s", frm.name);
469 return false;
470 }
471
472 SetFlag(frm.flags, SCFF_STREAMING);
473
474 SC_LOGD("Successfully VIDIOC_STREAMON for the %s", frm.name);
475 }
476
477 return true;
478 }
479
DQBuf(FrameInfo & frm)480 bool CScalerV4L2::DQBuf(FrameInfo &frm)
481 {
482 if (!TestFlag(frm.flags, SCFF_QBUF))
483 return true;
484
485 v4l2_buffer buffer;
486 v4l2_plane plane[SC_NUM_OF_PLANES];
487
488 memset(&buffer, 0, sizeof(buffer));
489
490 buffer.type = frm.type;
491 buffer.memory = frm.memory;
492
493 if (V4L2_TYPE_IS_MULTIPLANAR(buffer.type)) {
494 memset(plane, 0, sizeof(plane));
495
496 buffer.length = frm.out_num_planes;
497 buffer.m.planes = plane;
498 }
499
500 ClearFlag(frm.flags, SCFF_QBUF);
501
502 if (ioctl(m_fdScaler, VIDIOC_DQBUF, &buffer) < 0 ) {
503 SC_LOGERR("Failed to DQBuf the %s", frm.name);
504 return false;
505 }
506
507 if (buffer.flags & V4L2_BUF_FLAG_ERROR) {
508 SC_LOGE("Error occurred while processing streaming data");
509 return false;
510 }
511
512 SC_LOGD("Successfully VIDIOC_DQBUF for the %s", frm.name);
513
514 return true;
515 }
516
GetBuffer(CScalerV4L2::FrameInfo & frm,char * addr[])517 static bool GetBuffer(CScalerV4L2::FrameInfo &frm, char *addr[])
518 {
519 for (int i = 0; i < frm.out_num_planes; i++) {
520 if (frm.memory == V4L2_MEMORY_DMABUF) {
521 addr[i] = reinterpret_cast<char *>(mmap(NULL, frm.out_plane_size[i],
522 PROT_READ | PROT_WRITE, MAP_SHARED,
523 static_cast<int>(reinterpret_cast<long>(frm.addr[i])), 0));
524 if (addr[i] == MAP_FAILED) {
525 SC_LOGE("Failed to map FD %ld", reinterpret_cast<long>(frm.addr[i]));
526 while (i-- > 0)
527 munmap(addr[i], frm.out_plane_size[i]);
528 return false;
529 }
530 } else {
531 addr[i] = reinterpret_cast<char *>(frm.addr[i]);
532 }
533 }
534
535 return true;
536 }
537
PutBuffer(CScalerV4L2::FrameInfo & frm,char * addr[])538 static void PutBuffer(CScalerV4L2::FrameInfo &frm, char *addr[])
539 {
540 for (int i = 0; i < frm.out_num_planes; i++) {
541 if (frm.memory == V4L2_MEMORY_DMABUF) {
542 munmap(addr[i], frm.out_plane_size[i]);
543 }
544 }
545 }
546
RunSWScaling()547 bool CScalerV4L2::RunSWScaling()
548 {
549 if (m_frmSrc.color_format != m_frmDst.color_format) {
550 SC_LOGE("Source and target image format must be the same");
551 return false;
552 }
553
554 if (m_nRotDegree != 0) {
555 SC_LOGE("Rotation is not allowed for S/W Scaling");
556 return false;
557 }
558
559 SC_LOGI("Running S/W Scaler: %dx%d -> %dx%d",
560 m_frmSrc.crop.width, m_frmSrc.crop.height,
561 m_frmDst.crop.width, m_frmDst.crop.height);
562
563 CScalerSW *swsc;
564 char *src[3], *dst[3];
565
566 switch (m_frmSrc.color_format) {
567 case V4L2_PIX_FMT_YUYV:
568 case V4L2_PIX_FMT_YVYU:
569 m_frmSrc.out_num_planes = 1;
570 m_frmSrc.out_plane_size[0] = m_frmSrc.width * m_frmSrc.height * 2;
571 m_frmDst.out_num_planes = 1;
572 m_frmDst.out_plane_size[0] = m_frmDst.width * m_frmDst.height * 2;
573
574 if (!GetBuffer(m_frmSrc, src))
575 return false;
576
577 if (!GetBuffer(m_frmDst, dst)) {
578 PutBuffer(m_frmSrc, src);
579 return false;
580 }
581
582 swsc = new CScalerSW_YUYV(src[0], dst[0]);
583 break;
584 case V4L2_PIX_FMT_NV12M:
585 case V4L2_PIX_FMT_NV21M:
586 m_frmSrc.out_num_planes = 2;
587 m_frmDst.out_num_planes = 2;
588 m_frmSrc.out_plane_size[0] = m_frmSrc.width * m_frmSrc.height;
589 m_frmDst.out_plane_size[0] = m_frmDst.width * m_frmDst.height;
590 m_frmSrc.out_plane_size[1] = m_frmSrc.out_plane_size[0] / 2;
591 m_frmDst.out_plane_size[1] = m_frmDst.out_plane_size[0] / 2;
592
593 if (!GetBuffer(m_frmSrc, src))
594 return false;
595
596 if (!GetBuffer(m_frmDst, dst)) {
597 PutBuffer(m_frmSrc, src);
598 return false;
599 }
600
601 swsc = new CScalerSW_NV12(src[0], src[1], dst[0], dst[1]);
602 break;
603 case V4L2_PIX_FMT_NV12:
604 case V4L2_PIX_FMT_NV21:
605 m_frmSrc.out_num_planes = 1;
606 m_frmDst.out_num_planes = 1;
607 m_frmSrc.out_plane_size[0] = m_frmSrc.width * m_frmSrc.height;
608 m_frmDst.out_plane_size[0] = m_frmDst.width * m_frmDst.height;
609 m_frmSrc.out_plane_size[0] += m_frmSrc.out_plane_size[0] / 2;
610 m_frmDst.out_plane_size[0] += m_frmDst.out_plane_size[0] / 2;
611
612 if (!GetBuffer(m_frmSrc, src))
613 return false;
614
615 if (!GetBuffer(m_frmDst, dst)) {
616 PutBuffer(m_frmSrc, src);
617 return false;
618 }
619
620 src[1] = src[0] + m_frmSrc.width * m_frmSrc.height;
621 dst[1] = dst[0] + m_frmDst.width * m_frmDst.height;
622
623 swsc = new CScalerSW_NV12(src[0], src[1], dst[0], dst[1]);
624 break;
625 case V4L2_PIX_FMT_UYVY: // TODO: UYVY is not implemented yet.
626 default:
627 SC_LOGE("Format %x is not supported", m_frmSrc.color_format);
628 return false;
629 }
630
631 if (swsc == NULL) {
632 SC_LOGE("Failed to allocate SW Scaler");
633 PutBuffer(m_frmSrc, src);
634 PutBuffer(m_frmDst, dst);
635 return false;
636 }
637
638 swsc->SetSrcRect(m_frmSrc.crop.left, m_frmSrc.crop.top,
639 m_frmSrc.crop.width, m_frmSrc.crop.height, m_frmSrc.width);
640
641 swsc->SetDstRect(m_frmDst.crop.left, m_frmDst.crop.top,
642 m_frmDst.crop.width, m_frmDst.crop.height, m_frmDst.width);
643
644 bool ret = swsc->Scale();
645
646 delete swsc;
647
648 PutBuffer(m_frmSrc, src);
649 PutBuffer(m_frmDst, dst);
650
651 return ret;
652 }
653