239 lines
6.0 KiB
C++
239 lines
6.0 KiB
C++
//
|
|
// 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>
|
|
#include <errno.h>
|
|
#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;
|
|
subpixelorder = ZM_SUBPIX_ORDER_BGR;
|
|
video_stream = NULL;
|
|
|
|
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() {
|
|
int port_num = atoi(port.c_str());
|
|
//struct addrinfo *p;
|
|
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);
|
|
|
|
sd = socket(AF_INET, SOCK_STREAM, 0);
|
|
//for(p = hp; p != NULL; p = p->ai_next) {
|
|
//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;
|
|
}
|
|
|
|
//if ( connect( sd, p->ai_addr, p->ai_addrlen ) < 0 ) {
|
|
if ( connect( sd, (struct sockaddr *)&servaddr , sizeof(servaddr) ) < 0 ) {
|
|
close(sd);
|
|
sd = -1;
|
|
|
|
Warning("Can't connect to socket mid: %d : %s", monitor_id, strerror(errno) );
|
|
return -1;
|
|
}
|
|
|
|
//if ( p == NULL ) {
|
|
//Error("Unable to connect to the remote camera, aborting");
|
|
//return( -1 );
|
|
//}
|
|
|
|
Debug( 3, "Connected to host:%d, socket = %d", port_num, sd );
|
|
return sd;
|
|
}
|
|
|
|
int RemoteCameraNVSocket::Disconnect() {
|
|
close( sd );
|
|
sd = -1;
|
|
Debug( 3, "Disconnected from host" );
|
|
return( 0 );
|
|
}
|
|
|
|
int RemoteCameraNVSocket::SendRequest( std::string request ) {
|
|
//Debug( 4, "Sending request: %s", request.c_str() );
|
|
if ( write( sd, request.data(), request.length() ) < 0 ) {
|
|
Error( "Can't write: %s", strerror(errno) );
|
|
Disconnect();
|
|
return( -1 );
|
|
}
|
|
//Debug( 4, "Request sent" );
|
|
return( 0 );
|
|
}
|
|
|
|
int RemoteCameraNVSocket::PrimeCapture() {
|
|
if ( sd < 0 ) {
|
|
Connect();
|
|
if ( sd < 0 ) {
|
|
Error( "Unable to connect to camera" );
|
|
return( -1 );
|
|
}
|
|
}
|
|
buffer.clear();
|
|
struct image_def {
|
|
uint16_t width;
|
|
uint16_t height;
|
|
uint16_t type;
|
|
};
|
|
struct image_def image_def;
|
|
|
|
if ( SendRequest("GetImageParams\n") < 0 ) {
|
|
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;
|
|
}
|
|
mVideoStreamId=0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int RemoteCameraNVSocket::Capture( ZMPacket &zm_packet ) {
|
|
if ( SendRequest("GetNextImage\n") < 0 ) {
|
|
Warning( "Unable to capture image, retrying" );
|
|
return 0;
|
|
}
|
|
int bytes_read = Read(sd, buffer, imagesize);
|
|
if ( (bytes_read < 0) || ( (unsigned int)bytes_read < imagesize ) ) {
|
|
Warning("Unable to capture image, retrying");
|
|
return 0;
|
|
}
|
|
uint32_t end;
|
|
if ( Read(sd, (char *) &end , sizeof(end)) < 0 ) {
|
|
Warning("Unable to capture image, retrying");
|
|
return 0;
|
|
}
|
|
if ( end != 0xFFFFFFFF) {
|
|
Warning("End Bytes Failed\n");
|
|
return 0;
|
|
}
|
|
|
|
zm_packet.image->Assign(width, height, colours, subpixelorder, buffer, imagesize);
|
|
zm_packet.keyframe = 1;
|
|
return 1;
|
|
}
|
|
|
|
int RemoteCameraNVSocket::PostCapture() {
|
|
return( 0 );
|
|
}
|
|
AVStream *RemoteCameraNVSocket::get_VideoStream() {
|
|
if ( ! video_stream ) {
|
|
AVFormatContext *oc = avformat_alloc_context();
|
|
video_stream = avformat_new_stream( oc, NULL );
|
|
if ( video_stream ) {
|
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
|
video_stream->codecpar->width = width;
|
|
video_stream->codecpar->height = height;
|
|
video_stream->codecpar->format = GetFFMPEGPixelFormat(colours,subpixelorder);
|
|
video_stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
|
#else
|
|
video_stream->codec->width = width;
|
|
video_stream->codec->height = height;
|
|
video_stream->codec->pix_fmt = GetFFMPEGPixelFormat(colours,subpixelorder);
|
|
video_stream->codec->codec_type = AVMEDIA_TYPE_VIDEO;
|
|
#endif
|
|
} else {
|
|
Error("Can't create video stream");
|
|
}
|
|
} else {
|
|
Debug(5,"Have videostream");
|
|
}
|
|
return video_stream;
|
|
}
|