概要

基于thttpd对接录风者app基础指令。
实现app预览实时画面的基础功能。
为实现这一目标我们要实现如下三条HTTP请求

  • 获取产品信息
http://192.168.169.1/app/getproductinfo
返回参数示例
{
	"result": 0,
	"info": {
		"model": "x1",
		"company": "alibaba",
		"soc": " eeasytech ",
		"sp": "FH"
	}
}
参数名类型描述
modelstring该产品的型号,比如”iphone 11 pro“;
companystring该产品对应的生产商,比如”Apple“;如果是方案商的公版,就写和下面的sp 一样;
socstring对应的芯片平台,比如: “eeasy”、“sigmstar”等
spstring对应方案商的名称或代号,比如:烽航“FH”
  • 获取设备信息
http://192.168.169.1/app/getdeviceattr
返回参数示例
{
	"result": 0,
		"info": {
			"uuid": "12ad3f5b8c9d",
			"softver": "v1.2.3",
			"otaver": "v1.20230312.1",
			"hwver": "v1.2",
			"ssid": "cardv-12ad4f",
			"bssid": "12ad3f5b8c9d",
			"camnum":2,
			"curcamid":0,
			"wifireboot":0
		}
}
参数名类型描述
uuidstring设备的唯一标志,设备端可以用mac 地址或是sn
softverstring当前固件的版本号
otaverstring用来专门升级用的ota 版本号,需要满足版本号的定义规范,如果softver 满足ota 版本号规范,可以不用此字段,具体规范参考第7 章OTA;
hwverstring当前设备的硬件版本
ssidstringWiFi 的ssid
bssidstringWiFi 的mac 地址
camnumint摄像头的个数
curcamidint当前摄像头的id,front:0,rear:1,如果只有一个摄像头,则为0
wifirebootint更改WiFi 名、密码、恢复出厂设置后是否需要App下发重启WiFi:0-不需要,1-需要
  • 获取媒体信息
http://192.168.169.1/app/getmediainfo
返回参数示例
{
	"result": 0,
	"info": {
		"rtsp": "rtsp://192.168.169.1/stream.mp4",
		"transport":"tcp"
		"port": 6035
		"rtsps": ["rtsp://192.168.169.1/stream.mp4",
		"rtsp://192.168.169.1/stream1.mp4"]
		"page": 1"rectime": 1
	}
}
参数名类型描述
rtspstring用来播放RTSP 的地址
transportstringRTSP 的传输协议,“tcp” 、“udp”
portint推送消息设备端的tcp socket server 的监听端口
rtspsarray非必选;多路设备,当各路播流地址不同时,通过此字段返回每一路的播流地址
pageint非必选;App 默认一次性查询所有文件,如果设备支持分页查询,此字段返回1
rectimeint非必选;支持通过getrecduration 接口查询当前录像时间

技术细节

  • HTTP请求流程

在这里插入图片描述

  1. 录风者app应注意V821wifi配成AP模式且IP要固定为:192.168.169.1
    因为app那边的http请求的IP都是192.168.169.1
修改固定IP
源文件路径:
tina-v821-release\platform\allwinner\wireless\wifimanager\demo\wifi_test_tool\wifi_daemon.c
static wmg_status_t open_ap_mode(char *p)
  1. 以ap模式开启WiFi(V821 SDK默认是以station模式开启的WiFi)
wifi -o ap v821 12345678
  1. 基于thttpd实现设备端的HTTP server
    关于在全志V821上如何安装thttpd前文《全志V821对接录风者app》中已经有详细描述,这边不再赘述,这边只阐述基于thttpd实现目标功能。
    下面以伪代码形式描述基本流程
//注册用户操作回调函数
app_ezCam_http_property_json_info_reg(app_ezCam_http_get_property, app_ezCam_http_set_property);

//thttpd_start_main 和 app_viidure_service_reg_distriblink需要自己在thttpd的源码中改造
//(附件资源包中已经有改造好的源码欢迎大家下载使用)。
//注册http请求调度器
app_viidure_service_reg_distriblink(app_viidure_msg_dispatcher);
//启动thttpd服务
pthread_create(&g_webserver_pid, NULL, thttpd_start_main, args);

  1. http://192.168.169.1/app/getproductinfo请求为例,主要实现函数如下
void app_ezCam_http_get_property(char *devPropCode, void *data)
{
	EZ_U32 i,ret;

	if(strcmp(devPropCode, EZCAM_CGI_GET_DEVICE_ATTR) == 0) {

		EZ_U32 *dat = (EZ_U32 *)data;
		
		EZCAM_HTTP_DBG("data[0]: %d\n",dat[0]);

		if(dat[0] == DEV_GET_UUID) {
			memcpy(dat,WIFI_DEV_UUID,strlen(WIFI_DEV_UUID));
			dat[strlen(WIFI_DEV_UUID)] = '\0';
			EZCAM_HTTP_DBG("data => %s/%d\n",dat,strlen(WIFI_DEV_UUID));
		}
		
		else if(dat[0] == DEV_GET_SOFT_VER) {
			memcpy(dat,WIFI_DEV_SOFT_VER,strlen(WIFI_DEV_SOFT_VER));
			dat[strlen(WIFI_DEV_SOFT_VER)] = '\0';
			EZCAM_HTTP_DBG("data => %s/%d\n",dat,strlen(WIFI_DEV_SOFT_VER));
		}
		else if(dat[0] == DEV_GET_OTA_VER) {
			memcpy(dat,WIFI_DEV_OTA_VER,strlen(WIFI_DEV_OTA_VER));
			dat[strlen(WIFI_DEV_OTA_VER)] = '\0';
			EZCAM_HTTP_DBG("data => %s/%d\n",dat,strlen(WIFI_DEV_OTA_VER));
		}
		else if(dat[0] == DEV_GET_HW_VER) {
			memcpy(dat,WIFI_DEV_HW_VER,strlen(WIFI_DEV_HW_VER));
			dat[strlen(WIFI_DEV_HW_VER)] = '\0';
			EZCAM_HTTP_DBG("data => %s/%d\n",dat,strlen(WIFI_DEV_HW_VER));
		}
		else if(dat[0] == DEV_GET_SSID) {
			memcpy(dat,WIFI_DEV_SSID,strlen(WIFI_DEV_SSID));
			dat[strlen(WIFI_DEV_SSID)] = '\0';
			EZCAM_HTTP_DBG("data => %s/%d\n",dat,strlen(WIFI_DEV_SSID));
		}
		else if(dat[0] == DEV_GET_BSSID) {
			memcpy(dat,WIFI_DEV_BSSID,strlen(WIFI_DEV_BSSID));
			dat[strlen(WIFI_DEV_BSSID)] = '\0';
			EZCAM_HTTP_DBG("data => %s/%d\n",dat,strlen(WIFI_DEV_BSSID));
		}
		else if(dat[0] == DEV_GET_CAM_NUM) {
			*dat = WIFI_DEV_CAM_NUM;
		}
		else if(dat[0] == DEV_GET_CUR_CAM_ID) {
			*dat = WIFI_DEV_CUR_CAM_ID;
		}
		else if(dat[0] == DEV_GET_WIFI_REBOOT) {
			*dat = WIFI_DEV_WIFI_REBOOT;
		}
		
	}
	else if(strcmp(devPropCode, EZCAM_CGI_CAPABILITY) == 0) {
		EZ_U32 *dat = (EZ_U32 *)data;
		EZCAM_HTTP_DBG("data[0]: %d\n",dat[0]);

		/* capability_t. */
		if(dat[0] == CAPABILITY_OPTION_GPS) {
			*dat = 0;
		}
		else if(dat[0] == CAPABILITY_OPTION_CAMERA_TYPE) {
			*dat = 1;
		}
		else if(dat[0] == CAPABILITY_OPTION_PARK_MONITOR) {
			*dat = 0;
		}
		else if(dat[0] == CAPABILITY_OPTION_FILE_LOCK) {
			*dat = 1;
		}
		else if(dat[0] == CAPABILITY_OPTION_DEL_LOCK_FILE) {
			*dat = 0;
		}
		else if(dat[0] == CAPABILITY_OPTION_SUPPORT_CAP_MODE) {
			*dat = 0;
		}
		else if(dat[0] == CAPABILITY_OPTION_PB_USE_RTSP) {
			*dat = 0;
		}
		else if(dat[0] == CAPABILITY_OPTION_SUPPORT_CAP_FUNCTION) {
			*dat = 0;
		}
		else if(dat[0] == CAPABILITY_OPTION_SUPPORT_CHANGE_WIFI_NAME_PWD) {
			*dat = 0;
		}
		else if(dat[0] == CAPABILITY_OPTION_SUPPORT_FILE_COPY) {
			*dat = 0;
		}
	}
	else if(strcmp(devPropCode, EZCAM_CGI_GET_PRODUCT_INFO) == 0) {

		EZ_U32 *dat = (EZ_U32 *)data;
		
		EZCAM_HTTP_DBG("data[0]: %d\n",dat[0]);

		/* PRODUCT_MODEL */
		if(dat[0] == PRODUCT_MODEL) {
			memcpy(dat,WIFI_DEV_PRODUCT_MODEL,strlen(WIFI_DEV_PRODUCT_MODEL));
			dat[strlen(WIFI_DEV_PRODUCT_MODEL)] = '\0';
			EZCAM_HTTP_DBG("data => %s/%d\n",dat,strlen(WIFI_DEV_PRODUCT_MODEL));
		}
		/* PRODUCT_COMPANY */
		else if(dat[0] == PRODUCT_COMPANY) {
			memcpy(dat,WIFI_DEV_PRODUCT_COMPANY,strlen(WIFI_DEV_PRODUCT_COMPANY));
			dat[strlen(WIFI_DEV_PRODUCT_COMPANY)] = '\0';
			EZCAM_HTTP_DBG("data => %s/%d\n",dat,strlen(WIFI_DEV_PRODUCT_COMPANY));
		}
		/* PRODUCT_SOC */
		else if(dat[0] == PRODUCT_SOC) {
			
			memcpy(dat,WIFI_DEV_PRODUCT_SOC,strlen(WIFI_DEV_PRODUCT_SOC));
			dat[strlen(WIFI_DEV_PRODUCT_SOC)] = '\0';
			EZCAM_HTTP_DBG("data => %s/%d\n",dat,strlen(WIFI_DEV_PRODUCT_SOC));
		}
		/* PRODUCT_SP */
		else if(dat[0] == PRODUCT_SP) {
			memcpy(dat,WIFI_DEV_PRODUCT_SP,strlen(WIFI_DEV_PRODUCT_SP));
			dat[strlen(WIFI_DEV_PRODUCT_SP)] = '\0';
			EZCAM_HTTP_DBG("data => %s/%d\n",dat,strlen(WIFI_DEV_PRODUCT_SP));
		}
	}
	else if(strcmp(devPropCode, EZCAM_CGI_GET_MEDIA_INFO) == 0) {

		EZ_U32 *dat = (EZ_U32 *)data;
		
		EZCAM_HTTP_DBG("data[0]: %d\n",dat[0]);

		/* RTSP_URL */
		if(dat[0] == MEDIA_INFO_RTSP_URL) {

			memcpy(dat,WIFI_DEV_MEDIA_INFO_RTSP_URL,strlen(WIFI_DEV_MEDIA_INFO_RTSP_URL));
		}
		/* TRANSPORT */
		else if(dat[0] == MEDIA_INFO_TRANSPORT) {
			
			memcpy(dat,WIFI_DEV_MEDIA_INFO_TRANSPORT,strlen(WIFI_DEV_MEDIA_INFO_TRANSPORT));
		}
		/* PORT */
		else if(dat[0] == MEDIA_INFO_PORT) {
			
			memcpy(dat,WIFI_DEV_MEDIA_INFO_PORT,strlen(WIFI_DEV_MEDIA_INFO_PORT));
		}
	}

}

static void ezCam_http_json_get_productInfo(char *jsonStr)
{ 
	int dev_product_info[32];

	cJSON *cgiItem = cJSON_CreateObject();
	cJSON *cgiAddItem	= cJSON_CreateObject();

	cJSON_AddNumberToObject(cgiItem,"result",0);

	/* model */
	memset(dev_product_info,0x0,sizeof(dev_product_info));
	dev_product_info[0] = PRODUCT_MODEL;
	fp_json_httpdGetCamProperty((char *)EZCAM_CGI_GET_PRODUCT_INFO,(int *)dev_product_info);
	cJSON_AddStringToObject(cgiAddItem,"model",(char *)dev_product_info);

	/* company */
	memset(dev_product_info,0x0,sizeof(dev_product_info));
	dev_product_info[0] = PRODUCT_COMPANY;
	fp_json_httpdGetCamProperty((char *)EZCAM_CGI_GET_PRODUCT_INFO,(int *)dev_product_info);
	cJSON_AddStringToObject(cgiAddItem,"company",(char *)dev_product_info);

	/* soc */
	memset(dev_product_info,0x0,sizeof(dev_product_info));
	dev_product_info[0] = PRODUCT_SOC;
	fp_json_httpdGetCamProperty((char *)EZCAM_CGI_GET_PRODUCT_INFO,(int *)dev_product_info);
	cJSON_AddStringToObject(cgiAddItem,"soc",(char *)dev_product_info);

	/* sp */
	memset(dev_product_info,0x0,sizeof(dev_product_info));
	dev_product_info[0] = PRODUCT_SP;
	fp_json_httpdGetCamProperty((char *)EZCAM_CGI_GET_PRODUCT_INFO,(int *)dev_product_info);
	cJSON_AddStringToObject(cgiAddItem,"sp",(char *)dev_product_info);

	cJSON_AddItemToObject(cgiItem,"info",cgiAddItem);

	char *json_data = cJSON_Print(cgiItem);
	if(json_data == NULL){
		EZCAM_HTTP_DBG("json print malloc error");
	}
	memcpy(jsonStr,json_data,strlen(json_data));
	jsonStr[strlen(json_data)] = '\0';

	cJSON_Delete(cgiItem);
	free(json_data);
}

EZ_S32 app_ezCam_http_get_productInfo(EZ_S32 socket, EZ_CHAR *request, EZ_U32 req_len)
{
    int ret = EZ_SUCCESS;
	
	EZ_S32 body_len = 0, head_len = 0;
	
	char *json_data;
	EZ_CHAR *buf;

	EZCAM_HTTP_DBG("%s %d S\n",__FUNCTION__,__LINE__);
	
	json_data = malloc(JSON_DATA_BUFFER);
	if(json_data == NULL){
		EZCAM_HTTP_DBG("json_data malloc error");
	}

	
	buf = malloc(HTTP_RESPONSE_BUF);
	if(buf == NULL){
		EZCAM_HTTP_DBG("buf malloc error");
	}
	
	ezCam_http_json_get_productInfo(json_data);

	if(strlen(json_data) >= JSON_DATA_BUFFER - 1){
		EZCAM_HTTP_DBG("Array out of bounds, please increase the size of JSON_DATA_BUFFER \n");

	}

	body_len = strlen(json_data);

	head_len = app_ezCam_package_http_header(buf, body_len, 200, TRUE);
	
	if (body_len > 0)
		memcpy(buf + head_len, json_data, body_len);

	EZCAM_HTTP_DBG("http response: \n %s \n", buf);

	if (app_ezCam_send_data(socket, buf, strlen(buf)) != strlen(buf)) {
		EZCAM_HTTP_DBG("xcam_send_data() failed\n");
		return EZ_FAILURE;
	}

	if(json_data != NULL){
		free(json_data);
		json_data = NULL;
	}

	
	if(buf != NULL){
		free(buf);
		buf = NULL;
	}
	
	EZCAM_HTTP_DBG("%s %d E\n",__FUNCTION__,__LINE__);
	
	return ret;
}

HTTP请求测试方法:手机/电脑连接v821wifi打开网页输入请求指令
http://192.168.169.1/app/getproductinfo
得到如下反馈,代表基于thttpd的HTTP Server实现正常
在这里插入图片描述
其它两条请求类似添加,添加成功后手机端安装《录风者》APP。连接设备WiFi,打开APP应能正常出图,至此我们就成功实现了关键指令的对接。
在这里插入图片描述

其它诸如设置项管理,文件管理(在线回放/下载设备端视频)的功能大家有兴趣可以自己完善。
后续我也会慢慢完善到我们的ezCam上

小结

1.录风者APP是公版免费的且兼容多平台,可以助力我们快速完成自己的项目。
2.请期待下期,接入大模型

Logo

欢迎加入西安开发者社区!我们致力于为西安地区的开发者提供学习、合作和成长的机会。参与我们的活动,与专家分享最新技术趋势,解决挑战,探索创新。加入我们,共同打造技术社区!

更多推荐