方法有几种
1 rtsp 获取后转发到外网
2 直接配置大华摄像头发送到外网
第一种方法有缺陷,不直接,需要转发服务,但是一种比较可靠的方法,如果网络中不能直接发出去,只能通过转发服务,那可以使用最为通用的方案,就是rtsp拉取后直接转发送到外网。
第二种方法使用要必须内网直接访问到外网,也就是摄像头可以直接连接到外网。
我们使用第二种方法,大华里面有一个配置是可以直接配置一个IP地址和端口,使用tcp方式直接推到外网的,不过,缺点就是,你得使用大华的sdk去接收,这样工作量少。
程序下载在此
#pragma once
#include
#include
#include
#include
#include
#include "websocketpp_server.h"
#include "dhnetsdk.h"
#include "dhplay.h"
#include "../RTMPPusher/H264AACRtmp.h"
#include "../RTMPPusher/TPacket.h"
#include "..\RecordAudio\audioRecord.h"
#include "web_send.h"
#pragma comment( lib, "dhnetsdk.lib")
#pragma comment( lib, "dhplay.lib")
using namespace std;
typedef struct tagDH_DEVICE_INFO
{
string szDevSerial;
string szDevName;
string videofile_name;
string szIP;
int nPort;
string szUseName;
string szPassWord;
int nLoginType; // 0:IP登录1:主动注册登录
int nLoginStatus; // 设备状态,0:离线 1:排队登录 2:在线 3:停止预览 4 :当前设备正在播放中 5:注册失败 等待下次注册
int nLoginTimes; // 尝试登录次数
long long lLoginID; // 登录句柄
long long lRealHandle; //播放句柄
baseinfo * baseserver = NULL;
con_list connections; //摄像头连接链表
uint32_t frist_timestamp=0;
uint32_t current_timestamp=0;
LONG lRealPort ; //设备的播放库port号 一个设备一个 不能重复
//H264AACRtmp hr; //推送给RTMP的连接对象
TQPacket *packet=NULL;
telemetry_client web_client;//视频发送通道
string audio_url="";
string video_url = "";
telemetry_client send_aac;//发送音频通道
audioRecord gater_aac;//录音对象
}DH_DEVICE_INFO;
typedef struct tagNODE_SESSION
{
baseinfo * baseserver = NULL;
con_list connections;
long long heartTime = 0;
}NODE_SESSION;
class devClass
{
private:
devClass();
//node_list m_node_list;
public:
//set m_node_connect;
baseinfo * pWServer = NULL;
~devClass();
static devClass* GetInstance();
mutex mut;
map<string, DH_DEVICE_INFO *> mymap;
//map _node_map;
list<NODE_SESSION *> node_list;
map<string, NODE_SESSION *> node_map;
//map clientHdl_map;
void setBaseServer(baseinfo * info);
baseinfo * getBaseServer();
void addDevSession(string dev_serial, string username, string pass)
{
std::lock_guard<std::mutex> guard(mut);
DH_DEVICE_INFO * pinfo = NULL;
auto map = mymap.find(dev_serial); //通过key确认设备是否注册
if (map != mymap.end()) {//不等于end说明设备已经注册
pinfo = map->second;//将设备信息给pinfo
}
if (pinfo != NULL) {//更新mymap中key对应的设备信息
pinfo->baseserver = pWServer;//
pinfo->szDevSerial = dev_serial;
pinfo->szUseName = username;
pinfo->szPassWord = pass;
OUTINFO_3_PARAM("set info repate success id = %s , username = %s ,pwd = %s \n", dev_serial.c_str(),username.c_str(),pass.c_str());
}
else {
DH_DEVICE_INFO * pinfo = new DH_DEVICE_INFO();
pinfo->baseserver = pWServer;
pinfo->nLoginStatus = 0;
pinfo->szDevSerial = dev_serial;
pinfo->szUseName = username;
pinfo->szPassWord = pass;
mymap[dev_serial] = pinfo;
OUTINFO_3_PARAM("set info scuuess id = %s , username = %s ,pwd = %s \n", dev_serial.c_str(), username.c_str(), pass.c_str());
}
}
int addDevSession(string dev_serial, connection_hdl hd) {
std::lock_guard<std::mutex> guard(mut);
//char * p = (char*)&hd;
auto iter = mymap.find(dev_serial);
if (iter != mymap.end()) {
DH_DEVICE_INFO * pinfo = iter->second;
pinfo->connections.insert(hd);
int size = pinfo->connections.size();
OUTINFO_1_PARAM("set connections scuuess size = %d \n", size);
return 0;
}
OUTINFO_0_PARAM("set connections error = no this dev \n");
return -1;
}
void addNodeSession(string key, connection_hdl hd) {
OUTINFO_0_PARAM("BEGIN addNodeSession\n");
std::lock_guard<std::mutex> guard(mut);
NODE_SESSION * pnode = new NODE_SESSION();
pnode->connections.clear();
pnode->connections.insert(hd);
pnode->baseserver = pWServer;
//pnode->connections.clear();
node_map[key] = pnode;
int size = pnode->connections.size();
OUTINFO_1_PARAM("set node_hdl=%s scuuess\n", key.c_str());
OUTINFO_1_PARAM("this nodeconnect size = %d \n" , size );
OUTINFO_0_PARAM("END addNodeSession\n");
}
void addNodeSessionHeartTIme(string key, connection_hdl hd, long long heartTime) {
OUTINFO_0_PARAM("BEGIN addNodeSession\n");
std::lock_guard<std::mutex> guard(mut);
auto iter = node_list.begin();
int size;
while (iter != node_list.end())
{
NODE_SESSION * pnode = *iter;
con_list &set = pnode->connections;
if (set.find(hd) != set.end()) {//找到当前句柄
size = node_list.size();
OUTINFO_0_PARAM("have been addNodeSession\n");
OUTINFO_1_PARAM("this nodeconnect size = %d \n", size);
OUTINFO_0_PARAM("END addNodeSession\n");
return;
}
iter++;
}
NODE_SESSION * pnode = new NODE_SESSION();
pnode->connections.insert(hd);
pnode->baseserver = pWServer;
pnode->heartTime = heartTime;
node_list.push_back(pnode);
size = node_list.size();
OUTINFO_1_PARAM("set node_hdl=%s scuuess\n", key.c_str());
OUTINFO_1_PARAM("this nodeconnect size = %d \n", size);
OUTINFO_0_PARAM("END addNodeSession\n");
}
int removehd(string key, connection_hdl hd) {
std::lock_guard<std::mutex> guard(mut);
auto map = mymap.find(key);
DH_DEVICE_INFO * pinfo = NULL;
if (map != mymap.end())
{
pinfo = map->second;
pinfo->connections.erase(hd);
int size = pinfo->connections.size();
OUTINFO_1_PARAM(" connect size = %d \n", size);
}
if (pinfo != NULL && pinfo->nLoginStatus ==4 && pinfo->connections.size() == 0) {
OUTINFO_0_PARAM(" stop playing \n");
//当前没有浏览器请求流
devClass * pdevClass = devClass::GetInstance();
// 根据当前播放的 句柄断开连接
//关闭预览
//关闭预览
//启动一个线程关闭播放 不影响webscoket 通信
stopPlay(pinfo);
//注销用户
//CLIENT_Logout(pinfo->lLoginID);
}
return 0;
}
void stopPlay(DH_DEVICE_INFO * pinfo);
int set(string key, const char *pIp, WORD wPort, int status,LONG lRealPort);
void setheartTime(connection_hdl hdl,long long heartTime) {
auto iter = node_list.begin();
while (iter != node_list.end())
{
NODE_SESSION * pnode = *iter;
con_list &set = pnode->connections;
if (set.find(hdl) != set.end()) {//找到当前句柄
pnode->heartTime = heartTime;
OUTINFO_1_PARAM("set heart time = %lld \n", heartTime);
break;
}
iter++;
}
}
int setlLoginID(string key, long long lLoginID)
{
std::lock_guard<std::mutex> guard(mut);
DH_DEVICE_INFO * pinfo = NULL;
auto map = mymap.find(key);
if (map != mymap.end() ) {
pinfo = map->second;
}
if (pinfo != NULL)
{
pinfo->lLoginID = lLoginID;
}
else {
return -1;
}
return 0;
};
int setlRealHandle(string key, long long lRealHandle)
{
OUTINFO_0_PARAM(" BEGIN setlRealHandle \n");
std::lock_guard<std::mutex> guard(mut);
auto map = mymap.find(key);
DH_DEVICE_INFO * pinfo = NULL;
if (map != mymap.end()) {
pinfo = map->second;
}
if (pinfo != NULL)
{
pinfo->lRealHandle = lRealHandle;
OUTINFO_1_PARAM(" END setlRealHandle handeleid = %lld \n" , lRealHandle);
return 0;
}
else {
OUTINFO_0_PARAM(" END setlRealHandle error = -1 \n");
return -1;
}
}
int setLoginStatus(string key, int status);
int getLoginStatus(string key);
int getDevSession(string key, DH_DEVICE_INFO * dhInfo);
void delDevSession(string key);
void Send(char * p, int len, string key) {
std::lock_guard<std::mutex> guard(mut);
try {
DH_DEVICE_INFO * pinfo = NULL;
auto map = mymap.find(key);
if (map != mymap.end())
{
pinfo = map->second;
con_list &set = pinfo->connections;
con_list::iterator it;
for (it = set.begin(); it != set.end(); ++it) {
pinfo->baseserver->SendFrame(*it, p, len);
}
}
}
catch (string const & e) {
OUTINFO_1_PARAM("Send error = %s \n", e.c_str());
}
}
void Send(void * devSerial, int status) {
OUTINFO_0_PARAM("BEGIN SEND_DEV_STA\n");
std::lock_guard<std::mutex> guard(mut);
try {
auto iter = node_list.begin();
while (iter != node_list.end())
{
NODE_SESSION * pnode = *iter;
if (pnode != NULL) {
con_list &set = pnode->connections;
con_list::iterator it;
for (it = set.begin(); it != set.end(); ++it) {
pnode->baseserver->SendFrame(*it, devSerial, status);
}
}
iter++;
}
}
catch (string const & e) {
//std::cout << e.c_str() << std::endl;
OUTINFO_1_PARAM("SEND_DEV_STA error = %s \n", e.c_str());
}
OUTINFO_0_PARAM("END SEND_DEV_STA\n");
}
void Send(string devSerial,string pic_name) {
std::lock_guard<std::mutex> guard(mut);
try {
auto iter = node_list.begin();
while (iter != node_list.end())
{
NODE_SESSION * pnode = *iter;
if (pnode != NULL) {
con_list &set = pnode->connections;
con_list::iterator it;
for (it = set.begin(); it != set.end(); ++it) {
pnode->baseserver->SendFrame(*it, devSerial, pic_name);
}
}
iter++;
}
}
catch (string const & e) {
OUTINFO_1_PARAM("SEND_DEV_STA error = %s \n", e.c_str());
}
}
void delete_mem()
{
//lock
//map mymap;
//map _node_map;
//list node_map;
{
auto iter = mymap.begin();
while (iter != mymap.end())
{
DH_DEVICE_INFO *item = iter->second;
delete item;
iter++;
}
}
{
auto iter1 = node_list.begin();
while (iter1 != node_list.end())
{
NODE_SESSION * s = *iter1;
delete s;
iter1++;
}
}
}
};
为了使得数据能够被浏览器访问,建立一个websocket服务,直接转发h264,也可以转发到rtmp server,两种方式都可以,程序里面有。主要程序如下所示
#define _CRT_SECURE_NO_WARNINGS
#include "websocketpp_server.h"
#include "devClass.h"
#include "dhServer.h"
broadcast_server::broadcast_server() {
m_server.init_asio();
m_server.set_open_handler(bind(&broadcast_server::on_open, this, std::placeholders::_1));
m_server.set_close_handler(bind(&broadcast_server::on_close, this, std::placeholders::_1));
m_server.set_message_handler(bind(&broadcast_server::on_message, this, std::placeholders::_1, std::placeholders::_2));
}
void broadcast_server::run(uint16_t port) {
m_server.listen(port);
m_server.start_accept();
try {
OUTINFO_1_PARAM("***WS server Listen Success! port:%d ***\n", port);
m_server.run();
}
catch (const std::exception & e) {
OUTINFO_1_PARAM(" WS server Listen fail ! error:%s\n", e.what());
}
}
void broadcast_server::on_open(connection_hdl hdl) {
//lock_guard guard(m_action_lock);
OUTINFO_0_PARAM(" WS server on_open \n" );
//m_actions.push(action(SUBSCRIBE, hdl));
//m_action_cond.notify_one();
}
void broadcast_server::on_close(connection_hdl hdl) {
//lock_guard guard(m_action_lock);
OUTINFO_0_PARAM(" WS server on_close \n");
devClass * pdevclass = devClass::GetInstance();
/*map clientHdl_map = pdevclass->clientHdl_map;
string id = clientHdl_map[(char*)&hdl] ;*/
//string id = pdevclass->clientHdl_map[hdl] ;
map<string, DH_DEVICE_INFO *>::iterator iter;
iter = pdevclass->mymap.begin();
for (; iter != pdevclass->mymap.end(); iter++) {
DH_DEVICE_INFO * pinfo = iter->second;
string id = iter->first;
if (pinfo !=NULL)
{
con_list &set = pinfo->connections;
if (set.find(hdl) != set.end()) {
OUTINFO_1_PARAM("this disconnect id = %s \n",id.c_str());
pdevclass->removehd(id, hdl);
}
}
}
//m_actions.push(action(UNSUBSCRIBE, hdl));
//m_action_cond.notify_one();
}
//通过该方法从web端获得摄像头的配置信息(链接句柄,配置信息)
void broadcast_server::on_message(connection_hdl hdl, server::message_ptr msg) {
devClass * pdevclass = devClass::GetInstance();
OUTINFO_0_PARAM("BEGIN WS server on_message resove \n");
string tempstring = msg->get_payload();
//安全判断
if (tempstring == "undifined" || tempstring == "null" || tempstring == "[object Object]") {
OUTINFO_0_PARAM("WS server recieve error = undifined OR null \n");
std::string msg_str = "{\"type\":\"999\",\"info\":\"Bad Request,parameter error;\",\"code\":\"0\"}";
sendText(hdl, msg_str);
return;
}
string type = m_type_number(tempstring);
if (type == "0") {
OUTINFO_1_PARAM("recieve node msg : %s \n", tempstring.c_str());
pdevclass->addNodeSessionHeartTIme("node", hdl, getMilliTime());
//给当前变量全局 ms 数进行赋值
std::string msg_str = "{\"type\":\"0\",\"info\":\"u are node_client\"}";
sendText(hdl, msg_str);
}
else if (type == "1" || type == "2") //添加设备信息
{
device one_device = m_init_device_list(tempstring);
list<device_init_add>::iterator it;
list<device_init_add> list = one_device.dev_list;
it = list.begin();
while (it != list.end())
{
pdevclass->addDevSession(it->dev_serial, it->user_name, it->passwd);
it++;
}
}
//++++++++++++++++++++直播代码段++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
else if(type == "4")
{
OUTINFO_1_PARAM("recieve node msg : %s \n", tempstring.c_str());
//printf("recieve node msg : %s \n", tempstring.c_str());
string dev_serial = m_live_broadcast(tempstring);//浏览器将想要获得的摄像头的唯一序列号通过websocketpp(js_sion)传给服务器
//类似于申请获取那个摄像头的流
string type = m_video_type(tempstring);//要获取的视频流类型
if (dev_serial.empty())//没有连接到摄像头
{
OUTINFO_0_PARAM(" dev_serial = nullstr \n");
printf("dev_serial=nullstr");
std::string msg_str = "{\"type\":\"4\",\"info\":\"Bad Request,parameter error; \",\"code\":\"0\"}";
sendText(hdl, msg_str);
return;
}
//将当前请求直播的 hd ———— id 存入到map 中
//将当前请求直播的连接保存到connections属性中
int ret = pdevclass->addDevSession(dev_serial,hdl);
if (ret == -1) {//返回-1说明连接没有成功,没有找到设备
std::string msg_str = "{\"type\":\"4\",\"info\":\"Not Found This Dev;\",\"code\":\"1\"}";
sendText(hdl, msg_str);
}
else
{
//获得摄像头的状态
// 设备状态,0:离线 1:排队登录 2:在线 3:停止预览 4 :当前设备正在播放中 5:注册失败 等待下次注册
int loginStatus = pdevclass->getLoginStatus(dev_serial);
if(loginStatus == -1){
std::string msg_str = "{\"type\":\"4\",\"info\":\"This Dev Offline\",\"code\":\"2\"}";
sendText(hdl,msg_str);
}
else
{
//开启获取设备的线程
std::string msg_str = "{\"type\":\"4\",\"info\":\"Play It Right Now\",\"code\":\"3\"}";
sendText(hdl, msg_str);
dhServer dhserver;
dhserver.thread_getH264ById(dev_serial,type);
}
}
}
else if (type == "8") //截图
{
OUTINFO_1_PARAM("recieve node msg : %s \n", tempstring.c_str());
device_take_pic pics = m_device_take_pic(tempstring);
string dev_serial = pics.dev_serial;
string pic_name = pics.pic_name;
dhServer dhserver;
dhserver.thread_getpicture(dev_serial, pic_name);
}
else if (type == "10") //get cam isonline
{
OUTINFO_1_PARAM("recieve node msg : %s \n", tempstring.c_str());
char body [128] = "";
std::string head = "{\"type\":\"10\",\"info\":{";
device one_device = m_init_device_list(tempstring);
list<device_init_add>::iterator it;
list<device_init_add> list = one_device.dev_list;
it = list.begin();
while (it != list.end())
{
int status = pdevclass->getLoginStatus(it->dev_serial);
_snprintf(body, sizeof(body) - 1, " \"%s\":{\"deviceid\":\"%s\" ,\"status\":\"%d\"} ,", it->dev_serial.c_str(), it->dev_serial.c_str(), status);
string body1 = body;
head += body1;
*it++;
}
head.pop_back();
head = head + "}}";
sendText(hdl, head);
}
else if (type == "11") //接受node 心跳
{
OUTINFO_1_PARAM("recieve node msg : %s \n", tempstring.c_str());
//给当前变量全局 ms 数进行赋值
std::string msg_str = "{\"type\":\"11\",\"info\":\"heart beatting\"}";
sendText(hdl, msg_str);
//设置当前连接的心跳
pdevclass->setheartTime(hdl, getMilliTime());
/*function sfunc = std::bind(&broadcast_server::timer_callback, this, std::placeholders::_1);
m_server.set_timer(time, sfunc);*/
}
OUTINFO_0_PARAM("END WS server on_message resove\n");
}
void broadcast_server::timer_callback(error_code const &error) {
// printf("this is a test\n\n");
}
string broadcast_server::m_type_number(string json_string) {
std::stringstream str_stream(json_string);
boost::property_tree::ptree root;
boost::property_tree::read_json(str_stream, root);
//boost::property_tree::ptree::iterator root_it = root.BEGIN();
string type = root.get<string>("type");
return type;
}
device broadcast_server::m_init_device_list(string json_string) {
device one_device;
try{
std::stringstream str_stream(json_string);
boost::property_tree::ptree root;
boost::property_tree::read_json(str_stream, root);
boost::property_tree::ptree::iterator root_it = root.begin();
for (; root_it != root.end(); ++root_it)
{
string key = root_it->first;
if ("type" == key)
{
one_device.type = root.get<string>(key);
}
if ("info" == key)
{
boost::property_tree::ptree info_node = root.get_child(key);
boost::property_tree::ptree list_node = info_node.get_child("list");
boost::property_tree::ptree::iterator list_node_it = list_node.begin();
for (; list_node_it != list_node.end(); ++list_node_it)
{
device_init_add one_init_add;
boost::property_tree::ptree tkt = list_node_it->second;
boost::property_tree::ptree::iterator tkt_it = tkt.begin();
for (; tkt_it != tkt.end(); ++tkt_it)
{
string tkt_key = tkt_it->first;
string tkt_val = tkt.get<string>(tkt_key);
if (tkt_key == "deviceid")
one_init_add.dev_serial = tkt_val;
else if (tkt_key == "username")
one_init_add.user_name = tkt_val;
else if (tkt_key == "password")
one_init_add.passwd = tkt_val;
// cout << tkt_key << ":" << tkt_val << endl;
}
/*struct device
{
string type;
std::list dev_list;
};*/
one_device.dev_list.push_back(one_init_add);//push设备的deviceid、usename、password 到list中
}
}
else
{
/*string val = root.get(key);
cout << key << ":" << val << endl;
*/
}
}
}
catch (const std::exception& e)
{
OUTINFO_1_PARAM("m_init_device_list error = %s \n", e.what());
}
return one_device;
}
//获取操作的deviceid
string broadcast_server::m_live_broadcast(string json_string )
{
string device_s;
try
{
std::stringstream str_stream(json_string);
boost::property_tree::ptree root;
boost::property_tree::read_json(str_stream, root);
boost::property_tree::ptree info_node = root.get_child("info");
device_s = info_node.get<string>("deviceid");
}
catch (const std::exception& e)
{
OUTINFO_1_PARAM("m_live_broadcast error = %s \n", e.what());
}
return device_s;
}
//获取device传输码流的类型
string broadcast_server::m_video_type(string json_string)
{
string type;
try
{
std::stringstream str_stream(json_string);
boost::property_tree::ptree root;
boost::property_tree::read_json(str_stream, root);
boost::property_tree::ptree info_node = root.get_child("info");
type = info_node.get<string>("video_type");
//printf(">>>>>video_type:%s<<<<<",type.c_str());
}
catch (const std::exception& e)
{
OUTINFO_1_PARAM("m_video_type error = %s \n", e.what());
}
return type;
}
//获取截图的 摄像头 序列号 和 截取图片的name
device_take_pic broadcast_server::m_device_take_pic(string json_string)
{
device_take_pic takes;
try
{
std::stringstream str_stream(json_string);
boost::property_tree::ptree root;
boost::property_tree::read_json(str_stream, root);
boost::property_tree::ptree info_node = root.get_child("info");
takes.dev_serial = info_node.get<string>("deviceid");
takes.pic_name = info_node.get<string>("time");
}
catch (const std::exception& e)
{
OUTINFO_1_PARAM("m_device_take_pic error = %s \n", e.what());
}
return takes;
}
//{"type":8, "info" : {"bim_id":"123456", "deviceid" : "3CEF8CFC7990", "time" : ""}}
//{"type":4, "info" : {"bim_id":"123456", "deviceid": "3CEF8CFC7990"}}
//void broadcast_server::process_messages() {
//
// while (1) {
//
//
// unique_lock lock(m_action_lock);
//
//
// while (m_actions.empty()) {
// m_action_cond.wait(lock);
// }
//
//
// action a = m_actions.front();
//
//
// m_actions.pop();
//
// lock.unlock();
//
//
//
//
// if (a.type == SUBSCRIBE) {
// lock_guard guard(m_connection_lock);
// m_connections.insert(a.hdl);
// devClass * pdevClass = devClass::GetInstance();
// string key = "3CEF8CFC7990";
// string username = "admin";
// string pass = "ma11111111";
// pdevClass->addDevSession(key, username, pass);
//
// }
// else if (a.type == UNSUBSCRIBE) {
// lock_guard guard(m_connection_lock);
// printf("当前设备断开连接。。。。。。。。。。。。。。。。。。。。。。。。。");
// m_connections.erase(a.hdl);
// }
// else if (a.type == MESSAGE) {
// lock_guard guard(m_connection_lock);
//
// devClass * pdevClass = devClass::GetInstance();
// pdevClass->addDevSession("3CEF8CFC7990", a.hdl);
// dhServer dhserver;
// dhserver.thread_getH264ById("3CEF8CFC7990");
// //摄像头的信息在a.msg里面,组建结构,写到map里面去
// /*string payload = a.msg->get_payload();
// string DevSerial = analysePayload(payload);*/
//
//
// //con_list::iterator it;
// /*for (it = m_connections.begin(); it != m_connections.end(); ++it) {
// m_server.send(*it, a.msg);
// }*/
// }
// }
// else {
// // undefined.
// }
//
// }
//}
void broadcast_server::SendFrame(connection_hdl hd, char * p, int len)
{
try {//将数据以二进制的形式发出去
m_server.send(hd, p, len, websocketpp::frame::opcode::binary);
}
catch (websocketpp::exception const & e) {
OUTINFO_1_PARAM("SendFrame_video error = %s \n", e.what());
}
}
void broadcast_server::SendFrame(connection_hdl hd, void * devSerial, int status)
{
try {
string strSerial = (char*)devSerial;
char body[128] = "";
_snprintf(body, sizeof(body) - 1, "{ \"type\":\"0\",\"info\":{ \"deviceid\":\"%s\" ,\"status\":\"%d\"}}", strSerial.c_str(), status);
sendText(hd, (string)body);
}
catch (websocketpp::exception const & e) {
OUTINFO_1_PARAM("SendFrame_sendText error = %s \n", e.what());
}
}
void broadcast_server::SendFrame(connection_hdl hd,string devSerial,string pic_name)
{
try {
/* string id_name = (char*)devSerial;
int flag = id_name.find("#");
string id = id_name.substr(0, flag);
string pic_name = id_name.substr(++flag, -1);*/
char body[128] = "";
_snprintf(body, sizeof(body) - 1, "{ \"type\":\"8\",\"info\":{ \"deviceid\":\"%s\",\"pic_name\":\"%s\"}}", devSerial.c_str(), pic_name.c_str());
sendText(hd, (string)body);
/* char * p = (char *)devSerial;
delete[]p;*/
}
catch (websocketpp::exception const & e) {
OUTINFO_1_PARAM("SendFrame_pic error = %s \n", e.what());
}
}
void broadcast_server::CloseConnect(connection_hdl hd)
{
try {
m_server.close(hd,0,"heartbeat close");
OUTINFO_0_PARAM("close connect ,becauser no recieve data...\n");
}
catch (websocketpp::exception const & e) {
OUTINFO_1_PARAM("CloseConnect error = %s \n", e.what());
}
}
int broadcast_server::GetUserNumberByDevName(const char * devname)
{
return 0;
}
long long broadcast_server::getMilliTime()
{
struct timeb t1;
ftime(&t1);
return t1.time * 1000 + t1.millitm;
}
void broadcast_server::sendText(connection_hdl hdl,string & msg) {
OUTINFO_1_PARAM(" BEGIN sendText msg = %s\n" , msg.c_str());
try {
int len = msg.size();
server::message_ptr m;
char *p = (char *)msg.c_str();
m_server.send(hdl, p, len, websocketpp::frame::opcode::text);
}
catch (websocketpp::exception const & e)
{
OUTINFO_1_PARAM(" sendText error = %s \n", e.what());
}
}
html端使用h264 js解码,直接播放,这样的好处是可以让手机端使用html5也直接播放,当然,可以使用原生的程序直接播放,就可以避免一些限制。下面使用html5 解码,使用的decoder.js 等为开源程序,缺陷,只能解码baseline 的h264,各位要解码h264 和h265 请使用wasm的程序,网上有很多。
DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=320, initial-scale=1" />
<title>h264 streamingtitle>
<style type="text/css">
body {
background: #333;
text-align: center;
margin-top: 10%;
}
#videoCanvas {
/* Always stretch the canvas to 640x480, regardless of its
internal size. */
width: 640px;
height: 480px;
}
style>
head>
<body>
<script type="text/javascript" src="Decoder.js">script>
<script type="text/javascript" src="YUVCanvas.js">script>
<script type="text/javascript" src="Player.js">script>
<script type="text/javascript">
var player = new Player({size: {
width: 640,
height: 320
}});
document.body.appendChild(player.canvas);
//var strhost = "ws://" + window.location.host ;
var strhost = "ws://192.168.3.245:9002" ;
// Setup the WebSocket connection and start the player
var client = new WebSocket( strhost );
client.binaryType = 'arraybuffer';
client.onopen = function(evt) {
onOpen(evt)
};
client.onclose = function(evt) {
onClose(evt)
};
client.onmessage = function(evt) {
onMessage(evt)
};
client.onerror = function(evt) {
onError(evt)
};
function onOpen(evt) {
// document.getElementById('messages').innerHTML = 'Connection established';
console.log("connection ");
// alert("open");
}
function onClose(evt) {
alert("close");
}
function onMessage(evt) {
//console.log(evt.data);
//return;
var messageData = new Uint8Array(evt.data);
player.decode(messageData);
}
function onError(evt) {
alert("error");
}
script>
body>
html>