2017-10-03 00:57:40 +08:00
|
|
|
//
|
|
|
|
// ZoneMinder Remote Camera Class Implementation, $Date$, $Revision$
|
|
|
|
// Copyright (C) 2001-2008 Philip Coombes
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License
|
|
|
|
// as published by the Free Software Foundation; either version 2
|
|
|
|
// of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "zm_remote_camera_nvsocket.h"
|
|
|
|
|
|
|
|
#include "zm_mem_utils.h"
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
2021-02-04 06:56:42 +08:00
|
|
|
#include <cerrno>
|
2017-10-03 00:57:40 +08:00
|
|
|
#include <netdb.h>
|
|
|
|
|
|
|
|
#ifdef SOLARIS
|
|
|
|
#include <sys/filio.h> // FIONREAD and friends
|
|
|
|
#endif
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
RemoteCameraNVSocket::RemoteCameraNVSocket(
|
|
|
|
unsigned int p_monitor_id,
|
|
|
|
const std::string &p_host,
|
|
|
|
const std::string &p_port,
|
|
|
|
const std::string &p_path,
|
|
|
|
int p_width,
|
|
|
|
int p_height,
|
|
|
|
int p_colours,
|
|
|
|
int p_brightness,
|
|
|
|
int p_contrast,
|
|
|
|
int p_hue,
|
|
|
|
int p_colour,
|
|
|
|
bool p_capture,
|
|
|
|
bool p_record_audio ) :
|
|
|
|
RemoteCamera(
|
|
|
|
p_monitor_id,
|
|
|
|
"http",
|
|
|
|
p_host,
|
|
|
|
p_port,
|
|
|
|
p_path,
|
|
|
|
p_width,
|
|
|
|
p_height,
|
|
|
|
p_colours,
|
|
|
|
p_brightness,
|
|
|
|
p_contrast,
|
|
|
|
p_hue,
|
|
|
|
p_colour,
|
|
|
|
p_capture,
|
|
|
|
p_record_audio )
|
|
|
|
{
|
|
|
|
sd = -1;
|
|
|
|
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
timeout.tv_usec = 0;
|
2017-11-08 10:21:51 +08:00
|
|
|
subpixelorder = ZM_SUBPIX_ORDER_BGR;
|
2021-01-28 23:45:53 +08:00
|
|
|
mVideoStream = NULL;
|
2017-10-03 00:57:40 +08:00
|
|
|
|
|
|
|
if ( capture ) {
|
|
|
|
Initialise();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RemoteCameraNVSocket::~RemoteCameraNVSocket() {
|
|
|
|
if ( capture ) {
|
|
|
|
Terminate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemoteCameraNVSocket::Initialise() {
|
|
|
|
RemoteCamera::Initialise();
|
|
|
|
|
|
|
|
if ( !timeout.tv_sec ) {
|
|
|
|
timeout.tv_sec = config.http_timeout/1000;
|
|
|
|
timeout.tv_usec = (config.http_timeout%1000)*1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
int max_size = width*height*colours;
|
|
|
|
|
|
|
|
buffer.size( max_size );
|
|
|
|
}
|
|
|
|
|
|
|
|
int RemoteCameraNVSocket::Connect() {
|
2017-11-08 10:21:51 +08:00
|
|
|
int port_num = atoi(port.c_str());
|
2017-10-04 05:51:57 +08:00
|
|
|
//struct addrinfo *p;
|
2017-11-08 10:21:51 +08:00
|
|
|
struct sockaddr_in servaddr;
|
|
|
|
bzero( &servaddr, sizeof(servaddr));
|
|
|
|
servaddr.sin_family = AF_INET;
|
|
|
|
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
|
|
|
|
servaddr.sin_port = htons(port_num);
|
2017-10-03 00:57:40 +08:00
|
|
|
|
2017-11-08 10:21:51 +08:00
|
|
|
sd = socket(AF_INET, SOCK_STREAM, 0);
|
2017-10-04 05:51:57 +08:00
|
|
|
//for(p = hp; p != NULL; p = p->ai_next) {
|
2017-11-08 10:21:51 +08:00
|
|
|
//sd = socket( p->ai_family, p->ai_socktype, p->ai_protocol );
|
|
|
|
if ( sd < 0 ) {
|
|
|
|
Warning("Can't create socket: %s", strerror(errno) );
|
|
|
|
//continue;
|
|
|
|
return -1;
|
|
|
|
}
|
2017-10-03 00:57:40 +08:00
|
|
|
|
2017-11-08 10:21:51 +08:00
|
|
|
//if ( connect( sd, p->ai_addr, p->ai_addrlen ) < 0 ) {
|
|
|
|
if ( connect( sd, (struct sockaddr *)&servaddr , sizeof(servaddr) ) < 0 ) {
|
|
|
|
close(sd);
|
|
|
|
sd = -1;
|
2017-10-03 00:57:40 +08:00
|
|
|
|
2017-11-08 10:21:51 +08:00
|
|
|
Warning("Can't connect to socket mid: %d : %s", monitor_id, strerror(errno) );
|
|
|
|
return -1;
|
2017-10-03 00:57:40 +08:00
|
|
|
}
|
|
|
|
|
2017-11-08 10:21:51 +08:00
|
|
|
//if ( p == NULL ) {
|
|
|
|
//Error("Unable to connect to the remote camera, aborting");
|
|
|
|
//return( -1 );
|
|
|
|
//}
|
2017-10-03 00:57:40 +08:00
|
|
|
|
2017-11-08 10:21:51 +08:00
|
|
|
Debug( 3, "Connected to host:%d, socket = %d", port_num, sd );
|
|
|
|
return sd;
|
2017-10-03 00:57:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int RemoteCameraNVSocket::Disconnect() {
|
|
|
|
close( sd );
|
|
|
|
sd = -1;
|
|
|
|
Debug( 3, "Disconnected from host" );
|
|
|
|
return( 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
int RemoteCameraNVSocket::SendRequest( std::string request ) {
|
2017-11-15 00:53:08 +08:00
|
|
|
//Debug( 4, "Sending request: %s", request.c_str() );
|
2017-10-03 00:57:40 +08:00
|
|
|
if ( write( sd, request.data(), request.length() ) < 0 ) {
|
|
|
|
Error( "Can't write: %s", strerror(errno) );
|
|
|
|
Disconnect();
|
|
|
|
return( -1 );
|
|
|
|
}
|
2017-11-15 00:53:08 +08:00
|
|
|
//Debug( 4, "Request sent" );
|
2017-10-03 00:57:40 +08:00
|
|
|
return( 0 );
|
|
|
|
}
|
|
|
|
|
2017-11-08 10:21:51 +08:00
|
|
|
int RemoteCameraNVSocket::PrimeCapture() {
|
2017-10-03 00:57:40 +08:00
|
|
|
if ( sd < 0 ) {
|
|
|
|
Connect();
|
|
|
|
if ( sd < 0 ) {
|
|
|
|
Error( "Unable to connect to camera" );
|
|
|
|
return( -1 );
|
|
|
|
}
|
|
|
|
}
|
2017-11-08 10:21:51 +08:00
|
|
|
buffer.clear();
|
|
|
|
struct image_def {
|
|
|
|
uint16_t width;
|
|
|
|
uint16_t height;
|
|
|
|
uint16_t type;
|
|
|
|
};
|
|
|
|
struct image_def image_def;
|
|
|
|
|
|
|
|
if ( SendRequest("GetImageParams\n") < 0 ) {
|
2017-10-03 00:57:40 +08:00
|
|
|
Error( "Unable to send request" );
|
|
|
|
Disconnect();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if ( Read(sd, (char *) &image_def, sizeof(image_def)) != sizeof(image_def) ) {
|
|
|
|
Error("Unable to GetImageParams");
|
|
|
|
Disconnect();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if ( image_def.width != width || image_def.height != height ) {
|
|
|
|
Error("Incorrect width and height set. %dx%d != %dx%d", width, height, image_def.width, image_def.height );
|
|
|
|
Disconnect();
|
|
|
|
return -1;
|
|
|
|
}
|
2017-11-29 04:58:20 +08:00
|
|
|
mVideoStreamId=0;
|
2017-10-03 00:57:40 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-11-10 03:50:20 +08:00
|
|
|
int RemoteCameraNVSocket::Capture( ZMPacket &zm_packet ) {
|
2017-11-08 10:21:51 +08:00
|
|
|
if ( SendRequest("GetNextImage\n") < 0 ) {
|
2017-10-03 00:57:40 +08:00
|
|
|
Warning( "Unable to capture image, retrying" );
|
2017-11-08 10:21:51 +08:00
|
|
|
return 0;
|
2017-10-03 00:57:40 +08:00
|
|
|
}
|
2018-04-24 02:43:16 +08:00
|
|
|
int bytes_read = Read(sd, buffer, imagesize);
|
|
|
|
if ( (bytes_read < 0) || ( (unsigned int)bytes_read < imagesize ) ) {
|
|
|
|
Warning("Unable to capture image, retrying");
|
2017-11-08 10:21:51 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
uint32_t end;
|
|
|
|
if ( Read(sd, (char *) &end , sizeof(end)) < 0 ) {
|
2018-04-24 02:43:16 +08:00
|
|
|
Warning("Unable to capture image, retrying");
|
2017-11-08 10:21:51 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if ( end != 0xFFFFFFFF) {
|
|
|
|
Warning("End Bytes Failed\n");
|
|
|
|
return 0;
|
2017-10-03 00:57:40 +08:00
|
|
|
}
|
2017-10-04 04:28:56 +08:00
|
|
|
|
2018-05-06 00:25:11 +08:00
|
|
|
zm_packet.image->Assign(width, height, colours, subpixelorder, buffer, imagesize);
|
2017-12-02 07:42:19 +08:00
|
|
|
zm_packet.keyframe = 1;
|
2017-11-08 10:21:51 +08:00
|
|
|
return 1;
|
2017-10-03 00:57:40 +08:00
|
|
|
}
|
|
|
|
|
2017-11-08 10:21:51 +08:00
|
|
|
int RemoteCameraNVSocket::PostCapture() {
|
2017-10-03 00:57:40 +08:00
|
|
|
return( 0 );
|
|
|
|
}
|