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; } |
留言列表