Media Controller API淺嚐

最近有機會研究了一下Media Controller API在這邊做一下紀錄
Media Controller API主要是針對 /dev/mediaX device file 做存取

官方Medial Controller API文件的說明為:
https://www.linuxtv.org/downloads/v4l-dvb-apis/media_common.html

根據我對其在簡介部分解讀精簡如下
Media Controller API主要是要解決以下問題
1.近年來越來越多多媒體裝置都會有多重的功能,這些功能以前只能從 sysfs得知其關係
2.查出裝置內的拓樸關係,並可在運作期間組態它

以下只先針對三大部分來做實作,其餘留有興趣的人去研究
.media open()
.media close()
.media ioctl()
    -ioctl MEDIA_IOC_DEVICE_INFO — Query device information
    -ioctl MEDIA_IOC_ENUM_ENTITIES — Enumerate entities and their properties
    
我的裝置為msm8992,Android 6.0,開完機後用adb shell去看系統檔案,發現在/dev下有三個media裝置,分別為
/dev/media0
/dev/media1
/dev/media2

所以我們可以,建立兩個檔案 mediatest.c 與 Android.mk,這邊我是放在AOSP內 device\qcom\msm8992\mediatest\ 目錄下
build的方式,你必須已經有 make -j6過一次image,將目錄切換到 device\qcom\msm8992\mediatest\下,鍵入 mm 指令,就可以build
如果成功 build出的,檔案會產生在 out\target\product\msm8992\system\bin\mediatest

.media open()
 要開啟 /dev/mediaX,要 #include <fcntl.h>,呼叫 open函式,成功的話會得到傳回的 file descriptor
 函式原型為:
 int open(    const char *device_name,int flags);
 
.media close()
 要關閉 /dev/mediaX,要 #include <unistd.h>,呼叫 close 函式,成功的話會得到傳回 0
 函式原型為:
 int close(    int fd);
 
.media ioctl() - ioctl MEDIA_IOC_DEVICE_INFO — Query device information
 利用ioctl MEDIA_IOC_DEVICE_INFO 來得知裝置的資訊,第三個參數為struct media_device_info *argp 指標
 執行成功,會將資料填入 struct media_device_info *argp 指標內
 函式原型為:
 int ioctl(    int fd,    int request,    struct media_device_info *argp);
 media_device 結構如下: (include/media/media-device.h)
 ---
 struct media_device {
    /* dev->driver_data points to this struct. */
    struct device *dev;
    struct media_devnode devnode;

    char model[32];
    char serial[40];
    char bus_info[32];
    u32 hw_revision;
    u32 driver_version;

    u32 entity_id;
    struct list_head entities;

    /* Protects the entities list */
    spinlock_t lock;
    /* Serializes graph operations. */
    struct mutex graph_mutex;

    int (*link_notify)(struct media_pad *source,
               struct media_pad *sink, u32 flags);
  };
  --
 
 mediatest運行後,針對/dev/media0 下MEDIA_IOC_DEVICE_INFO ioctl command得到以下media_device_info資訊
 --------------------------
 mdev_info.driver=msm,
 mdev_info.model=msm_config,
 mdev_info.serial=,
 mdev_info.bus_info=,
 mdev_info.media_version=256,
 mdev_info.hw_revision=0,
 mdev_info.driver_version=0,
 --------------------------
 在kernel driver,這部分的code是位於 AOSP /driver/media/platform/msm/camera_v2/msm.c 中 msm_probe function
 可以看到以下的 code
 --
 #if defined(CONFIG_MEDIA_CONTROLLER)
   ...
     strlcpy(msm_v4l2_dev->mdev->model, MSM_CONFIGURATION_NAME,
            sizeof(msm_v4l2_dev->mdev->model));
    msm_v4l2_dev->mdev->dev = &(pdev->dev);

    rc = media_device_register(msm_v4l2_dev->mdev);            
  --
  其中 /dev/mediaX是呼叫 media_device_register 去註冊的
  呼叫 media_device_unregister(msm_v4l2_dev->mdev); 去 unregister
 
 
.media ioctl() -ioctl MEDIA_IOC_ENUM_ENTITIES — Enumerate entities and their properties
 利用ioctl MEDIA_IOC_ENUM_ENTITIES 來列舉實體裝置與性能,第三個參數為struct media_entity_desc *argp 指標
 執行成功,會將資料填入 struct media_entity_desc *argp 指標內
 函式原型為:
 int ioctl(    int fd,    int request,    struct media_entity_desc *argp);  
 media_entity 結構如下: (include/media/media-entity.h)
 --
 struct media_entity {
    struct list_head list;
    struct media_device *parent;    /* Media device this entity belongs to*/
    u32 id;                /* Entity ID, unique in the parent media
                     * device context */
    const char *name;        /* Entity name */
    u32 type;            /* Entity type (MEDIA_ENT_T_*) */
    u32 revision;            /* Entity revision, driver specific */
    unsigned long flags;        /* Entity flags (MEDIA_ENT_FL_*) */
    u32 group_id;            /* Entity group ID */

    u16 num_pads;            /* Number of sink and source pads */
    u16 num_links;            /* Number of existing links, both
                     * enabled and disabled */
    u16 num_backlinks;        /* Number of backlinks */
    u16 max_links;            /* Maximum number of links */

    struct media_pad *pads;        /* Pads array (num_pads elements) */
    struct media_link *links;    /* Links array (max_links elements)*/

    const struct media_entity_operations *ops;    /* Entity operations */

    /* Reference counts must never be negative, but are signed integers on
     * purpose: a simple WARN_ON(<0) check can be used to detect reference
     * count bugs that would make them negative.
     */
    int stream_count;        /* Stream count for the entity. */
    int use_count;            /* Use count for the entity. */

    struct media_pipeline *pipe;    /* Pipeline this entity belongs to. */

    union {
        /* Node specifications */
        struct {
            u32 major;
            u32 minor;
        } v4l;
        struct {
            u32 major;
            u32 minor;
        } fb;
        struct {
            u32 card;
            u32 device;
            u32 subdevice;
        } alsa;
        int dvb;

        /* Sub-device specifications */
        /* Nothing needed yet */
    } info;
  };
  --
  mediatest運行後,針對/dev/media0 下 MEDIA_IOC_ENUM_ENTITIES ioctl command得到以下 media_entity 資訊
  總共得到了19個 media_entity
  --------------------------
  main 97,ioctl success,id=1,name=video0
  --------------------------
  entity.id=1,
  entity.name=video0,
  entity.type=65537,
  entity.revision=0,
  entity.flags=0,
  entity.group_id=2,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 97,ioctl success,id=2,name=msm_cci
  --------------------------
  entity.id=2,
  entity.name=msm_cci,
  entity.type=131072,
  entity.revision=0,
  entity.flags=0,
  entity.group_id=0,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 97,ioctl success,id=3,name=v4l-subdev0
  --------------------------
  entity.id=3,
  entity.name=v4l-subdev0,
  entity.type=131072,
  entity.revision=0,
  entity.flags=0,
  entity.group_id=0,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 97,ioctl success,id=4,name=v4l-subdev1
  --------------------------
  entity.id=4,
  entity.name=v4l-subdev1,
  entity.type=131072,
  entity.revision=0,
  entity.flags=0,
  entity.group_id=0,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 97,ioctl success,id=5,name=v4l-subdev2
  --------------------------
  entity.id=5,
  entity.name=v4l-subdev2,
  entity.type=131072,
  entity.revision=0,
  entity.flags=0,
  entity.group_id=0,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 97,ioctl success,id=6,name=v4l-subdev3
  --------------------------
  entity.id=6,
  entity.name=v4l-subdev3,
  entity.type=131072,
  entity.revision=0,
  entity.flags=0,
  entity.group_id=1,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 97,ioctl success,id=7,name=v4l-subdev4
  --------------------------
  entity.id=7,
  entity.name=v4l-subdev4,
  entity.type=131072,
  entity.revision=0,
  entity.flags=0,
  entity.group_id=1,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 97,ioctl success,id=8,name=v4l-subdev5
  --------------------------
  entity.id=8,
  entity.name=v4l-subdev5,
  entity.type=131072,
  entity.revision=0,
  entity.flags=0,
  entity.group_id=1,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 97,ioctl success,id=9,name=v4l-subdev6
  --------------------------
  entity.id=9,
  entity.name=v4l-subdev6,
  entity.type=131072,
  entity.revision=0,
  entity.flags=0,
  entity.group_id=1,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 97,ioctl success,id=10,name=v4l-subdev7
  --------------------------
  entity.id=10,
  entity.name=v4l-subdev7,
  entity.type=131072,
  entity.revision=0,
  entity.flags=0,
  entity.group_id=7,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 97,ioctl success,id=11,name=v4l-subdev8
  --------------------------
  entity.id=11,
  entity.name=v4l-subdev8,
  entity.type=131072,
  entity.revision=0,
  entity.flags=0,
  entity.group_id=16,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 97,ioctl success,id=12,name=v4l-subdev9
  --------------------------
  entity.id=12,
  entity.name=v4l-subdev9,
  entity.type=131072,
  entity.revision=0,
  entity.flags=0,
  entity.group_id=14,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 97,ioctl success,id=13,name=v4l-subdev10
  --------------------------
  entity.id=13,
  entity.name=v4l-subdev10,
  entity.type=131072,
  entity.revision=10,
  entity.flags=0,
  entity.group_id=9,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 97,ioctl success,id=14,name=v4l-subdev11
  --------------------------
  entity.id=14,
  entity.name=v4l-subdev11,
  entity.type=131072,
  entity.revision=0,
  entity.flags=0,
  entity.group_id=3,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 97,ioctl success,id=15,name=v4l-subdev12
  --------------------------
  entity.id=15,
  entity.name=v4l-subdev12,
  entity.type=131072,
  entity.revision=0,
  entity.flags=0,
  entity.group_id=3,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 97,ioctl success,id=16,name=v4l-subdev13
  --------------------------
  entity.id=16,
  entity.name=v4l-subdev13,
  entity.type=131072,
  entity.revision=0,
  entity.flags=0,
  entity.group_id=2,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 97,ioctl success,id=17,name=v4l-subdev14
  --------------------------
  entity.id=17,
  entity.name=v4l-subdev14,
  entity.type=131072,
  entity.revision=0,
  entity.flags=0,
  entity.group_id=13,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 97,ioctl success,id=18,name=v4l-subdev15
  --------------------------
  entity.id=18,
  entity.name=v4l-subdev15,
  entity.type=131072,
  entity.revision=0,
  entity.flags=769,
  entity.group_id=6,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 103,id=18,name=v4l-subdev15
  main 112,open /dev/v4l-subdev15 success
  main 122,ioctl success
  main 124,ioctl success,sensor_name=ov8865
  main 127, sensor_info.subdev_id[0] = 1
  main 127, sensor_info.subdev_id[1] = -1
  main 127, sensor_info.subdev_id[2] = 0
  main 127, sensor_info.subdev_id[3] = -1
  main 127, sensor_info.subdev_id[4] = 0
  main 127, sensor_info.subdev_id[5] = -1
  main 127, sensor_info.subdev_id[6] = 0
  main 127, sensor_info.subdev_id[7] = -1
  main 127, sensor_info.subdev_id[8] = 0
  main 127, sensor_info.subdev_id[9] = -1
  main 127, sensor_info.subdev_id[10] = -1
  main 97,ioctl success,id=19,name=v4l-subdev16
  --------------------------
  entity.id=19,
  entity.name=v4l-subdev16,
  entity.type=131072,
  entity.revision=0,
  entity.flags=65793,
  entity.group_id=6,
  entity.pads=0,
  entity,links=0,
  --------------------------
  main 103,id=19,name=v4l-subdev16
  main 112,open /dev/v4l-subdev16 success
  main 122,ioctl success
  main 124,ioctl success,sensor_name=de2011
  main 127, sensor_info.subdev_id[0] = 2
  main 127, sensor_info.subdev_id[1] = -1
  main 127, sensor_info.subdev_id[2] = -1
  main 127, sensor_info.subdev_id[3] = -1
  main 127, sensor_info.subdev_id[4] = -1
  main 127, sensor_info.subdev_id[5] = -1
  main 127, sensor_info.subdev_id[6] = 2
  main 127, sensor_info.subdev_id[7] = -1
  main 127, sensor_info.subdev_id[8] = 2
  main 127, sensor_info.subdev_id[9] = -1
  main 127, sensor_info.subdev_id[10] = -1
  main 93, ioctl failed  
 ---
 針對第1個entity
 --------------------------
 entity.id=1,
 entity.name=video0,
 entity.type=65537,
 entity.revision=0,
 entity.flags=0,
 entity.group_id=2,
 entity.pads=0,
 entity,links=0,
 --------------------------
 code 落在 /driver/media/platform/msm/camera_v2/msm.c
 中 msm_probe 函式
#if defined(CONFIG_MEDIA_CONTROLLER)
  ..
    pvdev->vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;  //65537
    pvdev->vdev->entity.group_id = QCAMERA_VNODE_GROUP_ID;  // 2
#endif
 
  針對第 18,19 個 entity
 --------------------------
 entity.id=18,
 entity.name=v4l-subdev15,
 entity.type=131072,
 entity.revision=0,
 entity.flags=769,
 entity.group_id=6,
 entity.pads=0,
 entity,links=0,
 --------------------------
 entity.id=19,
 entity.name=v4l-subdev16,
 entity.type=131072,
 entity.revision=0,
 entity.flags=65793,
 entity.group_id=6,
 entity.pads=0,
 entity,links=0,
 --------------------------
 kernel code 落在 /driver/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
 中 msm_sensor_driver_create_v4l_subdev 函式
 entity.type 的值為 MEDIA_ENT_T_V4L2_SUBDEV (131072)
 entity.group_id 的值為 MSM_CAMERA_SUBDEV_SENSOR (6)
 
 mediatest程式會判斷當 (entity.type == MEDIA_ENT_T_V4L2_SUBDEV(131072) && entity.group_id == MSM_CAMERA_SUBDEV_SENSOR(6))
 去開啟 /dev/entity.name ,並下達
 cfg.cfgtype = CFG_GET_SENSOR_INFO;
 ioctl(sd_fd, VIDIOC_MSM_SENSOR_CFG, &cfg);
 去得到 sensor information 結構 struct sensorb_cfg_data cfg;
 

 kernel code 落在 /driver/media/platform/msm/camera_v2/sensor/msm_sensor.c  msm_sensor_config32 函式
 ---
    case CFG_GET_SENSOR_INFO:
        memcpy(cdata->cfg.sensor_info.sensor_name,
            s_ctrl->sensordata->sensor_name,
            sizeof(cdata->cfg.sensor_info.sensor_name));
        cdata->cfg.sensor_info.session_id =
            s_ctrl->sensordata->sensor_info->session_id;
        for (i = 0; i < SUB_MODULE_MAX; i++) {
            cdata->cfg.sensor_info.subdev_id[i] =
                s_ctrl->sensordata->sensor_info->subdev_id[i];
            cdata->cfg.sensor_info.subdev_intf[i] =
                s_ctrl->sensordata->sensor_info->subdev_intf[i];
        }
        cdata->cfg.sensor_info.is_mount_angle_valid =
            s_ctrl->sensordata->sensor_info->is_mount_angle_valid;
        cdata->cfg.sensor_info.sensor_mount_angle =
            s_ctrl->sensordata->sensor_info->sensor_mount_angle;
        cdata->cfg.sensor_info.position =
            s_ctrl->sensordata->sensor_info->position;
        cdata->cfg.sensor_info.modes_supported =
            s_ctrl->sensordata->sensor_info->modes_supported;
        CDBG("%s:%d sensor name %s\n", __func__, __LINE__,
            cdata->cfg.sensor_info.sensor_name);
        CDBG("%s:%d session id %d\n", __func__, __LINE__,
            cdata->cfg.sensor_info.session_id);
        for (i = 0; i < SUB_MODULE_MAX; i++) {
            CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i,
                cdata->cfg.sensor_info.subdev_id[i]);
            CDBG("%s:%d subdev_intf[%d] %d\n", __func__, __LINE__,
                i, cdata->cfg.sensor_info.subdev_intf[i]);
        }
        CDBG("%s:%d mount angle valid %d value %d\n", __func__,
            __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid,
            cdata->cfg.sensor_info.sensor_mount_angle);

        break;
  ---

 有了以上的實作,相信各位應該可以更清楚瞭解到 media controller API與 kernel dirver的對應關係了
 希望對各位有所幫助。
 
 最後附上 mediatest.c 與 Android.mk 完整 source code 給各位參考
 Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := eng
LOCAL_SRC_FILES:=mediatest.c
LOCAL_MODULE:=mediatest
LOCAL_CPPFLAGS += -DANDROID
LOCAL_SHARED_LIBRARIES:=libc
$(info "=========================================>>>>>>>>$(LOCAL_PATH)/$(KERNEL_DIR)")

LOCAL_C_INCLUDES+= $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include/media
LOCAL_C_INCLUDES+= $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
LOCAL_C_INCLUDES+= hardware/qcom/camera/QCamera2/stack/common
LOCAL_C_INCLUDES += \
           $(LOCAL_PATH) \
           $(LOCAL_PATH)/$(KERNEL_DIR)/include \
           
include $(BUILD_EXECUTABLE)
 mediatest.c
#include <fcntl.h>  // for open
#include <unistd.h>  // for close
#include <stdio.h>
#include <sys/ioctl.h> 
#include <linux/media.h>
#include <media/msm_cam_sensor.h>
#include <media/msmb_camera.h>
#include <string.h>  // for memset

struct media_device_info mdev_info;
struct media_entity_desc entity;
struct sensorb_cfg_data cfg;

int32_t num_media_devices = 0;

  
  
void showm_entity()
{
	printf("--------------------------\n"); 
	printf("entity.id=%d,\n",entity.id);   
	printf("entity.name=%s,\n",entity.name);   
	printf("entity.type=%d,\n",entity.type);   //MEDIA_ENT_T_V4L2_SUBDEV
	printf("entity.revision=%d,\n",entity.revision);   
	printf("entity.flags=%d,\n",entity.flags);   
	printf("entity.group_id=%d,\n",entity.group_id);   //MSM_CAMERA_SUBDEV_SENSOR
	printf("entity.pads=%d,\n",entity.pads);   
	printf("entity,links=%d,\n",entity.links);   
  printf("--------------------------\n"); 

  return ;	
}

  
void showm_mdev_info()
{
	printf("--------------------------\n");   
	printf("mdev_info.driver=%s,\n",mdev_info.driver);   
	printf("mdev_info.model=%s,\n",mdev_info.model);   
	printf("mdev_info.serial=%s,\n",mdev_info.serial);   
	printf("mdev_info.bus_info=%s,\n",mdev_info.bus_info); 
	printf("mdev_info.media_version=%d,\n",mdev_info.media_version);   
	printf("mdev_info.hw_revision=%d,\n",mdev_info.hw_revision); 		
	printf("mdev_info.driver_version=%d,\n",mdev_info.driver_version);   
	printf("--------------------------\n");   
	return;
}  
  
int main()
{

  int dev_fd=0;
  int sd_fd=0;
  int rc=-1;
  char dev_name[32];
  char subdev_name[32];
  int i;
  int32_t num_media_devices = 0;  //media file count 
  
  printf("%s+ %d,\n",__func__,__LINE__);
  
  
  while (1) {
	  int num_entities = 1;   
	  snprintf(dev_name, sizeof(dev_name), "/dev/media%d", num_media_devices);
	  //dev_fd=open("/dev/media0", O_RDWR );
	  dev_fd=open(dev_name, O_RDWR);
	  if(dev_fd<0){
	  	printf("%s %d, open %s failed\n",__func__,__LINE__,dev_name);   
	  	return rc;
	  }else{
	  	printf("%s %d,open %s success\n",__func__,__LINE__,dev_name);   
	  }
	  
	  num_media_devices++;
	  
	  memset(&mdev_info, 0, sizeof(mdev_info));
	  rc=ioctl(dev_fd,MEDIA_IOC_DEVICE_INFO,&mdev_info);  
	  if(rc < 0){
	  	printf("%s %d, ioctl failed\n",__func__,__LINE__);   
	  	goto close_media;
	  }else{
	  	printf("%s %d,ioctl success,model=%s\n",__func__,__LINE__,mdev_info.model);  
	  	showm_mdev_info();
	  }  
	  
	  while (1) {
	  //ioctl MEDIA_IOC_ENUM_ENTITIES
		  memset(&entity, 0, sizeof(entity));
		  entity.id=num_entities++;  //??
		  rc=ioctl(dev_fd,MEDIA_IOC_ENUM_ENTITIES,&entity);  
		  if(rc < 0){
		  	printf("%s %d, ioctl failed\n",__func__,__LINE__);   
		  	//goto close_media;
		  	break;
		  }else{
		  	printf("%s %d,ioctl success,id=%d,name=%s\n",__func__,__LINE__,entity.id,entity.name);  
		  	showm_entity();
		  }    
		  
		  //MEDIA_ENT_T_V4L2_SUBDEV= 131072 ,MSM_CAMERA_SUBDEV_SENSOR =6
	    if (entity.type == MEDIA_ENT_T_V4L2_SUBDEV && entity.group_id == MSM_CAMERA_SUBDEV_SENSOR) {
	        printf("%s %d,id=%d,name=%s\n",__func__,__LINE__,entity.id,entity.name); 
	        snprintf(subdev_name, sizeof(subdev_name), "/dev/%s", entity.name);
	        
	        sd_fd=open(subdev_name, O_RDWR);
				  if(sd_fd<0){
				  	printf("%s %d, open %s failed\n",__func__,__LINE__,subdev_name);   
				  	//goto close_media;
				  	continue;
				  }else{
				  	printf("%s %d,open %s success\n",__func__,__LINE__,subdev_name);   
				  }        
	        memset(&cfg, 0, sizeof(cfg));
	        cfg.cfgtype = CFG_GET_SENSOR_INFO;
	        rc=ioctl(sd_fd, VIDIOC_MSM_SENSOR_CFG, &cfg);
				  if(rc < 0){
				  	printf("%s %d, ioctl failed\n",__func__,__LINE__);   
				  	close(sd_fd);  
				  	continue;
				  }else{
				  	printf("%s %d,ioctl success\n",__func__,__LINE__); 			  	
				  }       
				  	printf("%s %d,ioctl success,sensor_name=%s\n",__func__,__LINE__,cfg.cfg.sensor_info.sensor_name); 			  	
				     
	        for (i = 0; i < SUB_MODULE_MAX; i++) {
	          printf("%s %d, sensor_info.subdev_id[%d] = %d\n",__func__,__LINE__, i, cfg.cfg.sensor_info.subdev_id[i]);
	        }			  
	        
	    }
		  
	  }
  }
  printf("%s %d,\n",__func__,__LINE__);    

close_sd: 
	close(sd_fd);  
	
close_media:    
  
  close(dev_fd);
  printf("%s %d, close \n",__func__,__LINE__);
	return rc;
}
 
 
 
 

arrow
arrow
    文章標籤
    Media Controller API dev media
    全站熱搜
    創作者介紹
    創作者 CuteParrot 的頭像
    CuteParrot

    馴龍窩

    CuteParrot 發表在 痞客邦 留言(0) 人氣()