当前位置: 首页 > news >正文

做网站放视频网站推广的方式和方法

做网站放视频,网站推广的方式和方法,天眼查在线查询系统,wordpress常用函数一、概述 关于 RN6752V1 这个芯片这里就不做介绍了,看到这篇笔记的小伙伴应该都明白,虽然说 RN6752V1 芯片是 AHD 信号的解码芯片,但是也可以把芯片当做是一个 YUV 信号的 MIPI 摄像头,所以驱动的编写和 MIPI 摄像头无太大的区别。…

一、概述

关于 RN6752V1 这个芯片这里就不做介绍了,看到这篇笔记的小伙伴应该都明白,虽然说 RN6752V1 芯片是 AHD 信号的解码芯片,但是也可以把芯片当做是一个 YUV 信号的 MIPI 摄像头,所以驱动的编写和 MIPI 摄像头无太大的区别。这里主要是介绍具体的函数,关于 MIPI 驱动的框架程序看我之前的笔记:Linux MIPI 摄像头驱动框架编写(RN6752解码芯片)

二、RN6752 帧格式

RN6752 支持 DVP 和 MIPI 信号,这里我主要是对 MIPI 信号的使用,当然 DVP 通信的操作也可以做参考。

  1. 寄存地配置通过代理商提供的头文件中可以获取到相关寄存器的配置,如下所示:

static const struct sensor_register rn6752_fhd_1080P25_video[] = {{ 0x19, 0x0A }, // 视频格式检测滞后控制{ 0x81, 0x01 }, // 打开视频解码器{ 0xDF, 0xFE }, // 启用HD格式{ 0xF0, 0xC0 },	// 使能 FIFO 和 144 MHz 解码器输出{ 0xA3, 0x04 }, // 启用 HD 输出{ 0x88, 0x40 }, // 禁用 SCLK1 输出{ 0xF6, 0x40 }, // 禁用 SCLK3A 输出/* 切换到ch0(默认;可选) */{ 0xFF, 0x00 },	// 寄存器集选择{ 0x33, 0x10 }, // 检测中的视频{ 0x4A, 0xA8 }, // 检测中的视频{ 0x00, 0x20 }, // internal use*{ 0x06, 0x08 }, // internal use*{ 0x07, 0x63 }, // 高清格式{ 0x2A, 0x01 }, // 滤波器控制{ 0x3A, 0x24 }, // 在SAV/EAV代码中插入通道ID{ 0x3F, 0x10 }, // 通道ID{ 0x4C, 0x37 }, // 均衡器{ 0x4F, 0x03 }, // 同步控制{ 0x50, 0x03 }, // 1080p分辨率{ 0x56, 0x02 }, // 144M 和 BT656模式{ 0x5F, 0x44 }, // 消隐电平{ 0x63, 0xF8 }, // 滤波器控制{ 0x59, 0x00 }, // 扩展寄存器存取{ 0x5A, 0x48 }, // 扩展寄存器的数据{ 0x58, 0x01 }, // 启用扩展寄存器写入{ 0x59, 0x33 }, // 扩展寄存器存取{ 0x5A, 0x23 }, // 扩展寄存器的数据{ 0x58, 0x01 }, // 启用扩展寄存器写入{ 0x51, 0xF4 }, // 比例因子1{ 0x52, 0x29 }, // 比例因子2{ 0x53, 0x15 }, // 比例因子3{ 0x5B, 0x01 }, // H-标度控制{ 0x5E, 0x08 }, // 启用H缩放控制{ 0x6A, 0x87 }, // H-标度控制{ 0x28, 0x92 }, // 剪裁{ 0x03, 0x80 }, // 饱和{ 0x04, 0x80 }, // 颜色{ 0x05, 0x04 }, // 尖锐{ 0x57, 0x23 }, // 黑色/白色拉伸{ 0x68, 0x00 }, // coring{ 0x37, 0x33 }, // { 0x61, 0x6C }, //
#ifdef USE_BLUE_SCREEN{ 0x3A, 0x24 }, // AHD 断开链接时,屏幕为蓝色
#else{ 0x3A, 0x2C }, // AHD 断开链接时,屏幕为黑色{ 0x3B, 0x00 }, //{ 0x3C, 0x80 }, //{ 0x3D, 0x80 }, //
#endif{ 0x2E, 0x30 }, // 强制不播放视频{ 0x2E, 0x00 }, // 回归平常/* mipi 连接 */{ 0xFF, 0x09 }, // 切换到 mipi tx1{ 0x00, 0x03 }, // enable bias{ 0xFF, 0x08 }, // 切换到 mipi csi1{ 0x04, 0x03 }, // csi1 和 tx1 重置{ 0x6C, 0x11 }, // 禁用 ch 输出,打开 ch0
#ifdef USE_MIPI_4LANES{ 0x06, 0x7C }, // mipi 4 线
#else{ 0x06, 0x4C }, // mipi 2 线
#endif{ 0x21, 0x01 }, // 启用 hs 时钟{ 0x34, 0x06 }, //{ 0x35, 0x0B }, // { 0x78, 0xC0 }, // ch0 的 Y/C 计数{ 0x79, 0x03 }, // ch0 的 Y/C 计数{ 0x6C, 0x01 }, // 启用 ch 输出{ 0x04, 0x00 }, // csi1 和 tx1 重置完成{ 0x20, 0xAA }, // 
#ifdef USE_MIPI_NON_CONTINUOUS_CLOCK{ 0x07, 0x05 }, // 启用非连续时钟
#else{ 0x07, 0x04 }, // 启用连续时钟
#endif{ 0xFF, 0x0A }, // 切换到 mipi csi3{ 0x6C, 0x10 }, // 禁用 ch 输出;关闭 ch0~3{REG_NULL, 0x00},
};

注意: 其他格式的寄存器我这里就不附上了,可以参考代理商提供的头文件

  1. 将配置信息存入帧列表中

static const struct rn6752_framesize rn6752_mipi_framesizes[] = {{.width		= 1280,.height		= 720,.max_fps = {.numerator = 10000,.denominator = 250000,},.regs		= rn6752_fhd_720P25_video,}, {.width		= 1280,.height		= 720,.max_fps = {.numerator = 10000,.denominator = 300000,},.regs		= rn6752_fhd_720P30_video,}, {.width		= 1920,.height		= 1080,.max_fps = {.numerator = 10000,.denominator = 250000,},.regs		= rn6752_fhd_1080P25_video,}, {.width		= 1920,.height		= 1080,.max_fps = {.numerator = 10000,.denominator = 300000,},.regs		= rn6752_fhd_1080P30_video,}, {.width		= 1280,.height		= 960,.max_fps = {.numerator = 10000,.denominator = 250000,},.regs		= rn6752_fhd_960P25_video,}, {.width		= 1280,.height		= 960,.max_fps = {.numerator = 10000,.denominator = 300000,},.regs		= rn6752_fhd_960P30_video,}
};

  1. 配置默认帧在 rn6752_probe 函数中存入默认支持的帧列表,如下所示

static void rn6752_get_default_format(struct rn6752 *rn6752,struct v4l2_mbus_framefmt *format)
{format->width = rn6752->framesize_cfg[2].width; 	/* 设置默认宽度 */format->height = rn6752->framesize_cfg[2].height; 	/* 设置默认高度 */format->colorspace = V4L2_COLORSPACE_SRGB; 			/* 设置默认色彩空间为标准的 sRGB 色彩空间 */format->code = rn6752_formats[0].code; 				/* 设置默认编码格式 */format->field = V4L2_FIELD_NONE; 					/* 设置默认场模式 */
}/* rn6752_mipi_framesizes 是 rn6752 mipi 通信支持的所有帧格式 */
rn6752->framesize_cfg = rn6752_mipi_framesizes;
rn6752->cfg_num = ARRAY_SIZE(rn6752_mipi_framesizes);
/* 获取摄像头传感器支持的图像帧格式 */
rn6752_get_default_format(rn6752, &rn6752->format);
rn6752->frame_size = &rn6752->framesize_cfg[2]; 			/* 设置帧大小 */
rn6752->format.width = rn6752->framesize_cfg[2].width; 		/* 设置宽度 */
rn6752->format.height = rn6752->framesize_cfg[2].height; 	/* 设置高度 */
rn6752->fps = DIV_ROUND_CLOSEST(rn6752->framesize_cfg[2].max_fps.denominator,rn6752->framesize_cfg[2].max_fps.numerator); 			/* 设置最大帧速率 */

注意:

  • 首先将所有支持的帧列表存入了 rn6752->framesize_cfg 中

  • 将支持的列表数量存入 rn6752->cfg_num 中

  • 将默认支持的帧格式和大小存入 rn6752->format 中,这个在用户空间可以查看

  • 将默认支持的帧大小存入 rn6752->frame_size 中

  • 将默认支持的帧率存入 rn6752->fps 中

  • 以上这些默认变量将在后面的函数中经常用到,所以需要特别注意一下,不然很难理解数据从哪里来的

三、Media 设备节点

之前在 Media 子系统中提到过模块之间的关系查看命令media-ctl -p -d /dev/mediaX,通过命令可以得到驱动中的一些信息,如下图所示

  1. Media 帧大小Media 帧大小是在驱动初始化时,通过 rn6752_get_fmt 函数获取的,程序如下

static int rn6752_get_fmt(struct v4l2_subdev *sd,struct v4l2_subdev_pad_config *cfg,struct v4l2_subdev_format *fmt)
{struct i2c_client *client = v4l2_get_subdevdata(sd); /* 获取i2c_client指针 */struct rn6752 *rn6752 = to_rn6752(sd);/* 使用dev_dbg打印日志,显示当前函数进入 */// dev_info(&client->dev, "%s enter\n", __func__);/* 条件成立时,表示要获取正在尝试的格式 */if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_APIstruct v4l2_mbus_framefmt *mf;/* 获取正在尝试的格式 */mf = v4l2_subdev_get_try_format(sd, cfg, 0);mutex_lock(&rn6752->lock);fmt->format = *mf;mutex_unlock(&rn6752->lock);return 0;
#elsereturn -ENOTTY;
#endif}/* 条件不成立时,表示要获取当前的格式 */mutex_lock(&rn6752->lock);fmt->format = rn6752->format;mutex_unlock(&rn6752->lock);/* 使用dev_dbg打印日志,显示当前格式的代码值、宽度和高度 */dev_dbg(&client->dev, "%s: %x %dx%d\n", __func__, rn6752->format.code,rn6752->format.width, rn6752->format.height);return 0;
}

  1. 帧格式判断

Media 设备是通过 rn6752_enum_frame_sizes 和 rn6752_enum_frame_interval 函数枚举了帧大小和帧率,这两个函数主要起到判断的作用,确实当前帧率是否是驱动支持的,程序如下

static int rn6752_enum_frame_sizes(struct v4l2_subdev *sd,struct v4l2_subdev_pad_config *cfg,struct v4l2_subdev_frame_size_enum *fse)
{struct rn6752 *rn6752 = to_rn6752(sd);struct i2c_client *client = v4l2_get_subdevdata(sd);int i = ARRAY_SIZE(rn6752_formats);printk(KERN_INFO"rn6752_enum_frame_sizes................................................\n");dev_dbg(&client->dev, "%s:\n", __func__);if (fse->index >= rn6752->cfg_num)return -EINVAL;while (--i)if (fse->code == rn6752_formats[i].code)break;fse->code = rn6752_formats[i].code;fse->min_width  = rn6752->framesize_cfg[fse->index].width;fse->max_width  = fse->min_width;fse->max_height = rn6752->framesize_cfg[fse->index].height;fse->min_height = fse->max_height;return 0;
}static int rn6752_enum_frame_interval(struct v4l2_subdev *sd,struct v4l2_subdev_pad_config *cfg,struct v4l2_subdev_frame_interval_enum *fie)
{struct rn6752 *rn6752 = to_rn6752(sd);printk(KERN_INFO"rn6752_enum_frame_interval index: %d....................\n", fie->index );/* 检查传入的 fie 结构体中的 index 字段是否超出了 rn6752 所支持的帧间隔配置数量(cfg_num) */if (fie->index >= rn6752->cfg_num)return -EINVAL;/* 检查传入的 fie 结构体中的 code 字段是否与期望的媒体总线格式(MEDIA_BUS_FMT_UYVY8_2X8)匹配 */if (fie->code != MEDIA_BUS_FMT_UYVY8_2X8)return -EINVAL;fie->width = rn6752->framesize_cfg[fie->index].width;           /* 宽 */fie->height = rn6752->framesize_cfg[fie->index].height;         /* 高 */fie->interval = rn6752->framesize_cfg[fie->index].max_fps;      /* 最大帧率 */return 0;
}

  1. 帧大小设置

可以通过 rn6752_set_fmt 函数设置帧的大小,程序如下

tatic int rn6752_set_fmt(struct v4l2_subdev *sd,struct v4l2_subdev_pad_config *cfg,struct v4l2_subdev_format *fmt)
{struct i2c_client *client = v4l2_get_subdevdata(sd);int index = ARRAY_SIZE(rn6752_formats);struct v4l2_mbus_framefmt *mf = &fmt->format;const struct rn6752_framesize *size = NULL;struct rn6752 *rn6752 = to_rn6752(sd);printk(KERN_INFO"rn6752_set_fmt................................................\n");dev_info(&client->dev, "%s enter\n", __func__);/* 根据传入的参数调整帧大小和帧速率,并返回适合的帧大小和帧速率 */__rn6752_try_frame_size_fps(rn6752, mf, &size, rn6752->fps);/* 遍历rn6752_formats数组 */while (--index >= 0)if (rn6752_formats[index].code == mf->code)break;if (index < 0)return -EINVAL;/* 色彩空间为sRGB,场为无 */mf->colorspace = V4L2_COLORSPACE_SRGB;mf->code = rn6752_formats[index].code;mf->field = V4L2_FIELD_NONE;mutex_lock(&rn6752->lock);if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_APImf = v4l2_subdev_get_try_format(sd, cfg,fmt->pad); /* 使用v4l2_subdev_get_try_format函数获取正在尝试的格式 */*mf = fmt->format;
#elsereturn -ENOTTY;
#endif} else {if (rn6752->streaming) {mutex_unlock(&rn6752->lock);return -EBUSY;}/* 分别设置为获取到的帧大小和传入的格式 */rn6752->frame_size = size;rn6752->format = fmt->format;}mutex_unlock(&rn6752->lock);return 0;
}

  1. 帧间隔获取

static int rn6752_g_frame_interval(struct v4l2_subdev *sd,struct v4l2_subdev_frame_interval *fi)
{struct rn6752 *rn6752 = to_rn6752(sd);printk(KERN_INFO"rn6752_g_frame_interval................................................\n");mutex_lock(&rn6752->lock);fi->interval = rn6752->frame_size->max_fps;mutex_unlock(&rn6752->lock);return 0;
}

四、总线编码格式

之前有提到过,RN6752 支持 DVP 和 MIPI 总线格式,所以可以在一个驱动中实现两个功能,这里我就是写了 MIPI 的通信方式,我目前对 DVP 也不了解,以后在补上。

刚好驱动中提供了两个函数可以获取驱动总线的格式,如下所示

  1. 获取当前媒体总线配置的函数

static int rn6752_g_mbus_config(struct v4l2_subdev *sd,struct v4l2_mbus_config *config)
{printk(KERN_INFO"rn6752_g_mbus_config................................................\n");/* 总线类型是CSI-2 */config->type = V4L2_MBUS_CSI2;config->flags = V4L2_MBUS_CSI2_4_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |V4L2_MBUS_CSI2_CHANNEL_1 |V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;return 0;
}

  1. 枚举所有支持的媒体总线编码和格式

static int rn6752_enum_mbus_code(struct v4l2_subdev *sd,struct v4l2_subdev_pad_config *cfg,struct v4l2_subdev_mbus_code_enum *code)
{struct i2c_client *client = v4l2_get_subdevdata(sd);printk(KERN_INFO"rn6752_enum_mbus_code................................................\n");dev_dbg(&client->dev, "%s:\n", __func__);if (code->index >= ARRAY_SIZE(rn6752_formats))return -EINVAL;code->code = rn6752_formats[code->index].code;return 0;
}

五、电源管理

摄像头每次开启和关闭时,都需要通过电源管理函数配置摄像头电源

static int rn6752_power(struct v4l2_subdev *sd, int on)
{struct rn6752 *rn6752 = to_rn6752(sd);struct i2c_client *client = rn6752->client;int ret = 0;/* 使用dev_info打印日志,显示当前函数和行号,并打印on参数的值 */dev_dbg(&client->dev, "%s(%d) on(%d)\n", __func__, __LINE__, on);mutex_lock(&rn6752->lock);if (rn6752->power_on == !! on)goto unlock_and_return;if (on) {ret = pm_runtime_get_sync(&client->dev);if (ret < 0) {pm_runtime_put_noidle(&client->dev);goto unlock_and_return;}rn6752->power_on = true;} else {pm_runtime_put(&client->dev);rn6752->power_on = false;}unlock_and_return:mutex_unlock(&rn6752->lock);return ret;
}

六、摄像头控制

由于这里我没有实现太多的控制功能,所以只实现了必要的两个控制,最主要的是复位时执行的 RKMODULE_SET_QUICK_STREAM 功能

static long rn6752_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{struct rn6752 *rn6752 = to_rn6752(sd);// struct rkmodule_hdr_cfg *hdr;long ret = 0;u32 stream = 0;// dev_dbg(KERN_INFO "rn6752_ioctl  0x%x..........\n", cmd);switch (cmd) {case RKMODULE_GET_MODULE_INFO:rn6752_get_module_info(rn6752, (struct rkmodule_inf *)arg);break;case RKMODULE_SET_QUICK_STREAM:stream = *((u32 *)arg);rn6752_set_streaming(rn6752, !!stream);break;default:ret = -ENOIOCTLCMD;break;}return ret;
}#ifdef CONFIG_COMPAT
static long rn6752_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd,unsigned long arg)
{void __user *up = compat_ptr(arg);struct rkmodule_inf *inf;struct rkmodule_awb_cfg *cfg;long ret;u32 stream = 0;// dev_dbg(KERN_INFO "rn6752_compat_ioctl32..........\n");switch (cmd) {case RKMODULE_GET_MODULE_INFO:inf = kzalloc(sizeof(*inf), GFP_KERNEL);if (!inf) {ret = -ENOMEM;return ret;}ret = rn6752_ioctl(sd, cmd, inf);if (!ret)ret = copy_to_user(up, inf, sizeof(*inf));kfree(inf);break;case RKMODULE_AWB_CFG:cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);if (!cfg) {ret = -ENOMEM;return ret;}ret = copy_from_user(cfg, up, sizeof(*cfg));if (!ret)ret = rn6752_ioctl(sd, cmd, cfg);kfree(cfg);break;case RKMODULE_SET_QUICK_STREAM:ret = copy_from_user(&stream, up, sizeof(u32));if (!ret)ret = rn6752_ioctl(sd, cmd, &stream);break;default:ret = -ENOIOCTLCMD;break;}return 0;
}
#endif

七、数据流控制

整个驱动最重要的便是流控制函数,通过此函数完成了摄像头的启动和停止

static int rn6752_set_streaming(struct rn6752 *rn6752, int on)
{struct i2c_client *client = rn6752->client;int ret = 0;dev_info(&client->dev, "%s: on: %d\n", __func__, on);if (on){ret = rn6752_write(client, 0x80, 0x31);usleep_range(200, 500);ret |= rn6752_write(client, 0x80, 0x30);if (ret){dev_err(&client->dev, "rn6752 soft reset failed\n");return ret;}ret = rn6752_write_array(client, rn6752->frame_size->regs);if (ret)dev_err(&client->dev, "rn6752 start initialization failed\n");}else{ret = rn6752_write(client, 0x80, 0x00);if (ret)dev_err(&client->dev, "rn6752 soft standby failed\n");}return ret;
}static int rn6752_s_stream(struct v4l2_subdev *sd, int on)
{struct i2c_client *client = v4l2_get_subdevdata(sd);struct rn6752 *rn6752 = to_rn6752(sd);int ret = 0;unsigned int fps;/* 计算帧率和延迟时间 */fps = DIV_ROUND_CLOSEST(rn6752->frame_size->max_fps.denominator,rn6752->frame_size->max_fps.numerator);dev_info(&client->dev, "%s: on: %d, %dx%d@%d\n", __func__, on,rn6752->frame_size->width, rn6752->frame_size->height,DIV_ROUND_CLOSEST(rn6752->frame_size->max_fps.denominator,rn6752->frame_size->max_fps.numerator));mutex_lock(&rn6752->lock);on = !!on;if (rn6752->streaming == on)goto unlock;if (on) {ret = pm_runtime_get_sync(&client->dev);if (ret < 0){pm_runtime_put_noidle(&client->dev);goto unlock;}}rn6752->streaming = on;ret = rn6752_set_streaming(rn6752, on);if (ret)rn6752->streaming = !on;pm_runtime_put(&client->dev);unlock:mutex_unlock(&rn6752->lock);return ret;
}

注意: 摄像头驱动中并没有图像接收之类的关系,而数据流操作函数主要的作用是对芯片进行初始化,使摄像头进入工作模式。从上面的驱动程序可以看出,整个驱动并没有其他特别的功能,就是一个 I2C 控制功能,所以摄像头的驱动其实就是一个 I2C 驱动程序。

由于笔记内容有点多,这里我就不附上完成的驱动程序了,其次是驱动程序也比较简单,看完的小伙伴应该都能明白。主要的难度都在调试摄像头驱动上面,我也折腾了很久,有需要的小伙变可以看我后面的笔记

参考资料

gc2145.c 和 imx335.c 驱动程序

文章转载自:浇筑菜鸟

原文链接:https://www.cnblogs.com/jzcn/p/17825502.html

http://www.zhongyajixie.com/news/29144.html

相关文章:

  • 响应式布局网站模板seo网站优化知识
  • 提供小企业网站建设seo优化师就业前景
  • 请人做外贸网站应注意什么问题潮州网站建设
  • 做网站被骗属于诈骗吗跨境网站建站
  • 从网站优化之角度出发做网站策划百度资源共享链接分享组
  • 建设通网站怎么投诉宁波seo
  • 外贸网站优化公司北京seo运营
  • 沈阳建站模板系统包括网络推广收费价目表
  • 手机商城网站制作百度指数的搜索指数代表什么
  • 全套免费代码大全陕西新站seo
  • 内蒙古电子商务网站优化方案官方网站
  • 有什么网站可以做中间人的网上教育培训机构排名
  • mvc5 网站开发之学 pdf石家庄seo培训
  • 北京大学廉政建设研究中心网站男生短期培训就业
  • 17一起广州做网站seo关键词推广多少钱
  • 两学一做测试网站seo联盟
  • 定制建站网站简单的网页设计作品
  • 华大 建设网站seo在线工具
  • 做公司网站每年多少钱怎样在网上推广
  • 苏州塔维斯网站建设宁波网站建设推广平台
  • 电子商务网站功能设计与分析岳阳seo公司
  • 优质高职院校建设网站全国疫情最新报告
  • 检察网站建设温州seo团队
  • 连云港网站建设wang怎样在百度上发布广告
  • 成都城乡建设局官方网站如何让百度搜索排名靠前
  • 江苏建设厅官方网站百度站长工具平台
  • 淘宝客怎么做的网站推广潍坊做网站哪家好
  • 全面了解网站开发1688的网站特色
  • 做婚恋网站代理商挣钱吗全网seo
  • 商务网站建设体会市场推广计划方案