S5PV210 多媒体预留内存空间 1 - FIMC控制器
[复制链接]
由于GPU 多媒体解码 camera输入以及overlay显示等操作需要大块的连续物理内存,S5PV210开发板在初始化的过程中,会为这些多媒体相关驱动预留内存,这些预留的物理内存不能再被系统的其他部件使用,因此调整这些预留空间使之既能满足项目的需求,同时把浪费部分最小化,有必要分析每一部分内存需求的计算公式。
FIMC0, FMIC1, FIMC2预留空间计算
在arch/arm/plat-s5p/bootmem.c中,s5p_reserve_bootmem为media设备预留内存
[cpp] view plaincopy
- 80 void s5p_reserve_bootmem(struct s5p_media_device *mdevs, int nr_mdevs)
- 81 {
- 82 struct s5p_media_device *mdev;
- 83 void *virt_mem;
- 84 int i;
- 85
- 86 media_devs = mdevs;
- 87 nr_media_devs = nr_mdevs;
- 88
- 89 for (i = 0; i < nr_media_devs; i++) {
- 90 mdev = &media_devs;
- 91 if (mdev->memsize <= 0)
- 92 continue;
- 93
- 94 if (mdev->paddr)
- 95 virt_mem = __alloc_bootmem(mdev->memsize, PAGE_SIZE,
- 96 mdev->paddr);
- 97 else {
- 98 printk(KERN_INFO "s5pv210: meminfo.back[mdev->bank].start=0x%08lx\n",
- 99 meminfo.bank[mdev->bank].start);
- 100 virt_mem = __alloc_bootmem(mdev->memsize, PAGE_SIZE,
- 101 meminfo.bank[mdev->bank].start);
- 102 }
- 103
- 104 if (virt_mem != NULL) {
- 105 mdev->paddr = virt_to_phys(virt_mem);
- 106 } else {
- 107 mdev->paddr = (dma_addr_t)NULL;
- 108 printk(KERN_INFO "s5p: Failed to reserve system memory\n");
- 109 }
- 110
- 111 printk(KERN_INFO "s5pv210: %lu bytes system memory reserved "
- 112 "for %s at 0x%08x\n", (unsigned long) mdev->memsize,
- 113 mdev->name, mdev->paddr);
- 114 }
- 115 }
@mdevs 是在mach-s5pv210.c中定义的
[cpp] view plaincopy
- 174 #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC0 (24576 * SZ_1K)
- 175 #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC1 (9900 * SZ_1K)
-
- 177 #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC2 (24576 * SZ_1K)
- 178 #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC0 (36864 * SZ_1K)
- 179 #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC1 (36864 * SZ_1K)
- 180 #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMD (S5PV210_LCD_WIDTH * \
- 181 S5PV210_LCD_HEIGHT * 4 * \
- 182 CONFIG_FB_S3C_NR_BUFFERS)
- 183 #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_JPEG (8192 * SZ_1K)
- 184
- 185 /* 1920 * 1080 * 4 (RGBA)
- 186 * - framesize == 1080p : 1920 * 1080 * 2(16bpp) * 2(double buffer) = 8MB
- 187 * - framesize < 1080p : 1080 * 720 * 4(32bpp) * 2(double buffer) = under 8MB
- 188 **/
- 189 #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_G2D (8192 * SZ_1K)
- 190 #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_TEXSTREAM (3000 * SZ_1K)
- 191 #define S5PV210_ANDROID_PMEM_MEMSIZE_PMEM_GPU1 (3300 * SZ_1K)
- 192
- 193 static struct s5p_media_device smdkc110_media_devs[] = {
- 194 [0] = {
- 195 .id = S5P_MDEV_MFC,
- 196 .name = "mfc",
- 197 .bank = 0,
- 198 .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC0,
- 199 .paddr = 0,
- 200 },
- 201 [1] = {
- 202 .id = S5P_MDEV_MFC,
- 203 .name = "mfc",
- 204 .bank = 1,
- 205 .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC1,
- 206 .paddr = 0,
- 207 },
- 208 [2] = {
- 209 .id = S5P_MDEV_FIMC0,
- 210 .name = "fimc0",
- 211 .bank = 1,
- 212 .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC0,
- 213 .paddr = 0,
- 214 },
- 215 [3] = {
- 216 .id = S5P_MDEV_FIMC1,
- 217 .name = "fimc1",
- 218 .bank = 1,
- 219 .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC1,
- 220 .paddr = 0,
- 221 },
- 222 [4] = {
- 223 .id = S5P_MDEV_FIMC2,
- 224 .name = "fimc2",
- 225 .bank = 1,
- 226 .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC2,
- 227 .paddr = 0,
- 228 },
- 229 [5] = {
- 230 .id = S5P_MDEV_JPEG,
- 231 .name = "jpeg",
- 232 .bank = 0,
- 233 .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_JPEG,
- 234 .paddr = 0,
- 235 },
- 236 [6] = {
- 237 .id = S5P_MDEV_FIMD,
- 238 .name = "fimd",
- 239 .bank = 1,
- 240 .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMD,
- 241 .paddr = 0,
- 242 },
- 243 [7] = {
- 244 .id = S5P_MDEV_TEXSTREAM,
- 245 .name = "texstream",
- 246 .bank = 1,
- 247 .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_TEXSTREAM,
- 248 .paddr = 0,
- 249 },
- 250 [8] = {
- 251 .id = S5P_MDEV_PMEM_GPU1,
- 252 .name = "pmem_gpu1",
- 253 .bank = 0, /* OneDRAM */
- 254 .memsize = S5PV210_ANDROID_PMEM_MEMSIZE_PMEM_GPU1,
- 255 .paddr = 0,
- 256 },
- 257 [9] = {
- 258 .id = S5P_MDEV_G2D,
- 259 .name = "g2d",
- 260 .bank = 0,
- 261 .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_G2D,
- 262 .paddr = 0,
- 263 },
- 264 };
结构smdkc110_media_devs定义了每个驱动的名字,物理内存的bank位置,需要的物理内存大小,以及希望的物理内存位置
下面我们一一分析如何计算每个驱动实际需要的物理内存大小
FIMC0,原生代码预留了32MB的物理内存空间
关于fimc0, fimc1, fimc2控制器的作用,参看http://blog.csdn.net/kickxxx/article/details/7728947 FIMC0在拍照以及preview时,系统从camera sensor获取数据时使用。拍照或者preview的数据需要放在request buffer中,应用通过VIDIOC_REQBUFS从内核申请request buffer,kernel从这块预留的物理内存分配buffer:
[cpp] view plaincopy
- 897 static int fimc_alloc_buffers(struct fimc_control *ctrl, int size[], int align)
- 898 {
- 899 struct fimc_capinfo *cap = ctrl->cap;
- 900 int i, plane;
- 901
- 902 for (i = 0; i < cap->nr_bufs; i++) {
- 903 for (plane = 0; plane < 4; plane++) {
- 904 cap->bufs.length[plane] = size[plane];
- 905 if (!cap->bufs.length[plane])
- 906 continue;
- 907
- 908 fimc_dma_alloc(ctrl, &cap->bufs, plane, align);
- 909
- 910 if (!cap->bufs.base[plane])
- 911 goto err_alloc;
- 912 }
- 913
- 914 cap->bufs.state = VIDEOBUF_PREPARED;
- 915 cap->bufs.id = i;
- 916 }
- 917
- 918 return 0;
- 919
- 920 err_alloc:
- 921 for (i = 0; i < cap->nr_bufs; i++) {
- 922 if (cap->bufs.base[plane])
- 923 fimc_dma_free(ctrl, &cap->bufs, plane);
- 924
- 925 memset(&cap->bufs, 0, sizeof(cap->bufs));
- 926 }
- 927
- 928 return -ENOMEM;
- 929 }
预留空间计算公式 = cam->nr_bufs * SUM(size),因此CameraHal的申请的buffer队列越大,需要预留的空间越多,CameraHal中定义buffer count 为 8,此外kenerl本身也有一个最大限制FIMC_CAPBUFS(16)
@size之所以是个数组,是因为不同的pixelformat对应的层数不一样,size的大小和preview,capture的图片大小是成正比的,因此系统支持的camera sensor分辨率越高,@size越大 我们看下@size的计算方法
[cpp] view plaincopy
- 950 int fimc_reqbufs_capture(void *fh, struct v4l2_requestbuffers *b)
-
- ..............
-
- 996 switch (cap->fmt.pixelformat) {
- 997 case V4L2_PIX_FMT_RGB32: /* fall through */
- 998 case V4L2_PIX_FMT_RGB565: /* fall through */
- 999 case V4L2_PIX_FMT_YUYV: /* fall through */
- 1000 case V4L2_PIX_FMT_UYVY: /* fall through */
- 1001 case V4L2_PIX_FMT_VYUY: /* fall through */
- 1002 case V4L2_PIX_FMT_YVYU: /* fall through */
- 1003 case V4L2_PIX_FMT_YUV422P: /* fall through */
- 1004 size[0] = cap->fmt.sizeimage;
- 1005 break;
- 1006
- 1007 case V4L2_PIX_FMT_NV16: /* fall through */
- 1008 case V4L2_PIX_FMT_NV61:
- 1009 size[0] = cap->fmt.width * cap->fmt.height;
- 1010 size[1] = cap->fmt.width * cap->fmt.height;
- 1011 size[3] = 16; /* Padding buffer */
- 1012 break;
- 1013 case V4L2_PIX_FMT_NV12:
- 1014 size[0] = cap->fmt.width * cap->fmt.height;
- 1015 size[1] = cap->fmt.width * cap->fmt.height/2;
- 1016 break;
- 1017 case V4L2_PIX_FMT_NV21:
- 1018 size[0] = cap->fmt.width * cap->fmt.height;
- 1019 size[1] = cap->fmt.width * cap->fmt.height/2;
- 1020 size[3] = 16; /* Padding buffer */
- 1021 break;
- 1022 case V4L2_PIX_FMT_NV12T:
- 1023 /* Tiled frame size calculations as per 4x2 tiles
- 1024 * - Width: Has to be aligned to 2 times the tile width
- 1025 * - Height: Has to be aligned to the tile height
- 1026 * - Alignment: Has to be aligned to the size of the
- 1027 * macrotile (size of 4 tiles)
- 1028 *
- 1029 * NOTE: In case of rotation, we need modified calculation as
- 1030 * width and height are aligned to different values.
- 1031 */
- 1032 if (cap->rotate == 90 || cap->rotate == 270) {
- 1033 size[0] = ALIGN(ALIGN(cap->fmt.height, 128) *
- 1034 ALIGN(cap->fmt.width, 32),
- 1035 SZ_8K);
- 1036 size[1] = ALIGN(ALIGN(cap->fmt.height, 128) *
- 1037 ALIGN(cap->fmt.width/2, 32),
- 1038 SZ_8K);
- 1039 } else {
- 1040 size[0] = ALIGN(ALIGN(cap->fmt.width, 128) *
- 1041 ALIGN(cap->fmt.height, 32),
- 1042 SZ_8K);
- 1043 size[1] = ALIGN(ALIGN(cap->fmt.width, 128) *
- 1044 ALIGN(cap->fmt.height/2, 32),
- 1045 SZ_8K);
- 1046 }
- 1047 align = SZ_8K;
- 1048 break;
- 1049
- 1050 case V4L2_PIX_FMT_YUV420:
- 1051 size[0] = cap->fmt.width * cap->fmt.height;
- 1052 size[1] = cap->fmt.width * cap->fmt.height >> 2;
- 1053 size[2] = cap->fmt.width * cap->fmt.height >> 2;
- 1054 size[3] = 16; /* Padding buffer */
- 1055 break;
- 1056
- 1057 case V4L2_PIX_FMT_JPEG:
- 1058 size[0] = fimc_camera_get_jpeg_memsize(ctrl);
- 1059 default:
- 1060 break;
- 1061 }
-
- ...............
fmt.width和fmt.height 和capture需要的图片尺寸大小或者preview的大小相关,因此需要根据项目预估这个值,我们的项目使用的是video AD转换芯片,sensor raw size最大为720*576,preview最大为WVGA 800*480,取二者的最大值720*576 一般来说上层应用使用YUYV或者NV12T作为image格式,考虑对齐方式和安全边界,那么每个buffer最大不会超过1024KB
因此我们可以大致估算FIMC0预留空间大小: cam->nr_bufs * SUM(size) = 16 * 720 * 576 * 2 = 13MB
FIMC2
Recording过程中,中间件使用fimc0获取preview数据,使用fimc2获取recording的数据 预留空间计算公式 = buffer_count * (record_width * record_height * pixel_size)
CameraHal层在调用REQBUFS时指定buffer count大小为8,kernel对申请request buffer的数目限制为16
一般来说录像的宽高等于LCD的尺寸(当然这是项目相关的) 所以对于WVGA计算得到 cam->nr_bufs * (record_width * record_height * pixel_size) = 16 * (800 * 480 * 2) =13MB
FIMC1
FIMC1用来实现overlay功能,不论是camera preview还是视频播放,都会通过FIMC1进行数据转换,预留的内存空间用来保存转换后的数据,转换的image大小是和LCD屏尺寸相关 FIMC1预留空间计算公式=buffer_count * (lcd_width * lcd_height * pixel_size) + buffer_count *(video_width * video_height * pixel_size)
对于WVGA lcd, lcd_width=800, lcd_height=480, pixel_size根据pixelformat不同,分别为4, 2, 1.5,这里取最大值4 Video_width和video_height是解码后的视频宽高,有些解码器需要从overlay设备分配这个解码后端buffer,但有些解码器不需要从FIMC1申请内存。samsung平台的有些解码器在从FIMC1申请buffer失败后,会转到软件显示(surfaceflinger),申请后端解码buffer失败则转到软件解码。用例比较多,我自己也没搞太清楚。
buffer count虽然是CameraHAL申请request buffer 时设定的,但是kernel对最大buffer count做了限制 为FIMC_OUTBUFS=3 buffer_count * (lcd_width * lcd_height * pixel_size) = 3 * (800 * 480 * 4) = 4608000 buffer_count * (1080p * 3) = 3 * 1980 * 1300 * 4 = 29.45MB,注意这里的1300,我们一般认为1080P的高度为1080,实际上仍然有些不规范的视频高度超过了1300,三星在fimc_output.c对最大输入高度做了限制FIMC_SRC_MAX_H = 1300,所以在这里我们以1300为准
考虑对齐等因素,需要为FIMC1预留35MB
转载文章原文地址 http://blog.csdn.net/kickxxx/article/details/8064585 这位老兄对摄像头多媒体颇有研究啊。现在来学习学习。
|