| /* |
| * Copyright 2011, Havlena Petr <havlenapetr@gmail.com> |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #define LOG_NDEBUG 0 |
| #include <utils/Log.h> |
| |
| #include <string.h> |
| #include <stdlib.h> |
| #include <sys/poll.h> |
| |
| #include <sec_lcd.h> |
| |
| #include "SecHDMI.h" |
| #include "fimd.h" |
| |
| using namespace android; |
| |
| #define RETURN_IF(return_value) \ |
| if (return_value < 0) { \ |
| ALOGE("%s::%d fail. errno: %s", \ |
| __func__, __LINE__, strerror(errno)); \ |
| return -1; \ |
| } |
| |
| #define ALOG_IF(return_value) \ |
| if (return_value < 0) { \ |
| ALOGE("%s::%d fail. errno: %s", \ |
| __func__, __LINE__, strerror(errno)); \ |
| } |
| |
| #define ALIGN_TO_32B(x) ((((x) + (1 << 5) - 1) >> 5) << 5) |
| #define ALIGN_TO_128B(x) ((((x) + (1 << 7) - 1) >> 7) << 7) |
| #define ALIGN_TO_8KB(x) ((((x) + (1 << 13) - 1) >> 13) << 13) |
| |
| struct s5p_tv_standart_internal { |
| int index; |
| unsigned long value; |
| } s5p_tv_standards[] = { |
| { |
| S5P_TV_STD_NTSC_M, |
| V4L2_STD_NTSC_M, |
| }, { |
| S5P_TV_STD_PAL_BDGHI, |
| V4L2_STD_PAL_BDGHI, |
| }, { |
| S5P_TV_STD_PAL_M, |
| V4L2_STD_PAL_M, |
| }, { |
| S5P_TV_STD_PAL_N, |
| V4L2_STD_PAL_N, |
| }, { |
| S5P_TV_STD_PAL_Nc, |
| V4L2_STD_PAL_Nc, |
| }, { |
| S5P_TV_STD_PAL_60, |
| V4L2_STD_PAL_60, |
| }, { |
| S5P_TV_STD_NTSC_443, |
| V4L2_STD_NTSC_443, |
| }, { |
| S5P_TV_STD_480P_60_16_9, |
| V4L2_STD_480P_60_16_9, |
| }, { |
| S5P_TV_STD_480P_60_4_3, |
| V4L2_STD_480P_60_4_3, |
| }, { |
| S5P_TV_STD_576P_50_16_9, |
| V4L2_STD_576P_50_16_9, |
| }, { |
| S5P_TV_STD_576P_50_4_3, |
| V4L2_STD_576P_50_4_3, |
| }, { |
| S5P_TV_STD_720P_60, |
| V4L2_STD_720P_60, |
| }, { |
| S5P_TV_STD_720P_50, |
| V4L2_STD_720P_50, |
| }, |
| }; |
| |
| static inline int calcFrameSize(int format, int width, int height) |
| { |
| int size = 0; |
| |
| switch (format) { |
| case V4L2_PIX_FMT_YUV420: |
| case V4L2_PIX_FMT_NV12: |
| case V4L2_PIX_FMT_NV21: |
| size = (width * height * 3 / 2); |
| break; |
| |
| case V4L2_PIX_FMT_NV12T: |
| size = ALIGN_TO_8KB(ALIGN_TO_128B(width) * ALIGN_TO_32B(height)) + |
| ALIGN_TO_8KB(ALIGN_TO_128B(width) * ALIGN_TO_32B(height / 2)); |
| break; |
| |
| case V4L2_PIX_FMT_YUV422P: |
| case V4L2_PIX_FMT_YUYV: |
| case V4L2_PIX_FMT_UYVY: |
| size = (width * height * 2); |
| break; |
| |
| default : |
| ALOGE("ERR(%s):Invalid V4L2 pixel format(%d)\n", __func__, format); |
| case V4L2_PIX_FMT_RGB565: |
| size = (width * height * 2); |
| break; |
| } |
| return size; |
| } |
| |
| static int get_pixel_depth(unsigned int fmt) |
| { |
| int depth = 0; |
| |
| switch (fmt) { |
| case V4L2_PIX_FMT_NV12: |
| depth = 12; |
| break; |
| case V4L2_PIX_FMT_NV12T: |
| depth = 12; |
| break; |
| case V4L2_PIX_FMT_NV21: |
| depth = 12; |
| break; |
| case V4L2_PIX_FMT_YUV420: |
| depth = 12; |
| break; |
| |
| case V4L2_PIX_FMT_RGB565: |
| case V4L2_PIX_FMT_YUYV: |
| case V4L2_PIX_FMT_YVYU: |
| case V4L2_PIX_FMT_UYVY: |
| case V4L2_PIX_FMT_VYUY: |
| case V4L2_PIX_FMT_NV16: |
| case V4L2_PIX_FMT_NV61: |
| case V4L2_PIX_FMT_YUV422P: |
| depth = 16; |
| break; |
| |
| case V4L2_PIX_FMT_RGB32: |
| depth = 32; |
| break; |
| } |
| |
| return depth; |
| } |
| |
| // ====================================================================== |
| // Video ioctls |
| |
| static int tv20_v4l2_querycap(int fp) |
| { |
| struct v4l2_capability cap; |
| |
| int ret = ioctl(fp, VIDIOC_QUERYCAP, &cap); |
| if (ret < 0) { |
| ALOGE("ERR(%s):VIDIOC_QUERYCAP failed", __func__); |
| return -1; |
| } |
| |
| if (!(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) { |
| ALOGE("ERR(%s):no output devices\n", __func__); |
| return -1; |
| } |
| ALOGV("Name of cap driver is %s", cap.driver); |
| |
| return ret; |
| } |
| |
| static const __u8* tv20_v4l2_enum_output(int fp, int index) |
| { |
| static struct v4l2_output output; |
| |
| output.index = index; |
| if (ioctl(fp, VIDIOC_ENUMOUTPUT, &output) != 0) { |
| ALOGE("ERR(%s):No matching index found", __func__); |
| return NULL; |
| } |
| ALOGV("Name of output channel[%d] is %s", output.index, output.name); |
| |
| return output.name; |
| } |
| |
| static const __u8* tv20_v4l2_enum_standarts(int fp, int index) |
| { |
| static struct v4l2_standard standart; |
| |
| standart.index = index; |
| if (ioctl(fp, VIDIOC_ENUMSTD, &standart) != 0) { |
| ALOGE("ERR(%s):No matching index found\n", __func__); |
| return NULL; |
| } |
| ALOGV("Name of output standart[%d] is %s\n", standart.index, standart.name); |
| |
| return standart.name; |
| } |
| |
| static int tv20_v4l2_s_output(int fp, int index) |
| { |
| struct v4l2_output output; |
| int ret; |
| |
| output.index = index; |
| |
| ret = ioctl(fp, VIDIOC_S_OUTPUT, &output); |
| if (ret < 0) { |
| ALOGE("ERR(%s):VIDIOC_S_OUPUT failed\n", __func__); |
| return ret; |
| } |
| return ret; |
| } |
| |
| static int tv20_v4l2_s_std(int fp, unsigned long id) |
| { |
| v4l2_std_id std; |
| int ret; |
| |
| std = id; |
| |
| ret = ioctl(fp, VIDIOC_S_STD, &std); |
| if (ret < 0) { |
| ALOGE("ERR(%s):VIDIOC_S_OUPUT failed\n", __func__); |
| return ret; |
| } |
| return ret; |
| } |
| |
| static int tv20_v4l2_enum_fmt(int fp, unsigned int fmt) |
| { |
| struct v4l2_fmtdesc fmtdesc; |
| int found = 0; |
| |
| fmtdesc.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; |
| fmtdesc.index = 0; |
| |
| while (ioctl(fp, VIDIOC_ENUM_FMT, &fmtdesc) == 0) { |
| if (fmtdesc.pixelformat == fmt) { |
| ALOGV("passed fmt = %#x found pixel format[%d]: %s\n", fmt, fmtdesc.index, fmtdesc.description); |
| found = 1; |
| break; |
| } |
| |
| fmtdesc.index++; |
| } |
| |
| if (!found) { |
| ALOGE("unsupported pixel format\n"); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| static int tv20_v4l2_s_fmt(int fp, int width, int height, |
| unsigned int fmt, unsigned int yAddr, unsigned int cAddr) |
| { |
| struct v4l2_format v4l2_fmt; |
| struct v4l2_pix_format_s5p_tvout pixfmt; |
| int ret; |
| |
| v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; |
| #if 0 |
| ret = ioctl(fp, VIDIOC_G_FMT, &v4l2_fmt); |
| if (ret < 0) { |
| ALOGE("ERR(%s):VIDIOC_G_FMT failed", __func__); |
| return -1; |
| } |
| #endif |
| |
| memset(&pixfmt, 0, sizeof(pixfmt)); |
| pixfmt.pix_fmt.width = width; |
| pixfmt.pix_fmt.height = height; |
| pixfmt.pix_fmt.pixelformat = fmt; |
| pixfmt.pix_fmt.sizeimage = (width * height * get_pixel_depth(fmt)) / 8; |
| pixfmt.pix_fmt.field = V4L2_FIELD_NONE; |
| |
| // here we must set addresses of our memory for video out |
| pixfmt.base_y = (void *)yAddr; |
| pixfmt.base_c = (void* )cAddr; |
| |
| v4l2_fmt.fmt.pix = pixfmt.pix_fmt; |
| memcpy(v4l2_fmt.fmt.raw_data, &pixfmt, |
| sizeof(struct v4l2_pix_format_s5p_tvout)); |
| |
| /* Set up for capture */ |
| ret = ioctl(fp, VIDIOC_S_FMT, &v4l2_fmt); |
| if (ret < 0) { |
| ALOGE("ERR(%s):VIDIOC_S_FMT failed\n", __func__); |
| return -1; |
| } |
| return 0; |
| } |
| |
| static int tv20_v4l2_streamon(int fp) |
| { |
| enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_OUTPUT; |
| int ret; |
| |
| ret = ioctl(fp, VIDIOC_STREAMON, &type); |
| if (ret < 0) { |
| ALOGE("ERR(%s):VIDIOC_STREAMON failed\n", __func__); |
| return ret; |
| } |
| |
| return ret; |
| } |
| |
| static int tv20_v4l2_streamoff(int fp) |
| { |
| enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_OUTPUT; |
| int ret; |
| |
| ALOGV("%s :", __func__); |
| ret = ioctl(fp, VIDIOC_STREAMOFF, &type); |
| if (ret < 0) { |
| ALOGE("ERR(%s):VIDIOC_STREAMOFF failed\n", __func__); |
| return ret; |
| } |
| |
| return ret; |
| } |
| |
| static int tv20_v4l2_g_parm(int fp, struct v4l2_streamparm *streamparm) |
| { |
| int ret; |
| |
| streamparm->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; |
| |
| ret = ioctl(fp, VIDIOC_G_PARM, streamparm); |
| if (ret < 0) { |
| ALOGE("ERR(%s):VIDIOC_G_PARM failed\n", __func__); |
| return -1; |
| } |
| |
| ALOGV("%s : timeperframe: numerator %d, denominator %d\n", __func__, |
| streamparm->parm.capture.timeperframe.numerator, |
| streamparm->parm.capture.timeperframe.denominator); |
| |
| return 0; |
| } |
| |
| static int tv20_v4l2_s_parm(int fp, struct v4l2_streamparm *streamparm) |
| { |
| int ret; |
| |
| streamparm->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; |
| |
| ret = ioctl(fp, VIDIOC_S_PARM, streamparm); |
| if (ret < 0) { |
| ALOGE("ERR(%s):VIDIOC_S_PARM failed\n", __func__); |
| return ret; |
| } |
| return 0; |
| } |
| |
| static int tv20_v4l2_s_crop(int fp, int offset_x, int offset_y, int width, int height) |
| { |
| struct v4l2_crop crop; |
| |
| crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; |
| crop.c.left = offset_x; |
| crop.c.top = offset_y; |
| crop.c.width = width; |
| crop.c.height = height; |
| |
| int ret = ioctl(fp, VIDIOC_S_CROP, &crop); |
| if (ret < 0) { |
| ALOGE("ERR(%s):VIDIOC_S_PARM failed\n", __func__); |
| return ret; |
| } |
| return 0; |
| } |
| |
| static int tv20_v4l2_start_overlay(int fp) |
| { |
| int ret, start = 1; |
| |
| ret = ioctl(fp, VIDIOC_OVERLAY, &start); |
| if (ret < 0) { |
| ALOGE("ERR(%s): VIDIOC_OVERLAY start failed\n", __func__); |
| return ret; |
| } |
| |
| return ret; |
| } |
| |
| static int tv20_v4l2_stop_overlay(int fp) |
| { |
| int ret, stop = 0; |
| |
| ret = ioctl(fp, VIDIOC_OVERLAY, &stop); |
| if (ret < 0) { |
| ALOGE("ERR(%s): VIDIOC_OVERLAY stop failed\n", __func__); |
| return ret; |
| } |
| |
| return ret; |
| } |
| |
| static int tv20_v4l2_s_baseaddr(int fp, void *base_addr) |
| { |
| int ret; |
| |
| ret = ioctl(fp, S5PTVFB_WIN_SET_ADDR, base_addr); |
| if (ret < 0) { |
| ALOGE("ERR(%s): VIDIOC_S_BASEADDR failed %d", __func__, ret); |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static int tv20_v4l2_s_position(int fp, int x, int y) |
| { |
| int ret; |
| struct s5ptvfb_user_window window; |
| |
| memset(&window, 0, sizeof(struct s5ptvfb_user_window)); |
| window.x = x; |
| window.y = y; |
| |
| ret = ioctl(fp, S5PTVFB_WIN_POSITION, &window); |
| if (ret < 0) { |
| ALOGE("ERR(%s): VIDIOC_S_WIN_POSITION failed %d", __func__, ret); |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| // ====================================================================== |
| // Audio ioctls |
| |
| static int tv20_v4l2_audio_enable(int fp) |
| { |
| return ioctl(fp, VIDIOC_INIT_AUDIO, 1); |
| } |
| |
| static int tv20_v4l2_audio_disable(int fp) |
| { |
| return ioctl(fp, VIDIOC_INIT_AUDIO, 0); |
| } |
| |
| static int tv20_v4l2_audio_mute(int fp) |
| { |
| return ioctl(fp, VIDIOC_AV_MUTE, 1); |
| } |
| |
| static int tv20_v4l2_audio_unmute(int fp) |
| { |
| return ioctl(fp, VIDIOC_AV_MUTE, 0); |
| } |
| |
| static int tv20_v4l2_audio_get_mute_state(int fp) |
| { |
| return ioctl(fp, VIDIOC_G_AVMUTE, 0); |
| } |
| |
| // ====================================================================== |
| // Class which comunicate with kernel driver |
| |
| SecHDMI::SecHDMI() |
| : mTvOutFd(-1), |
| mTvOutVFd(-1), |
| mLcdFd(-1), |
| mHdcpEnabled(0), |
| mFlagConnected(false) |
| { |
| ALOGV("%s", __func__); |
| |
| memset(&mParams, 0, sizeof(struct v4l2_streamparm)); |
| memset(&mFlagLayerEnable, 0, sizeof(bool) * S5P_TV_LAYER_MAX); |
| |
| int ret = ioctl(mTvOutFd, VIDIOC_HDCP_ENABLE, &mHdcpEnabled); |
| ALOG_IF(ret); |
| } |
| |
| SecHDMI::~SecHDMI() |
| { |
| destroy(); |
| } |
| |
| /* static */ |
| int SecHDMI::getCableStatus() |
| { |
| int fd = 0; |
| char value[8] = {0}; |
| |
| ALOGV("%s", __func__); |
| |
| fd = open("/sys/class/switch/h2w/state", O_RDWR); |
| if(fd < 0) { |
| goto close; |
| } |
| |
| if(read(fd, &value, 8) <= 0) { |
| goto close; |
| } |
| |
| close: |
| close(fd); |
| return strtol(value, NULL, 10); |
| } |
| |
| const __u8* SecHDMI::getName(int index) |
| { |
| ALOGV("%s", __func__); |
| return tv20_v4l2_enum_output(mTvOutFd, index); |
| } |
| |
| int SecHDMI::destroy() |
| { |
| ALOGV("%s", __func__); |
| |
| if(mFlagConnected) { |
| disconnect(); |
| } |
| if(mTvOutFd > 0) { |
| close(mTvOutFd); |
| mTvOutFd = -1; |
| } |
| if(mFimc.dev_fd > 0) { |
| fimc_close(&mFimc); |
| mFimc.dev_fd = -1; |
| } |
| if (mLcdFd > 0) { |
| fb_close(mLcdFd); |
| mLcdFd = -1; |
| } |
| |
| return 0; |
| } |
| |
| int SecHDMI::startLayer(s5p_tv_layer layer) |
| { |
| int ret; |
| |
| if (mFlagLayerEnable[layer]) { |
| return 0; |
| } |
| |
| switch (layer) { |
| case S5P_TV_LAYER_VIDEO: |
| if(mTvOutVFd < 0) { |
| mTvOutVFd = open(TVOUT_DEV_V, O_RDWR); |
| RETURN_IF(mTvOutVFd); |
| } |
| ret = tv20_v4l2_start_overlay(mTvOutVFd); |
| RETURN_IF(ret); |
| break; |
| case S5P_TV_LAYER_GRAPHIC_0 : |
| ret = ioctl(0/*fp_tvout_g0*/, FBIOBLANK, (void *)FB_BLANK_UNBLANK); |
| RETURN_IF(ret); |
| break; |
| case S5P_TV_LAYER_GRAPHIC_1 : |
| ret = ioctl(0/*fp_tvout_g1*/, FBIOBLANK, (void *)FB_BLANK_UNBLANK); |
| RETURN_IF(ret); |
| break; |
| default : |
| RETURN_IF(-1); |
| } |
| |
| mFlagLayerEnable[layer] = true; |
| |
| return 0; |
| } |
| |
| int SecHDMI::stopLayer(s5p_tv_layer layer) |
| { |
| int ret; |
| |
| if (!mFlagLayerEnable[layer]) { |
| return 0; |
| } |
| |
| switch (layer) { |
| case S5P_TV_LAYER_VIDEO: |
| ret = tv20_v4l2_stop_overlay(mTvOutVFd); |
| RETURN_IF(ret); |
| close(mTvOutVFd); |
| mTvOutVFd = -1; |
| break; |
| case S5P_TV_LAYER_GRAPHIC_0 : |
| ret = ioctl(0/*fp_tvout_g0*/, FBIOBLANK, (void *)FB_BLANK_POWERDOWN); |
| RETURN_IF(ret); |
| break; |
| case S5P_TV_LAYER_GRAPHIC_1 : |
| ret = ioctl(0/*fp_tvout_g1*/, FBIOBLANK, (void *)FB_BLANK_POWERDOWN); |
| RETURN_IF(ret); |
| break; |
| default : |
| RETURN_IF(-1); |
| } |
| |
| mFlagLayerEnable[layer] = false; |
| |
| return 0; |
| } |
| |
| int SecHDMI::create(int width, int height) |
| { |
| int ret, y_size; |
| unsigned int addr; |
| |
| ALOGV("%s", __func__); |
| |
| mTvOutFd = open(TVOUT_DEV, O_RDWR); |
| RETURN_IF(mTvOutFd); |
| |
| memset(&mFimc, 0, sizeof(s5p_fimc_t)); |
| mFimc.dev_fd = -1; |
| ret = fimc_open(&mFimc, "/dev/video2"); |
| RETURN_IF(ret); |
| |
| ALOGV("query capabilities"); |
| ret = tv20_v4l2_querycap(mTvOutFd); |
| RETURN_IF(ret); |
| |
| struct s5p_tv_standart_internal std = |
| s5p_tv_standards[(int) S5P_TV_STD_PAL_BDGHI]; |
| |
| ALOGV("searching for standart: %i", std.index); |
| if(!tv20_v4l2_enum_standarts(mTvOutFd, std.index)) |
| return -1; |
| |
| ret = tv20_v4l2_s_std(mTvOutFd, std.value); |
| RETURN_IF(ret); |
| |
| ALOGV("searching for output: %i", S5P_TV_OUTPUT_TYPE_COMPOSITE); |
| if (!tv20_v4l2_enum_output(mTvOutFd, S5P_TV_OUTPUT_TYPE_COMPOSITE)) |
| return -1; |
| |
| ret = tv20_v4l2_s_output(mTvOutFd, S5P_TV_OUTPUT_TYPE_COMPOSITE); |
| RETURN_IF(ret); |
| |
| struct v4l2_window_s5p_tvout* p = |
| (struct v4l2_window_s5p_tvout*)&mParams.parm.raw_data; |
| p->win.w.top = 0; |
| p->win.w.left = 0; |
| p->win.w.width = width; |
| p->win.w.height = height; |
| |
| ALOGV("searching for format: %i", V4L2_PIX_FMT_NV12); |
| ret = tv20_v4l2_enum_fmt(mTvOutFd, V4L2_PIX_FMT_NV12); |
| RETURN_IF(ret); |
| |
| addr = (unsigned int) mFimc.out_buf.phys_addr; |
| y_size = ALIGN_TO_8KB(ALIGN_TO_128B(width) * ALIGN_TO_32B(height)); |
| ret = tv20_v4l2_s_fmt(mTvOutFd, width, height, V4L2_PIX_FMT_NV12, |
| (unsigned int) addr, |
| (unsigned int) addr + y_size); |
| RETURN_IF(ret); |
| |
| return 0; |
| } |
| |
| int SecHDMI::connect() |
| { |
| int ret; |
| |
| ALOGV("%s", __func__); |
| |
| RETURN_IF(mTvOutFd); |
| |
| if(mFlagConnected) { |
| return 0; |
| } |
| |
| #if 0 |
| ret = getCableStatus() <= 0 ? -1 : 0; |
| RETURN_IF(ret); |
| #endif |
| |
| ret = tv20_v4l2_s_parm(mTvOutFd, &mParams); |
| RETURN_IF(ret); |
| |
| ret = tv20_v4l2_streamon(mTvOutFd); |
| RETURN_IF(ret); |
| |
| #if 0 |
| ret = startLayer(S5P_TV_LAYER_VIDEO); |
| RETURN_IF(ret); |
| #endif |
| |
| mFlagConnected = true; |
| |
| return 0; |
| } |
| |
| int SecHDMI::disconnect() |
| { |
| int ret; |
| |
| ALOGV("%s", __func__); |
| |
| RETURN_IF(mTvOutFd); |
| |
| if(!mFlagConnected) { |
| return 0; |
| } |
| |
| ret = tv20_v4l2_streamoff(mTvOutFd); |
| RETURN_IF(ret); |
| |
| #if 0 |
| ret = stopLayer(S5P_TV_LAYER_VIDEO); |
| RETURN_IF(ret); |
| #endif |
| |
| mFlagConnected = false; |
| |
| return 0; |
| } |
| |
| int SecHDMI::flush(int srcW, int srcH, int srcColorFormat, |
| unsigned int srcYAddr, unsigned int srcCbAddr, unsigned int srcCrAddr, |
| int dstX, int dstY, |
| int layer, |
| int num_of_hwc_layer) |
| { |
| int ret; |
| |
| #if 0 |
| usleep(1000 * 10); |
| #else |
| sec_img src_img; |
| sec_img dst_img; |
| sec_rect src_rect; |
| sec_rect dst_rect; |
| unsigned int phyAddr[3/*MAX_NUM_PLANES*/]; |
| |
| if(!srcYAddr) { |
| struct s3cfb_next_info fb_info; |
| |
| if (mLcdFd < 0) { |
| mLcdFd = fb_open(0); |
| } |
| |
| RETURN_IF(mLcdFd); |
| |
| ret = ioctl(mLcdFd, S3CFB_GET_CURR_FB_INFO, &fb_info); |
| RETURN_IF(ret); |
| |
| srcYAddr = fb_info.phy_start_addr; |
| srcCbAddr = srcYAddr; |
| } |
| |
| memset(&src_img, 0, sizeof(src_img)); |
| memset(&dst_img, 0, sizeof(src_img)); |
| memset(&src_rect, 0, sizeof(src_rect)); |
| memset(&dst_rect, 0, sizeof(src_rect)); |
| memset(&phyAddr, 0, sizeof(int) * sizeof(phyAddr)); |
| |
| phyAddr[0] = srcYAddr; |
| phyAddr[1] = srcCbAddr; |
| phyAddr[2] = srcCrAddr; |
| |
| src_img.w = srcW; |
| src_img.h = srcH; |
| src_img.format = HAL_PIXEL_FORMAT_YCbCr_420_SP/*srcColorFormat*/; |
| src_img.base = 0; |
| src_img.offset = 0; |
| src_img.mem_id = 0; |
| src_img.mem_type = FIMC_MEM_TYPE_PHYS; |
| src_img.w = (src_img.w + 15) & (~15); |
| src_img.h = (src_img.h + 1) & (~1) ; |
| |
| src_rect.x = 0; |
| src_rect.y = 0; |
| src_rect.w = src_img.w; |
| src_rect.h = src_img.h; |
| |
| struct v4l2_window_s5p_tvout* p = |
| (struct v4l2_window_s5p_tvout*)&mParams.parm.raw_data; |
| if (!p) { |
| return -1; |
| } |
| |
| dst_img.w = p->win.w.width; |
| dst_img.h = p->win.w.height; |
| dst_img.format = HAL_PIXEL_FORMAT_YCbCr_420_SP; |
| dst_img.base = (unsigned int) mFimc.out_buf.phys_addr; |
| dst_img.offset = 0; |
| dst_img.mem_id = 0; |
| dst_img.mem_type = FIMC_MEM_TYPE_PHYS; |
| |
| dst_rect.x = p->win.w.top; |
| dst_rect.y = p->win.w.left; |
| dst_rect.w = dst_img.w; |
| dst_rect.h = dst_img.h; |
| |
| ALOGV("%s::sr_x %d sr_y %d sr_w %d sr_h %d dr_x %d dr_y %d dr_w %d dr_h %d ", |
| __func__, src_rect.x, src_rect.y, src_rect.w, src_rect.h, |
| dst_rect.x, dst_rect.y, dst_rect.w, dst_rect.h); |
| |
| ret = fimc_flush(&mFimc, &src_img, &src_rect, &dst_img, &dst_rect, |
| phyAddr, 0); |
| RETURN_IF(ret); |
| |
| /* |
| struct fb_var_screeninfo var; |
| var.xres = srcW; |
| var.yres = srcH; |
| var.xres_virtual = var.xres; |
| var.yres_virtual = var.yres; |
| var.xoffset = 0; |
| var.yoffset = 0; |
| var.width = srcW; |
| var.height = srcH; |
| var.activate = FB_ACTIVATE_FORCE; |
| if (srcColorFormat == HAL_PIXEL_FORMAT_RGB_565) { |
| var.bits_per_pixel = 16; |
| var.transp.length = 0; |
| } |
| else { |
| var.bits_per_pixel = 32; |
| var.transp.length = 8; |
| } |
| |
| ret = tv20_v4l2_s_baseaddr(mTvOutFd, (void *)srcYAddr); |
| RETURN_IF(ret); |
| |
| ret = fb_put_vscreeninfo(mLcdFd, &var); |
| RETURN_IF(ret); |
| |
| ret = tv20_v4l2_s_position(mTvOutFd, dstX, dstY); |
| RETURN_IF(ret); |
| */ |
| #endif |
| |
| return 0; |
| } |