mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-03-30 11:42:22 -04:00
Merge pull request #3907 from webgeek1234/master
Format code using astyle google format
This commit is contained in:
4533
src/bindings.h
4533
src/bindings.h
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Core 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.h"
|
||||
|
||||
|
||||
8
src/zm.h
8
src/zm.h
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Core Interfaces, $Date$, $Revision$
|
||||
// $Copyright$
|
||||
//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
#ifndef ZM_H
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "zm_time.h"
|
||||
|
||||
AnalysisThread::AnalysisThread(Monitor *monitor) :
|
||||
monitor_(monitor), terminate_(false) {
|
||||
monitor_(monitor), terminate_(false) {
|
||||
thread_ = std::thread(&AnalysisThread::Run, this);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Box Class Interfaces, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_BOX_H
|
||||
#define ZM_BOX_H
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* ZoneMinder flexible memory 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_buffer.h"
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* ZoneMinder Flexible Memory Interface, $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.
|
||||
*/
|
||||
*/
|
||||
|
||||
#ifndef ZM_BUFFER_H
|
||||
#define ZM_BUFFER_H
|
||||
@@ -87,7 +87,7 @@ class Buffer {
|
||||
unsigned int consume(unsigned int count) {
|
||||
if (count > mSize) {
|
||||
Warning("Attempt to consume %d bytes of buffer, size is only %d bytes",
|
||||
count, mSize);
|
||||
count, mSize);
|
||||
count = mSize;
|
||||
}
|
||||
mHead += count;
|
||||
@@ -99,7 +99,7 @@ class Buffer {
|
||||
unsigned int shrink(unsigned int count) {
|
||||
if (count > mSize) {
|
||||
Warning("Attempt to shrink buffer by %d bytes, size is only %d bytes",
|
||||
count, mSize);
|
||||
count, mSize);
|
||||
count = mSize;
|
||||
}
|
||||
mSize -= count;
|
||||
@@ -117,7 +117,7 @@ class Buffer {
|
||||
unsigned char *extract(unsigned int pSize) {
|
||||
if (pSize > mSize) {
|
||||
Warning("Attempt to extract %d bytes of buffer, size is only %d bytes",
|
||||
pSize, mSize);
|
||||
pSize, mSize);
|
||||
pSize = mSize;
|
||||
}
|
||||
unsigned char *oldHead = mHead;
|
||||
|
||||
@@ -22,52 +22,51 @@
|
||||
#include "zm_monitor.h"
|
||||
|
||||
Camera::Camera(
|
||||
const Monitor *monitor,
|
||||
SourceType p_type,
|
||||
unsigned int p_width,
|
||||
unsigned int p_height,
|
||||
int p_colours,
|
||||
int p_subpixelorder,
|
||||
int p_brightness,
|
||||
int p_contrast,
|
||||
int p_hue,
|
||||
int p_colour,
|
||||
bool p_capture,
|
||||
bool p_record_audio
|
||||
) :
|
||||
monitor(monitor),
|
||||
type(p_type),
|
||||
width(p_width),
|
||||
height(p_height),
|
||||
colours(p_colours),
|
||||
subpixelorder(p_subpixelorder),
|
||||
brightness(p_brightness),
|
||||
hue(p_hue),
|
||||
colour(p_colour),
|
||||
contrast(p_contrast),
|
||||
capture(p_capture),
|
||||
record_audio(p_record_audio),
|
||||
mVideoStreamId(-1),
|
||||
mAudioStreamId(-1),
|
||||
mVideoCodecContext(nullptr),
|
||||
mAudioCodecContext(nullptr),
|
||||
mVideoStream(nullptr),
|
||||
mAudioStream(nullptr),
|
||||
mFormatContext(nullptr),
|
||||
mSecondFormatContext(nullptr),
|
||||
mFirstVideoPTS(0),
|
||||
mFirstAudioPTS(0),
|
||||
mLastVideoPTS(0),
|
||||
mLastAudioPTS(0),
|
||||
bytes(0),
|
||||
mIsPrimed(false)
|
||||
{
|
||||
const Monitor *monitor,
|
||||
SourceType p_type,
|
||||
unsigned int p_width,
|
||||
unsigned int p_height,
|
||||
int p_colours,
|
||||
int p_subpixelorder,
|
||||
int p_brightness,
|
||||
int p_contrast,
|
||||
int p_hue,
|
||||
int p_colour,
|
||||
bool p_capture,
|
||||
bool p_record_audio
|
||||
) :
|
||||
monitor(monitor),
|
||||
type(p_type),
|
||||
width(p_width),
|
||||
height(p_height),
|
||||
colours(p_colours),
|
||||
subpixelorder(p_subpixelorder),
|
||||
brightness(p_brightness),
|
||||
hue(p_hue),
|
||||
colour(p_colour),
|
||||
contrast(p_contrast),
|
||||
capture(p_capture),
|
||||
record_audio(p_record_audio),
|
||||
mVideoStreamId(-1),
|
||||
mAudioStreamId(-1),
|
||||
mVideoCodecContext(nullptr),
|
||||
mAudioCodecContext(nullptr),
|
||||
mVideoStream(nullptr),
|
||||
mAudioStream(nullptr),
|
||||
mFormatContext(nullptr),
|
||||
mSecondFormatContext(nullptr),
|
||||
mFirstVideoPTS(0),
|
||||
mFirstAudioPTS(0),
|
||||
mLastVideoPTS(0),
|
||||
mLastAudioPTS(0),
|
||||
bytes(0),
|
||||
mIsPrimed(false) {
|
||||
linesize = width * colours;
|
||||
pixels = width * height;
|
||||
imagesize = static_cast<unsigned long long>(height) * linesize;
|
||||
|
||||
Debug(2, "New camera id: %d width: %d line size: %d height: %d colours: %d subpixelorder: %d capture: %d, size: %llu",
|
||||
monitor->Id(), width, linesize, height, colours, subpixelorder, capture, imagesize);
|
||||
monitor->Id(), width, linesize, height, colours, subpixelorder, capture, imagesize);
|
||||
}
|
||||
|
||||
Camera::~Camera() {
|
||||
@@ -92,7 +91,7 @@ AVStream *Camera::getVideoStream() {
|
||||
Debug(1, "Allocating avstream");
|
||||
mVideoStream = avformat_new_stream(mFormatContext, nullptr);
|
||||
if ( mVideoStream ) {
|
||||
mVideoStream->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate
|
||||
mVideoStream->time_base = (AVRational) {1, 1000000}; // microseconds as base frame rate
|
||||
mVideoStream->codecpar->width = width;
|
||||
mVideoStream->codecpar->height = height;
|
||||
mVideoStream->codecpar->format = GetFFMPEGPixelFormat(colours, subpixelorder);
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Camera Class Interface, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_CAMERA_H
|
||||
#define ZM_CAMERA_H
|
||||
@@ -34,7 +34,7 @@ class ZMPacket;
|
||||
// common attributes
|
||||
//
|
||||
class Camera {
|
||||
protected:
|
||||
protected:
|
||||
typedef enum { LOCAL_SRC, REMOTE_SRC, FILE_SRC, FFMPEG_SRC, LIBVLC_SRC, CURL_SRC, VNC_SRC } SourceType;
|
||||
|
||||
const Monitor *monitor;
|
||||
@@ -67,21 +67,21 @@ protected:
|
||||
unsigned int bytes;
|
||||
bool mIsPrimed;
|
||||
|
||||
public:
|
||||
public:
|
||||
Camera(
|
||||
const Monitor* monitor,
|
||||
SourceType p_type,
|
||||
unsigned int p_width,
|
||||
unsigned int p_height,
|
||||
int p_colours,
|
||||
int p_subpixelorder,
|
||||
int p_brightness,
|
||||
int p_contrast,
|
||||
int p_hue,
|
||||
int p_colour,
|
||||
bool p_capture,
|
||||
bool p_record_audio
|
||||
);
|
||||
const Monitor* monitor,
|
||||
SourceType p_type,
|
||||
unsigned int p_width,
|
||||
unsigned int p_height,
|
||||
int p_colours,
|
||||
int p_subpixelorder,
|
||||
int p_brightness,
|
||||
int p_contrast,
|
||||
int p_hue,
|
||||
int p_colour,
|
||||
bool p_capture,
|
||||
bool p_record_audio
|
||||
);
|
||||
virtual ~Camera();
|
||||
|
||||
SourceType Type() const { return type; }
|
||||
@@ -104,9 +104,11 @@ public:
|
||||
int getFrequency() { return mAudioStream ? mAudioStream->codecpar->sample_rate : -1; }
|
||||
int getChannels() {
|
||||
#if LIBAVUTIL_VERSION_CHECK(57, 28, 100, 28, 0)
|
||||
return mAudioStream ? mAudioStream->codecpar->ch_layout.nb_channels : -1; }
|
||||
return mAudioStream ? mAudioStream->codecpar->ch_layout.nb_channels : -1;
|
||||
}
|
||||
#else
|
||||
return mAudioStream ? mAudioStream->codecpar->channels : -1; }
|
||||
return mAudioStream ? mAudioStream->codecpar->channels : -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual int Brightness( int/*p_brightness*/=-1 ) { return -1; }
|
||||
|
||||
@@ -144,9 +144,9 @@ class SockAddrInet : public SockAddr {
|
||||
public:
|
||||
SockAddrInet() : SockAddr((sockaddr *) &mAddrIn) {}
|
||||
explicit SockAddrInet(const SockAddrInet &addr)
|
||||
: SockAddr((const sockaddr *) &mAddrIn), mAddrIn(addr.mAddrIn) {}
|
||||
: SockAddr((const sockaddr *) &mAddrIn), mAddrIn(addr.mAddrIn) {}
|
||||
explicit SockAddrInet(const sockaddr_in *addr)
|
||||
: SockAddr((const sockaddr *) &mAddrIn), mAddrIn(*addr) {}
|
||||
: SockAddr((const sockaddr *) &mAddrIn), mAddrIn(*addr) {}
|
||||
|
||||
bool resolve(const char *host, const char *serv, const char *proto);
|
||||
bool resolve(const char *host, int port, const char *proto);
|
||||
@@ -167,9 +167,9 @@ class SockAddrUnix : public SockAddr {
|
||||
public:
|
||||
SockAddrUnix() : SockAddr((sockaddr *) &mAddrUn) {}
|
||||
SockAddrUnix(const SockAddrUnix &addr)
|
||||
: SockAddr((const sockaddr *) &mAddrUn), mAddrUn(addr.mAddrUn) {}
|
||||
: SockAddr((const sockaddr *) &mAddrUn), mAddrUn(addr.mAddrUn) {}
|
||||
explicit SockAddrUnix(const sockaddr_un *addr)
|
||||
: SockAddr((const sockaddr *) &mAddrUn), mAddrUn(*addr) {}
|
||||
: SockAddr((const sockaddr *) &mAddrUn), mAddrUn(*addr) {}
|
||||
|
||||
bool resolve(const char *path, const char *proto);
|
||||
|
||||
@@ -188,15 +188,15 @@ class Socket : public CommsBase {
|
||||
enum State { CLOSED, DISCONNECTED, LISTENING, CONNECTED };
|
||||
|
||||
Socket() : CommsBase(mSd, mSd),
|
||||
mSd(-1),
|
||||
mState(CLOSED),
|
||||
mLocalAddr(nullptr),
|
||||
mRemoteAddr(nullptr) {}
|
||||
mSd(-1),
|
||||
mState(CLOSED),
|
||||
mLocalAddr(nullptr),
|
||||
mRemoteAddr(nullptr) {}
|
||||
Socket(const Socket &socket, int newSd) : CommsBase(mSd, mSd),
|
||||
mSd(newSd),
|
||||
mState(CONNECTED),
|
||||
mLocalAddr(nullptr),
|
||||
mRemoteAddr(nullptr) {
|
||||
mSd(newSd),
|
||||
mState(CONNECTED),
|
||||
mLocalAddr(nullptr),
|
||||
mRemoteAddr(nullptr) {
|
||||
if (socket.mLocalAddr)
|
||||
mLocalAddr = SockAddr::newSockAddr(mLocalAddr);
|
||||
if (socket.mRemoteAddr)
|
||||
@@ -511,14 +511,14 @@ class TcpInetSocket : virtual public TcpSocket, virtual public InetSocket {
|
||||
public:
|
||||
TcpInetSocket() = default;
|
||||
TcpInetSocket(const TcpInetSocket &socket, int newSd)
|
||||
: TcpSocket(socket, newSd) {}
|
||||
: TcpSocket(socket, newSd) {}
|
||||
};
|
||||
|
||||
class TcpUnixSocket : virtual public TcpSocket, virtual public UnixSocket {
|
||||
public:
|
||||
TcpUnixSocket() = default;
|
||||
TcpUnixSocket(const TcpUnixSocket &socket, int newSd)
|
||||
: TcpSocket(socket, newSd) {}
|
||||
: TcpSocket(socket, newSd) {}
|
||||
};
|
||||
|
||||
class TcpInetClient : public TcpInetSocket {
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
//
|
||||
// ZoneMinder Configuration 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.
|
||||
@@ -27,8 +27,8 @@
|
||||
#include <dirent.h>
|
||||
#include <glob.h>
|
||||
|
||||
// Note that Error and Debug calls won't actually go anywhere unless you
|
||||
// set the relevant ENV vars because the logger gets it's setting from the
|
||||
// Note that Error and Debug calls won't actually go anywhere unless you
|
||||
// set the relevant ENV vars because the logger gets it's setting from the
|
||||
// config.
|
||||
|
||||
void zmLoadStaticConfig() {
|
||||
@@ -364,7 +364,7 @@ void Config::Load() {
|
||||
}
|
||||
|
||||
void Config::Assign() {
|
||||
ZM_CFG_ASSIGN_LIST
|
||||
ZM_CFG_ASSIGN_LIST
|
||||
}
|
||||
|
||||
const ConfigItem &Config::Item(int id) {
|
||||
@@ -379,12 +379,12 @@ const ConfigItem &Config::Item(int id) {
|
||||
}
|
||||
|
||||
ConfigItem *item = items[id];
|
||||
|
||||
|
||||
if ( !item ) {
|
||||
Error("Can't find config item %d", id);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
return *item;
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ struct StaticConfig {
|
||||
extern StaticConfig staticConfig;
|
||||
|
||||
class ConfigItem {
|
||||
private:
|
||||
private:
|
||||
char *name;
|
||||
char *value;
|
||||
char *type;
|
||||
@@ -88,7 +88,7 @@ private:
|
||||
} cfg_value;
|
||||
mutable bool accessed;
|
||||
|
||||
public:
|
||||
public:
|
||||
ConfigItem(const char *p_name, const char *p_value, const char *const p_type);
|
||||
ConfigItem(const ConfigItem &);
|
||||
~ConfigItem();
|
||||
@@ -118,14 +118,14 @@ public:
|
||||
};
|
||||
|
||||
class Config {
|
||||
public:
|
||||
public:
|
||||
ZM_CFG_DECLARE_LIST
|
||||
|
||||
private:
|
||||
private:
|
||||
int n_items;
|
||||
ConfigItem **items;
|
||||
|
||||
public:
|
||||
public:
|
||||
Config();
|
||||
~Config();
|
||||
|
||||
|
||||
@@ -33,15 +33,15 @@ std::pair <std::string, unsigned int> verifyToken(const std::string &jwt_token_s
|
||||
Error("Error setting Algorithm for JWT decode");
|
||||
return std::make_pair("", 0);
|
||||
}
|
||||
|
||||
|
||||
err = jwt_decode(&jwt, jwt_token_str.c_str(),
|
||||
reinterpret_cast<const unsigned char *>(key.c_str()), key.length());
|
||||
reinterpret_cast<const unsigned char *>(key.c_str()), key.length());
|
||||
if (err) {
|
||||
jwt_free(jwt);
|
||||
Error("Could not decode JWT");
|
||||
return std::make_pair("", 0);
|
||||
}
|
||||
|
||||
|
||||
const char *c_type = jwt_get_grant(jwt, (const char*)"type");
|
||||
if (!c_type) {
|
||||
jwt_free(jwt);
|
||||
@@ -62,14 +62,14 @@ std::pair <std::string, unsigned int> verifyToken(const std::string &jwt_token_s
|
||||
|
||||
username = std::string(c_username);
|
||||
Debug(1, "Got %s as user claim from token", username.c_str());
|
||||
|
||||
|
||||
token_issued_at = (unsigned int)jwt_get_grant_int(jwt, "iat");
|
||||
if (errno == ENOENT) {
|
||||
jwt_free(jwt);
|
||||
Error("IAT not found in claim. This should not happen");
|
||||
return std::make_pair("", 0);
|
||||
}
|
||||
|
||||
|
||||
Debug(1, "Got IAT token=%u", token_issued_at);
|
||||
jwt_free(jwt);
|
||||
return std::make_pair(username, token_issued_at);
|
||||
@@ -82,9 +82,9 @@ std::pair <std::string, unsigned int> verifyToken(const std::string &jwt_token_s
|
||||
// is it decodable?
|
||||
auto decoded = jwt::decode(jwt_token_str);
|
||||
auto verifier = jwt::verify()
|
||||
.allow_algorithm(jwt::algorithm::hs256{ key })
|
||||
.with_issuer("ZoneMinder");
|
||||
|
||||
.allow_algorithm(jwt::algorithm::hs256{ key })
|
||||
.with_issuer("ZoneMinder");
|
||||
|
||||
// signature verified?
|
||||
verifier.verify(decoded);
|
||||
|
||||
@@ -120,8 +120,7 @@ std::pair <std::string, unsigned int> verifyToken(const std::string &jwt_token_s
|
||||
catch (const std::exception &e) {
|
||||
Error("Unable to verify token: %s", e.what());
|
||||
return std::make_pair("", 0);
|
||||
}
|
||||
catch (...) {
|
||||
} catch (...) {
|
||||
Error("unknown exception");
|
||||
return std::make_pair("", 0);
|
||||
}
|
||||
@@ -148,13 +147,13 @@ bool verifyPassword(const char *username, const char *input_password, const char
|
||||
Debug(1, "Computed password_hash: %s, stored password_hash: %s", hex_digest.c_str(), db_password_hash);
|
||||
password_correct = (strcmp(db_password_hash, hex_digest.c_str()) == 0);
|
||||
} else if (
|
||||
(db_password_hash[0] == '$')
|
||||
&&
|
||||
(db_password_hash[1] == '2')
|
||||
&&
|
||||
(db_password_hash[3] == '$')
|
||||
) {
|
||||
// BCRYPT
|
||||
(db_password_hash[0] == '$')
|
||||
&&
|
||||
(db_password_hash[1] == '2')
|
||||
&&
|
||||
(db_password_hash[3] == '$')
|
||||
) {
|
||||
// BCRYPT
|
||||
Debug(1, "%s is using a bcrypt encoded password", username);
|
||||
BCrypt bcrypt;
|
||||
password_correct = bcrypt.validatePassword(std::string(input_password), std::string(db_password_hash));
|
||||
@@ -164,23 +163,23 @@ bool verifyPassword(const char *username, const char *input_password, const char
|
||||
} else {
|
||||
Warning("%s is using a plain text (not recommended) or scheme not understood", username);
|
||||
password_correct = (strcmp(input_password, db_password_hash) == 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return password_correct;
|
||||
}
|
||||
|
||||
std::string generateKey(const int length) {
|
||||
|
||||
const std::string lookup = "0123456789ABCDEF";
|
||||
const std::string lookup = "0123456789ABCDEF";
|
||||
|
||||
std::random_device rnd;
|
||||
std::mt19937 rng(rnd());
|
||||
std::uniform_int_distribution<> genDigit(0,15);
|
||||
std::string keyBuffer (length, '0');
|
||||
for ( int i = 0; i < length; i++ ) {
|
||||
keyBuffer[i] = lookup[genDigit(rng)];
|
||||
}
|
||||
return keyBuffer;
|
||||
std::random_device rnd;
|
||||
std::mt19937 rng(rnd());
|
||||
std::uniform_int_distribution<> genDigit(0,15);
|
||||
std::string keyBuffer (length, '0');
|
||||
for ( int i = 0; i < length; i++ ) {
|
||||
keyBuffer[i] = lookup[genDigit(rng)];
|
||||
}
|
||||
return keyBuffer;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder General Utility Functions, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_CRYPT_H
|
||||
#define ZM_CRYPT_H
|
||||
|
||||
@@ -32,7 +32,7 @@ bool zmDbConnected = false;
|
||||
|
||||
bool zmDbConnect() {
|
||||
// For some reason having these lines causes memory corruption and crashing on newer debian/ubuntu
|
||||
// But they really need to be here in order to prevent a double open of mysql
|
||||
// But they really need to be here in order to prevent a double open of mysql
|
||||
if (zmDbConnected) {
|
||||
//Warning("Calling zmDbConnect when already connected");
|
||||
return true;
|
||||
@@ -52,11 +52,11 @@ bool zmDbConnect() {
|
||||
std::string::size_type colonIndex = staticConfig.DB_HOST.find(":");
|
||||
if ( colonIndex == std::string::npos ) {
|
||||
if ( !mysql_real_connect(
|
||||
&dbconn,
|
||||
staticConfig.DB_HOST.c_str(),
|
||||
staticConfig.DB_USER.c_str(),
|
||||
staticConfig.DB_PASS.c_str(),
|
||||
nullptr, 0, nullptr, 0) ) {
|
||||
&dbconn,
|
||||
staticConfig.DB_HOST.c_str(),
|
||||
staticConfig.DB_USER.c_str(),
|
||||
staticConfig.DB_PASS.c_str(),
|
||||
nullptr, 0, nullptr, 0) ) {
|
||||
Error("Can't connect to server: %s", mysql_error(&dbconn));
|
||||
mysql_close(&dbconn);
|
||||
return false;
|
||||
@@ -66,24 +66,24 @@ bool zmDbConnect() {
|
||||
std::string dbPortOrSocket = staticConfig.DB_HOST.substr(colonIndex+1);
|
||||
if ( dbPortOrSocket[0] == '/' ) {
|
||||
if ( !mysql_real_connect(
|
||||
&dbconn,
|
||||
nullptr,
|
||||
staticConfig.DB_USER.c_str(),
|
||||
staticConfig.DB_PASS.c_str(),
|
||||
nullptr, 0, dbPortOrSocket.c_str(), 0) ) {
|
||||
&dbconn,
|
||||
nullptr,
|
||||
staticConfig.DB_USER.c_str(),
|
||||
staticConfig.DB_PASS.c_str(),
|
||||
nullptr, 0, dbPortOrSocket.c_str(), 0) ) {
|
||||
Error("Can't connect to server: %s", mysql_error(&dbconn));
|
||||
mysql_close(&dbconn);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ( !mysql_real_connect(
|
||||
&dbconn,
|
||||
dbHost.c_str(),
|
||||
staticConfig.DB_USER.c_str(),
|
||||
staticConfig.DB_PASS.c_str(),
|
||||
nullptr,
|
||||
atoi(dbPortOrSocket.c_str()),
|
||||
nullptr, 0) ) {
|
||||
&dbconn,
|
||||
dbHost.c_str(),
|
||||
staticConfig.DB_USER.c_str(),
|
||||
staticConfig.DB_PASS.c_str(),
|
||||
nullptr,
|
||||
atoi(dbPortOrSocket.c_str()),
|
||||
nullptr, 0) ) {
|
||||
Error("Can't connect to server: %s", mysql_error(&dbconn));
|
||||
mysql_close(&dbconn);
|
||||
return false;
|
||||
@@ -272,8 +272,7 @@ zmDbRow::~zmDbRow() {
|
||||
}
|
||||
|
||||
zmDbQueue::zmDbQueue() :
|
||||
mTerminate(false)
|
||||
{
|
||||
mTerminate(false) {
|
||||
mThread = std::thread(&zmDbQueue::process, this);
|
||||
}
|
||||
|
||||
|
||||
36
src/zm_db.h
36
src/zm_db.h
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Core Interfaces, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_DB_H
|
||||
#define ZM_DB_H
|
||||
@@ -29,13 +29,13 @@
|
||||
#include <thread>
|
||||
|
||||
class zmDbQueue {
|
||||
private:
|
||||
private:
|
||||
std::queue<std::string> mQueue;
|
||||
std::thread mThread;
|
||||
std::mutex mMutex;
|
||||
std::condition_variable mCondition;
|
||||
bool mTerminate;
|
||||
public:
|
||||
public:
|
||||
zmDbQueue();
|
||||
~zmDbQueue();
|
||||
void push(std::string &&sql);
|
||||
@@ -44,20 +44,20 @@ class zmDbQueue {
|
||||
};
|
||||
|
||||
class zmDbRow {
|
||||
private:
|
||||
MYSQL_RES *result_set;
|
||||
MYSQL_ROW row;
|
||||
public:
|
||||
zmDbRow() : result_set(nullptr), row(nullptr) { };
|
||||
MYSQL_RES *fetch(const std::string &query);
|
||||
zmDbRow(MYSQL_RES *, MYSQL_ROW *row);
|
||||
~zmDbRow();
|
||||
private:
|
||||
MYSQL_RES *result_set;
|
||||
MYSQL_ROW row;
|
||||
public:
|
||||
zmDbRow() : result_set(nullptr), row(nullptr) { };
|
||||
MYSQL_RES *fetch(const std::string &query);
|
||||
zmDbRow(MYSQL_RES *, MYSQL_ROW *row);
|
||||
~zmDbRow();
|
||||
|
||||
MYSQL_ROW mysql_row() const { return row; };
|
||||
MYSQL_ROW mysql_row() const { return row; };
|
||||
|
||||
char *operator[](unsigned int index) const {
|
||||
return row[index];
|
||||
}
|
||||
char *operator[](unsigned int index) const {
|
||||
return row[index];
|
||||
}
|
||||
};
|
||||
|
||||
extern MYSQL dbconn;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "zm_signal.h"
|
||||
|
||||
DecoderThread::DecoderThread(Monitor *monitor) :
|
||||
monitor_(monitor), terminate_(false) {
|
||||
monitor_(monitor), terminate_(false) {
|
||||
thread_ = std::thread(&DecoderThread::Run, this);
|
||||
}
|
||||
|
||||
|
||||
209
src/zm_event.cpp
209
src/zm_event.cpp
@@ -40,11 +40,11 @@ int Event::pre_alarm_count = 0;
|
||||
Event::PreAlarmData Event::pre_alarm_data[MAX_PRE_ALARM_FRAMES] = {};
|
||||
|
||||
Event::Event(
|
||||
Monitor *p_monitor,
|
||||
SystemTimePoint p_start_time,
|
||||
const std::string &p_cause,
|
||||
const StringSetMap &p_noteSetMap
|
||||
) :
|
||||
Monitor *p_monitor,
|
||||
SystemTimePoint p_start_time,
|
||||
const std::string &p_cause,
|
||||
const StringSetMap &p_noteSetMap
|
||||
) :
|
||||
id(0),
|
||||
monitor(p_monitor),
|
||||
start_time(p_start_time),
|
||||
@@ -67,8 +67,7 @@ Event::Event(
|
||||
have_video_keyframe(false),
|
||||
//scheme
|
||||
save_jpegs(0),
|
||||
terminate_(false)
|
||||
{
|
||||
terminate_(false) {
|
||||
std::string notes;
|
||||
createNotes(notes);
|
||||
|
||||
@@ -115,26 +114,26 @@ Event::Event(
|
||||
}
|
||||
|
||||
std::string sql = stringtf(
|
||||
"INSERT INTO `Events` "
|
||||
"( `MonitorId`, `StorageId`, `Name`, `StartDateTime`, `Width`, `Height`, `Cause`, `Notes`, `StateId`, `Orientation`, `Videoed`, `DefaultVideo`, `SaveJPEGs`, `Scheme`, `Latitude`, `Longitude` )"
|
||||
" VALUES "
|
||||
"( %d, %d, 'New Event', from_unixtime(%" PRId64 "), %u, %u, '%s', '%s', %d, %d, %d, '%s', %d, '%s', '%f', '%f' )",
|
||||
monitor->Id(),
|
||||
storage->Id(),
|
||||
static_cast<int64>(std::chrono::system_clock::to_time_t(start_time)),
|
||||
monitor->Width(),
|
||||
monitor->Height(),
|
||||
cause.c_str(),
|
||||
notes.c_str(),
|
||||
state_id,
|
||||
monitor->getOrientation(),
|
||||
0,
|
||||
video_incomplete_file.c_str(),
|
||||
save_jpegs,
|
||||
storage->SchemeString().c_str(),
|
||||
monitor->Latitude(),
|
||||
monitor->Longitude()
|
||||
);
|
||||
"INSERT INTO `Events` "
|
||||
"( `MonitorId`, `StorageId`, `Name`, `StartDateTime`, `Width`, `Height`, `Cause`, `Notes`, `StateId`, `Orientation`, `Videoed`, `DefaultVideo`, `SaveJPEGs`, `Scheme`, `Latitude`, `Longitude` )"
|
||||
" VALUES "
|
||||
"( %d, %d, 'New Event', from_unixtime(%" PRId64 "), %u, %u, '%s', '%s', %d, %d, %d, '%s', %d, '%s', '%f', '%f' )",
|
||||
monitor->Id(),
|
||||
storage->Id(),
|
||||
static_cast<int64>(std::chrono::system_clock::to_time_t(start_time)),
|
||||
monitor->Width(),
|
||||
monitor->Height(),
|
||||
cause.c_str(),
|
||||
notes.c_str(),
|
||||
state_id,
|
||||
monitor->getOrientation(),
|
||||
0,
|
||||
video_incomplete_file.c_str(),
|
||||
save_jpegs,
|
||||
storage->SchemeString().c_str(),
|
||||
monitor->Latitude(),
|
||||
monitor->Longitude()
|
||||
);
|
||||
do {
|
||||
id = zmDbDoInsert(sql);
|
||||
} while (!id and !zm_terminate);
|
||||
@@ -177,24 +176,24 @@ Event::~Event() {
|
||||
if (frame_data.size()) WriteDbFrames();
|
||||
|
||||
std::string sql = stringtf(
|
||||
"UPDATE Events SET Name='%s%" PRIu64 "', EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo='%s' WHERE Id = %" PRIu64 " AND Name='New Event'",
|
||||
monitor->Substitute(monitor->EventPrefix(), start_time).c_str(), id, std::chrono::system_clock::to_time_t(end_time),
|
||||
delta_time.count(),
|
||||
frames, alarm_frames,
|
||||
tot_score, static_cast<uint32>(alarm_frames ? (tot_score / alarm_frames) : 0), max_score,
|
||||
video_file.c_str(), // defaults to ""
|
||||
id);
|
||||
"UPDATE Events SET Name='%s%" PRIu64 "', EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo='%s' WHERE Id = %" PRIu64 " AND Name='New Event'",
|
||||
monitor->Substitute(monitor->EventPrefix(), start_time).c_str(), id, std::chrono::system_clock::to_time_t(end_time),
|
||||
delta_time.count(),
|
||||
frames, alarm_frames,
|
||||
tot_score, static_cast<uint32>(alarm_frames ? (tot_score / alarm_frames) : 0), max_score,
|
||||
video_file.c_str(), // defaults to ""
|
||||
id);
|
||||
|
||||
if (!zmDbDoUpdate(sql)) {
|
||||
// Name might have been changed during recording, so just do the update without changing the name.
|
||||
sql = stringtf(
|
||||
"UPDATE Events SET EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo='%s' WHERE Id = %" PRIu64,
|
||||
std::chrono::system_clock::to_time_t(end_time),
|
||||
delta_time.count(),
|
||||
frames, alarm_frames,
|
||||
tot_score, static_cast<uint32>(alarm_frames ? (tot_score / alarm_frames) : 0), max_score,
|
||||
video_file.c_str(), // defaults to ""
|
||||
id);
|
||||
"UPDATE Events SET EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo='%s' WHERE Id = %" PRIu64,
|
||||
std::chrono::system_clock::to_time_t(end_time),
|
||||
delta_time.count(),
|
||||
frames, alarm_frames,
|
||||
tot_score, static_cast<uint32>(alarm_frames ? (tot_score / alarm_frames) : 0), max_score,
|
||||
video_file.c_str(), // defaults to ""
|
||||
id);
|
||||
zmDbDoUpdate(sql);
|
||||
} // end if no changed rows due to Name change during recording
|
||||
} // Event::~Event()
|
||||
@@ -218,7 +217,7 @@ void Event::addNote(const char *cause, const std::string ¬e) {
|
||||
}
|
||||
|
||||
bool Event::WriteFrameImage(Image *image, SystemTimePoint timestamp, const char *event_file, bool alarm_frame) const {
|
||||
int thisquality =
|
||||
int thisquality =
|
||||
(alarm_frame && (config.jpeg_alarm_file_quality > config.jpeg_file_quality)) ?
|
||||
config.jpeg_alarm_file_quality : 0; // quality to use, zero is default
|
||||
|
||||
@@ -256,8 +255,8 @@ void Event::updateNotes(const StringSetMap &newNoteSetMap) {
|
||||
update = true;
|
||||
} else {
|
||||
for (StringSetMap::const_iterator newNoteSetMapIter = newNoteSetMap.begin();
|
||||
newNoteSetMapIter != newNoteSetMap.end();
|
||||
++newNoteSetMapIter) {
|
||||
newNoteSetMapIter != newNoteSetMap.end();
|
||||
++newNoteSetMapIter) {
|
||||
const std::string &newNoteGroup = newNoteSetMapIter->first;
|
||||
const StringSet &newNoteSet = newNoteSetMapIter->second;
|
||||
//Info( "Got %d new strings", newNoteSet.size() );
|
||||
@@ -271,8 +270,8 @@ void Event::updateNotes(const StringSetMap &newNoteSetMap) {
|
||||
StringSet ¬eSet = noteSetMapIter->second;
|
||||
//Debug(3, "Found note group %s, got %d strings", newNoteGroup.c_str(), newNoteSet.size());
|
||||
for (StringSet::const_iterator newNoteSetIter = newNoteSet.begin();
|
||||
newNoteSetIter != newNoteSet.end();
|
||||
++newNoteSetIter) {
|
||||
newNoteSetIter != newNoteSet.end();
|
||||
++newNoteSetIter) {
|
||||
const std::string &newNote = *newNoteSetIter;
|
||||
StringSet::iterator noteSetIter = noteSet.find(newNote);
|
||||
if (noteSetIter == noteSet.end()) {
|
||||
@@ -308,11 +307,11 @@ void Event::AddPacket(const std::shared_ptr<ZMPacket>&packet) {
|
||||
}
|
||||
|
||||
void Event::AddPacket_(const std::shared_ptr<ZMPacket>&packet) {
|
||||
have_video_keyframe = have_video_keyframe ||
|
||||
( ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) &&
|
||||
( packet->keyframe || monitor->GetOptVideoWriter() == Monitor::ENCODE) );
|
||||
have_video_keyframe = have_video_keyframe ||
|
||||
( ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) &&
|
||||
( packet->keyframe || monitor->GetOptVideoWriter() == Monitor::ENCODE) );
|
||||
Debug(2, "have_video_keyframe %d codec_type %d == video? %d packet keyframe %d",
|
||||
have_video_keyframe, packet->codec_type, (packet->codec_type == AVMEDIA_TYPE_VIDEO), packet->keyframe);
|
||||
have_video_keyframe, packet->codec_type, (packet->codec_type == AVMEDIA_TYPE_VIDEO), packet->keyframe);
|
||||
ZM_DUMP_PACKET(packet->packet, "Adding to event");
|
||||
|
||||
if (videoStore) {
|
||||
@@ -333,9 +332,9 @@ void Event::AddPacket_(const std::shared_ptr<ZMPacket>&packet) {
|
||||
void Event::WriteDbFrames() {
|
||||
std::string frame_insert_sql = "INSERT INTO `Frames` (`EventId`, `FrameId`, `Type`, `TimeStamp`, `Delta`, `Score`) VALUES ";
|
||||
std::string stats_insert_sql = "INSERT INTO `Stats` (`EventId`, `FrameId`, `MonitorId`, `ZoneId`, "
|
||||
"`PixelDiff`, `AlarmPixels`, `FilterPixels`, `BlobPixels`,"
|
||||
"`Blobs`,`MinBlobSize`, `MaxBlobSize`, "
|
||||
"`MinX`, `MinY`, `MaxX`, `MaxY`,`Score`) VALUES ";
|
||||
"`PixelDiff`, `AlarmPixels`, `FilterPixels`, `BlobPixels`,"
|
||||
"`Blobs`,`MinBlobSize`, `MaxBlobSize`, "
|
||||
"`MinX`, `MinY`, `MaxX`, `MaxY`,`Score`) VALUES ";
|
||||
|
||||
Debug(1, "Inserting %zu frames", frame_data.size());
|
||||
while (frame_data.size()) {
|
||||
@@ -350,21 +349,21 @@ void Event::WriteDbFrames() {
|
||||
if (config.record_event_stats and frame->zone_stats.size()) {
|
||||
for (ZoneStats &stats : frame->zone_stats) {
|
||||
stats_insert_sql += stringtf("\n(%" PRIu64 ",%d,%u,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%u),",
|
||||
id, frame->frame_id,
|
||||
monitor->Id(),
|
||||
stats.zone_id_,
|
||||
stats.pixel_diff_,
|
||||
stats.alarm_pixels_,
|
||||
stats.alarm_filter_pixels_,
|
||||
stats.alarm_blob_pixels_,
|
||||
stats.alarm_blobs_,
|
||||
stats.min_blob_size_,
|
||||
stats.max_blob_size_,
|
||||
stats.alarm_box_.Lo().x_,
|
||||
stats.alarm_box_.Lo().y_,
|
||||
stats.alarm_box_.Hi().x_,
|
||||
stats.alarm_box_.Hi().y_,
|
||||
stats.score_);
|
||||
id, frame->frame_id,
|
||||
monitor->Id(),
|
||||
stats.zone_id_,
|
||||
stats.pixel_diff_,
|
||||
stats.alarm_pixels_,
|
||||
stats.alarm_filter_pixels_,
|
||||
stats.alarm_blob_pixels_,
|
||||
stats.alarm_blobs_,
|
||||
stats.min_blob_size_,
|
||||
stats.max_blob_size_,
|
||||
stats.alarm_box_.Lo().x_,
|
||||
stats.alarm_box_.Lo().y_,
|
||||
stats.alarm_box_.Hi().x_,
|
||||
stats.alarm_box_.Hi().y_,
|
||||
stats.score_);
|
||||
} // end foreach zone stats
|
||||
} // end if recording stats
|
||||
delete frame;
|
||||
@@ -391,19 +390,19 @@ void Event::AddFrame(const std::shared_ptr<ZMPacket>&packet) {
|
||||
|
||||
bool write_to_db = false;
|
||||
FrameType frame_type = ( ( score > 0 ) ? ALARM : (
|
||||
(
|
||||
( monitor_state == Monitor::IDLE )
|
||||
and
|
||||
( config.bulk_frame_interval > 1 )
|
||||
and
|
||||
( ! (frames % config.bulk_frame_interval) )
|
||||
) ? BULK : NORMAL
|
||||
) );
|
||||
(
|
||||
( monitor_state == Monitor::IDLE )
|
||||
and
|
||||
( config.bulk_frame_interval > 1 )
|
||||
and
|
||||
( ! (frames % config.bulk_frame_interval) )
|
||||
) ? BULK : NORMAL
|
||||
) );
|
||||
|
||||
if (frame_type == ALARM) alarm_frames++;
|
||||
|
||||
Debug(1, "Have frame type %s from score(%d) state %d frames %d bulk frame interval %d and mod%d",
|
||||
frame_type_names[frame_type], score, monitor_state, frames, config.bulk_frame_interval, (frames % config.bulk_frame_interval));
|
||||
Debug(1, "Have frame type %s from score(%d) state %d frames %d bulk frame interval %d and mod%d",
|
||||
frame_type_names[frame_type], score, monitor_state, frames, config.bulk_frame_interval, (frames % config.bulk_frame_interval));
|
||||
|
||||
if (score < 0) score = 0;
|
||||
tot_score += score;
|
||||
@@ -459,12 +458,12 @@ void Event::AddFrame(const std::shared_ptr<ZMPacket>&packet) {
|
||||
} // end if has image
|
||||
|
||||
bool db_frame = ( frame_type == BULK )
|
||||
or ( frame_type == ALARM )
|
||||
or ( frames == 1 )
|
||||
or ( score > max_score )
|
||||
or ( monitor_state == Monitor::ALERT )
|
||||
or ( monitor_state == Monitor::ALARM )
|
||||
or ( monitor_state == Monitor::PREALARM );
|
||||
or ( frame_type == ALARM )
|
||||
or ( frames == 1 )
|
||||
or ( score > max_score )
|
||||
or ( monitor_state == Monitor::ALERT )
|
||||
or ( monitor_state == Monitor::ALARM )
|
||||
or ( monitor_state == Monitor::PREALARM );
|
||||
|
||||
if (score > max_score) {
|
||||
max_score = score;
|
||||
@@ -495,14 +494,14 @@ void Event::AddFrame(const std::shared_ptr<ZMPacket>&packet) {
|
||||
last_db_frame = frames;
|
||||
|
||||
std::string sql = stringtf(
|
||||
"UPDATE Events SET Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64,
|
||||
FPSeconds(delta_time).count(),
|
||||
frames,
|
||||
alarm_frames,
|
||||
tot_score,
|
||||
static_cast<uint32>(alarm_frames ? (tot_score / alarm_frames) : 0),
|
||||
max_score,
|
||||
id);
|
||||
"UPDATE Events SET Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64,
|
||||
FPSeconds(delta_time).count(),
|
||||
frames,
|
||||
alarm_frames,
|
||||
tot_score,
|
||||
static_cast<uint32>(alarm_frames ? (tot_score / alarm_frames) : 0),
|
||||
max_score,
|
||||
id);
|
||||
dbQueue.push(std::move(sql));
|
||||
} else {
|
||||
Debug(1, "Not Adding %zu frames to DB because write_to_db:%d or frames > analysis fps %f or BULK",
|
||||
@@ -545,9 +544,9 @@ bool Event::SetPath(Storage *storage) {
|
||||
return false;
|
||||
}
|
||||
if (i == 2)
|
||||
date_path = path;
|
||||
date_path = path;
|
||||
}
|
||||
time_path = stringtf("%02d/%02d/%02d", stime.tm_hour, stime.tm_min, stime.tm_sec);
|
||||
time_path = stringtf("%02d/%02d/%02d", stime.tm_hour, stime.tm_min, stime.tm_sec);
|
||||
|
||||
// Create event id symlink
|
||||
std::string id_file = stringtf("%s/.%" PRIu64, date_path.c_str(), id);
|
||||
@@ -557,8 +556,8 @@ bool Event::SetPath(Storage *storage) {
|
||||
}
|
||||
} else if (scheme == Storage::MEDIUM) {
|
||||
path += stringtf("/%04d-%02d-%02d",
|
||||
stime.tm_year+1900, stime.tm_mon+1, stime.tm_mday
|
||||
);
|
||||
stime.tm_year+1900, stime.tm_mon+1, stime.tm_mday
|
||||
);
|
||||
if (mkdir(path.c_str(), 0755) and (errno != EEXIST)) {
|
||||
Error("Can't mkdir %s: %s", path.c_str(), strerror(errno));
|
||||
return false;
|
||||
@@ -582,7 +581,7 @@ bool Event::SetPath(Storage *storage) {
|
||||
} else {
|
||||
Error("Can't fopen %s: %s", id_file.c_str(), strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} // deep storage or not
|
||||
return true;
|
||||
} // end bool Event::SetPath
|
||||
@@ -648,13 +647,13 @@ void Event::Run() {
|
||||
if (monitor->GetOptVideoWriter() != 0) {
|
||||
/* Save as video */
|
||||
videoStore = new VideoStore(
|
||||
video_incomplete_path.c_str(),
|
||||
container.c_str(),
|
||||
monitor->GetVideoStream(),
|
||||
monitor->GetVideoCodecContext(),
|
||||
( monitor->RecordAudio() ? monitor->GetAudioStream() : nullptr ),
|
||||
( monitor->RecordAudio() ? monitor->GetAudioCodecContext() : nullptr ),
|
||||
monitor );
|
||||
video_incomplete_path.c_str(),
|
||||
container.c_str(),
|
||||
monitor->GetVideoStream(),
|
||||
monitor->GetVideoCodecContext(),
|
||||
( monitor->RecordAudio() ? monitor->GetAudioStream() : nullptr ),
|
||||
( monitor->RecordAudio() ? monitor->GetAudioCodecContext() : nullptr ),
|
||||
monitor );
|
||||
|
||||
if (!videoStore->open()) {
|
||||
Warning("Failed to open videostore, turning on jpegs");
|
||||
@@ -686,7 +685,7 @@ void Event::Run() {
|
||||
if (terminate_ or zm_terminate) break;
|
||||
packet_queue_condition.wait(lck);
|
||||
// Necessary because we don't hold the lock in the while condition
|
||||
}
|
||||
}
|
||||
if (!packet_queue.empty()) {
|
||||
packet = packet_queue.front();
|
||||
packet_queue.pop();
|
||||
|
||||
216
src/zm_event.h
216
src/zm_event.h
@@ -58,140 +58,140 @@ class Event {
|
||||
friend class EventStream;
|
||||
|
||||
public:
|
||||
typedef std::set<std::string> StringSet;
|
||||
typedef std::map<std::string,StringSet> StringSetMap;
|
||||
typedef std::set<std::string> StringSet;
|
||||
typedef std::map<std::string,StringSet> StringSetMap;
|
||||
|
||||
protected:
|
||||
static const char * frame_type_names[3];
|
||||
static const char * frame_type_names[3];
|
||||
|
||||
struct PreAlarmData {
|
||||
Image *image;
|
||||
struct timeval timestamp;
|
||||
unsigned int score;
|
||||
Image *alarm_frame;
|
||||
};
|
||||
std::queue<Frame*> frame_data;
|
||||
struct PreAlarmData {
|
||||
Image *image;
|
||||
struct timeval timestamp;
|
||||
unsigned int score;
|
||||
Image *alarm_frame;
|
||||
};
|
||||
std::queue<Frame*> frame_data;
|
||||
|
||||
static int pre_alarm_count;
|
||||
static PreAlarmData pre_alarm_data[MAX_PRE_ALARM_FRAMES];
|
||||
static int pre_alarm_count;
|
||||
static PreAlarmData pre_alarm_data[MAX_PRE_ALARM_FRAMES];
|
||||
|
||||
uint64_t id;
|
||||
Monitor *monitor;
|
||||
SystemTimePoint start_time;
|
||||
SystemTimePoint end_time;
|
||||
std::string cause;
|
||||
StringSetMap noteSetMap;
|
||||
int frames;
|
||||
int alarm_frames;
|
||||
bool alarm_frame_written;
|
||||
int tot_score;
|
||||
int max_score;
|
||||
std::string path;
|
||||
std::string snapshot_file;
|
||||
bool snapshot_file_written;
|
||||
std::string alarm_file;
|
||||
VideoStore *videoStore;
|
||||
uint64_t id;
|
||||
Monitor *monitor;
|
||||
SystemTimePoint start_time;
|
||||
SystemTimePoint end_time;
|
||||
std::string cause;
|
||||
StringSetMap noteSetMap;
|
||||
int frames;
|
||||
int alarm_frames;
|
||||
bool alarm_frame_written;
|
||||
int tot_score;
|
||||
int max_score;
|
||||
std::string path;
|
||||
std::string snapshot_file;
|
||||
bool snapshot_file_written;
|
||||
std::string alarm_file;
|
||||
VideoStore *videoStore;
|
||||
|
||||
std::string container;
|
||||
std::string codec;
|
||||
std::string video_file;
|
||||
std::string video_path;
|
||||
std::string video_incomplete_file;
|
||||
std::string video_incomplete_path;
|
||||
std::string container;
|
||||
std::string codec;
|
||||
std::string video_file;
|
||||
std::string video_path;
|
||||
std::string video_incomplete_file;
|
||||
std::string video_incomplete_path;
|
||||
|
||||
int last_db_frame;
|
||||
bool have_video_keyframe; // a flag to tell us if we have had a video keyframe when writing an mp4. The first frame SHOULD be a video keyframe.
|
||||
Storage::Schemes scheme;
|
||||
int save_jpegs;
|
||||
int last_db_frame;
|
||||
bool have_video_keyframe; // a flag to tell us if we have had a video keyframe when writing an mp4. The first frame SHOULD be a video keyframe.
|
||||
Storage::Schemes scheme;
|
||||
int save_jpegs;
|
||||
|
||||
void createNotes(std::string ¬es);
|
||||
void createNotes(std::string ¬es);
|
||||
|
||||
std::queue<std::shared_ptr<ZMPacket>> packet_queue;
|
||||
std::mutex packet_queue_mutex;
|
||||
std::condition_variable packet_queue_condition;
|
||||
std::queue<std::shared_ptr<ZMPacket>> packet_queue;
|
||||
std::mutex packet_queue_mutex;
|
||||
std::condition_variable packet_queue_condition;
|
||||
|
||||
void Run();
|
||||
void Run();
|
||||
|
||||
std::atomic<bool> terminate_;
|
||||
std::thread thread_;
|
||||
std::atomic<bool> terminate_;
|
||||
std::thread thread_;
|
||||
|
||||
public:
|
||||
static bool OpenFrameSocket(int);
|
||||
static bool ValidateFrameSocket(int);
|
||||
static bool OpenFrameSocket(int);
|
||||
static bool ValidateFrameSocket(int);
|
||||
|
||||
Event(Monitor *p_monitor,
|
||||
SystemTimePoint p_start_time,
|
||||
const std::string &p_cause,
|
||||
const StringSetMap &p_noteSetMap);
|
||||
~Event();
|
||||
Event(Monitor *p_monitor,
|
||||
SystemTimePoint p_start_time,
|
||||
const std::string &p_cause,
|
||||
const StringSetMap &p_noteSetMap);
|
||||
~Event();
|
||||
|
||||
uint64_t Id() const { return id; }
|
||||
const std::string &Cause() const { return cause; }
|
||||
void addNote(const char *cause, const std::string ¬e);
|
||||
int Frames() const { return frames; }
|
||||
int AlarmFrames() const { return alarm_frames; }
|
||||
uint64_t Id() const { return id; }
|
||||
const std::string &Cause() const { return cause; }
|
||||
void addNote(const char *cause, const std::string ¬e);
|
||||
int Frames() const { return frames; }
|
||||
int AlarmFrames() const { return alarm_frames; }
|
||||
|
||||
SystemTimePoint StartTime() const { return start_time; }
|
||||
SystemTimePoint EndTime() const { return end_time; }
|
||||
TimePoint::duration Duration() const { return end_time - start_time; };
|
||||
SystemTimePoint StartTime() const { return start_time; }
|
||||
SystemTimePoint EndTime() const { return end_time; }
|
||||
TimePoint::duration Duration() const { return end_time - start_time; };
|
||||
|
||||
void AddPacket(const std::shared_ptr<ZMPacket> &p);
|
||||
void AddPacket_(const std::shared_ptr<ZMPacket> &p);
|
||||
bool WritePacket(const std::shared_ptr<ZMPacket> &p);
|
||||
bool SendFrameImage(const Image *image, bool alarm_frame=false);
|
||||
bool WriteFrameImage(Image *image, SystemTimePoint timestamp, const char *event_file, bool alarm_frame = false) const;
|
||||
void AddPacket(const std::shared_ptr<ZMPacket> &p);
|
||||
void AddPacket_(const std::shared_ptr<ZMPacket> &p);
|
||||
bool WritePacket(const std::shared_ptr<ZMPacket> &p);
|
||||
bool SendFrameImage(const Image *image, bool alarm_frame=false);
|
||||
bool WriteFrameImage(Image *image, SystemTimePoint timestamp, const char *event_file, bool alarm_frame = false) const;
|
||||
|
||||
void updateNotes(const StringSetMap &stringSetMap);
|
||||
void updateNotes(const StringSetMap &stringSetMap);
|
||||
|
||||
void AddFrame(const std::shared_ptr<ZMPacket>&packet);
|
||||
void AddFrame(const std::shared_ptr<ZMPacket>&packet);
|
||||
|
||||
void Stop() {
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(packet_queue_mutex);
|
||||
terminate_ = true;
|
||||
}
|
||||
packet_queue_condition.notify_all();
|
||||
void Stop() {
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(packet_queue_mutex);
|
||||
terminate_ = true;
|
||||
}
|
||||
bool Stopped() const { return terminate_; }
|
||||
packet_queue_condition.notify_all();
|
||||
}
|
||||
bool Stopped() const { return terminate_; }
|
||||
|
||||
private:
|
||||
void WriteDbFrames();
|
||||
bool SetPath(Storage *storage);
|
||||
void WriteDbFrames();
|
||||
bool SetPath(Storage *storage);
|
||||
|
||||
public:
|
||||
static std::string getSubPath(tm time) {
|
||||
std::string subpath = stringtf("%02d/%02d/%02d/%02d/%02d/%02d",
|
||||
time.tm_year - 100, time.tm_mon + 1, time.tm_mday,
|
||||
time.tm_hour, time.tm_min, time.tm_sec);
|
||||
return subpath;
|
||||
}
|
||||
static std::string getSubPath(time_t *time) {
|
||||
tm time_tm = {};
|
||||
localtime_r(time, &time_tm);
|
||||
return Event::getSubPath(time_tm);
|
||||
}
|
||||
static std::string getSubPath(tm time) {
|
||||
std::string subpath = stringtf("%02d/%02d/%02d/%02d/%02d/%02d",
|
||||
time.tm_year - 100, time.tm_mon + 1, time.tm_mday,
|
||||
time.tm_hour, time.tm_min, time.tm_sec);
|
||||
return subpath;
|
||||
}
|
||||
static std::string getSubPath(time_t *time) {
|
||||
tm time_tm = {};
|
||||
localtime_r(time, &time_tm);
|
||||
return Event::getSubPath(time_tm);
|
||||
}
|
||||
|
||||
const char* getEventFile() const {
|
||||
return video_file.c_str();
|
||||
}
|
||||
const char* getEventFile() const {
|
||||
return video_file.c_str();
|
||||
}
|
||||
|
||||
static int PreAlarmCount() {
|
||||
return pre_alarm_count;
|
||||
}
|
||||
static void EmptyPreAlarmFrames() {
|
||||
pre_alarm_count = 0;
|
||||
}
|
||||
static void AddPreAlarmFrame(
|
||||
Image *image,
|
||||
SystemTimePoint timestamp,
|
||||
int score=0,
|
||||
Image *alarm_frame=nullptr
|
||||
) {
|
||||
pre_alarm_count++;
|
||||
}
|
||||
void SavePreAlarmFrames() {
|
||||
EmptyPreAlarmFrames();
|
||||
}
|
||||
int MonitorId() const;
|
||||
static int PreAlarmCount() {
|
||||
return pre_alarm_count;
|
||||
}
|
||||
static void EmptyPreAlarmFrames() {
|
||||
pre_alarm_count = 0;
|
||||
}
|
||||
static void AddPreAlarmFrame(
|
||||
Image *image,
|
||||
SystemTimePoint timestamp,
|
||||
int score=0,
|
||||
Image *alarm_frame=nullptr
|
||||
) {
|
||||
pre_alarm_count++;
|
||||
}
|
||||
void SavePreAlarmFrames() {
|
||||
EmptyPreAlarmFrames();
|
||||
}
|
||||
int MonitorId() const;
|
||||
};
|
||||
#endif // ZM_EVENT_H
|
||||
|
||||
@@ -88,9 +88,9 @@ bool EventStream::loadInitialEventData(int monitor_id, SystemTimePoint event_tim
|
||||
} // bool EventStream::loadInitialEventData( int monitor_id, time_t event_time )
|
||||
|
||||
bool EventStream::loadInitialEventData(
|
||||
uint64_t init_event_id,
|
||||
int init_frame_id
|
||||
) {
|
||||
uint64_t init_event_id,
|
||||
int init_frame_id
|
||||
) {
|
||||
loadEventData(init_event_id);
|
||||
|
||||
if ( init_frame_id ) {
|
||||
@@ -111,10 +111,10 @@ bool EventStream::loadInitialEventData(
|
||||
|
||||
bool EventStream::loadEventData(uint64_t event_id) {
|
||||
std::string sql = stringtf(
|
||||
"SELECT `MonitorId`, `StorageId`, `Frames`, unix_timestamp( `StartDateTime` ) AS StartTimestamp, "
|
||||
"unix_timestamp( `EndDateTime` ) AS EndTimestamp, "
|
||||
"(SELECT max(`Delta`)-min(`Delta`) FROM `Frames` WHERE `EventId`=`Events`.`Id`) AS FramesDuration, "
|
||||
"`DefaultVideo`, `Scheme`, `SaveJPEGs`, `Orientation`+0 FROM `Events` WHERE `Id` = %" PRIu64, event_id);
|
||||
"SELECT `MonitorId`, `StorageId`, `Frames`, unix_timestamp( `StartDateTime` ) AS StartTimestamp, "
|
||||
"unix_timestamp( `EndDateTime` ) AS EndTimestamp, "
|
||||
"(SELECT max(`Delta`)-min(`Delta`) FROM `Frames` WHERE `EventId`=`Events`.`Id`) AS FramesDuration, "
|
||||
"`DefaultVideo`, `Scheme`, `SaveJPEGs`, `Orientation`+0 FROM `Events` WHERE `Id` = %" PRIu64, event_id);
|
||||
|
||||
MYSQL_RES *result = zmDbFetch(sql);
|
||||
if (!result) {
|
||||
@@ -142,7 +142,7 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
||||
event_data->end_time = dbrow[4] ? SystemTimePoint(Seconds(atoi(dbrow[4]))) : std::chrono::system_clock::now();
|
||||
event_data->duration = std::chrono::duration_cast<Microseconds>(event_data->end_time - event_data->start_time);
|
||||
event_data->frames_duration =
|
||||
std::chrono::duration_cast<Microseconds>(dbrow[5] ? FPSeconds(atof(dbrow[5])) : FPSeconds(0.0));
|
||||
std::chrono::duration_cast<Microseconds>(dbrow[5] ? FPSeconds(atof(dbrow[5])) : FPSeconds(0.0));
|
||||
event_data->video_file = std::string(dbrow[6]);
|
||||
std::string scheme_str = std::string(dbrow[7]);
|
||||
if ( scheme_str == "Deep" ) {
|
||||
@@ -232,7 +232,7 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
||||
if (event_data->frame_count < event_data->n_frames) {
|
||||
event_data->frame_count = event_data->n_frames;
|
||||
Warning("Event %" PRId64 " has more frames in the Frames table (%d) than in the Event record (%d)",
|
||||
event_data->event_id, event_data->n_frames, event_data->frame_count);
|
||||
event_data->event_id, event_data->n_frames, event_data->frame_count);
|
||||
}
|
||||
event_data->frames.clear();
|
||||
event_data->frames.reserve(event_data->frame_count);
|
||||
@@ -253,20 +253,20 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
||||
|
||||
int id_diff = id - last_id;
|
||||
Microseconds delta =
|
||||
std::chrono::duration_cast<Microseconds>(id_diff ? (offset - last_offset) / id_diff : (offset - last_offset));
|
||||
std::chrono::duration_cast<Microseconds>(id_diff ? (offset - last_offset) / id_diff : (offset - last_offset));
|
||||
Debug(4, "New delta %f from id_diff %d = id %d - last_id %d offset %f - last)_offset %f",
|
||||
FPSeconds(delta).count(), id_diff, id, last_id, FPSeconds(offset).count(), FPSeconds(last_offset).count());
|
||||
FPSeconds(delta).count(), id_diff, id, last_id, FPSeconds(offset).count(), FPSeconds(last_offset).count());
|
||||
|
||||
// Fill in data between bulk frames
|
||||
if (id_diff > 1) {
|
||||
for (int i = last_id + 1; i < id; i++) {
|
||||
auto frame = event_data->frames.emplace_back(
|
||||
i,
|
||||
last_timestamp + ((i - last_id) * delta),
|
||||
std::chrono::duration_cast<Microseconds>((last_frame->timestamp - event_data->start_time) + delta),
|
||||
delta,
|
||||
false
|
||||
);
|
||||
i,
|
||||
last_timestamp + ((i - last_id) * delta),
|
||||
std::chrono::duration_cast<Microseconds>((last_frame->timestamp - event_data->start_time) + delta),
|
||||
delta,
|
||||
false
|
||||
);
|
||||
last_frame = &frame;
|
||||
Debug(4, "Frame %d %d timestamp (%f s), offset (%f s) delta (%f s), in_db (%d)",
|
||||
i, frame.id,
|
||||
@@ -291,17 +291,17 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
||||
|
||||
if (event_data->end_time.time_since_epoch() != Seconds(0)) {
|
||||
Microseconds delta = (last_frame && (last_frame->delta > Microseconds(0)))
|
||||
? last_frame->delta
|
||||
: Microseconds( static_cast<int>(1000000 * base_fps / FPSeconds(event_data->duration).count()) );
|
||||
? last_frame->delta
|
||||
: Microseconds( static_cast<int>(1000000 * base_fps / FPSeconds(event_data->duration).count()) );
|
||||
if (!last_frame) {
|
||||
// There were no frames in db
|
||||
auto frame = event_data->frames.emplace_back(
|
||||
1,
|
||||
event_data->start_time,
|
||||
Microseconds(0),
|
||||
Microseconds(0),
|
||||
false
|
||||
);
|
||||
1,
|
||||
event_data->start_time,
|
||||
Microseconds(0),
|
||||
Microseconds(0),
|
||||
false
|
||||
);
|
||||
last_frame = &frame;
|
||||
last_id ++;
|
||||
last_timestamp = event_data->start_time;
|
||||
@@ -313,19 +313,19 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
||||
last_id ++;
|
||||
|
||||
auto frame = event_data->frames.emplace_back(
|
||||
last_id,
|
||||
last_timestamp,
|
||||
last_frame->offset + delta,
|
||||
delta,
|
||||
false
|
||||
);
|
||||
last_id,
|
||||
last_timestamp,
|
||||
last_frame->offset + delta,
|
||||
delta,
|
||||
false
|
||||
);
|
||||
last_frame = &frame;
|
||||
Debug(3, "Trailing Frame %d timestamp (%f s), offset (%f s), delta(%f s), in_db(%d)",
|
||||
last_id,
|
||||
FPSeconds(frame.timestamp.time_since_epoch()).count(),
|
||||
FPSeconds(frame.offset).count(),
|
||||
FPSeconds(frame.delta).count(),
|
||||
frame.in_db);
|
||||
last_id,
|
||||
FPSeconds(frame.timestamp.time_since_epoch()).count(),
|
||||
FPSeconds(frame.offset).count(),
|
||||
FPSeconds(frame.delta).count(),
|
||||
frame.in_db);
|
||||
event_data->frame_count ++;
|
||||
} // end while
|
||||
} // end if have endtime
|
||||
@@ -377,258 +377,252 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
||||
Debug(2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0]);
|
||||
// Check for incoming command
|
||||
switch ((MsgCommand)msg->msg_data[0]) {
|
||||
case CMD_PAUSE :
|
||||
Debug(1, "Got PAUSE command");
|
||||
paused = true;
|
||||
break;
|
||||
case CMD_PLAY :
|
||||
{
|
||||
std::scoped_lock lck{mutex};
|
||||
Debug(1, "Got PLAY command");
|
||||
paused = false;
|
||||
case CMD_PAUSE :
|
||||
Debug(1, "Got PAUSE command");
|
||||
paused = true;
|
||||
break;
|
||||
case CMD_PLAY : {
|
||||
std::scoped_lock lck{mutex};
|
||||
Debug(1, "Got PLAY command");
|
||||
paused = false;
|
||||
|
||||
// If we are in single event mode and at the last frame, replay the current event
|
||||
if (
|
||||
(mode == MODE_SINGLE || mode == MODE_NONE)
|
||||
&&
|
||||
(curr_frame_id == event_data->last_frame_id)
|
||||
) {
|
||||
Debug(1, "Was in single or no replay mode, and at last frame, so jumping to 1st frame");
|
||||
curr_frame_id = 1;
|
||||
} else {
|
||||
Debug(1, "mode is %s, current frame is %d, frame count is %d, last frame id is %d",
|
||||
StreamMode_Strings[(int) mode].c_str(),
|
||||
curr_frame_id,
|
||||
event_data->frame_count,
|
||||
event_data->last_frame_id);
|
||||
}
|
||||
// If we are in single event mode and at the last frame, replay the current event
|
||||
if (
|
||||
(mode == MODE_SINGLE || mode == MODE_NONE)
|
||||
&&
|
||||
(curr_frame_id == event_data->last_frame_id)
|
||||
) {
|
||||
Debug(1, "Was in single or no replay mode, and at last frame, so jumping to 1st frame");
|
||||
curr_frame_id = 1;
|
||||
} else {
|
||||
Debug(1, "mode is %s, current frame is %d, frame count is %d, last frame id is %d",
|
||||
StreamMode_Strings[(int) mode].c_str(),
|
||||
curr_frame_id,
|
||||
event_data->frame_count,
|
||||
event_data->last_frame_id);
|
||||
}
|
||||
|
||||
replay_rate = ZM_RATE_BASE;
|
||||
break;
|
||||
}
|
||||
case CMD_VARPLAY :
|
||||
{
|
||||
std::scoped_lock lck{mutex};
|
||||
Debug(1, "Got VARPLAY command");
|
||||
paused = false;
|
||||
replay_rate = ntohs(((unsigned char)msg->msg_data[2]<<8)|(unsigned char)msg->msg_data[1])-32768;
|
||||
if (replay_rate > 50 * ZM_RATE_BASE) {
|
||||
Warning("requested replay rate (%d) is too high. We only support up to 50x", replay_rate);
|
||||
replay_rate = 50 * ZM_RATE_BASE;
|
||||
} else if (replay_rate < -50*ZM_RATE_BASE) {
|
||||
Warning("requested replay rate (%d) is too low. We only support up to -50x", replay_rate);
|
||||
replay_rate = -50 * ZM_RATE_BASE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMD_STOP :
|
||||
Debug(1, "Got STOP command");
|
||||
paused = false;
|
||||
break;
|
||||
case CMD_FASTFWD :
|
||||
{
|
||||
Debug(1, "Got FAST FWD command");
|
||||
std::scoped_lock lck{mutex};
|
||||
paused = false;
|
||||
// Set play rate
|
||||
switch (replay_rate) {
|
||||
case 2 * ZM_RATE_BASE :
|
||||
replay_rate = 5 * ZM_RATE_BASE;
|
||||
break;
|
||||
case 5 * ZM_RATE_BASE :
|
||||
replay_rate = 10 * ZM_RATE_BASE;
|
||||
break;
|
||||
case 10 * ZM_RATE_BASE :
|
||||
replay_rate = 25 * ZM_RATE_BASE;
|
||||
break;
|
||||
case 25 * ZM_RATE_BASE :
|
||||
case 50 * ZM_RATE_BASE :
|
||||
replay_rate = 50 * ZM_RATE_BASE;
|
||||
break;
|
||||
default :
|
||||
Debug(1,"Defaulting replay_rate to 2*ZM_RATE_BASE because it is %d", replay_rate);
|
||||
replay_rate = 2 * ZM_RATE_BASE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMD_SLOWFWD :
|
||||
{
|
||||
std::scoped_lock lck{mutex};
|
||||
paused = true;
|
||||
replay_rate = ZM_RATE_BASE;
|
||||
step = 1;
|
||||
if (curr_frame_id < event_data->last_frame_id)
|
||||
curr_frame_id += 1;
|
||||
Debug(1, "Got SLOWFWD command new frame id %d", curr_frame_id);
|
||||
break;
|
||||
}
|
||||
case CMD_SLOWREV :
|
||||
{
|
||||
std::scoped_lock lck{mutex};
|
||||
paused = true;
|
||||
replay_rate = ZM_RATE_BASE;
|
||||
step = -1;
|
||||
if (curr_frame_id > 1) curr_frame_id -= 1;
|
||||
Debug(1, "Got SLOWREV command new frame id %d", curr_frame_id);
|
||||
break;
|
||||
}
|
||||
case CMD_FASTREV :
|
||||
Debug(1, "Got FAST REV command");
|
||||
paused = false;
|
||||
// Set play rate
|
||||
switch (replay_rate) {
|
||||
case -1 * ZM_RATE_BASE :
|
||||
replay_rate = -2 * ZM_RATE_BASE;
|
||||
break;
|
||||
case -2 * ZM_RATE_BASE :
|
||||
replay_rate = -5 * ZM_RATE_BASE;
|
||||
break;
|
||||
case -5 * ZM_RATE_BASE :
|
||||
replay_rate = -10 * ZM_RATE_BASE;
|
||||
break;
|
||||
case -10 * ZM_RATE_BASE :
|
||||
replay_rate = -25 * ZM_RATE_BASE;
|
||||
break;
|
||||
case -25 * ZM_RATE_BASE :
|
||||
case -50 * ZM_RATE_BASE :
|
||||
replay_rate = -50 * ZM_RATE_BASE;
|
||||
break;
|
||||
default :
|
||||
replay_rate = -1 * ZM_RATE_BASE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case CMD_ZOOMIN :
|
||||
x = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2];
|
||||
y = ((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4];
|
||||
Debug(1, "Got ZOOM IN command, to %d,%d", x, y);
|
||||
zoom += 10;
|
||||
send_frame = true;
|
||||
if (paused) {
|
||||
step = 1;
|
||||
send_twice = true;
|
||||
}
|
||||
break;
|
||||
case CMD_ZOOMOUT :
|
||||
Debug(1, "Got ZOOM OUT command");
|
||||
zoom -= 10;
|
||||
if (zoom < 100) zoom = 100;
|
||||
send_frame = true;
|
||||
if (paused) {
|
||||
step = 1;
|
||||
send_twice = true;
|
||||
}
|
||||
break;
|
||||
case CMD_ZOOMSTOP :
|
||||
Debug(1, "Got ZOOM STOP command");
|
||||
zoom = 100;
|
||||
send_frame = true;
|
||||
if (paused) {
|
||||
step = 1;
|
||||
send_twice = true;
|
||||
}
|
||||
break;
|
||||
case CMD_PAN :
|
||||
x = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2];
|
||||
y = ((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4];
|
||||
Debug(1, "Got PAN command, to %d,%d", x, y);
|
||||
break;
|
||||
case CMD_SCALE :
|
||||
scale = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2];
|
||||
Debug(1, "Got SCALE command, to %d", scale);
|
||||
break;
|
||||
case CMD_PREV :
|
||||
Debug(1, "Got PREV command");
|
||||
curr_frame_id = replay_rate >= 0 ? 1 : event_data->last_frame_id+1;
|
||||
paused = false;
|
||||
forceEventChange = true;
|
||||
break;
|
||||
case CMD_NEXT :
|
||||
Debug(1, "Got NEXT command");
|
||||
curr_frame_id = replay_rate >= 0 ? event_data->last_frame_id+1 : 1;
|
||||
paused = false;
|
||||
forceEventChange = true;
|
||||
break;
|
||||
case CMD_SEEK :
|
||||
{
|
||||
double int_part = ((unsigned char) msg->msg_data[1] << 24) | ((unsigned char) msg->msg_data[2] << 16)
|
||||
| ((unsigned char) msg->msg_data[3] << 8) | (unsigned char) msg->msg_data[4];
|
||||
double dec_part = ((unsigned char) msg->msg_data[5] << 24) | ((unsigned char) msg->msg_data[6] << 16)
|
||||
| ((unsigned char) msg->msg_data[7] << 8) | (unsigned char) msg->msg_data[8];
|
||||
replay_rate = ZM_RATE_BASE;
|
||||
break;
|
||||
}
|
||||
case CMD_VARPLAY : {
|
||||
std::scoped_lock lck{mutex};
|
||||
Debug(1, "Got VARPLAY command");
|
||||
paused = false;
|
||||
replay_rate = ntohs(((unsigned char)msg->msg_data[2]<<8)|(unsigned char)msg->msg_data[1])-32768;
|
||||
if (replay_rate > 50 * ZM_RATE_BASE) {
|
||||
Warning("requested replay rate (%d) is too high. We only support up to 50x", replay_rate);
|
||||
replay_rate = 50 * ZM_RATE_BASE;
|
||||
} else if (replay_rate < -50*ZM_RATE_BASE) {
|
||||
Warning("requested replay rate (%d) is too low. We only support up to -50x", replay_rate);
|
||||
replay_rate = -50 * ZM_RATE_BASE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMD_STOP :
|
||||
Debug(1, "Got STOP command");
|
||||
paused = false;
|
||||
break;
|
||||
case CMD_FASTFWD : {
|
||||
Debug(1, "Got FAST FWD command");
|
||||
std::scoped_lock lck{mutex};
|
||||
paused = false;
|
||||
// Set play rate
|
||||
switch (replay_rate) {
|
||||
case 2 * ZM_RATE_BASE :
|
||||
replay_rate = 5 * ZM_RATE_BASE;
|
||||
break;
|
||||
case 5 * ZM_RATE_BASE :
|
||||
replay_rate = 10 * ZM_RATE_BASE;
|
||||
break;
|
||||
case 10 * ZM_RATE_BASE :
|
||||
replay_rate = 25 * ZM_RATE_BASE;
|
||||
break;
|
||||
case 25 * ZM_RATE_BASE :
|
||||
case 50 * ZM_RATE_BASE :
|
||||
replay_rate = 50 * ZM_RATE_BASE;
|
||||
break;
|
||||
default :
|
||||
Debug(1,"Defaulting replay_rate to 2*ZM_RATE_BASE because it is %d", replay_rate);
|
||||
replay_rate = 2 * ZM_RATE_BASE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMD_SLOWFWD : {
|
||||
std::scoped_lock lck{mutex};
|
||||
paused = true;
|
||||
replay_rate = ZM_RATE_BASE;
|
||||
step = 1;
|
||||
if (curr_frame_id < event_data->last_frame_id)
|
||||
curr_frame_id += 1;
|
||||
Debug(1, "Got SLOWFWD command new frame id %d", curr_frame_id);
|
||||
break;
|
||||
}
|
||||
case CMD_SLOWREV : {
|
||||
std::scoped_lock lck{mutex};
|
||||
paused = true;
|
||||
replay_rate = ZM_RATE_BASE;
|
||||
step = -1;
|
||||
if (curr_frame_id > 1) curr_frame_id -= 1;
|
||||
Debug(1, "Got SLOWREV command new frame id %d", curr_frame_id);
|
||||
break;
|
||||
}
|
||||
case CMD_FASTREV :
|
||||
Debug(1, "Got FAST REV command");
|
||||
paused = false;
|
||||
// Set play rate
|
||||
switch (replay_rate) {
|
||||
case -1 * ZM_RATE_BASE :
|
||||
replay_rate = -2 * ZM_RATE_BASE;
|
||||
break;
|
||||
case -2 * ZM_RATE_BASE :
|
||||
replay_rate = -5 * ZM_RATE_BASE;
|
||||
break;
|
||||
case -5 * ZM_RATE_BASE :
|
||||
replay_rate = -10 * ZM_RATE_BASE;
|
||||
break;
|
||||
case -10 * ZM_RATE_BASE :
|
||||
replay_rate = -25 * ZM_RATE_BASE;
|
||||
break;
|
||||
case -25 * ZM_RATE_BASE :
|
||||
case -50 * ZM_RATE_BASE :
|
||||
replay_rate = -50 * ZM_RATE_BASE;
|
||||
break;
|
||||
default :
|
||||
replay_rate = -1 * ZM_RATE_BASE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case CMD_ZOOMIN :
|
||||
x = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2];
|
||||
y = ((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4];
|
||||
Debug(1, "Got ZOOM IN command, to %d,%d", x, y);
|
||||
zoom += 10;
|
||||
send_frame = true;
|
||||
if (paused) {
|
||||
step = 1;
|
||||
send_twice = true;
|
||||
}
|
||||
break;
|
||||
case CMD_ZOOMOUT :
|
||||
Debug(1, "Got ZOOM OUT command");
|
||||
zoom -= 10;
|
||||
if (zoom < 100) zoom = 100;
|
||||
send_frame = true;
|
||||
if (paused) {
|
||||
step = 1;
|
||||
send_twice = true;
|
||||
}
|
||||
break;
|
||||
case CMD_ZOOMSTOP :
|
||||
Debug(1, "Got ZOOM STOP command");
|
||||
zoom = 100;
|
||||
send_frame = true;
|
||||
if (paused) {
|
||||
step = 1;
|
||||
send_twice = true;
|
||||
}
|
||||
break;
|
||||
case CMD_PAN :
|
||||
x = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2];
|
||||
y = ((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4];
|
||||
Debug(1, "Got PAN command, to %d,%d", x, y);
|
||||
break;
|
||||
case CMD_SCALE :
|
||||
scale = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2];
|
||||
Debug(1, "Got SCALE command, to %d", scale);
|
||||
break;
|
||||
case CMD_PREV :
|
||||
Debug(1, "Got PREV command");
|
||||
curr_frame_id = replay_rate >= 0 ? 1 : event_data->last_frame_id+1;
|
||||
paused = false;
|
||||
forceEventChange = true;
|
||||
break;
|
||||
case CMD_NEXT :
|
||||
Debug(1, "Got NEXT command");
|
||||
curr_frame_id = replay_rate >= 0 ? event_data->last_frame_id+1 : 1;
|
||||
paused = false;
|
||||
forceEventChange = true;
|
||||
break;
|
||||
case CMD_SEEK : {
|
||||
double int_part = ((unsigned char) msg->msg_data[1] << 24) | ((unsigned char) msg->msg_data[2] << 16)
|
||||
| ((unsigned char) msg->msg_data[3] << 8) | (unsigned char) msg->msg_data[4];
|
||||
double dec_part = ((unsigned char) msg->msg_data[5] << 24) | ((unsigned char) msg->msg_data[6] << 16)
|
||||
| ((unsigned char) msg->msg_data[7] << 8) | (unsigned char) msg->msg_data[8];
|
||||
|
||||
FPSeconds offset = FPSeconds(int_part + dec_part / 1000000.0);
|
||||
if (offset < Seconds(0)) {
|
||||
Warning("Invalid offset, not seeking");
|
||||
break;
|
||||
} else if (offset > event_data->duration) {
|
||||
Warning("Invalid offset past end of event, seeking to end");
|
||||
offset = event_data->duration;
|
||||
}
|
||||
FPSeconds offset = FPSeconds(int_part + dec_part / 1000000.0);
|
||||
if (offset < Seconds(0)) {
|
||||
Warning("Invalid offset, not seeking");
|
||||
break;
|
||||
} else if (offset > event_data->duration) {
|
||||
Warning("Invalid offset past end of event, seeking to end");
|
||||
offset = event_data->duration;
|
||||
}
|
||||
|
||||
std::scoped_lock lck{mutex};
|
||||
// This should get us close, but not all frames will have the same duration
|
||||
curr_frame_id = (int) (event_data->frame_count * offset / event_data->duration) + 1;
|
||||
if (curr_frame_id < 1) {
|
||||
Debug(1, "curr_frame_id = %d, so setting to 1", curr_frame_id);
|
||||
curr_frame_id = 1;
|
||||
} else if (curr_frame_id > event_data->last_frame_id) {
|
||||
curr_frame_id = event_data->last_frame_id;
|
||||
}
|
||||
std::scoped_lock lck{mutex};
|
||||
// This should get us close, but not all frames will have the same duration
|
||||
curr_frame_id = (int) (event_data->frame_count * offset / event_data->duration) + 1;
|
||||
if (curr_frame_id < 1) {
|
||||
Debug(1, "curr_frame_id = %d, so setting to 1", curr_frame_id);
|
||||
curr_frame_id = 1;
|
||||
} else if (curr_frame_id > event_data->last_frame_id) {
|
||||
curr_frame_id = event_data->last_frame_id;
|
||||
}
|
||||
|
||||
// TODO Replace this with a binary search
|
||||
if (event_data->frames[curr_frame_id - 1].offset > offset) {
|
||||
Debug(1, "Searching for frame at %.6f, offset of frame %d is %.6f",
|
||||
// TODO Replace this with a binary search
|
||||
if (event_data->frames[curr_frame_id - 1].offset > offset) {
|
||||
Debug(1, "Searching for frame at %.6f, offset of frame %d is %.6f",
|
||||
FPSeconds(offset).count(),
|
||||
curr_frame_id,
|
||||
FPSeconds(event_data->frames[curr_frame_id - 1].offset).count()
|
||||
);
|
||||
while ((curr_frame_id--) && (event_data->frames[curr_frame_id - 1].offset > offset)) {
|
||||
Debug(1, "Searching for frame at %.6f, offset of frame %d is %.6f",
|
||||
FPSeconds(offset).count(),
|
||||
curr_frame_id,
|
||||
FPSeconds(event_data->frames[curr_frame_id - 1].offset).count()
|
||||
);
|
||||
while ((curr_frame_id--) && (event_data->frames[curr_frame_id - 1].offset > offset)) {
|
||||
Debug(1, "Searching for frame at %.6f, offset of frame %d is %.6f",
|
||||
FPSeconds(offset).count(),
|
||||
curr_frame_id,
|
||||
FPSeconds(event_data->frames[curr_frame_id - 1].offset).count()
|
||||
);
|
||||
}
|
||||
} else if (event_data->frames[curr_frame_id - 1].offset < offset) {
|
||||
while ((curr_frame_id++ < event_data->last_frame_id) && (event_data->frames[curr_frame_id - 1].offset < offset)) {
|
||||
Debug(1, "Searching for frame at %.6f, offset of frame %d is %.6f",
|
||||
FPSeconds(offset).count(),
|
||||
curr_frame_id,
|
||||
FPSeconds(event_data->frames[curr_frame_id - 1].offset).count()
|
||||
);
|
||||
}
|
||||
curr_frame_id--;
|
||||
}
|
||||
|
||||
if (curr_frame_id < 1) {
|
||||
Debug(1, "curr_frame_id = %d, so setting to 1", curr_frame_id);
|
||||
curr_frame_id = 1;
|
||||
} else if (curr_frame_id > event_data->last_frame_id) {
|
||||
curr_frame_id = event_data->last_frame_id;
|
||||
}
|
||||
|
||||
curr_stream_time = event_data->frames[curr_frame_id-1].timestamp;
|
||||
Debug(1, "Got SEEK command, to %f s (new current frame id: %d offset %f s)",
|
||||
);
|
||||
}
|
||||
} else if (event_data->frames[curr_frame_id - 1].offset < offset) {
|
||||
while ((curr_frame_id++ < event_data->last_frame_id) && (event_data->frames[curr_frame_id - 1].offset < offset)) {
|
||||
Debug(1, "Searching for frame at %.6f, offset of frame %d is %.6f",
|
||||
FPSeconds(offset).count(),
|
||||
curr_frame_id,
|
||||
FPSeconds(event_data->frames[curr_frame_id - 1].offset).count());
|
||||
if (paused) {
|
||||
step = 1; // if we are paused, we won't send a frame except a keepalive.
|
||||
send_twice = true;
|
||||
}
|
||||
send_frame = true;
|
||||
break;
|
||||
FPSeconds(event_data->frames[curr_frame_id - 1].offset).count()
|
||||
);
|
||||
}
|
||||
case CMD_QUERY :
|
||||
Debug(1, "Got QUERY command, sending STATUS");
|
||||
break;
|
||||
case CMD_QUIT :
|
||||
Info("User initiated exit - CMD_QUIT");
|
||||
break;
|
||||
default :
|
||||
// Do nothing, for now
|
||||
break;
|
||||
curr_frame_id--;
|
||||
}
|
||||
|
||||
if (curr_frame_id < 1) {
|
||||
Debug(1, "curr_frame_id = %d, so setting to 1", curr_frame_id);
|
||||
curr_frame_id = 1;
|
||||
} else if (curr_frame_id > event_data->last_frame_id) {
|
||||
curr_frame_id = event_data->last_frame_id;
|
||||
}
|
||||
|
||||
curr_stream_time = event_data->frames[curr_frame_id-1].timestamp;
|
||||
Debug(1, "Got SEEK command, to %f s (new current frame id: %d offset %f s)",
|
||||
FPSeconds(offset).count(),
|
||||
curr_frame_id,
|
||||
FPSeconds(event_data->frames[curr_frame_id - 1].offset).count());
|
||||
if (paused) {
|
||||
step = 1; // if we are paused, we won't send a frame except a keepalive.
|
||||
send_twice = true;
|
||||
}
|
||||
send_frame = true;
|
||||
break;
|
||||
}
|
||||
case CMD_QUERY :
|
||||
Debug(1, "Got QUERY command, sending STATUS");
|
||||
break;
|
||||
case CMD_QUIT :
|
||||
Info("User initiated exit - CMD_QUIT");
|
||||
break;
|
||||
default :
|
||||
// Do nothing, for now
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -657,14 +651,14 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
||||
status_data.scale = scale;
|
||||
status_data.paused = paused;
|
||||
Debug(2, "Event:%" PRIu64 ", Duration %f, Paused:%d, progress:%f Rate:%d, Zoom:%d Scale:%d",
|
||||
status_data.event_id,
|
||||
FPSeconds(status_data.duration).count(),
|
||||
status_data.paused,
|
||||
FPSeconds(status_data.progress).count(),
|
||||
status_data.rate,
|
||||
status_data.zoom,
|
||||
status_data.scale
|
||||
);
|
||||
status_data.event_id,
|
||||
FPSeconds(status_data.duration).count(),
|
||||
status_data.paused,
|
||||
FPSeconds(status_data.progress).count(),
|
||||
status_data.rate,
|
||||
status_data.zoom,
|
||||
status_data.scale
|
||||
);
|
||||
double fps = 1.0;
|
||||
if ((event_data->frame_count and event_data->duration != Seconds(0))) {
|
||||
fps = static_cast<double>(event_data->frame_count) / FPSeconds(event_data->duration).count();
|
||||
@@ -695,8 +689,8 @@ bool EventStream::checkEventLoaded() {
|
||||
|
||||
if (curr_frame_id <= 0) {
|
||||
sql = stringtf(
|
||||
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %d AND `Id` < %" PRIu64 " ORDER BY `Id` DESC LIMIT 1",
|
||||
event_data->monitor_id, event_data->event_id);
|
||||
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %d AND `Id` < %" PRIu64 " ORDER BY `Id` DESC LIMIT 1",
|
||||
event_data->monitor_id, event_data->event_id);
|
||||
} else if (curr_frame_id > event_data->last_frame_id) {
|
||||
if (event_data->end_time.time_since_epoch() == Seconds(0)) {
|
||||
// We are viewing an in-process event, so just reload it.
|
||||
@@ -706,12 +700,12 @@ bool EventStream::checkEventLoaded() {
|
||||
return false;
|
||||
}
|
||||
sql = stringtf(
|
||||
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %d AND `Id` > %" PRIu64 " ORDER BY `Id` ASC LIMIT 1",
|
||||
event_data->monitor_id, event_data->event_id);
|
||||
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %d AND `Id` > %" PRIu64 " ORDER BY `Id` ASC LIMIT 1",
|
||||
event_data->monitor_id, event_data->event_id);
|
||||
} else {
|
||||
// No event change required
|
||||
Debug(4, "No event change required, as curr frame %d <=> event frames %d",
|
||||
curr_frame_id, event_data->frame_count);
|
||||
curr_frame_id, event_data->frame_count);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -798,7 +792,7 @@ bool EventStream::sendFrame(Microseconds delta_us) {
|
||||
|
||||
if ( !vid_stream ) {
|
||||
vid_stream = new VideoStream("pipe:", format, bitrate, effective_fps,
|
||||
send_image->Colours(), send_image->SubpixelOrder(), send_image->Width(), send_image->Height());
|
||||
send_image->Colours(), send_image->SubpixelOrder(), send_image->Width(), send_image->Height());
|
||||
fprintf(stdout, "Content-type: %s\r\n\r\n", vid_stream->MimeType());
|
||||
vid_stream->OpenStream();
|
||||
}
|
||||
@@ -824,8 +818,8 @@ bool EventStream::sendFrame(Microseconds delta_us) {
|
||||
// Get the frame from the mp4 input
|
||||
const FrameData *frame_data = &event_data->frames[curr_frame_id-1];
|
||||
AVFrame *frame = ffmpeg_input->get_frame(
|
||||
ffmpeg_input->get_video_stream_id(),
|
||||
FPSeconds(frame_data->offset).count());
|
||||
ffmpeg_input->get_video_stream_id(),
|
||||
FPSeconds(frame_data->offset).count());
|
||||
if (frame) {
|
||||
image = new Image(frame, monitor->Width(), monitor->Height());
|
||||
} else {
|
||||
@@ -836,26 +830,26 @@ bool EventStream::sendFrame(Microseconds delta_us) {
|
||||
// when stored as an mp4, we just have the rotation as a flag in the headers
|
||||
// so we need to rotate it before outputting
|
||||
if (
|
||||
(monitor->GetOptVideoWriter() == Monitor::PASSTHROUGH)
|
||||
and
|
||||
(event_data->Orientation != Monitor::ROTATE_0)
|
||||
) {
|
||||
(monitor->GetOptVideoWriter() == Monitor::PASSTHROUGH)
|
||||
and
|
||||
(event_data->Orientation != Monitor::ROTATE_0)
|
||||
) {
|
||||
Debug(2, "Rotating image %d", event_data->Orientation);
|
||||
switch ( event_data->Orientation ) {
|
||||
case Monitor::ROTATE_0 :
|
||||
// No action required
|
||||
break;
|
||||
case Monitor::ROTATE_90 :
|
||||
case Monitor::ROTATE_180 :
|
||||
case Monitor::ROTATE_270 :
|
||||
image->Rotate((event_data->Orientation-1)*90);
|
||||
break;
|
||||
case Monitor::FLIP_HORI :
|
||||
case Monitor::FLIP_VERT :
|
||||
image->Flip(event_data->Orientation==Monitor::FLIP_HORI);
|
||||
break;
|
||||
default:
|
||||
Error("Invalid Orientation: %d", event_data->Orientation);
|
||||
case Monitor::ROTATE_0 :
|
||||
// No action required
|
||||
break;
|
||||
case Monitor::ROTATE_90 :
|
||||
case Monitor::ROTATE_180 :
|
||||
case Monitor::ROTATE_270 :
|
||||
image->Rotate((event_data->Orientation-1)*90);
|
||||
break;
|
||||
case Monitor::FLIP_HORI :
|
||||
case Monitor::FLIP_VERT :
|
||||
image->Flip(event_data->Orientation==Monitor::FLIP_HORI);
|
||||
break;
|
||||
default:
|
||||
Error("Invalid Orientation: %d", event_data->Orientation);
|
||||
}
|
||||
} else {
|
||||
Debug(2, "Not Rotating image %d", event_data->Orientation);
|
||||
@@ -872,24 +866,24 @@ bool EventStream::sendFrame(Microseconds delta_us) {
|
||||
|
||||
fprintf(stdout, "--" BOUNDARY "\r\n");
|
||||
switch ( type ) {
|
||||
case STREAM_JPEG :
|
||||
send_image->EncodeJpeg(img_buffer, &img_buffer_size);
|
||||
fputs("Content-Type: image/jpeg\r\n", stdout);
|
||||
break;
|
||||
case STREAM_ZIP :
|
||||
unsigned long zip_buffer_size;
|
||||
send_image->Zip(img_buffer, &zip_buffer_size);
|
||||
img_buffer_size = zip_buffer_size;
|
||||
fputs("Content-Type: image/x-rgbz\r\n", stdout);
|
||||
break;
|
||||
case STREAM_RAW :
|
||||
img_buffer = send_image->Buffer();
|
||||
img_buffer_size = send_image->Size();
|
||||
fputs("Content-Type: image/x-rgb\r\n", stdout);
|
||||
break;
|
||||
default:
|
||||
Fatal("Unexpected frame type %d", type);
|
||||
break;
|
||||
case STREAM_JPEG :
|
||||
send_image->EncodeJpeg(img_buffer, &img_buffer_size);
|
||||
fputs("Content-Type: image/jpeg\r\n", stdout);
|
||||
break;
|
||||
case STREAM_ZIP :
|
||||
unsigned long zip_buffer_size;
|
||||
send_image->Zip(img_buffer, &zip_buffer_size);
|
||||
img_buffer_size = zip_buffer_size;
|
||||
fputs("Content-Type: image/x-rgbz\r\n", stdout);
|
||||
break;
|
||||
case STREAM_RAW :
|
||||
img_buffer = send_image->Buffer();
|
||||
img_buffer_size = send_image->Size();
|
||||
fputs("Content-Type: image/x-rgb\r\n", stdout);
|
||||
break;
|
||||
default:
|
||||
Fatal("Unexpected frame type %d", type);
|
||||
break;
|
||||
}
|
||||
int rc = send_buffer(img_buffer, img_buffer_size);
|
||||
delete image;
|
||||
@@ -932,7 +926,7 @@ void EventStream::runStream() {
|
||||
command_processor = std::thread(&EventStream::checkCommandQueue, this);
|
||||
}
|
||||
|
||||
// Has to go here, at the moment, for sendFrame(delta).
|
||||
// Has to go here, at the moment, for sendFrame(delta).
|
||||
Microseconds delta = Microseconds(0);
|
||||
|
||||
while (!zm_terminate) {
|
||||
@@ -951,7 +945,7 @@ void EventStream::runStream() {
|
||||
// so if it is 2, then we send every other frame, if is it 4 then every fourth frame, etc.
|
||||
|
||||
//if ( (frame_mod == 1) || (((curr_frame_id-1)%frame_mod) == 0) ) {
|
||||
send_frame = true;
|
||||
send_frame = true;
|
||||
//}
|
||||
} else if (step != 0) {
|
||||
Debug(2, "Paused with step %d", step);
|
||||
@@ -975,8 +969,8 @@ void EventStream::runStream() {
|
||||
char frame_text[64];
|
||||
|
||||
snprintf(frame_text, sizeof(frame_text), "Time to %s event = %f s",
|
||||
(replay_rate > 0 ? "next" : "previous"),
|
||||
FPSeconds(time_to_event).count());
|
||||
(replay_rate > 0 ? "next" : "previous"),
|
||||
FPSeconds(time_to_event).count());
|
||||
|
||||
if (!sendTextFrame(frame_text)) {
|
||||
zm_terminate = true;
|
||||
@@ -987,7 +981,7 @@ void EventStream::runStream() {
|
||||
|
||||
// FIXME ICON But we are not paused. We are somehow still in the event?
|
||||
Milliseconds sleep_time = std::chrono::duration_cast<Milliseconds>(
|
||||
(replay_rate > 0 ? 1 : -1) * ((1.0L * replay_rate * STREAM_PAUSE_WAIT) / ZM_RATE_BASE));
|
||||
(replay_rate > 0 ? 1 : -1) * ((1.0L * replay_rate * STREAM_PAUSE_WAIT) / ZM_RATE_BASE));
|
||||
if (sleep_time == Seconds(0)) {
|
||||
sleep_time += STREAM_PAUSE_WAIT;
|
||||
}
|
||||
@@ -995,8 +989,8 @@ void EventStream::runStream() {
|
||||
curr_stream_time += sleep_time;
|
||||
time_to_event -= sleep_time;
|
||||
Debug(2, "Sleeping (%" PRIi64 " ms) because we are not at the next event yet, adding %" PRIi64 " ms",
|
||||
static_cast<int64>(Milliseconds(STREAM_PAUSE_WAIT).count()),
|
||||
static_cast<int64>(Milliseconds(sleep_time).count()));
|
||||
static_cast<int64>(Milliseconds(STREAM_PAUSE_WAIT).count()),
|
||||
static_cast<int64>(Milliseconds(sleep_time).count()));
|
||||
std::this_thread::sleep_for(STREAM_PAUSE_WAIT);
|
||||
|
||||
continue;
|
||||
@@ -1026,7 +1020,7 @@ void EventStream::runStream() {
|
||||
// we incremented by replay_rate, so might have jumped past frame_count
|
||||
if ((mode == MODE_SINGLE) && (
|
||||
(curr_frame_id < 1 ) || (curr_frame_id >= event_data->frame_count)
|
||||
)
|
||||
)
|
||||
) {
|
||||
Debug(2, "Have mode==MODE_SINGLE and at end of event, looping back to start");
|
||||
curr_frame_id = 1;
|
||||
@@ -1035,11 +1029,11 @@ void EventStream::runStream() {
|
||||
if (curr_frame_id <= event_data->frame_count) {
|
||||
const FrameData *next_frame_data = &event_data->frames[curr_frame_id-1];
|
||||
Debug(3, "Have Frame %d %d timestamp (%f s), offset (%f s) delta (%f s), in_db (%d)",
|
||||
curr_frame_id, next_frame_data->id,
|
||||
FPSeconds(next_frame_data->timestamp.time_since_epoch()).count(),
|
||||
FPSeconds(next_frame_data->offset).count(),
|
||||
FPSeconds(next_frame_data->delta).count(),
|
||||
next_frame_data->in_db);
|
||||
curr_frame_id, next_frame_data->id,
|
||||
FPSeconds(next_frame_data->timestamp.time_since_epoch()).count(),
|
||||
FPSeconds(next_frame_data->offset).count(),
|
||||
FPSeconds(next_frame_data->delta).count(),
|
||||
next_frame_data->in_db);
|
||||
|
||||
// frame_data->delta is the time since last frame as a float in seconds
|
||||
// but what if we are skipping frames? We need the distance from the last frame sent
|
||||
@@ -1047,34 +1041,34 @@ void EventStream::runStream() {
|
||||
|
||||
delta = abs(next_frame_data->offset - last_frame_data->offset);
|
||||
Debug(2, "New delta: %fs from last frame offset %fs - next_frame_offset %fs",
|
||||
FPSeconds(delta).count(),
|
||||
FPSeconds(last_frame_data->offset).count(),
|
||||
FPSeconds(next_frame_data->offset).count());
|
||||
FPSeconds(delta).count(),
|
||||
FPSeconds(last_frame_data->offset).count(),
|
||||
FPSeconds(next_frame_data->offset).count());
|
||||
// if effective > base we should speed up frame delivery
|
||||
if (base_fps < effective_fps) {
|
||||
delta = std::chrono::duration_cast<Microseconds>((delta * base_fps) / effective_fps);
|
||||
Debug(3, "delta %" PRIi64 " us = base_fps (%f) / effective_fps (%f)",
|
||||
static_cast<int64>(std::chrono::duration_cast<Microseconds>(delta).count()),
|
||||
base_fps,
|
||||
effective_fps);
|
||||
static_cast<int64>(std::chrono::duration_cast<Microseconds>(delta).count()),
|
||||
base_fps,
|
||||
effective_fps);
|
||||
|
||||
// but must not exceed maxfps
|
||||
delta = std::max(delta, Microseconds(lround(Microseconds::period::den / maxfps)));
|
||||
Debug(3, "delta %" PRIi64 " us = base_fps (%f) / effective_fps (%f) from 30fps",
|
||||
static_cast<int64>(std::chrono::duration_cast<Microseconds>(delta).count()),
|
||||
base_fps,
|
||||
effective_fps);
|
||||
static_cast<int64>(std::chrono::duration_cast<Microseconds>(delta).count()),
|
||||
base_fps,
|
||||
effective_fps);
|
||||
}
|
||||
now = std::chrono::steady_clock::now();
|
||||
TimePoint::duration elapsed = now - start;
|
||||
delta -= std::chrono::duration_cast<Microseconds>(elapsed); // sending frames takes time, so remove it from the sleep time
|
||||
|
||||
Debug(2, "New delta: %fs from last frame offset %fs - next_frame_offset %fs - elapsed %fs",
|
||||
FPSeconds(delta).count(),
|
||||
FPSeconds(last_frame_data->offset).count(),
|
||||
FPSeconds(next_frame_data->offset).count(),
|
||||
FPSeconds(elapsed).count()
|
||||
);
|
||||
FPSeconds(delta).count(),
|
||||
FPSeconds(last_frame_data->offset).count(),
|
||||
FPSeconds(next_frame_data->offset).count(),
|
||||
FPSeconds(elapsed).count()
|
||||
);
|
||||
} // end if not at end of event
|
||||
} else {
|
||||
// Paused
|
||||
@@ -1091,8 +1085,8 @@ void EventStream::runStream() {
|
||||
if (delta > Seconds(0)) {
|
||||
if (delta > MAX_SLEEP) {
|
||||
Debug(1, "Limiting sleep to %" PRIi64 " ms because calculated sleep is too long %" PRIi64,
|
||||
static_cast<int64>(std::chrono::duration_cast<Milliseconds>(MAX_SLEEP).count()),
|
||||
static_cast<int64>(std::chrono::duration_cast<Microseconds>(delta).count()));
|
||||
static_cast<int64>(std::chrono::duration_cast<Milliseconds>(MAX_SLEEP).count()),
|
||||
static_cast<int64>(std::chrono::duration_cast<Microseconds>(delta).count()));
|
||||
delta = MAX_SLEEP;
|
||||
}
|
||||
|
||||
@@ -1112,18 +1106,18 @@ void EventStream::runStream() {
|
||||
// This doesn't make sense unless we have hit the end of the event.
|
||||
time_to_event = event_data->frames[0].timestamp - curr_stream_time;
|
||||
Debug(1, "replay rate (%d) time_to_event (%f s) = frame timestamp (%f s) - curr_stream_time (%f s)",
|
||||
replay_rate,
|
||||
FPSeconds(time_to_event).count(),
|
||||
FPSeconds(event_data->frames[0].timestamp.time_since_epoch()).count(),
|
||||
FPSeconds(curr_stream_time.time_since_epoch()).count());
|
||||
replay_rate,
|
||||
FPSeconds(time_to_event).count(),
|
||||
FPSeconds(event_data->frames[0].timestamp.time_since_epoch()).count(),
|
||||
FPSeconds(curr_stream_time.time_since_epoch()).count());
|
||||
|
||||
} else if (replay_rate < 0) {
|
||||
time_to_event = curr_stream_time - event_data->frames[event_data->frame_count-1].timestamp;
|
||||
Debug(1, "replay rate (%d), time_to_event(%f s) = curr_stream_time (%f s) - frame timestamp (%f s)",
|
||||
replay_rate,
|
||||
FPSeconds(time_to_event).count(),
|
||||
FPSeconds(curr_stream_time.time_since_epoch()).count(),
|
||||
FPSeconds(event_data->frames[event_data->frame_count - 1].timestamp.time_since_epoch()).count());
|
||||
replay_rate,
|
||||
FPSeconds(time_to_event).count(),
|
||||
FPSeconds(curr_stream_time.time_since_epoch()).count(),
|
||||
FPSeconds(event_data->frames[event_data->frame_count - 1].timestamp.time_since_epoch()).count());
|
||||
} // end if forward or reverse
|
||||
} // end if checkEventLoaded
|
||||
} // end scope for lock
|
||||
@@ -1173,7 +1167,7 @@ bool EventStream::send_file(const std::string &filepath) {
|
||||
if (rc < 0) break;
|
||||
if (rc > 0) {
|
||||
remaining -= rc;
|
||||
}
|
||||
}
|
||||
} // end while remaining
|
||||
|
||||
if (!remaining) {
|
||||
@@ -1182,7 +1176,7 @@ bool EventStream::send_file(const std::string &filepath) {
|
||||
return true;
|
||||
}
|
||||
Warning("Unable to send raw frame %d: %s %zu remaining",
|
||||
curr_frame_id, strerror(errno), remaining);
|
||||
curr_frame_id, strerror(errno), remaining);
|
||||
return false;
|
||||
} // end bool EventStream::send_file(const std::string &filepath)
|
||||
|
||||
@@ -1201,8 +1195,8 @@ bool EventStream::send_buffer(uint8_t* buffer, int size) {
|
||||
} // end bool EventStream::send_buffer(uint8_t* buffer, int size)
|
||||
|
||||
void EventStream::setStreamStart(
|
||||
uint64_t init_event_id,
|
||||
int init_frame_id=0) {
|
||||
uint64_t init_event_id,
|
||||
int init_frame_id=0) {
|
||||
loadInitialEventData(init_event_id, init_frame_id);
|
||||
} // end void EventStream::setStreamStart(init_event_id,init_frame_id=0)
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Core Interfaces, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_EVENTSTREAM_H
|
||||
#define ZM_EVENTSTREAM_H
|
||||
@@ -35,98 +35,97 @@ extern "C" {
|
||||
#include <mutex>
|
||||
|
||||
class EventStream : public StreamBase {
|
||||
public:
|
||||
typedef enum { MODE_NONE, MODE_SINGLE, MODE_ALL, MODE_ALL_GAPLESS } StreamMode;
|
||||
static const std::string StreamMode_Strings[4];
|
||||
public:
|
||||
typedef enum { MODE_NONE, MODE_SINGLE, MODE_ALL, MODE_ALL_GAPLESS } StreamMode;
|
||||
static const std::string StreamMode_Strings[4];
|
||||
|
||||
protected:
|
||||
struct FrameData {
|
||||
unsigned int id;
|
||||
SystemTimePoint timestamp;
|
||||
Microseconds offset; // distance from event->starttime
|
||||
Microseconds delta; // distance from last frame
|
||||
bool in_db;
|
||||
public:
|
||||
FrameData(unsigned int p_id, SystemTimePoint p_timestamp, Microseconds p_offset, Microseconds p_delta, bool p_in_db) :
|
||||
id(p_id),
|
||||
timestamp(p_timestamp),
|
||||
offset(p_offset),
|
||||
delta(p_delta),
|
||||
in_db(p_in_db)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct EventData {
|
||||
uint64_t event_id;
|
||||
unsigned int monitor_id;
|
||||
unsigned int storage_id;
|
||||
int frame_count; // Value of Frames column in Event
|
||||
int last_frame_id; // Highest frame id known about. Can be < frame_count in incomplete events
|
||||
SystemTimePoint start_time;
|
||||
SystemTimePoint end_time;
|
||||
Microseconds duration;
|
||||
Microseconds frames_duration;
|
||||
std::string path;
|
||||
int n_frames; // # of frame rows returned from database
|
||||
std::vector<FrameData> frames;
|
||||
std::string video_file;
|
||||
Storage::Schemes scheme;
|
||||
int SaveJPEGs;
|
||||
Monitor::Orientation Orientation;
|
||||
};
|
||||
|
||||
protected:
|
||||
static constexpr Milliseconds STREAM_PAUSE_WAIT = Milliseconds(250);
|
||||
|
||||
static const StreamMode DEFAULT_MODE = MODE_SINGLE;
|
||||
|
||||
StreamMode mode;
|
||||
bool forceEventChange;
|
||||
|
||||
std::mutex mutex;
|
||||
int curr_frame_id;
|
||||
SystemTimePoint curr_stream_time;
|
||||
bool send_frame;
|
||||
TimePoint start; // clock time when started the event
|
||||
|
||||
EventData *event_data;
|
||||
|
||||
protected:
|
||||
bool loadEventData(uint64_t event_id);
|
||||
bool loadInitialEventData(uint64_t init_event_id, int init_frame_id);
|
||||
bool loadInitialEventData(int monitor_id, SystemTimePoint event_time);
|
||||
|
||||
bool checkEventLoaded();
|
||||
void processCommand(const CmdMsg *msg) override;
|
||||
bool sendFrame(Microseconds delta);
|
||||
|
||||
public:
|
||||
EventStream() :
|
||||
mode(DEFAULT_MODE),
|
||||
forceEventChange(false),
|
||||
curr_frame_id(0),
|
||||
send_frame(false),
|
||||
event_data(nullptr),
|
||||
storage(nullptr),
|
||||
ffmpeg_input(nullptr)
|
||||
{}
|
||||
|
||||
~EventStream() {
|
||||
delete event_data;
|
||||
delete storage;
|
||||
delete ffmpeg_input;
|
||||
protected:
|
||||
struct FrameData {
|
||||
unsigned int id;
|
||||
SystemTimePoint timestamp;
|
||||
Microseconds offset; // distance from event->starttime
|
||||
Microseconds delta; // distance from last frame
|
||||
bool in_db;
|
||||
public:
|
||||
FrameData(unsigned int p_id, SystemTimePoint p_timestamp, Microseconds p_offset, Microseconds p_delta, bool p_in_db) :
|
||||
id(p_id),
|
||||
timestamp(p_timestamp),
|
||||
offset(p_offset),
|
||||
delta(p_delta),
|
||||
in_db(p_in_db) {
|
||||
}
|
||||
void setStreamStart(uint64_t init_event_id, int init_frame_id);
|
||||
void setStreamStart(int monitor_id, time_t event_time);
|
||||
void setStreamMode(StreamMode p_mode) { mode = p_mode; }
|
||||
void runStream() override;
|
||||
Image *getImage();
|
||||
private:
|
||||
bool send_file(const std::string &filepath);
|
||||
bool send_buffer(uint8_t * buffer, int size);
|
||||
Storage *storage;
|
||||
FFmpeg_Input *ffmpeg_input;
|
||||
};
|
||||
|
||||
struct EventData {
|
||||
uint64_t event_id;
|
||||
unsigned int monitor_id;
|
||||
unsigned int storage_id;
|
||||
int frame_count; // Value of Frames column in Event
|
||||
int last_frame_id; // Highest frame id known about. Can be < frame_count in incomplete events
|
||||
SystemTimePoint start_time;
|
||||
SystemTimePoint end_time;
|
||||
Microseconds duration;
|
||||
Microseconds frames_duration;
|
||||
std::string path;
|
||||
int n_frames; // # of frame rows returned from database
|
||||
std::vector<FrameData> frames;
|
||||
std::string video_file;
|
||||
Storage::Schemes scheme;
|
||||
int SaveJPEGs;
|
||||
Monitor::Orientation Orientation;
|
||||
};
|
||||
|
||||
protected:
|
||||
static constexpr Milliseconds STREAM_PAUSE_WAIT = Milliseconds(250);
|
||||
|
||||
static const StreamMode DEFAULT_MODE = MODE_SINGLE;
|
||||
|
||||
StreamMode mode;
|
||||
bool forceEventChange;
|
||||
|
||||
std::mutex mutex;
|
||||
int curr_frame_id;
|
||||
SystemTimePoint curr_stream_time;
|
||||
bool send_frame;
|
||||
TimePoint start; // clock time when started the event
|
||||
|
||||
EventData *event_data;
|
||||
|
||||
protected:
|
||||
bool loadEventData(uint64_t event_id);
|
||||
bool loadInitialEventData(uint64_t init_event_id, int init_frame_id);
|
||||
bool loadInitialEventData(int monitor_id, SystemTimePoint event_time);
|
||||
|
||||
bool checkEventLoaded();
|
||||
void processCommand(const CmdMsg *msg) override;
|
||||
bool sendFrame(Microseconds delta);
|
||||
|
||||
public:
|
||||
EventStream() :
|
||||
mode(DEFAULT_MODE),
|
||||
forceEventChange(false),
|
||||
curr_frame_id(0),
|
||||
send_frame(false),
|
||||
event_data(nullptr),
|
||||
storage(nullptr),
|
||||
ffmpeg_input(nullptr)
|
||||
{}
|
||||
|
||||
~EventStream() {
|
||||
delete event_data;
|
||||
delete storage;
|
||||
delete ffmpeg_input;
|
||||
}
|
||||
void setStreamStart(uint64_t init_event_id, int init_frame_id);
|
||||
void setStreamStart(int monitor_id, time_t event_time);
|
||||
void setStreamMode(StreamMode p_mode) { mode = p_mode; }
|
||||
void runStream() override;
|
||||
Image *getImage();
|
||||
private:
|
||||
bool send_file(const std::string &filepath);
|
||||
bool send_buffer(uint8_t * buffer, int size);
|
||||
Storage *storage;
|
||||
FFmpeg_Input *ffmpeg_input;
|
||||
};
|
||||
|
||||
#endif // ZM_EVENTSTREAM_H
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Exception 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_exception.h"
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Exception Class Interface, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_EXCEPTION_H
|
||||
#define ZM_EXCEPTION_H
|
||||
@@ -23,18 +23,17 @@
|
||||
#include <string>
|
||||
|
||||
class Exception {
|
||||
protected:
|
||||
protected:
|
||||
typedef enum { INFO, WARNING, ERROR, FATAL } Severity;
|
||||
|
||||
protected:
|
||||
protected:
|
||||
std::string mMessage;
|
||||
Severity mSeverity;
|
||||
|
||||
public:
|
||||
public:
|
||||
explicit Exception(const std::string &message, const Severity severity=ERROR) :
|
||||
mMessage(message),
|
||||
mSeverity(severity)
|
||||
{
|
||||
mSeverity(severity) {
|
||||
}
|
||||
|
||||
const std::string &getMessage() const {
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* ZoneMinder FFMPEG 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_ffmpeg.h"
|
||||
|
||||
@@ -79,7 +79,7 @@ void FFMPEGInit() {
|
||||
if (!bInit) {
|
||||
if (logDebugging() && config.log_ffmpeg) {
|
||||
av_log_set_level(AV_LOG_DEBUG);
|
||||
av_log_set_callback(log_libav_callback);
|
||||
av_log_set_callback(log_libav_callback);
|
||||
Info("Enabling ffmpeg logs, as LOG_DEBUG+LOG_FFMPEG are enabled in options");
|
||||
} else {
|
||||
Debug(1,"Not enabling ffmpeg logs, as LOG_FFMPEG and/or LOG_DEBUG is disabled in options, or this monitor is not part of your debug targets");
|
||||
@@ -104,44 +104,44 @@ enum _AVPIXELFORMAT GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subp
|
||||
Debug(8,"Colours: %d SubpixelOrder: %d",p_colours,p_subpixelorder);
|
||||
|
||||
switch (p_colours) {
|
||||
case ZM_COLOUR_RGB24:
|
||||
if(p_subpixelorder == ZM_SUBPIX_ORDER_BGR) {
|
||||
/* BGR subpixel order */
|
||||
pf = AV_PIX_FMT_BGR24;
|
||||
} else {
|
||||
/* Assume RGB subpixel order */
|
||||
pf = AV_PIX_FMT_RGB24;
|
||||
}
|
||||
break;
|
||||
case ZM_COLOUR_RGB32:
|
||||
if (p_subpixelorder == ZM_SUBPIX_ORDER_ARGB) {
|
||||
/* ARGB subpixel order */
|
||||
pf = AV_PIX_FMT_ARGB;
|
||||
} else if (p_subpixelorder == ZM_SUBPIX_ORDER_ABGR) {
|
||||
/* ABGR subpixel order */
|
||||
pf = AV_PIX_FMT_ABGR;
|
||||
} else if (p_subpixelorder == ZM_SUBPIX_ORDER_BGRA) {
|
||||
/* BGRA subpixel order */
|
||||
pf = AV_PIX_FMT_BGRA;
|
||||
} else {
|
||||
/* Assume RGBA subpixel order */
|
||||
pf = AV_PIX_FMT_RGBA;
|
||||
}
|
||||
break;
|
||||
case ZM_COLOUR_GRAY8:
|
||||
pf = AV_PIX_FMT_GRAY8;
|
||||
break;
|
||||
default:
|
||||
Panic("Unexpected colours: %d", p_colours);
|
||||
pf = AV_PIX_FMT_GRAY8; /* Just to shush gcc variable may be unused warning */
|
||||
break;
|
||||
case ZM_COLOUR_RGB24:
|
||||
if(p_subpixelorder == ZM_SUBPIX_ORDER_BGR) {
|
||||
/* BGR subpixel order */
|
||||
pf = AV_PIX_FMT_BGR24;
|
||||
} else {
|
||||
/* Assume RGB subpixel order */
|
||||
pf = AV_PIX_FMT_RGB24;
|
||||
}
|
||||
break;
|
||||
case ZM_COLOUR_RGB32:
|
||||
if (p_subpixelorder == ZM_SUBPIX_ORDER_ARGB) {
|
||||
/* ARGB subpixel order */
|
||||
pf = AV_PIX_FMT_ARGB;
|
||||
} else if (p_subpixelorder == ZM_SUBPIX_ORDER_ABGR) {
|
||||
/* ABGR subpixel order */
|
||||
pf = AV_PIX_FMT_ABGR;
|
||||
} else if (p_subpixelorder == ZM_SUBPIX_ORDER_BGRA) {
|
||||
/* BGRA subpixel order */
|
||||
pf = AV_PIX_FMT_BGRA;
|
||||
} else {
|
||||
/* Assume RGBA subpixel order */
|
||||
pf = AV_PIX_FMT_RGBA;
|
||||
}
|
||||
break;
|
||||
case ZM_COLOUR_GRAY8:
|
||||
pf = AV_PIX_FMT_GRAY8;
|
||||
break;
|
||||
default:
|
||||
Panic("Unexpected colours: %d", p_colours);
|
||||
pf = AV_PIX_FMT_GRAY8; /* Just to shush gcc variable may be unused warning */
|
||||
break;
|
||||
}
|
||||
|
||||
return pf;
|
||||
}
|
||||
|
||||
#if LIBAVUTIL_VERSION_CHECK(56, 0, 0, 17, 100)
|
||||
int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb){
|
||||
int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb) {
|
||||
int64_t a, b, this_thing;
|
||||
|
||||
av_assert0(in_ts != AV_NOPTS_VALUE);
|
||||
@@ -180,65 +180,65 @@ static void zm_log_fps(double d, const char *postfix) {
|
||||
|
||||
void zm_dump_codecpar(const AVCodecParameters *par) {
|
||||
Debug(1, "Dumping codecpar codec_type %d %s codec_id %d %s codec_tag %" PRIu32
|
||||
" width %d height %d bit_rate%" PRIu64 " bpcs %d bprs %d format%d %s"
|
||||
" extradata:%d:%s profile %d level %d field order %d color_range %d"
|
||||
" color_primaries %d color_trc %d color_space %d location %d video_delay %d",
|
||||
static_cast<int>(par->codec_type),
|
||||
av_get_media_type_string(par->codec_type),
|
||||
static_cast<int>(par->codec_id),
|
||||
avcodec_get_name(par->codec_id),
|
||||
par->codec_tag,
|
||||
par->width,
|
||||
par->height,
|
||||
par->bit_rate,
|
||||
par->bits_per_coded_sample,
|
||||
par->bits_per_raw_sample,
|
||||
par->format,
|
||||
(((AVPixelFormat)par->format == AV_PIX_FMT_NONE) ? "none" : av_get_pix_fmt_name((AVPixelFormat)par->format)),
|
||||
par->extradata_size, ByteArrayToHexString(nonstd::span<const uint8>{
|
||||
par->extradata,
|
||||
static_cast<nonstd::span_lite::span<const unsigned char>::size_type>(par->extradata_size)
|
||||
}).c_str(),
|
||||
par->profile,
|
||||
par->level,
|
||||
static_cast<int>(par->field_order),
|
||||
static_cast<int>(par->color_range),
|
||||
static_cast<int>(par->color_primaries),
|
||||
static_cast<int>(par->color_trc),
|
||||
static_cast<int>(par->color_space),
|
||||
static_cast<int>(par->chroma_location),
|
||||
static_cast<int>(par->video_delay)
|
||||
);
|
||||
" width %d height %d bit_rate%" PRIu64 " bpcs %d bprs %d format%d %s"
|
||||
" extradata:%d:%s profile %d level %d field order %d color_range %d"
|
||||
" color_primaries %d color_trc %d color_space %d location %d video_delay %d",
|
||||
static_cast<int>(par->codec_type),
|
||||
av_get_media_type_string(par->codec_type),
|
||||
static_cast<int>(par->codec_id),
|
||||
avcodec_get_name(par->codec_id),
|
||||
par->codec_tag,
|
||||
par->width,
|
||||
par->height,
|
||||
par->bit_rate,
|
||||
par->bits_per_coded_sample,
|
||||
par->bits_per_raw_sample,
|
||||
par->format,
|
||||
(((AVPixelFormat)par->format == AV_PIX_FMT_NONE) ? "none" : av_get_pix_fmt_name((AVPixelFormat)par->format)),
|
||||
par->extradata_size, ByteArrayToHexString(nonstd::span<const uint8> {
|
||||
par->extradata,
|
||||
static_cast<nonstd::span_lite::span<const unsigned char>::size_type>(par->extradata_size)
|
||||
}).c_str(),
|
||||
par->profile,
|
||||
par->level,
|
||||
static_cast<int>(par->field_order),
|
||||
static_cast<int>(par->color_range),
|
||||
static_cast<int>(par->color_primaries),
|
||||
static_cast<int>(par->color_trc),
|
||||
static_cast<int>(par->color_space),
|
||||
static_cast<int>(par->chroma_location),
|
||||
static_cast<int>(par->video_delay)
|
||||
);
|
||||
}
|
||||
|
||||
void zm_dump_codec(const AVCodecContext *codec) {
|
||||
Debug(1, "Dumping codec_context codec_type %d %s codec_id %d %s width %d height %d timebase %d/%d format %s profile %d level %d "
|
||||
"gop_size %d has_b_frames %d max_b_frames %d me_cmp %d me_range %d qmin %d qmax %d bit_rate %" PRId64 " extradata:%d:%s",
|
||||
codec->codec_type,
|
||||
av_get_media_type_string(codec->codec_type),
|
||||
codec->codec_id,
|
||||
avcodec_get_name(codec->codec_id),
|
||||
codec->width,
|
||||
codec->height,
|
||||
codec->time_base.num,
|
||||
codec->time_base.den,
|
||||
(codec->pix_fmt == AV_PIX_FMT_NONE ? "none" : av_get_pix_fmt_name(codec->pix_fmt)),
|
||||
codec->profile,
|
||||
codec->level,
|
||||
codec->gop_size,
|
||||
codec->has_b_frames,
|
||||
codec->max_b_frames,
|
||||
codec->me_cmp,
|
||||
codec->me_range,
|
||||
codec->qmin,
|
||||
codec->qmax,
|
||||
codec->bit_rate,
|
||||
codec->extradata_size,
|
||||
ByteArrayToHexString(nonstd::span<const uint8>{
|
||||
codec->extradata,
|
||||
static_cast<nonstd::span_lite::span<const unsigned char>::size_type>(codec->extradata_size)
|
||||
}).c_str()
|
||||
);
|
||||
"gop_size %d has_b_frames %d max_b_frames %d me_cmp %d me_range %d qmin %d qmax %d bit_rate %" PRId64 " extradata:%d:%s",
|
||||
codec->codec_type,
|
||||
av_get_media_type_string(codec->codec_type),
|
||||
codec->codec_id,
|
||||
avcodec_get_name(codec->codec_id),
|
||||
codec->width,
|
||||
codec->height,
|
||||
codec->time_base.num,
|
||||
codec->time_base.den,
|
||||
(codec->pix_fmt == AV_PIX_FMT_NONE ? "none" : av_get_pix_fmt_name(codec->pix_fmt)),
|
||||
codec->profile,
|
||||
codec->level,
|
||||
codec->gop_size,
|
||||
codec->has_b_frames,
|
||||
codec->max_b_frames,
|
||||
codec->me_cmp,
|
||||
codec->me_range,
|
||||
codec->qmin,
|
||||
codec->qmax,
|
||||
codec->bit_rate,
|
||||
codec->extradata_size,
|
||||
ByteArrayToHexString(nonstd::span<const uint8> {
|
||||
codec->extradata,
|
||||
static_cast<nonstd::span_lite::span<const unsigned char>::size_type>(codec->extradata_size)
|
||||
}).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
/* "user interface" functions */
|
||||
@@ -258,30 +258,30 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output)
|
||||
if (lang)
|
||||
Debug(1, "language (%s)", lang->value);
|
||||
Debug(1, "frame_size:%d stream timebase: %d/%d",
|
||||
codec->frame_size,
|
||||
st->time_base.num, st->time_base.den
|
||||
);
|
||||
codec->frame_size,
|
||||
st->time_base.num, st->time_base.den
|
||||
);
|
||||
|
||||
Debug(1, "codec: %s %s",
|
||||
avcodec_get_name(st->codecpar->codec_id),
|
||||
av_get_media_type_string(st->codecpar->codec_type)
|
||||
);
|
||||
avcodec_get_name(st->codecpar->codec_id),
|
||||
av_get_media_type_string(st->codecpar->codec_type)
|
||||
);
|
||||
|
||||
if (st->sample_aspect_ratio.num && // default
|
||||
av_cmp_q(st->sample_aspect_ratio, codec->sample_aspect_ratio)
|
||||
) {
|
||||
) {
|
||||
AVRational display_aspect_ratio;
|
||||
av_reduce(&display_aspect_ratio.num,
|
||||
&display_aspect_ratio.den,
|
||||
codec->width * (int64_t)st->sample_aspect_ratio.num,
|
||||
codec->height * (int64_t)st->sample_aspect_ratio.den,
|
||||
1024 * 1024);
|
||||
&display_aspect_ratio.den,
|
||||
codec->width * (int64_t)st->sample_aspect_ratio.num,
|
||||
codec->height * (int64_t)st->sample_aspect_ratio.den,
|
||||
1024 * 1024);
|
||||
Debug(1, ", SAR %d:%d DAR %d:%d",
|
||||
st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
|
||||
display_aspect_ratio.num, display_aspect_ratio.den);
|
||||
st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
|
||||
display_aspect_ratio.num, display_aspect_ratio.den);
|
||||
} else {
|
||||
Debug(1, ", SAR %d:%d ",
|
||||
st->sample_aspect_ratio.num, st->sample_aspect_ratio.den);
|
||||
st->sample_aspect_ratio.num, st->sample_aspect_ratio.den);
|
||||
}
|
||||
|
||||
if (codec->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
@@ -295,10 +295,10 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output)
|
||||
} else if (codec->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||
#if LIBAVUTIL_VERSION_CHECK(57, 28, 100, 28, 0)
|
||||
Debug(1, "profile %d channels %d sample_rate %d",
|
||||
codec->profile, codec->ch_layout.nb_channels, codec->sample_rate);
|
||||
codec->profile, codec->ch_layout.nb_channels, codec->sample_rate);
|
||||
#else
|
||||
Debug(1, "profile %d channels %d sample_rate %d",
|
||||
codec->profile, codec->channels, codec->sample_rate);
|
||||
codec->profile, codec->channels, codec->sample_rate);
|
||||
#endif
|
||||
} else {
|
||||
Debug(1, "Unknown codec type %d", codec->codec_type);
|
||||
@@ -345,17 +345,17 @@ int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt) {
|
||||
enum AVPixelFormat fix_deprecated_pix_fmt(enum AVPixelFormat fmt) {
|
||||
// Fix deprecated formats
|
||||
switch ( fmt ) {
|
||||
case AV_PIX_FMT_YUVJ422P :
|
||||
return AV_PIX_FMT_YUV422P;
|
||||
case AV_PIX_FMT_YUVJ444P :
|
||||
return AV_PIX_FMT_YUV444P;
|
||||
case AV_PIX_FMT_YUVJ440P :
|
||||
return AV_PIX_FMT_YUV440P;
|
||||
case AV_PIX_FMT_NONE :
|
||||
case AV_PIX_FMT_YUVJ420P :
|
||||
return AV_PIX_FMT_YUV420P;
|
||||
default:
|
||||
return fmt;
|
||||
case AV_PIX_FMT_YUVJ422P :
|
||||
return AV_PIX_FMT_YUV422P;
|
||||
case AV_PIX_FMT_YUVJ444P :
|
||||
return AV_PIX_FMT_YUV444P;
|
||||
case AV_PIX_FMT_YUVJ440P :
|
||||
return AV_PIX_FMT_YUV440P;
|
||||
case AV_PIX_FMT_NONE :
|
||||
case AV_PIX_FMT_YUVJ420P :
|
||||
return AV_PIX_FMT_YUV420P;
|
||||
default:
|
||||
return fmt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,11 +399,11 @@ int zm_send_packet_receive_frame(AVCodecContext *context, AVFrame *frame, AVPack
|
||||
return packet.size;
|
||||
} else if (pkt_ret != 0 && pkt_ret != AVERROR(EAGAIN)) {
|
||||
Error("Could not send packet (error %d = %s)", pkt_ret,
|
||||
av_make_error_string(pkt_ret).c_str());
|
||||
av_make_error_string(pkt_ret).c_str());
|
||||
return pkt_ret;
|
||||
} else if (frm_ret != 0 && frm_ret != AVERROR(EAGAIN)) {
|
||||
Error("Could not receive frame (error %d = %s)", frm_ret,
|
||||
av_make_error_string(frm_ret).c_str());
|
||||
av_make_error_string(frm_ret).c_str());
|
||||
return frm_ret;
|
||||
}
|
||||
|
||||
@@ -459,14 +459,14 @@ int zm_resample_audio(SwrContext *resample_ctx, AVFrame *in_frame, AVFrame *out_
|
||||
// Resample the in_frame into the audioSampleBuffer until we process the whole
|
||||
// decoded data. Note: pts does not survive resampling or converting
|
||||
Debug(2, "Converting %d to %d samples using swresample",
|
||||
in_frame->nb_samples, out_frame->nb_samples);
|
||||
in_frame->nb_samples, out_frame->nb_samples);
|
||||
} else {
|
||||
Debug(2, "Sending NULL frame to flush resampler");
|
||||
}
|
||||
int ret = swr_convert_frame(resample_ctx, out_frame, in_frame);
|
||||
if (ret < 0) {
|
||||
Error("Could not resample frame (error '%s')",
|
||||
av_make_error_string(ret).c_str());
|
||||
av_make_error_string(ret).c_str());
|
||||
return 0;
|
||||
}
|
||||
Debug(3, "swr_get_delay %" PRIi64, swr_get_delay(resample_ctx, out_frame->sample_rate));
|
||||
@@ -482,14 +482,14 @@ int zm_add_samples_to_fifo(AVAudioFifo *fifo, AVFrame *frame) {
|
||||
int ret = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + frame->nb_samples);
|
||||
if (ret < 0) {
|
||||
Error("Could not reallocate FIFO to %d samples",
|
||||
av_audio_fifo_size(fifo) + frame->nb_samples);
|
||||
av_audio_fifo_size(fifo) + frame->nb_samples);
|
||||
return 0;
|
||||
}
|
||||
/** Store the new samples in the FIFO buffer. */
|
||||
ret = av_audio_fifo_write(fifo, (void **)frame->data, frame->nb_samples);
|
||||
if (ret < frame->nb_samples) {
|
||||
Error("Could not write data to FIFO. %d written, expecting %d. Reason %s",
|
||||
ret, frame->nb_samples, av_make_error_string(ret).c_str());
|
||||
ret, frame->nb_samples, av_make_error_string(ret).c_str());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@@ -499,7 +499,7 @@ int zm_get_samples_from_fifo(AVAudioFifo *fifo, AVFrame *frame) {
|
||||
// AAC requires 1024 samples per encode. Our input tends to be something else, so need to buffer them.
|
||||
if (frame->nb_samples > av_audio_fifo_size(fifo)) {
|
||||
Debug(1, "Not enough samples in fifo for AAC codec frame_size %d > fifo size %d",
|
||||
frame->nb_samples, av_audio_fifo_size(fifo));
|
||||
frame->nb_samples, av_audio_fifo_size(fifo));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
143
src/zm_ffmpeg.h
143
src/zm_ffmpeg.h
@@ -1,17 +1,17 @@
|
||||
/*
|
||||
* ZoneMinder FFMPEG Interface, $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.
|
||||
@@ -38,14 +38,14 @@ extern "C" {
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libavutil/opt.h>
|
||||
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
||||
#include <libavutil/hwcontext.h>
|
||||
#include <libavutil/hwcontext.h>
|
||||
#endif
|
||||
|
||||
/* LIBAVUTIL_VERSION_CHECK checks for the right version of libav and FFmpeg
|
||||
* The original source is vlc (in modules/codec/avcodec/avcommon_compat.h)
|
||||
* a is the major version
|
||||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
/* LIBAVUTIL_VERSION_CHECK checks for the right version of libav and FFmpeg
|
||||
* The original source is vlc (in modules/codec/avcodec/avcommon_compat.h)
|
||||
* a is the major version
|
||||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
#define LIBAVUTIL_VERSION_CHECK(a, b, c, d, e) \
|
||||
( (LIBAVUTIL_VERSION_MICRO < 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBAVUTIL_VERSION_MICRO >= 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
@@ -55,12 +55,12 @@ extern "C" {
|
||||
// AVCODEC
|
||||
#include <libavcodec/avcodec.h>
|
||||
|
||||
/*
|
||||
* LIBAVCODEC_VERSION_CHECK checks for the right version of libav and FFmpeg
|
||||
* The original source is vlc (in modules/codec/avcodec/avcommon_compat.h)
|
||||
* a is the major version
|
||||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
/*
|
||||
* LIBAVCODEC_VERSION_CHECK checks for the right version of libav and FFmpeg
|
||||
* The original source is vlc (in modules/codec/avcodec/avcommon_compat.h)
|
||||
* a is the major version
|
||||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
#define LIBAVCODEC_VERSION_CHECK(a, b, c, d, e) \
|
||||
( (LIBAVCODEC_VERSION_MICRO < 100 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBAVCODEC_VERSION_MICRO >= 100 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
@@ -70,11 +70,11 @@ extern "C" {
|
||||
// AVFORMAT
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
/* LIBAVFORMAT_VERSION_CHECK checks for the right version of libav and FFmpeg
|
||||
* The original source is vlc (in modules/codec/avcodec/avcommon_compat.h)
|
||||
* a is the major version
|
||||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
/* LIBAVFORMAT_VERSION_CHECK checks for the right version of libav and FFmpeg
|
||||
* The original source is vlc (in modules/codec/avcodec/avcommon_compat.h)
|
||||
* a is the major version
|
||||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
#define LIBAVFORMAT_VERSION_CHECK(a, b, c, d, e) \
|
||||
( (LIBAVFORMAT_VERSION_MICRO < 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBAVFORMAT_VERSION_MICRO >= 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
@@ -82,10 +82,10 @@ extern "C" {
|
||||
// SWSCALE
|
||||
#include <libswscale/swscale.h>
|
||||
|
||||
/* LIBSWSCALE_VERSION_CHECK checks for the right version of libav and FFmpeg
|
||||
* a is the major version
|
||||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
/* LIBSWSCALE_VERSION_CHECK checks for the right version of libav and FFmpeg
|
||||
* a is the major version
|
||||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
#define LIBSWSCALE_VERSION_CHECK(a, b, c, d, e) \
|
||||
( (LIBSWSCALE_VERSION_MICRO < 100 && LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBSWSCALE_VERSION_MICRO >= 100 && LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
@@ -109,14 +109,14 @@ enum _AVPIXELFORMAT GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subp
|
||||
* C++ friendly version of av_err2str taken from http://libav-users.943685.n4.nabble.com/Libav-user-g-4-7-2-fails-to-compile-av-err2str-td4656417.html.
|
||||
* Newer g++ versions fail with "error: taking address of temporary array" when using native libav version.
|
||||
*/
|
||||
inline static const std::string av_make_error_string(int errnum) {
|
||||
static char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
||||
av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
return (std::string)errbuf;
|
||||
}
|
||||
inline static const std::string av_make_error_string(int errnum) {
|
||||
static char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
||||
av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
return (std::string)errbuf;
|
||||
}
|
||||
|
||||
#undef av_err2str
|
||||
#define av_err2str(errnum) av_make_error_string(errnum).c_str()
|
||||
#undef av_err2str
|
||||
#define av_err2str(errnum) av_make_error_string(errnum).c_str()
|
||||
|
||||
#ifndef av_rescale_delta
|
||||
/**
|
||||
@@ -133,11 +133,10 @@ int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int
|
||||
* @param amax maximum value of the clip range
|
||||
* @return clipped value
|
||||
*/
|
||||
static av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, int64_t amax)
|
||||
{
|
||||
if (a < amin) return amin;
|
||||
else if (a > amax) return amax;
|
||||
else return a;
|
||||
static av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, int64_t amax) {
|
||||
if (a < amin) return amin;
|
||||
else if (a > amax) return amax;
|
||||
else return a;
|
||||
}
|
||||
|
||||
#define av_clip64 av_clip64_c
|
||||
@@ -253,56 +252,44 @@ int zm_resample_get_delay(SwrContext *resample_ctx, int time_base);
|
||||
int zm_add_samples_to_fifo(AVAudioFifo *fifo, AVFrame *frame);
|
||||
int zm_get_samples_from_fifo(AVAudioFifo *fifo, AVFrame *frame);
|
||||
|
||||
struct zm_free_av_packet
|
||||
{
|
||||
void operator()(AVPacket *pkt) const
|
||||
{
|
||||
av_packet_free(&pkt);
|
||||
}
|
||||
struct zm_free_av_packet {
|
||||
void operator()(AVPacket *pkt) const {
|
||||
av_packet_free(&pkt);
|
||||
}
|
||||
};
|
||||
|
||||
using av_packet_ptr = std::unique_ptr<AVPacket, zm_free_av_packet>;
|
||||
|
||||
struct av_packet_guard
|
||||
{
|
||||
av_packet_guard() : packet{nullptr}
|
||||
{
|
||||
}
|
||||
explicit av_packet_guard(const av_packet_ptr& p) : packet{p.get()}
|
||||
{
|
||||
}
|
||||
explicit av_packet_guard(AVPacket *p) : packet{p}
|
||||
{
|
||||
}
|
||||
~av_packet_guard()
|
||||
{
|
||||
if (packet)
|
||||
av_packet_unref(packet);
|
||||
}
|
||||
struct av_packet_guard {
|
||||
av_packet_guard() : packet{nullptr} {
|
||||
}
|
||||
explicit av_packet_guard(const av_packet_ptr& p) : packet{p.get()} {
|
||||
}
|
||||
explicit av_packet_guard(AVPacket *p) : packet{p} {
|
||||
}
|
||||
~av_packet_guard() {
|
||||
if (packet)
|
||||
av_packet_unref(packet);
|
||||
}
|
||||
|
||||
void acquire(const av_packet_ptr& p)
|
||||
{
|
||||
packet = p.get();
|
||||
}
|
||||
void acquire(AVPacket *p)
|
||||
{
|
||||
packet = p;
|
||||
}
|
||||
void release()
|
||||
{
|
||||
packet = nullptr;
|
||||
}
|
||||
void acquire(const av_packet_ptr& p) {
|
||||
packet = p.get();
|
||||
}
|
||||
void acquire(AVPacket *p) {
|
||||
packet = p;
|
||||
}
|
||||
void release() {
|
||||
packet = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
AVPacket *packet;
|
||||
private:
|
||||
AVPacket *packet;
|
||||
};
|
||||
|
||||
struct zm_free_av_frame
|
||||
{
|
||||
void operator()(AVFrame *frame) const
|
||||
{
|
||||
av_frame_free(&frame);
|
||||
}
|
||||
struct zm_free_av_frame {
|
||||
void operator()(AVFrame *frame) const {
|
||||
av_frame_free(&frame);
|
||||
}
|
||||
};
|
||||
|
||||
using av_frame_ptr = std::unique_ptr<AVFrame, zm_free_av_frame>;
|
||||
|
||||
@@ -36,8 +36,8 @@ TimePoint start_read_time;
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0)
|
||||
static enum AVPixelFormat hw_pix_fmt;
|
||||
static enum AVPixelFormat get_hw_format(
|
||||
AVCodecContext *ctx,
|
||||
const enum AVPixelFormat *pix_fmts
|
||||
AVCodecContext *ctx,
|
||||
const enum AVPixelFormat *pix_fmts
|
||||
) {
|
||||
const enum AVPixelFormat *p;
|
||||
|
||||
@@ -47,36 +47,36 @@ static enum AVPixelFormat get_hw_format(
|
||||
}
|
||||
|
||||
Error("Failed to get HW surface format for %s.",
|
||||
av_get_pix_fmt_name(hw_pix_fmt));
|
||||
av_get_pix_fmt_name(hw_pix_fmt));
|
||||
for ( p = pix_fmts; *p != -1; p++ )
|
||||
Error("Available HW surface format was %s.",
|
||||
av_get_pix_fmt_name(*p));
|
||||
av_get_pix_fmt_name(*p));
|
||||
|
||||
return AV_PIX_FMT_NONE;
|
||||
}
|
||||
#if !LIBAVUTIL_VERSION_CHECK(56, 22, 0, 14, 0)
|
||||
static enum AVPixelFormat find_fmt_by_hw_type(const enum AVHWDeviceType type) {
|
||||
switch (type) {
|
||||
case AV_HWDEVICE_TYPE_VAAPI:
|
||||
return AV_PIX_FMT_VAAPI;
|
||||
case AV_HWDEVICE_TYPE_DXVA2:
|
||||
return AV_PIX_FMT_DXVA2_VLD;
|
||||
case AV_HWDEVICE_TYPE_D3D11VA:
|
||||
return AV_PIX_FMT_D3D11;
|
||||
case AV_HWDEVICE_TYPE_VDPAU:
|
||||
return AV_PIX_FMT_VDPAU;
|
||||
case AV_HWDEVICE_TYPE_CUDA:
|
||||
return AV_PIX_FMT_CUDA;
|
||||
case AV_HWDEVICE_TYPE_QSV:
|
||||
return AV_PIX_FMT_VAAPI;
|
||||
case AV_HWDEVICE_TYPE_VAAPI:
|
||||
return AV_PIX_FMT_VAAPI;
|
||||
case AV_HWDEVICE_TYPE_DXVA2:
|
||||
return AV_PIX_FMT_DXVA2_VLD;
|
||||
case AV_HWDEVICE_TYPE_D3D11VA:
|
||||
return AV_PIX_FMT_D3D11;
|
||||
case AV_HWDEVICE_TYPE_VDPAU:
|
||||
return AV_PIX_FMT_VDPAU;
|
||||
case AV_HWDEVICE_TYPE_CUDA:
|
||||
return AV_PIX_FMT_CUDA;
|
||||
case AV_HWDEVICE_TYPE_QSV:
|
||||
return AV_PIX_FMT_VAAPI;
|
||||
#ifdef AV_HWDEVICE_TYPE_MMAL
|
||||
case AV_HWDEVICE_TYPE_MMAL:
|
||||
return AV_PIX_FMT_MMAL;
|
||||
case AV_HWDEVICE_TYPE_MMAL:
|
||||
return AV_PIX_FMT_MMAL;
|
||||
#endif
|
||||
case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
|
||||
return AV_PIX_FMT_VIDEOTOOLBOX;
|
||||
default:
|
||||
return AV_PIX_FMT_NONE;
|
||||
case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
|
||||
return AV_PIX_FMT_VIDEOTOOLBOX;
|
||||
default:
|
||||
return AV_PIX_FMT_NONE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -84,38 +84,38 @@ static enum AVPixelFormat find_fmt_by_hw_type(const enum AVHWDeviceType type) {
|
||||
#endif
|
||||
|
||||
FfmpegCamera::FfmpegCamera(
|
||||
const Monitor *monitor,
|
||||
const std::string &p_path,
|
||||
const std::string &p_second_path,
|
||||
const std::string &p_user,
|
||||
const std::string &p_pass,
|
||||
const std::string &p_method,
|
||||
const std::string &p_options,
|
||||
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,
|
||||
const std::string &p_hwaccel_name,
|
||||
const std::string &p_hwaccel_device) :
|
||||
const Monitor *monitor,
|
||||
const std::string &p_path,
|
||||
const std::string &p_second_path,
|
||||
const std::string &p_user,
|
||||
const std::string &p_pass,
|
||||
const std::string &p_method,
|
||||
const std::string &p_options,
|
||||
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,
|
||||
const std::string &p_hwaccel_name,
|
||||
const std::string &p_hwaccel_device) :
|
||||
Camera(
|
||||
monitor,
|
||||
FFMPEG_SRC,
|
||||
p_width,
|
||||
p_height,
|
||||
p_colours,
|
||||
ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours),
|
||||
p_brightness,
|
||||
p_contrast,
|
||||
p_hue,
|
||||
p_colour,
|
||||
p_capture,
|
||||
p_record_audio
|
||||
),
|
||||
monitor,
|
||||
FFMPEG_SRC,
|
||||
p_width,
|
||||
p_height,
|
||||
p_colours,
|
||||
ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours),
|
||||
p_brightness,
|
||||
p_contrast,
|
||||
p_hue,
|
||||
p_colour,
|
||||
p_capture,
|
||||
p_record_audio
|
||||
),
|
||||
mPath(p_path),
|
||||
mSecondPath(p_second_path),
|
||||
mUser(p_user),
|
||||
@@ -130,8 +130,7 @@ FfmpegCamera::FfmpegCamera(
|
||||
mConvertContext(nullptr),
|
||||
error_count(0),
|
||||
stream_width(0),
|
||||
stream_height(0)
|
||||
{
|
||||
stream_height(0) {
|
||||
mMaskedPath = remove_authentication(mPath);
|
||||
mMaskedSecondPath = remove_authentication(mSecondPath);
|
||||
if ( capture ) {
|
||||
@@ -192,52 +191,52 @@ int FfmpegCamera::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
|
||||
int64_t lastPTS;
|
||||
|
||||
if ( mSecondFormatContext and
|
||||
(
|
||||
av_rescale_q(mLastAudioPTS, mAudioStream->time_base, AV_TIME_BASE_Q)
|
||||
<
|
||||
av_rescale_q(mLastVideoPTS, mVideoStream->time_base, AV_TIME_BASE_Q)
|
||||
) ) {
|
||||
(
|
||||
av_rescale_q(mLastAudioPTS, mAudioStream->time_base, AV_TIME_BASE_Q)
|
||||
<
|
||||
av_rescale_q(mLastVideoPTS, mVideoStream->time_base, AV_TIME_BASE_Q)
|
||||
) ) {
|
||||
// if audio stream is behind video stream, then read from audio, otherwise video
|
||||
formatContextPtr = mSecondFormatContext;
|
||||
lastPTS = mLastAudioPTS;
|
||||
Debug(4, "Using audio input because audio PTS %" PRId64 " < video PTS %" PRId64,
|
||||
av_rescale_q(mLastAudioPTS, mAudioStream->time_base, AV_TIME_BASE_Q),
|
||||
av_rescale_q(mLastVideoPTS, mVideoStream->time_base, AV_TIME_BASE_Q)
|
||||
);
|
||||
av_rescale_q(mLastAudioPTS, mAudioStream->time_base, AV_TIME_BASE_Q),
|
||||
av_rescale_q(mLastVideoPTS, mVideoStream->time_base, AV_TIME_BASE_Q)
|
||||
);
|
||||
if ((ret = av_read_frame(formatContextPtr, packet.get())) < 0) {
|
||||
if (
|
||||
// Check if EOF.
|
||||
(ret == AVERROR_EOF || (formatContextPtr->pb && formatContextPtr->pb->eof_reached)) ||
|
||||
// Check for Connection failure.
|
||||
(ret == -110)
|
||||
) {
|
||||
// Check if EOF.
|
||||
(ret == AVERROR_EOF || (formatContextPtr->pb && formatContextPtr->pb->eof_reached)) ||
|
||||
// Check for Connection failure.
|
||||
(ret == -110)
|
||||
) {
|
||||
Info("Unable to read packet from stream %d: error %d \"%s\".",
|
||||
packet->stream_index, ret, av_make_error_string(ret).c_str());
|
||||
packet->stream_index, ret, av_make_error_string(ret).c_str());
|
||||
} else {
|
||||
Error("Unable to read packet from stream %d: error %d \"%s\".",
|
||||
packet->stream_index, ret, av_make_error_string(ret).c_str());
|
||||
packet->stream_index, ret, av_make_error_string(ret).c_str());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
formatContextPtr = mFormatContext;
|
||||
Debug(4, "Using video input because %" PRId64 " >= %" PRId64,
|
||||
(mAudioStream?av_rescale_q(mLastAudioPTS, mAudioStream->time_base, AV_TIME_BASE_Q):0),
|
||||
av_rescale_q(mLastVideoPTS, mVideoStream->time_base, AV_TIME_BASE_Q)
|
||||
);
|
||||
(mAudioStream?av_rescale_q(mLastAudioPTS, mAudioStream->time_base, AV_TIME_BASE_Q):0),
|
||||
av_rescale_q(mLastVideoPTS, mVideoStream->time_base, AV_TIME_BASE_Q)
|
||||
);
|
||||
|
||||
if ((ret = av_read_frame(formatContextPtr, packet.get())) < 0) {
|
||||
if (
|
||||
// Check if EOF.
|
||||
(ret == AVERROR_EOF || (formatContextPtr->pb && formatContextPtr->pb->eof_reached)) ||
|
||||
// Check for Connection failure.
|
||||
(ret == -110)
|
||||
) {
|
||||
// Check if EOF.
|
||||
(ret == AVERROR_EOF || (formatContextPtr->pb && formatContextPtr->pb->eof_reached)) ||
|
||||
// Check for Connection failure.
|
||||
(ret == -110)
|
||||
) {
|
||||
Info("Unable to read packet from stream %d: error %d \"%s\".",
|
||||
packet->stream_index, ret, av_make_error_string(ret).c_str());
|
||||
packet->stream_index, ret, av_make_error_string(ret).c_str());
|
||||
} else {
|
||||
Error("Unable to read packet from stream %d: error %d \"%s\".",
|
||||
packet->stream_index, ret, av_make_error_string(ret).c_str());
|
||||
packet->stream_index, ret, av_make_error_string(ret).c_str());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -264,7 +263,7 @@ int FfmpegCamera::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
|
||||
double pts_time = static_cast<double>(av_rescale_q(packet->pts, stream->time_base, AV_TIME_BASE_Q)) / AV_TIME_BASE;
|
||||
double last_pts_time = static_cast<double>(av_rescale_q(lastPTS, stream->time_base, AV_TIME_BASE_Q)) / AV_TIME_BASE;
|
||||
logPrintf(Logger::WARNING + monitor->Importance(), "Stream pts jumped back in time too far. pts %.2f - last pts %.2f = %.2f > 40seconds",
|
||||
pts_time, last_pts_time, pts_time - last_pts_time);
|
||||
pts_time, last_pts_time, pts_time - last_pts_time);
|
||||
if (error_count > 5)
|
||||
return -1;
|
||||
error_count += 1;
|
||||
@@ -310,7 +309,7 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
#if LIBAVFORMAT_VERSION_CHECK(59, 16, 100, 16, 100)
|
||||
const
|
||||
#endif
|
||||
AVInputFormat *input_format = nullptr;
|
||||
AVInputFormat *input_format = nullptr;
|
||||
// Handle options
|
||||
AVDictionary *opts = nullptr;
|
||||
if (!mOptions.empty()) {
|
||||
@@ -365,8 +364,8 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
ret = avformat_open_input(&mFormatContext, mPath.c_str(), input_format, &opts);
|
||||
if (ret != 0) {
|
||||
logPrintf(Logger::ERROR + monitor->Importance(),
|
||||
"Unable to open input %s due to: %s", mMaskedPath.c_str(),
|
||||
av_make_error_string(ret).c_str());
|
||||
"Unable to open input %s due to: %s", mMaskedPath.c_str(),
|
||||
av_make_error_string(ret).c_str());
|
||||
avformat_close_input(&mFormatContext);
|
||||
mFormatContext = nullptr;
|
||||
av_dict_free(&opts);
|
||||
@@ -382,7 +381,7 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
ret = avformat_find_stream_info(mFormatContext, nullptr);
|
||||
if (ret < 0) {
|
||||
Error("Unable to find stream info from %s due to: %s",
|
||||
mMaskedPath.c_str(), av_make_error_string(ret).c_str());
|
||||
mMaskedPath.c_str(), av_make_error_string(ret).c_str());
|
||||
avformat_close_input(&mFormatContext);
|
||||
return -1;
|
||||
}
|
||||
@@ -420,7 +419,7 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
}
|
||||
|
||||
Debug(3, "Found video stream at index %d, audio stream at index %d",
|
||||
mVideoStreamId, mAudioStreamId);
|
||||
mVideoStreamId, mAudioStreamId);
|
||||
|
||||
const AVCodec *mVideoCodec = nullptr;
|
||||
if (!monitor->DecoderName().empty() and (monitor->DecoderName() != "auto")) {
|
||||
@@ -452,7 +451,7 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
if (use_hwaccel && (hwaccel_name != "")) {
|
||||
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
||||
// 3.2 doesn't seem to have all the bits in place, so let's require 3.4 and up
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 107, 0, 107, 0)
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 107, 0, 107, 0)
|
||||
// Print out available types
|
||||
enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;
|
||||
while ((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE)
|
||||
@@ -466,44 +465,44 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
Debug(1, "Found hwdevice %s", av_hwdevice_get_type_name(type));
|
||||
}
|
||||
|
||||
#if LIBAVUTIL_VERSION_CHECK(56, 22, 0, 14, 0)
|
||||
#if LIBAVUTIL_VERSION_CHECK(56, 22, 0, 14, 0)
|
||||
// Get hw_pix_fmt
|
||||
for (int i = 0;; i++) {
|
||||
const AVCodecHWConfig *config = avcodec_get_hw_config(mVideoCodec, i);
|
||||
if (!config) {
|
||||
Debug(1, "Decoder %s does not support config %d.",
|
||||
mVideoCodec->name, i);
|
||||
mVideoCodec->name, i);
|
||||
break;
|
||||
}
|
||||
if ((config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)
|
||||
&& (config->device_type == type)
|
||||
) {
|
||||
) {
|
||||
hw_pix_fmt = config->pix_fmt;
|
||||
Debug(1, "Decoder %s does support our type %s.",
|
||||
mVideoCodec->name, av_hwdevice_get_type_name(type));
|
||||
mVideoCodec->name, av_hwdevice_get_type_name(type));
|
||||
//break;
|
||||
} else {
|
||||
Debug(1, "Decoder %s hwConfig doesn't match our type: %s != %s, pix_fmt %s.",
|
||||
mVideoCodec->name,
|
||||
av_hwdevice_get_type_name(type),
|
||||
av_hwdevice_get_type_name(config->device_type),
|
||||
av_get_pix_fmt_name(config->pix_fmt)
|
||||
);
|
||||
mVideoCodec->name,
|
||||
av_hwdevice_get_type_name(type),
|
||||
av_hwdevice_get_type_name(config->device_type),
|
||||
av_get_pix_fmt_name(config->pix_fmt)
|
||||
);
|
||||
}
|
||||
} // end foreach hwconfig
|
||||
#else
|
||||
#else
|
||||
hw_pix_fmt = find_fmt_by_hw_type(type);
|
||||
#endif
|
||||
#endif
|
||||
if (hw_pix_fmt != AV_PIX_FMT_NONE) {
|
||||
Debug(1, "Selected hw_pix_fmt %d %s",
|
||||
hw_pix_fmt, av_get_pix_fmt_name(hw_pix_fmt));
|
||||
hw_pix_fmt, av_get_pix_fmt_name(hw_pix_fmt));
|
||||
|
||||
mVideoCodecContext->hwaccel_flags |= AV_HWACCEL_FLAG_IGNORE_LEVEL;
|
||||
//if (!lavc_param->check_hw_profile)
|
||||
mVideoCodecContext->hwaccel_flags |= AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH;
|
||||
mVideoCodecContext->hwaccel_flags |= AV_HWACCEL_FLAG_IGNORE_LEVEL;
|
||||
//if (!lavc_param->check_hw_profile)
|
||||
mVideoCodecContext->hwaccel_flags |= AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH;
|
||||
|
||||
ret = av_hwdevice_ctx_create(&hw_device_ctx, type,
|
||||
(hwaccel_device != "" ? hwaccel_device.c_str() : nullptr), nullptr, 0);
|
||||
(hwaccel_device != "" ? hwaccel_device.c_str() : nullptr), nullptr, 0);
|
||||
if (ret < 0 and hwaccel_device != "") {
|
||||
ret = av_hwdevice_ctx_create(&hw_device_ctx, type, nullptr, nullptr, 0);
|
||||
}
|
||||
@@ -518,9 +517,9 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
} else {
|
||||
Debug(1, "Failed to find suitable hw_pix_fmt.");
|
||||
}
|
||||
#else
|
||||
#else
|
||||
Debug(1, "AVCodec not new enough for hwaccel");
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
Warning("HWAccel support not compiled in.");
|
||||
#endif
|
||||
@@ -585,12 +584,12 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
} // end if have audio stream
|
||||
|
||||
if (
|
||||
((unsigned int)mVideoCodecContext->width != width)
|
||||
||
|
||||
((unsigned int)mVideoCodecContext->height != height)
|
||||
) {
|
||||
((unsigned int)mVideoCodecContext->width != width)
|
||||
||
|
||||
((unsigned int)mVideoCodecContext->height != height)
|
||||
) {
|
||||
Debug(1, "Monitor dimensions are %dx%d but camera is sending %dx%d",
|
||||
width, height, mVideoCodecContext->width, mVideoCodecContext->height);
|
||||
width, height, mVideoCodecContext->width, mVideoCodecContext->height);
|
||||
}
|
||||
|
||||
mIsPrimed = true;
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Ffmpeg Class Interface, $Date: 2008-07-25 10:33:23 +0100 (Fri, 25 Jul 2008) $, $Revision: 2611 $
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_FFMPEG_CAMERA_H
|
||||
#define ZM_FFMPEG_CAMERA_H
|
||||
@@ -28,7 +28,7 @@ class FFmpeg_Input;
|
||||
|
||||
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
||||
typedef struct DecodeContext {
|
||||
AVBufferRef *hw_device_ref;
|
||||
AVBufferRef *hw_device_ref;
|
||||
} DecodeContext;
|
||||
#endif
|
||||
//
|
||||
@@ -36,77 +36,77 @@ typedef struct DecodeContext {
|
||||
// accessed using ffmpeg multimedia framework
|
||||
//
|
||||
class FfmpegCamera : public Camera {
|
||||
protected:
|
||||
std::string mPath;
|
||||
std::string mMaskedPath;
|
||||
std::string mSecondPath;
|
||||
std::string mUser;
|
||||
std::string mPass;
|
||||
std::string mMaskedSecondPath;
|
||||
std::string mMethod;
|
||||
std::string mOptions;
|
||||
protected:
|
||||
std::string mPath;
|
||||
std::string mMaskedPath;
|
||||
std::string mSecondPath;
|
||||
std::string mUser;
|
||||
std::string mPass;
|
||||
std::string mMaskedSecondPath;
|
||||
std::string mMethod;
|
||||
std::string mOptions;
|
||||
|
||||
std::string encoder_options;
|
||||
std::string hwaccel_name;
|
||||
std::string hwaccel_device;
|
||||
std::string encoder_options;
|
||||
std::string hwaccel_name;
|
||||
std::string hwaccel_device;
|
||||
|
||||
std::unique_ptr<FFmpeg_Input> mSecondInput;
|
||||
std::unique_ptr<FFmpeg_Input> mSecondInput;
|
||||
|
||||
int frameCount;
|
||||
int frameCount;
|
||||
|
||||
_AVPIXELFORMAT imagePixFormat;
|
||||
_AVPIXELFORMAT imagePixFormat;
|
||||
|
||||
bool use_hwaccel; //will default to on if hwaccel specified, will get turned off if there is a failure
|
||||
bool use_hwaccel; //will default to on if hwaccel specified, will get turned off if there is a failure
|
||||
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
||||
AVBufferRef *hw_device_ctx = nullptr;
|
||||
AVBufferRef *hw_device_ctx = nullptr;
|
||||
#endif
|
||||
|
||||
// Used to store the incoming packet, it will get copied when queued.
|
||||
// We only ever need one at a time, so instead of constantly allocating
|
||||
// and freeing this structure, we will just make it a member of the object.
|
||||
av_packet_ptr packet;
|
||||
// Used to store the incoming packet, it will get copied when queued.
|
||||
// We only ever need one at a time, so instead of constantly allocating
|
||||
// and freeing this structure, we will just make it a member of the object.
|
||||
av_packet_ptr packet;
|
||||
|
||||
int OpenFfmpeg();
|
||||
int Close() override;
|
||||
int OpenFfmpeg();
|
||||
int Close() override;
|
||||
|
||||
struct SwsContext *mConvertContext;
|
||||
struct SwsContext *mConvertContext;
|
||||
|
||||
int error_count;
|
||||
int stream_width; /* What the camera is actually sending */
|
||||
int stream_height;
|
||||
int error_count;
|
||||
int stream_width; /* What the camera is actually sending */
|
||||
int stream_height;
|
||||
|
||||
public:
|
||||
FfmpegCamera(
|
||||
const Monitor *monitor,
|
||||
const std::string &p_path,
|
||||
const std::string &p_second_path,
|
||||
const std::string &p_user,
|
||||
const std::string &p_pass,
|
||||
const std::string &p_method,
|
||||
const std::string &p_options,
|
||||
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,
|
||||
const std::string &p_hwaccel_name,
|
||||
const std::string &p_hwaccel_device
|
||||
);
|
||||
~FfmpegCamera();
|
||||
public:
|
||||
FfmpegCamera(
|
||||
const Monitor *monitor,
|
||||
const std::string &p_path,
|
||||
const std::string &p_second_path,
|
||||
const std::string &p_user,
|
||||
const std::string &p_pass,
|
||||
const std::string &p_method,
|
||||
const std::string &p_options,
|
||||
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,
|
||||
const std::string &p_hwaccel_name,
|
||||
const std::string &p_hwaccel_device
|
||||
);
|
||||
~FfmpegCamera();
|
||||
|
||||
const std::string &Path() const { return mPath; }
|
||||
const std::string &Options() const { return mOptions; }
|
||||
const std::string &Method() const { return mMethod; }
|
||||
const std::string &Path() const { return mPath; }
|
||||
const std::string &Options() const { return mOptions; }
|
||||
const std::string &Method() const { return mMethod; }
|
||||
|
||||
int PrimeCapture() override;
|
||||
int PreCapture() override;
|
||||
int Capture(std::shared_ptr<ZMPacket> &p) override;
|
||||
int PostCapture() override;
|
||||
private:
|
||||
static int FfmpegInterruptCallback(void*ctx);
|
||||
int PrimeCapture() override;
|
||||
int PreCapture() override;
|
||||
int Capture(std::shared_ptr<ZMPacket> &p) override;
|
||||
int PostCapture() override;
|
||||
private:
|
||||
static int FfmpegInterruptCallback(void*ctx);
|
||||
};
|
||||
#endif // ZM_FFMPEG_CAMERA_H
|
||||
|
||||
@@ -9,7 +9,7 @@ FFmpeg_Input::FFmpeg_Input() {
|
||||
audio_stream_id = -1;
|
||||
FFMPEGInit();
|
||||
streams = nullptr;
|
||||
last_seek_request = -1;
|
||||
last_seek_request = -1;
|
||||
}
|
||||
|
||||
FFmpeg_Input::~FFmpeg_Input() {
|
||||
@@ -21,11 +21,11 @@ FFmpeg_Input::~FFmpeg_Input() {
|
||||
/* Takes streams provided from elsewhere. They might not come from the same source
|
||||
* but we will treat them as if they are. */
|
||||
int FFmpeg_Input::Open(
|
||||
const AVStream * video_in_stream,
|
||||
const AVCodecContext * video_in_ctx,
|
||||
const AVStream * audio_in_stream,
|
||||
const AVCodecContext * audio_in_ctx
|
||||
) {
|
||||
const AVStream * video_in_stream,
|
||||
const AVCodecContext * video_in_ctx,
|
||||
const AVStream * audio_in_stream,
|
||||
const AVCodecContext * audio_in_ctx
|
||||
) {
|
||||
int max_stream_index = video_stream_id = video_in_stream->index;
|
||||
|
||||
if (audio_in_stream) {
|
||||
@@ -43,7 +43,7 @@ int FFmpeg_Input::Open(const char *filepath) {
|
||||
error = avformat_open_input(&input_format_context, filepath, nullptr, nullptr);
|
||||
if ( error < 0 ) {
|
||||
Error("Could not open input file '%s' (error '%s')",
|
||||
filepath, av_make_error_string(error).c_str());
|
||||
filepath, av_make_error_string(error).c_str());
|
||||
input_format_context = nullptr;
|
||||
return error;
|
||||
}
|
||||
@@ -51,9 +51,9 @@ int FFmpeg_Input::Open(const char *filepath) {
|
||||
/** Get information on the input file (number of streams etc.). */
|
||||
if ( (error = avformat_find_stream_info(input_format_context, nullptr)) < 0 ) {
|
||||
Error(
|
||||
"Could not open find stream info (error '%s')",
|
||||
av_make_error_string(error).c_str()
|
||||
);
|
||||
"Could not open find stream info (error '%s')",
|
||||
av_make_error_string(error).c_str()
|
||||
);
|
||||
avformat_close_input(&input_format_context);
|
||||
return error;
|
||||
}
|
||||
@@ -98,7 +98,7 @@ int FFmpeg_Input::Open(const char *filepath) {
|
||||
error = avcodec_open2(streams[i].context, streams[i].codec, nullptr);
|
||||
if (error < 0) {
|
||||
Error("Could not open input codec (error '%s')",
|
||||
av_make_error_string(error).c_str());
|
||||
av_make_error_string(error).c_str());
|
||||
avcodec_free_context(&streams[i].context);
|
||||
avformat_close_input(&input_format_context);
|
||||
input_format_context = nullptr;
|
||||
@@ -151,16 +151,16 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id) {
|
||||
int ret = av_read_frame(input_format_context, packet.get());
|
||||
if (ret < 0) {
|
||||
if (
|
||||
// Check if EOF.
|
||||
(ret == AVERROR_EOF || (input_format_context->pb && input_format_context->pb->eof_reached)) ||
|
||||
// Check for Connection failure.
|
||||
(ret == -110)
|
||||
) {
|
||||
// Check if EOF.
|
||||
(ret == AVERROR_EOF || (input_format_context->pb && input_format_context->pb->eof_reached)) ||
|
||||
// Check for Connection failure.
|
||||
(ret == -110)
|
||||
) {
|
||||
Info("av_read_frame returned %s.", av_make_error_string(ret).c_str());
|
||||
return nullptr;
|
||||
}
|
||||
Error("Unable to read packet from stream %d: error %d \"%s\".",
|
||||
packet->stream_index, ret, av_make_error_string(ret).c_str());
|
||||
packet->stream_index, ret, av_make_error_string(ret).c_str());
|
||||
return nullptr;
|
||||
}
|
||||
ZM_DUMP_STREAM_PACKET(input_format_context->streams[packet->stream_index], packet, "Received packet");
|
||||
@@ -182,7 +182,7 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id) {
|
||||
ret = zm_send_packet_receive_frame(context, frame.get(), *packet);
|
||||
if ( ret < 0 ) {
|
||||
Error("Unable to decode frame at frame %d: %d %s, continuing",
|
||||
streams[packet->stream_index].frame_count, ret, av_make_error_string(ret).c_str());
|
||||
streams[packet->stream_index].frame_count, ret, av_make_error_string(ret).c_str());
|
||||
frame = nullptr;
|
||||
continue;
|
||||
} else {
|
||||
@@ -231,18 +231,18 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id, double at) {
|
||||
}
|
||||
} // end if ! frame
|
||||
|
||||
if (
|
||||
(last_seek_request >= 0)
|
||||
&&
|
||||
(last_seek_request > seek_target)
|
||||
&&
|
||||
(frame->pts > seek_target)
|
||||
) {
|
||||
if (
|
||||
(last_seek_request >= 0)
|
||||
&&
|
||||
(last_seek_request > seek_target)
|
||||
&&
|
||||
(frame->pts > seek_target)
|
||||
) {
|
||||
zm_dump_frame(frame, "frame->pts > seek_target, seek backwards");
|
||||
// our frame must be beyond our seek target. so go backwards to before it
|
||||
if (( ret = av_seek_frame(input_format_context, stream_id, seek_target,
|
||||
AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME
|
||||
) ) < 0) {
|
||||
// our frame must be beyond our seek target. so go backwards to before it
|
||||
if (( ret = av_seek_frame(input_format_context, stream_id, seek_target,
|
||||
AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME
|
||||
) ) < 0) {
|
||||
Error("Unable to seek in stream %d", ret);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -258,7 +258,7 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id, double at) {
|
||||
return frame.get();
|
||||
} // end if frame->pts > seek_target
|
||||
|
||||
last_seek_request = seek_target;
|
||||
last_seek_request = seek_target;
|
||||
|
||||
// Normally it is likely just the next packet. Need a heuristic for seeking, something like duration * keyframe interval
|
||||
#if LIBAVCODEC_VERSION_CHECK(60, 3, 0, 3, 0)
|
||||
@@ -269,8 +269,8 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id, double at) {
|
||||
{
|
||||
Debug(1, "Jumping ahead");
|
||||
if (( ret = av_seek_frame(input_format_context, stream_id, seek_target,
|
||||
AVSEEK_FLAG_FRAME
|
||||
) ) < 0) {
|
||||
AVSEEK_FLAG_FRAME
|
||||
) ) < 0) {
|
||||
Error("Unable to seek in stream %d", ret);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -279,8 +279,8 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id, double at) {
|
||||
zm_dump_frame(frame, "got");
|
||||
if (frame->pts > seek_target) {
|
||||
if (( ret = av_seek_frame(input_format_context, stream_id, seek_target,
|
||||
AVSEEK_FLAG_FRAME|AVSEEK_FLAG_BACKWARD
|
||||
) ) < 0) {
|
||||
AVSEEK_FLAG_FRAME|AVSEEK_FLAG_BACKWARD
|
||||
) ) < 0) {
|
||||
Error("Unable to seek in stream %d", ret);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -291,20 +291,20 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id, double at) {
|
||||
// Seeking seems to typically seek to a keyframe, so then we have to decode until we get the frame we want.
|
||||
if (frame->pts <= seek_target) {
|
||||
Debug(1, "Frame pts %" PRId64 " + duration %" PRId64 "= %" PRId64 " <=? %" PRId64,
|
||||
frame->pts,
|
||||
frame->pts,
|
||||
#if LIBAVCODEC_VERSION_CHECK(60, 3, 0, 3, 0)
|
||||
frame->duration, frame->pts + frame->duration,
|
||||
frame->duration, frame->pts + frame->duration,
|
||||
#else
|
||||
frame->pkt_duration, frame->pts + frame->pkt_duration,
|
||||
frame->pkt_duration, frame->pts + frame->pkt_duration,
|
||||
#endif
|
||||
seek_target);
|
||||
seek_target);
|
||||
while (frame && (frame->pts +
|
||||
#if LIBAVCODEC_VERSION_CHECK(60, 3, 0, 3, 0)
|
||||
frame->duration
|
||||
frame->duration
|
||||
#else
|
||||
frame->pkt_duration
|
||||
frame->pkt_duration
|
||||
#endif
|
||||
< seek_target)) {
|
||||
< seek_target)) {
|
||||
if (is_video_stream(input_format_context->streams[stream_id])) {
|
||||
zm_dump_video_frame(frame, "pts <= seek_target");
|
||||
} else {
|
||||
|
||||
@@ -12,48 +12,48 @@ extern "C" {
|
||||
|
||||
class FFmpeg_Input {
|
||||
|
||||
public:
|
||||
FFmpeg_Input();
|
||||
~FFmpeg_Input();
|
||||
public:
|
||||
FFmpeg_Input();
|
||||
~FFmpeg_Input();
|
||||
|
||||
int Open(const char *filename );
|
||||
int Open(
|
||||
const AVStream *,
|
||||
const AVCodecContext *,
|
||||
const AVStream *,
|
||||
const AVCodecContext *);
|
||||
int Close();
|
||||
AVFrame *get_frame(int stream_id=-1);
|
||||
AVFrame *get_frame(int stream_id, double at);
|
||||
int get_video_stream_id() const {
|
||||
return video_stream_id;
|
||||
}
|
||||
int get_audio_stream_id() const {
|
||||
return audio_stream_id;
|
||||
}
|
||||
AVStream *get_video_stream() {
|
||||
return ( video_stream_id >= 0 ) ? input_format_context->streams[video_stream_id] : nullptr;
|
||||
}
|
||||
AVStream *get_audio_stream() {
|
||||
return ( audio_stream_id >= 0 ) ? input_format_context->streams[audio_stream_id] : nullptr;
|
||||
}
|
||||
AVFormatContext *get_format_context() { return input_format_context; };
|
||||
AVCodecContext *get_video_codec_context() { return ( video_stream_id >= 0 ) ? streams[video_stream_id].context : nullptr; };
|
||||
AVCodecContext *get_audio_codec_context() { return ( audio_stream_id >= 0 ) ? streams[audio_stream_id].context : nullptr; };
|
||||
int Open(const char *filename );
|
||||
int Open(
|
||||
const AVStream *,
|
||||
const AVCodecContext *,
|
||||
const AVStream *,
|
||||
const AVCodecContext *);
|
||||
int Close();
|
||||
AVFrame *get_frame(int stream_id=-1);
|
||||
AVFrame *get_frame(int stream_id, double at);
|
||||
int get_video_stream_id() const {
|
||||
return video_stream_id;
|
||||
}
|
||||
int get_audio_stream_id() const {
|
||||
return audio_stream_id;
|
||||
}
|
||||
AVStream *get_video_stream() {
|
||||
return ( video_stream_id >= 0 ) ? input_format_context->streams[video_stream_id] : nullptr;
|
||||
}
|
||||
AVStream *get_audio_stream() {
|
||||
return ( audio_stream_id >= 0 ) ? input_format_context->streams[audio_stream_id] : nullptr;
|
||||
}
|
||||
AVFormatContext *get_format_context() { return input_format_context; };
|
||||
AVCodecContext *get_video_codec_context() { return ( video_stream_id >= 0 ) ? streams[video_stream_id].context : nullptr; };
|
||||
AVCodecContext *get_audio_codec_context() { return ( audio_stream_id >= 0 ) ? streams[audio_stream_id].context : nullptr; };
|
||||
|
||||
private:
|
||||
typedef struct {
|
||||
AVCodecContext *context;
|
||||
const AVCodec *codec;
|
||||
int frame_count;
|
||||
} stream;
|
||||
private:
|
||||
typedef struct {
|
||||
AVCodecContext *context;
|
||||
const AVCodec *codec;
|
||||
int frame_count;
|
||||
} stream;
|
||||
|
||||
stream *streams;
|
||||
int video_stream_id;
|
||||
int audio_stream_id;
|
||||
AVFormatContext *input_format_context;
|
||||
av_frame_ptr frame;
|
||||
int64_t last_seek_request;
|
||||
stream *streams;
|
||||
int video_stream_id;
|
||||
int audio_stream_id;
|
||||
AVFormatContext *input_format_context;
|
||||
av_frame_ptr frame;
|
||||
int64_t last_seek_request;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,15 +21,15 @@ int FFmpeg_Output::Open( const char *filepath ) {
|
||||
if ( (error = avformat_open_input( &input_format_context, filepath, NULL, NULL)) < 0 ) {
|
||||
|
||||
Error("Could not open input file '%s' (error '%s')\n",
|
||||
filepath, av_make_error_string(error).c_str() );
|
||||
filepath, av_make_error_string(error).c_str() );
|
||||
input_format_context = NULL;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
/** Get information on the input file (number of streams etc.). */
|
||||
if ( (error = avformat_find_stream_info(input_format_context, NULL)) < 0 ) {
|
||||
Error( "Could not open find stream info (error '%s')\n",
|
||||
av_make_error_string(error).c_str() );
|
||||
av_make_error_string(error).c_str() );
|
||||
avformat_close_input(&input_format_context);
|
||||
return error;
|
||||
}
|
||||
@@ -65,7 +65,7 @@ int FFmpeg_Output::Open( const char *filepath ) {
|
||||
|
||||
if ((error = avcodec_open2( streams[i].context, streams[i].codec, NULL)) < 0) {
|
||||
Error( "Could not open input codec (error '%s')\n",
|
||||
av_make_error_string(error).c_str() );
|
||||
av_make_error_string(error).c_str() );
|
||||
avcodec_free_context( &streams[i].context );
|
||||
avformat_close_input(&input_format_context);
|
||||
return error;
|
||||
@@ -103,11 +103,11 @@ AVFrame *FFmpeg_Output::get_frame( int stream_id ) {
|
||||
if ( ret < 0 ) {
|
||||
av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
if (
|
||||
// Check if EOF.
|
||||
(ret == AVERROR_EOF || (input_format_context->pb && input_format_context->pb->eof_reached)) ||
|
||||
// Check for Connection failure.
|
||||
(ret == -110)
|
||||
) {
|
||||
// Check if EOF.
|
||||
(ret == AVERROR_EOF || (input_format_context->pb && input_format_context->pb->eof_reached)) ||
|
||||
// Check for Connection failure.
|
||||
(ret == -110)
|
||||
) {
|
||||
Info( "av_read_frame returned %s.", errbuf );
|
||||
return NULL;
|
||||
}
|
||||
@@ -122,45 +122,45 @@ AVFrame *FFmpeg_Output::get_frame( int stream_id ) {
|
||||
|
||||
AVCodecContext *context = streams[packet->stream_index].context;
|
||||
|
||||
ret = avcodec_send_packet( context, packet.get() );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to send packet at frame %d: %s, continuing", streams[packet->stream_index].frame_count, errbuf );
|
||||
continue;
|
||||
} else {
|
||||
Debug(1, "Success getting a packet");
|
||||
}
|
||||
|
||||
#if HAVE_AVUTIL_HWCONTEXT_H
|
||||
if ( hwaccel ) {
|
||||
ret = avcodec_receive_frame( context, hwFrame );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to receive frame %d: %s, continuing", streams[packet->stream_index].frame_count, errbuf );
|
||||
continue;
|
||||
}
|
||||
ret = av_hwframe_transfer_data(frame, hwFrame, 0);
|
||||
if (ret < 0) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to transfer frame at frame %d: %s, continuing", streams[packet->stream_index].frame_count, errbuf );
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
Debug(1,"Getting a frame?");
|
||||
ret = avcodec_receive_frame( context, frame.get() );
|
||||
ret = avcodec_send_packet( context, packet.get() );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to send packet at frame %d: %s, continuing", streams[packet->stream_index].frame_count, errbuf );
|
||||
continue;
|
||||
} else {
|
||||
Debug(1, "Success getting a packet");
|
||||
}
|
||||
|
||||
#if HAVE_AVUTIL_HWCONTEXT_H
|
||||
}
|
||||
if ( hwaccel ) {
|
||||
ret = avcodec_receive_frame( context, hwFrame );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to receive frame %d: %s, continuing", streams[packet->stream_index].frame_count, errbuf );
|
||||
continue;
|
||||
}
|
||||
ret = av_hwframe_transfer_data(frame, hwFrame, 0);
|
||||
if (ret < 0) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to transfer frame at frame %d: %s, continuing", streams[packet->stream_index].frame_count, errbuf );
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
Debug(1,"Getting a frame?");
|
||||
ret = avcodec_receive_frame( context, frame.get() );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to send packet at frame %d: %s, continuing", streams[packet->stream_index].frame_count, errbuf );
|
||||
continue;
|
||||
}
|
||||
|
||||
#if HAVE_AVUTIL_HWCONTEXT_H
|
||||
}
|
||||
#endif
|
||||
|
||||
frameComplete = 1;
|
||||
} // end if it's the right stream
|
||||
frameComplete = 1;
|
||||
} // end if it's the right stream
|
||||
|
||||
} // end while ! frameComplete
|
||||
return frame.get();
|
||||
|
||||
@@ -9,33 +9,33 @@ extern "C" {
|
||||
|
||||
class FFmpeg_Output {
|
||||
|
||||
public:
|
||||
FFmpeg_Output();
|
||||
~FFmpeg_Output();
|
||||
public:
|
||||
FFmpeg_Output();
|
||||
~FFmpeg_Output();
|
||||
|
||||
int Open( const char *filename );
|
||||
int Close();
|
||||
AVFrame *put_frame( int stream_id=-1 );
|
||||
AVFrame *put_packet( int stream_id=-1 );
|
||||
int get_video_stream_id() {
|
||||
return video_stream_id;
|
||||
}
|
||||
int get_audio_stream_id() {
|
||||
return audio_stream_id;
|
||||
}
|
||||
int Open( const char *filename );
|
||||
int Close();
|
||||
AVFrame *put_frame( int stream_id=-1 );
|
||||
AVFrame *put_packet( int stream_id=-1 );
|
||||
int get_video_stream_id() {
|
||||
return video_stream_id;
|
||||
}
|
||||
int get_audio_stream_id() {
|
||||
return audio_stream_id;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef struct {
|
||||
AVCodecContext *context;
|
||||
AVCodec *codec;
|
||||
int frame_count;
|
||||
} stream;
|
||||
private:
|
||||
typedef struct {
|
||||
AVCodecContext *context;
|
||||
AVCodec *codec;
|
||||
int frame_count;
|
||||
} stream;
|
||||
|
||||
stream streams[2];
|
||||
int video_stream_id;
|
||||
int audio_stream_id;
|
||||
AVFormatContext *input_format_context;
|
||||
av_frame_ptr frame;
|
||||
stream streams[2];
|
||||
int video_stream_id;
|
||||
int audio_stream_id;
|
||||
AVFormatContext *input_format_context;
|
||||
av_frame_ptr frame;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,35 +26,35 @@ class Monitor;
|
||||
|
||||
class Fifo {
|
||||
private:
|
||||
std::string path;
|
||||
bool on_blocking_abort;
|
||||
FILE *outfile;
|
||||
int raw_fd;
|
||||
std::string path;
|
||||
bool on_blocking_abort;
|
||||
FILE *outfile;
|
||||
int raw_fd;
|
||||
|
||||
public:
|
||||
static void file_create_if_missing(const std::string &path, bool is_fifo, bool delete_fake_fifo = true);
|
||||
static void fifo_create_if_missing(const std::string &path, bool delete_fake_fifo = true);
|
||||
|
||||
Fifo() :
|
||||
on_blocking_abort(true),
|
||||
outfile(nullptr),
|
||||
raw_fd(-1)
|
||||
{}
|
||||
Fifo(const char *p_path, bool p_on_blocking_abort) :
|
||||
path(p_path),
|
||||
on_blocking_abort(p_on_blocking_abort),
|
||||
outfile(nullptr),
|
||||
raw_fd(-1)
|
||||
{}
|
||||
~Fifo();
|
||||
Fifo() :
|
||||
on_blocking_abort(true),
|
||||
outfile(nullptr),
|
||||
raw_fd(-1)
|
||||
{}
|
||||
Fifo(const char *p_path, bool p_on_blocking_abort) :
|
||||
path(p_path),
|
||||
on_blocking_abort(p_on_blocking_abort),
|
||||
outfile(nullptr),
|
||||
raw_fd(-1)
|
||||
{}
|
||||
~Fifo();
|
||||
|
||||
static bool writePacket(const std::string &filename, const ZMPacket &packet);
|
||||
static bool write(const std::string &filename, uint8_t *data, size_t size);
|
||||
static bool writePacket(const std::string &filename, const ZMPacket &packet);
|
||||
static bool write(const std::string &filename, uint8_t *data, size_t size);
|
||||
|
||||
bool open();
|
||||
bool close();
|
||||
bool open();
|
||||
bool close();
|
||||
|
||||
bool writePacket(const ZMPacket &packet);
|
||||
bool write(uint8_t *data, size_t size, int64_t pts);
|
||||
bool writePacket(const ZMPacket &packet);
|
||||
bool write(uint8_t *data, size_t size, int64_t pts);
|
||||
};
|
||||
#endif // ZM_FIFO_H
|
||||
|
||||
@@ -60,13 +60,13 @@ int zmFifoDbgInit(Monitor *monitor) {
|
||||
}
|
||||
|
||||
void zmFifoDbgOutput(
|
||||
int hex,
|
||||
const char * const file,
|
||||
const int line,
|
||||
const int level,
|
||||
const char *fstring,
|
||||
...
|
||||
) {
|
||||
int hex,
|
||||
const char * const file,
|
||||
const int line,
|
||||
const int level,
|
||||
const char *fstring,
|
||||
...
|
||||
) {
|
||||
char dbg_string[8192];
|
||||
int str_size = sizeof(dbg_string);
|
||||
|
||||
|
||||
@@ -31,12 +31,12 @@ class Monitor;
|
||||
#define FifoDebug(level, params...)
|
||||
#endif
|
||||
void zmFifoDbgOutput(
|
||||
int hex,
|
||||
const char * const file,
|
||||
const int line,
|
||||
const int level,
|
||||
const char *fstring,
|
||||
...) __attribute__((format(printf, 5, 6)));
|
||||
int hex,
|
||||
const char * const file,
|
||||
const int line,
|
||||
const int level,
|
||||
const char *fstring,
|
||||
...) __attribute__((format(printf, 5, 6)));
|
||||
int zmFifoDbgInit(Monitor * monitor);
|
||||
|
||||
#endif // ZM_FIFO_DEBUG_H
|
||||
|
||||
@@ -41,7 +41,7 @@ bool FifoStream::sendRAWFrames() {
|
||||
return false;
|
||||
}
|
||||
if ( fwrite(buffer, bytes_read, 1, stdout) != 1 ) {
|
||||
if ( !zm_terminate )
|
||||
if ( !zm_terminate )
|
||||
Error("Problem during writing: %s", strerror(errno));
|
||||
close(fd);
|
||||
return false;
|
||||
@@ -61,8 +61,8 @@ bool FifoStream::sendMJEGFrames() {
|
||||
}
|
||||
total_read = 0;
|
||||
while (
|
||||
(bytes_read = read(fd, buffer+total_read, ZM_MAX_IMAGE_SIZE-total_read))
|
||||
) {
|
||||
(bytes_read = read(fd, buffer+total_read, ZM_MAX_IMAGE_SIZE-total_read))
|
||||
) {
|
||||
if ( bytes_read < 0 ) {
|
||||
Error("Problem during reading: %s", strerror(errno));
|
||||
close(fd);
|
||||
@@ -76,10 +76,10 @@ bool FifoStream::sendMJEGFrames() {
|
||||
return true;
|
||||
|
||||
if ( fprintf(stdout,
|
||||
"--" BOUNDARY "\r\n"
|
||||
"Content-Type: image/jpeg\r\n"
|
||||
"Content-Length: %d\r\n\r\n",
|
||||
total_read) < 0 ) {
|
||||
"--" BOUNDARY "\r\n"
|
||||
"Content-Type: image/jpeg\r\n"
|
||||
"Content-Length: %d\r\n\r\n",
|
||||
total_read) < 0 ) {
|
||||
Error("Problem during writing: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -25,27 +25,27 @@ class Monitor;
|
||||
|
||||
class FifoStream : public StreamBase {
|
||||
private:
|
||||
std::string stream_path;
|
||||
int total_read;
|
||||
int bytes_read;
|
||||
std::string stream_path;
|
||||
int total_read;
|
||||
int bytes_read;
|
||||
|
||||
protected:
|
||||
typedef enum { UNKNOWN, MJPEG, RAW } StreamType;
|
||||
StreamType stream_type;
|
||||
bool sendMJEGFrames();
|
||||
bool sendRAWFrames();
|
||||
void processCommand(const CmdMsg *msg) override {}
|
||||
typedef enum { UNKNOWN, MJPEG, RAW } StreamType;
|
||||
StreamType stream_type;
|
||||
bool sendMJEGFrames();
|
||||
bool sendRAWFrames();
|
||||
void processCommand(const CmdMsg *msg) override {}
|
||||
|
||||
public:
|
||||
FifoStream() :
|
||||
StreamBase(),
|
||||
total_read(0),
|
||||
bytes_read(0),
|
||||
stream_type(UNKNOWN)
|
||||
{}
|
||||
FifoStream() :
|
||||
StreamBase(),
|
||||
total_read(0),
|
||||
bytes_read(0),
|
||||
stream_type(UNKNOWN)
|
||||
{}
|
||||
|
||||
void setStreamStart(const std::string &path);
|
||||
void setStreamStart(int monitor_id, const char * format);
|
||||
void runStream() override;
|
||||
void setStreamStart(const std::string &path);
|
||||
void setStreamStart(int monitor_id, const char * format);
|
||||
void runStream() override;
|
||||
};
|
||||
#endif // ZM_FIFO_STREAM_H
|
||||
|
||||
@@ -23,17 +23,17 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
FileCamera::FileCamera(
|
||||
const Monitor *monitor,
|
||||
const char *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)
|
||||
const Monitor *monitor,
|
||||
const char *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)
|
||||
: Camera(
|
||||
monitor,
|
||||
FILE_SRC,
|
||||
@@ -47,8 +47,7 @@ FileCamera::FileCamera(
|
||||
p_colour,
|
||||
p_capture,
|
||||
p_record_audio),
|
||||
path(p_path)
|
||||
{
|
||||
path(p_path) {
|
||||
if (capture) {
|
||||
Initialise();
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder File Camera Class Interface, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_FILE_CAMERA_H
|
||||
#define ZM_FILE_CAMERA_H
|
||||
|
||||
@@ -29,7 +29,7 @@ constexpr uint8 FontVariant::kMaxCharWidth;
|
||||
FontVariant::FontVariant() : char_height_(0), char_width_(0), char_padding_(0), codepoint_count_(0) {}
|
||||
|
||||
FontVariant::FontVariant(uint16 char_height, uint16 char_width, uint8 char_padding, std::vector<uint64> bitmap)
|
||||
: char_height_(char_height), char_width_(char_width), char_padding_(char_padding), bitmap_(std::move(bitmap)) {
|
||||
: char_height_(char_height), char_width_(char_width), char_padding_(char_padding), bitmap_(std::move(bitmap)) {
|
||||
if (char_height_ > kMaxCharHeight) {
|
||||
throw std::invalid_argument("char_height > kMaxCharHeight");
|
||||
}
|
||||
@@ -107,7 +107,7 @@ FontLoadError ZmFont::LoadFontFile(const std::string &loc) {
|
||||
font_file.read(reinterpret_cast<char *>(bitmap.data()), static_cast<std::streamsize>(bitmap_bytes));
|
||||
|
||||
variants_[i] =
|
||||
{bitmap_header.char_height, bitmap_header.char_width, bitmap_header.char_padding, std::move(bitmap)};
|
||||
{bitmap_header.char_height, bitmap_header.char_width, bitmap_header.char_padding, std::move(bitmap)};
|
||||
}
|
||||
|
||||
if (font_file.fail()) {
|
||||
|
||||
@@ -7,10 +7,10 @@ Frame::Frame(event_id_t p_event_id,
|
||||
Microseconds p_delta,
|
||||
int p_score,
|
||||
std::vector<ZoneStats> p_stats)
|
||||
: event_id(p_event_id),
|
||||
frame_id(p_frame_id),
|
||||
type(p_type),
|
||||
timestamp(p_timestamp),
|
||||
delta(p_delta),
|
||||
score(p_score),
|
||||
zone_stats(std::move(p_stats)) {}
|
||||
: event_id(p_event_id),
|
||||
frame_id(p_frame_id),
|
||||
type(p_type),
|
||||
timestamp(p_timestamp),
|
||||
delta(p_delta),
|
||||
score(p_score),
|
||||
zone_stats(std::move(p_stats)) {}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Frame Class Interfaces, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_FRAME_H
|
||||
#define ZM_FRAME_H
|
||||
@@ -43,7 +43,7 @@ class Frame {
|
||||
Microseconds p_delta,
|
||||
int p_score,
|
||||
std::vector<ZoneStats> p_stats
|
||||
);
|
||||
);
|
||||
|
||||
event_id_t event_id;
|
||||
int frame_id;
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/*
|
||||
* ZoneMinder regular expression 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
@@ -27,14 +27,15 @@ Group::Group() :
|
||||
id(0),
|
||||
parent_id(0),
|
||||
name("Default") {
|
||||
Warning("Instantiating default Group Object. Should not happen.");
|
||||
Warning("Instantiating default Group Object. Should not happen.");
|
||||
}
|
||||
|
||||
// The order of columns is: Id, ParentId, Name
|
||||
Group::Group(const MYSQL_ROW &dbrow) {
|
||||
unsigned int index = 0;
|
||||
id = atoi(dbrow[index++]);
|
||||
parent_id = dbrow[index] ? atoi(dbrow[index]): 0; index++;
|
||||
unsigned int index = 0;
|
||||
id = atoi(dbrow[index++]);
|
||||
parent_id = dbrow[index] ? atoi(dbrow[index]): 0;
|
||||
index++;
|
||||
name = dbrow[index++];
|
||||
}
|
||||
|
||||
@@ -92,10 +93,10 @@ std::vector<int> Group::MonitorIds() {
|
||||
std::vector<int> child_monitor_ids = child.MonitorIds();
|
||||
if (!child_monitor_ids.empty()) {
|
||||
monitor_ids.insert(
|
||||
monitor_ids.end(),
|
||||
std::make_move_iterator(child_monitor_ids.begin()),
|
||||
std::make_move_iterator(child_monitor_ids.end())
|
||||
);
|
||||
monitor_ids.end(),
|
||||
std::make_move_iterator(child_monitor_ids.begin()),
|
||||
std::make_move_iterator(child_monitor_ids.end())
|
||||
);
|
||||
}
|
||||
} // end foreach child
|
||||
mysql_free_result(result);
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* ZoneMinder Group Class Interface, $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
*/
|
||||
|
||||
#ifndef ZM_GROUP_H
|
||||
#define ZM_GROUP_H
|
||||
|
||||
@@ -57,7 +57,7 @@ Group_Permission::Permission Group_Permission::getPermission(int monitor_id) {
|
||||
}
|
||||
|
||||
for (auto i = monitor_ids.begin();
|
||||
i != monitor_ids.end(); ++i ) {
|
||||
i != monitor_ids.end(); ++i ) {
|
||||
if ( *i == monitor_id ) {
|
||||
return permission;
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* ZoneMinder Group_Permission Class Interface
|
||||
* 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.
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -45,7 +45,8 @@ class Group_Permission {
|
||||
Group_Permission(const Group_Permission &gp) { Copy(gp); }
|
||||
void Copy(const Group_Permission &u);
|
||||
Group_Permission& operator=(const Group_Permission &gp) {
|
||||
Copy(gp); return *this;
|
||||
Copy(gp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
int Id() const { return id; }
|
||||
|
||||
1961
src/zm_image.cpp
1961
src/zm_image.cpp
File diff suppressed because it is too large
Load Diff
350
src/zm_image.h
350
src/zm_image.h
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Image Class Interface, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_IMAGE_H
|
||||
#define ZM_IMAGE_H
|
||||
@@ -36,7 +36,7 @@ class Box;
|
||||
class Polygon;
|
||||
|
||||
#define ZM_BUFTYPE_DONTFREE 0
|
||||
#define ZM_BUFTYPE_MALLOC 1
|
||||
#define ZM_BUFTYPE_MALLOC 1
|
||||
#define ZM_BUFTYPE_NEW 2
|
||||
#define ZM_BUFTYPE_AVMALLOC 3
|
||||
#define ZM_BUFTYPE_ZM 4
|
||||
@@ -51,178 +51,178 @@ extern imgbufcpy_fptr_t fptr_imgbufcpy;
|
||||
|
||||
/* Should be called from Image class functions */
|
||||
inline static uint8_t* AllocBuffer(size_t p_bufsize) {
|
||||
uint8_t* buffer = (uint8_t*)zm_mallocaligned(64, p_bufsize);
|
||||
if ( buffer == nullptr )
|
||||
Fatal("Memory allocation failed: %s", strerror(errno));
|
||||
|
||||
return buffer;
|
||||
uint8_t* buffer = (uint8_t*)zm_mallocaligned(64, p_bufsize);
|
||||
if ( buffer == nullptr )
|
||||
Fatal("Memory allocation failed: %s", strerror(errno));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline static void DumpBuffer(uint8_t* buffer, int buffertype) {
|
||||
if ( buffer && (buffertype != ZM_BUFTYPE_DONTFREE) ) {
|
||||
if ( buffer && (buffertype != ZM_BUFTYPE_DONTFREE) ) {
|
||||
if ( buffertype == ZM_BUFTYPE_ZM ) {
|
||||
zm_freealigned(buffer);
|
||||
} else if ( buffertype == ZM_BUFTYPE_MALLOC ) {
|
||||
free(buffer);
|
||||
} else if ( buffertype == ZM_BUFTYPE_NEW ) {
|
||||
delete buffer;
|
||||
/*else if(buffertype == ZM_BUFTYPE_AVMALLOC)
|
||||
av_free(buffer);
|
||||
*/
|
||||
/*else if(buffertype == ZM_BUFTYPE_AVMALLOC)
|
||||
av_free(buffer);
|
||||
*/
|
||||
} else {
|
||||
Error("Unknown buffer type in DumpBuffer(%d)", buffertype);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// This is image class, and represents a frame captured from a
|
||||
// This is image class, and represents a frame captured from a
|
||||
// camera in raw form.
|
||||
//
|
||||
class Image {
|
||||
private:
|
||||
delta_fptr_t delta8_rgb;
|
||||
delta_fptr_t delta8_bgr;
|
||||
delta_fptr_t delta8_rgba;
|
||||
delta_fptr_t delta8_bgra;
|
||||
delta_fptr_t delta8_argb;
|
||||
delta_fptr_t delta8_abgr;
|
||||
delta_fptr_t delta8_gray8;
|
||||
private:
|
||||
delta_fptr_t delta8_rgb;
|
||||
delta_fptr_t delta8_bgr;
|
||||
delta_fptr_t delta8_rgba;
|
||||
delta_fptr_t delta8_bgra;
|
||||
delta_fptr_t delta8_argb;
|
||||
delta_fptr_t delta8_abgr;
|
||||
delta_fptr_t delta8_gray8;
|
||||
|
||||
// Per object function pointer that we can set once we know the image dimensions
|
||||
blend_fptr_t blend;
|
||||
// Per object function pointer that we can set once we know the image dimensions
|
||||
blend_fptr_t blend;
|
||||
|
||||
void update_function_pointers();
|
||||
void update_function_pointers();
|
||||
|
||||
protected:
|
||||
inline void AllocImgBuffer(size_t p_bufsize) {
|
||||
if ( buffer )
|
||||
DumpImgBuffer();
|
||||
protected:
|
||||
inline void AllocImgBuffer(size_t p_bufsize) {
|
||||
if ( buffer )
|
||||
DumpImgBuffer();
|
||||
|
||||
buffer = AllocBuffer(p_bufsize);
|
||||
buffertype = ZM_BUFTYPE_ZM;
|
||||
allocation = p_bufsize;
|
||||
}
|
||||
buffer = AllocBuffer(p_bufsize);
|
||||
buffertype = ZM_BUFTYPE_ZM;
|
||||
allocation = p_bufsize;
|
||||
}
|
||||
|
||||
public:
|
||||
enum { ZM_CHAR_HEIGHT=11, ZM_CHAR_WIDTH=6 };
|
||||
enum { LINE_HEIGHT=ZM_CHAR_HEIGHT+0 };
|
||||
public:
|
||||
enum { ZM_CHAR_HEIGHT=11, ZM_CHAR_WIDTH=6 };
|
||||
enum { LINE_HEIGHT=ZM_CHAR_HEIGHT+0 };
|
||||
|
||||
protected:
|
||||
static bool initialised;
|
||||
static unsigned char *abs_table;
|
||||
static unsigned char *y_r_table;
|
||||
static unsigned char *y_g_table;
|
||||
static unsigned char *y_b_table;
|
||||
static jpeg_compress_struct *writejpg_ccinfo[101];
|
||||
static jpeg_compress_struct *encodejpg_ccinfo[101];
|
||||
static jpeg_decompress_struct *readjpg_dcinfo;
|
||||
static jpeg_decompress_struct *decodejpg_dcinfo;
|
||||
static struct zm_error_mgr jpg_err;
|
||||
protected:
|
||||
static bool initialised;
|
||||
static unsigned char *abs_table;
|
||||
static unsigned char *y_r_table;
|
||||
static unsigned char *y_g_table;
|
||||
static unsigned char *y_b_table;
|
||||
static jpeg_compress_struct *writejpg_ccinfo[101];
|
||||
static jpeg_compress_struct *encodejpg_ccinfo[101];
|
||||
static jpeg_decompress_struct *readjpg_dcinfo;
|
||||
static jpeg_decompress_struct *decodejpg_dcinfo;
|
||||
static struct zm_error_mgr jpg_err;
|
||||
|
||||
unsigned int width;
|
||||
unsigned int linesize;
|
||||
unsigned int height;
|
||||
unsigned int pixels;
|
||||
unsigned int colours;
|
||||
unsigned int padding;
|
||||
unsigned int size;
|
||||
unsigned int subpixelorder;
|
||||
unsigned long allocation;
|
||||
_AVPIXELFORMAT imagePixFormat;
|
||||
uint8_t *buffer;
|
||||
int buffertype; /* 0=not ours, no need to call free(), 1=malloc() buffer, 2=new buffer */
|
||||
int holdbuffer; /* Hold the buffer instead of replacing it with new one */
|
||||
std::string annotation_;
|
||||
std::string filename_;
|
||||
unsigned int width;
|
||||
unsigned int linesize;
|
||||
unsigned int height;
|
||||
unsigned int pixels;
|
||||
unsigned int colours;
|
||||
unsigned int padding;
|
||||
unsigned int size;
|
||||
unsigned int subpixelorder;
|
||||
unsigned long allocation;
|
||||
_AVPIXELFORMAT imagePixFormat;
|
||||
uint8_t *buffer;
|
||||
int buffertype; /* 0=not ours, no need to call free(), 1=malloc() buffer, 2=new buffer */
|
||||
int holdbuffer; /* Hold the buffer instead of replacing it with new one */
|
||||
std::string annotation_;
|
||||
std::string filename_;
|
||||
|
||||
public:
|
||||
Image();
|
||||
explicit Image(const std::string &filename);
|
||||
Image(int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0, unsigned int padding=0);
|
||||
Image(int p_width, int p_linesize, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0, unsigned int padding=0);
|
||||
explicit Image(const Image &p_image);
|
||||
explicit Image(const AVFrame *frame, int p_width=-1, int p_height=-1);
|
||||
public:
|
||||
Image();
|
||||
explicit Image(const std::string &filename);
|
||||
Image(int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0, unsigned int padding=0);
|
||||
Image(int p_width, int p_linesize, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0, unsigned int padding=0);
|
||||
explicit Image(const Image &p_image);
|
||||
explicit Image(const AVFrame *frame, int p_width=-1, int p_height=-1);
|
||||
|
||||
~Image();
|
||||
~Image();
|
||||
|
||||
static void Initialise();
|
||||
static void Deinitialise();
|
||||
static void Initialise();
|
||||
static void Deinitialise();
|
||||
|
||||
inline void DumpImgBuffer() {
|
||||
if (buffertype != ZM_BUFTYPE_DONTFREE)
|
||||
DumpBuffer(buffer, buffertype);
|
||||
buffertype = ZM_BUFTYPE_DONTFREE;
|
||||
buffer = nullptr;
|
||||
allocation = 0;
|
||||
}
|
||||
inline unsigned int Width() const { return width; }
|
||||
inline unsigned int LineSize() const { return linesize; }
|
||||
inline unsigned int Height() const { return height; }
|
||||
inline unsigned int Pixels() const { return pixels; }
|
||||
inline unsigned int Colours() const { return colours; }
|
||||
inline unsigned int SubpixelOrder() const { return subpixelorder; }
|
||||
inline unsigned int Size() const { return size; }
|
||||
std::string Filename() const { return filename_; }
|
||||
inline void DumpImgBuffer() {
|
||||
if (buffertype != ZM_BUFTYPE_DONTFREE)
|
||||
DumpBuffer(buffer, buffertype);
|
||||
buffertype = ZM_BUFTYPE_DONTFREE;
|
||||
buffer = nullptr;
|
||||
allocation = 0;
|
||||
}
|
||||
inline unsigned int Width() const { return width; }
|
||||
inline unsigned int LineSize() const { return linesize; }
|
||||
inline unsigned int Height() const { return height; }
|
||||
inline unsigned int Pixels() const { return pixels; }
|
||||
inline unsigned int Colours() const { return colours; }
|
||||
inline unsigned int SubpixelOrder() const { return subpixelorder; }
|
||||
inline unsigned int Size() const { return size; }
|
||||
std::string Filename() const { return filename_; }
|
||||
|
||||
AVPixelFormat AVPixFormat() const;
|
||||
AVPixelFormat AVPixFormat() const;
|
||||
|
||||
inline uint8_t* Buffer() { return buffer; }
|
||||
inline const uint8_t* Buffer() const { return buffer; }
|
||||
inline uint8_t* Buffer(unsigned int x, unsigned int y=0) { return &buffer[(y*linesize) + x*colours]; }
|
||||
inline const uint8_t* Buffer(unsigned int x, unsigned int y=0) const { return &buffer[(y*linesize) + x*colours]; }
|
||||
inline uint8_t* Buffer() { return buffer; }
|
||||
inline const uint8_t* Buffer() const { return buffer; }
|
||||
inline uint8_t* Buffer(unsigned int x, unsigned int y=0) { return &buffer[(y*linesize) + x*colours]; }
|
||||
inline const uint8_t* Buffer(unsigned int x, unsigned int y=0) const { return &buffer[(y*linesize) + x*colours]; }
|
||||
|
||||
/* Request writeable buffer */
|
||||
uint8_t* WriteBuffer(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder);
|
||||
// Is only acceptable on a pre-allocated buffer
|
||||
uint8_t* WriteBuffer() { return holdbuffer ? buffer : nullptr; };
|
||||
/* Request writeable buffer */
|
||||
uint8_t* WriteBuffer(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder);
|
||||
// Is only acceptable on a pre-allocated buffer
|
||||
uint8_t* WriteBuffer() { return holdbuffer ? buffer : nullptr; };
|
||||
|
||||
inline int IsBufferHeld() const { return holdbuffer; }
|
||||
inline void HoldBuffer(int tohold) { holdbuffer = tohold; }
|
||||
inline int IsBufferHeld() const { return holdbuffer; }
|
||||
inline void HoldBuffer(int tohold) { holdbuffer = tohold; }
|
||||
|
||||
inline void Empty() {
|
||||
if ( !holdbuffer )
|
||||
DumpImgBuffer();
|
||||
inline void Empty() {
|
||||
if ( !holdbuffer )
|
||||
DumpImgBuffer();
|
||||
|
||||
width = linesize = height = colours = size = pixels = subpixelorder = 0;
|
||||
}
|
||||
width = linesize = height = colours = size = pixels = subpixelorder = 0;
|
||||
}
|
||||
|
||||
void Assign(
|
||||
unsigned int p_width,
|
||||
unsigned int p_height,
|
||||
unsigned int p_colours,
|
||||
unsigned int p_subpixelorder,
|
||||
const uint8_t* new_buffer,
|
||||
const size_t buffer_size);
|
||||
void Assign(const Image &image);
|
||||
bool Assign(const AVFrame *frame);
|
||||
bool Assign(const AVFrame *frame, SwsContext *convert_context, AVFrame *temp_frame);
|
||||
void AssignDirect(
|
||||
const unsigned int p_width,
|
||||
const unsigned int p_height,
|
||||
const unsigned int p_colours,
|
||||
const unsigned int p_subpixelorder,
|
||||
uint8_t *new_buffer,
|
||||
const size_t buffer_size,
|
||||
const int p_buffertype);
|
||||
void Assign(
|
||||
unsigned int p_width,
|
||||
unsigned int p_height,
|
||||
unsigned int p_colours,
|
||||
unsigned int p_subpixelorder,
|
||||
const uint8_t* new_buffer,
|
||||
const size_t buffer_size);
|
||||
void Assign(const Image &image);
|
||||
bool Assign(const AVFrame *frame);
|
||||
bool Assign(const AVFrame *frame, SwsContext *convert_context, AVFrame *temp_frame);
|
||||
void AssignDirect(
|
||||
const unsigned int p_width,
|
||||
const unsigned int p_height,
|
||||
const unsigned int p_colours,
|
||||
const unsigned int p_subpixelorder,
|
||||
uint8_t *new_buffer,
|
||||
const size_t buffer_size,
|
||||
const int p_buffertype);
|
||||
|
||||
int PopulateFrame(AVFrame *frame);
|
||||
int PopulateFrame(AVFrame *frame);
|
||||
|
||||
inline void CopyBuffer(const Image &image) {
|
||||
Assign(image);
|
||||
}
|
||||
inline Image &operator=(const Image &image) {
|
||||
Assign(image);
|
||||
return *this;
|
||||
}
|
||||
inline Image &operator=(const unsigned char *new_buffer) {
|
||||
(*fptr_imgbufcpy)(buffer, new_buffer, size);
|
||||
return *this;
|
||||
}
|
||||
inline void CopyBuffer(const Image &image) {
|
||||
Assign(image);
|
||||
}
|
||||
inline Image &operator=(const Image &image) {
|
||||
Assign(image);
|
||||
return *this;
|
||||
}
|
||||
inline Image &operator=(const unsigned char *new_buffer) {
|
||||
(*fptr_imgbufcpy)(buffer, new_buffer, size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool ReadRaw(const std::string &filename);
|
||||
bool WriteRaw(const std::string &filename) const;
|
||||
bool ReadRaw(const std::string &filename);
|
||||
bool WriteRaw(const std::string &filename) const;
|
||||
|
||||
bool ReadJpeg(const std::string &filename, unsigned int p_colours, unsigned int p_subpixelorder);
|
||||
|
||||
@@ -236,56 +236,56 @@ class Image {
|
||||
SystemTimePoint timestamp,
|
||||
bool on_blocking_abort) const;
|
||||
|
||||
bool DecodeJpeg(const JOCTET *inbuffer, int inbuffer_size, unsigned int p_colours, unsigned int p_subpixelorder);
|
||||
bool EncodeJpeg(JOCTET *outbuffer, int *outbuffer_size, int quality_override=0) const;
|
||||
bool DecodeJpeg(const JOCTET *inbuffer, int inbuffer_size, unsigned int p_colours, unsigned int p_subpixelorder);
|
||||
bool EncodeJpeg(JOCTET *outbuffer, int *outbuffer_size, int quality_override=0) const;
|
||||
|
||||
#if HAVE_ZLIB_H
|
||||
bool Unzip(const Bytef *inbuffer, unsigned long inbuffer_size);
|
||||
bool Zip(Bytef *outbuffer, unsigned long *outbuffer_size, int compression_level=Z_BEST_SPEED) const;
|
||||
bool Unzip(const Bytef *inbuffer, unsigned long inbuffer_size);
|
||||
bool Zip(Bytef *outbuffer, unsigned long *outbuffer_size, int compression_level=Z_BEST_SPEED) const;
|
||||
#endif // HAVE_ZLIB_H
|
||||
|
||||
bool Crop(unsigned int lo_x, unsigned int lo_y, unsigned int hi_x, unsigned int hi_y);
|
||||
bool Crop(const Box &limits);
|
||||
bool Crop(unsigned int lo_x, unsigned int lo_y, unsigned int hi_x, unsigned int hi_y);
|
||||
bool Crop(const Box &limits);
|
||||
|
||||
void Overlay(const Image &image);
|
||||
void Overlay(const Image &image, unsigned int x, unsigned int y);
|
||||
void Blend(const Image &image, int transparency=12);
|
||||
static Image *Merge( unsigned int n_images, Image *images[] );
|
||||
static Image *Merge( unsigned int n_images, Image *images[], double weight );
|
||||
static Image *Highlight(unsigned int n_images, Image *images[], Rgb threshold = kRGBBlack, Rgb ref_colour = kRGBRed);
|
||||
//Image *Delta( const Image &image ) const;
|
||||
void Delta( const Image &image, Image* targetimage) const;
|
||||
void Overlay(const Image &image);
|
||||
void Overlay(const Image &image, unsigned int x, unsigned int y);
|
||||
void Blend(const Image &image, int transparency=12);
|
||||
static Image *Merge( unsigned int n_images, Image *images[] );
|
||||
static Image *Merge( unsigned int n_images, Image *images[], double weight );
|
||||
static Image *Highlight(unsigned int n_images, Image *images[], Rgb threshold = kRGBBlack, Rgb ref_colour = kRGBRed);
|
||||
//Image *Delta( const Image &image ) const;
|
||||
void Delta( const Image &image, Image* targetimage) const;
|
||||
|
||||
const Vector2 centreCoord(const char *text, const int size) const;
|
||||
void MaskPrivacy( const unsigned char *p_bitmask, const Rgb pixel_colour=0x00222222 );
|
||||
void Annotate(const std::string &text,
|
||||
const Vector2 centreCoord(const char *text, const int size) const;
|
||||
void MaskPrivacy( const unsigned char *p_bitmask, const Rgb pixel_colour=0x00222222 );
|
||||
void Annotate(const std::string &text,
|
||||
const Vector2 &coord,
|
||||
uint8 size = 1,
|
||||
Rgb fg_colour = kRGBWhite,
|
||||
Rgb bg_colour = kRGBBlack);
|
||||
Image *HighlightEdges( Rgb colour, unsigned int p_colours, unsigned int p_subpixelorder, const Box *limits=0 );
|
||||
//Image *HighlightEdges( Rgb colour, const Polygon &polygon );
|
||||
void Timestamp(const char *label, SystemTimePoint when, const Vector2 &coord, int label_size);
|
||||
void Colourise(const unsigned int p_reqcolours, const unsigned int p_reqsubpixelorder);
|
||||
void DeColourise();
|
||||
Image *HighlightEdges( Rgb colour, unsigned int p_colours, unsigned int p_subpixelorder, const Box *limits=0 );
|
||||
//Image *HighlightEdges( Rgb colour, const Polygon &polygon );
|
||||
void Timestamp(const char *label, SystemTimePoint when, const Vector2 &coord, int label_size);
|
||||
void Colourise(const unsigned int p_reqcolours, const unsigned int p_reqsubpixelorder);
|
||||
void DeColourise();
|
||||
|
||||
void Clear() { memset( buffer, 0, size ); }
|
||||
void Fill( Rgb colour, const Box *limits=0 );
|
||||
void Fill( Rgb colour, int density, const Box *limits=0 );
|
||||
void Outline( Rgb colour, const Polygon &polygon );
|
||||
void Fill(Rgb colour, const Polygon &polygon) { Fill(colour, 1, polygon); };
|
||||
void Fill(Rgb colour, int density, const Polygon &polygon);
|
||||
void Clear() { memset( buffer, 0, size ); }
|
||||
void Fill( Rgb colour, const Box *limits=0 );
|
||||
void Fill( Rgb colour, int density, const Box *limits=0 );
|
||||
void Outline( Rgb colour, const Polygon &polygon );
|
||||
void Fill(Rgb colour, const Polygon &polygon) { Fill(colour, 1, polygon); };
|
||||
void Fill(Rgb colour, int density, const Polygon &polygon);
|
||||
|
||||
void Rotate( int angle );
|
||||
void Flip( bool leftright );
|
||||
void Scale( unsigned int factor );
|
||||
void Scale(unsigned int x, unsigned int y);
|
||||
void Rotate( int angle );
|
||||
void Flip( bool leftright );
|
||||
void Scale( unsigned int factor );
|
||||
void Scale(unsigned int x, unsigned int y);
|
||||
|
||||
void Deinterlace_Discard();
|
||||
void Deinterlace_Linear();
|
||||
void Deinterlace_Blend();
|
||||
void Deinterlace_Blend_CustomRatio(int divider);
|
||||
void Deinterlace_4Field(const Image* next_image, unsigned int threshold);
|
||||
void Deinterlace_Discard();
|
||||
void Deinterlace_Linear();
|
||||
void Deinterlace_Blend();
|
||||
void Deinterlace_Blend_CustomRatio(int divider);
|
||||
void Deinterlace_4Field(const Image* next_image, unsigned int threshold);
|
||||
};
|
||||
|
||||
// Scan-line polygon fill algorithm
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
/*!\fn ImageAnalyser::ImageAnalyser(const ImageAnalyser& source)
|
||||
* \param source is the object to copy
|
||||
*/
|
||||
ImageAnalyser::ImageAnalyser(const ImageAnalyser& source)
|
||||
{
|
||||
ImageAnalyser::ImageAnalyser(const ImageAnalyser& source) {
|
||||
m_Detectors = source.m_Detectors;
|
||||
}
|
||||
|
||||
@@ -15,19 +14,17 @@ ImageAnalyser::ImageAnalyser(const ImageAnalyser& source)
|
||||
/*!\fn ImageAnalyser::operator=(const ImageAnalyser& source)
|
||||
* \param source is the object to copy
|
||||
*/
|
||||
ImageAnalyser& ImageAnalyser::operator=(const ImageAnalyser& source)
|
||||
{
|
||||
ImageAnalyser& ImageAnalyser::operator=(const ImageAnalyser& source) {
|
||||
m_Detectors = source.m_Detectors;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ImageAnalyser::~ImageAnalyser()
|
||||
{
|
||||
ImageAnalyser::~ImageAnalyser() {
|
||||
for(DetectorsList::reverse_iterator It = m_Detectors.rbegin();
|
||||
It != m_Detectors.rend();
|
||||
++It)
|
||||
It != m_Detectors.rend();
|
||||
++It)
|
||||
delete *It;
|
||||
}
|
||||
|
||||
@@ -40,18 +37,15 @@ ImageAnalyser::~ImageAnalyser()
|
||||
* \param noteSetMap is the map of events descriptions
|
||||
* \param det_cause is a string describing detection cause
|
||||
*/
|
||||
int ImageAnalyser::DoDetection(const Image &comp_image, Zone** zones, int n_numZones, Event::StringSetMap noteSetMap, std::string& det_cause)
|
||||
{
|
||||
int ImageAnalyser::DoDetection(const Image &comp_image, Zone** zones, int n_numZones, Event::StringSetMap noteSetMap, std::string& det_cause) {
|
||||
Event::StringSet zoneSet;
|
||||
int score = 0;
|
||||
|
||||
for(DetectorsList::iterator It = m_Detectors.begin();
|
||||
It != m_Detectors.end();
|
||||
++It)
|
||||
{
|
||||
It != m_Detectors.end();
|
||||
++It) {
|
||||
int detect_score = (*It)->Detect(comp_image, zones, n_numZones, zoneSet);
|
||||
if (detect_score)
|
||||
{
|
||||
if (detect_score) {
|
||||
score += detect_score;
|
||||
noteSetMap[(*It)->getDetectionCause()] = zoneSet;
|
||||
if (det_cause.length())
|
||||
|
||||
@@ -21,8 +21,8 @@ using namespace std;
|
||||
|
||||
//! Class for handling image detection.
|
||||
class ImageAnalyser {
|
||||
public:
|
||||
|
||||
public:
|
||||
|
||||
//!Default constructor.
|
||||
ImageAnalyser() {};
|
||||
|
||||
@@ -35,7 +35,7 @@ class ImageAnalyser {
|
||||
//! Overloaded operator=.
|
||||
ImageAnalyser& operator=(const ImageAnalyser& source);
|
||||
|
||||
private:
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
|
||||
746
src/zm_jpeg.cpp
746
src/zm_jpeg.cpp
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* ZoneMinder JPEG memory encoding/decoding, $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_jpeg.h"
|
||||
|
||||
@@ -26,416 +26,420 @@ extern "C" {
|
||||
|
||||
#define MAX_JPEG_ERRS 25
|
||||
|
||||
static int jpeg_err_count = 0;
|
||||
static int jpeg_err_count = 0;
|
||||
|
||||
void zm_jpeg_error_silent(j_common_ptr cinfo) {
|
||||
zm_error_ptr zmerr = (zm_error_ptr)cinfo->err;
|
||||
longjmp(zmerr->setjmp_buffer, 1);
|
||||
}
|
||||
|
||||
void zm_jpeg_emit_silence(j_common_ptr cinfo, int msg_level) {
|
||||
}
|
||||
|
||||
void zm_jpeg_error_exit(j_common_ptr cinfo) {
|
||||
zm_error_ptr zmerr = (zm_error_ptr) cinfo->err;
|
||||
|
||||
char buffer[JMSG_LENGTH_MAX];
|
||||
zmerr->pub.format_message(cinfo, buffer);
|
||||
|
||||
Error("%s", buffer);
|
||||
if (++jpeg_err_count == MAX_JPEG_ERRS) {
|
||||
Fatal("Maximum number (%d) of JPEG errors reached, exiting", jpeg_err_count);
|
||||
void zm_jpeg_error_silent(j_common_ptr cinfo) {
|
||||
zm_error_ptr zmerr = (zm_error_ptr)cinfo->err;
|
||||
longjmp(zmerr->setjmp_buffer, 1);
|
||||
}
|
||||
|
||||
longjmp(zmerr->setjmp_buffer, 1);
|
||||
}
|
||||
void zm_jpeg_emit_silence(j_common_ptr cinfo, int msg_level) {
|
||||
}
|
||||
|
||||
void zm_jpeg_emit_message(j_common_ptr cinfo, int msg_level) {
|
||||
char buffer[JMSG_LENGTH_MAX];
|
||||
zm_error_ptr zmerr = (zm_error_ptr) cinfo->err;
|
||||
void zm_jpeg_error_exit(j_common_ptr cinfo) {
|
||||
zm_error_ptr zmerr = (zm_error_ptr) cinfo->err;
|
||||
|
||||
if (msg_level < 0) {
|
||||
/* It's a warning message. Since corrupt files may generate many warnings,
|
||||
* the policy implemented here is to show only the first warning,
|
||||
* unless trace_level >= 3.
|
||||
*/
|
||||
if (zmerr->pub.num_warnings == 0 || zmerr->pub.trace_level >= 3) {
|
||||
zmerr->pub.format_message(cinfo, buffer);
|
||||
if (!strstr(buffer, "Corrupt JPEG data:"))
|
||||
Warning("%s", buffer);
|
||||
char buffer[JMSG_LENGTH_MAX];
|
||||
zmerr->pub.format_message(cinfo, buffer);
|
||||
|
||||
Error("%s", buffer);
|
||||
if (++jpeg_err_count == MAX_JPEG_ERRS) {
|
||||
Fatal("Maximum number (%d) of JPEG errors reached, exiting", jpeg_err_count);
|
||||
}
|
||||
/* Always count warnings in num_warnings. */
|
||||
zmerr->pub.num_warnings++;
|
||||
} else {
|
||||
/* It's a trace message. Show it if trace_level >= msg_level. */
|
||||
if (zmerr->pub.trace_level >= msg_level) {
|
||||
zmerr->pub.format_message(cinfo, buffer);
|
||||
Debug(msg_level, "%s", buffer);
|
||||
|
||||
longjmp(zmerr->setjmp_buffer, 1);
|
||||
}
|
||||
|
||||
void zm_jpeg_emit_message(j_common_ptr cinfo, int msg_level) {
|
||||
char buffer[JMSG_LENGTH_MAX];
|
||||
zm_error_ptr zmerr = (zm_error_ptr) cinfo->err;
|
||||
|
||||
if (msg_level < 0) {
|
||||
/* It's a warning message. Since corrupt files may generate many warnings,
|
||||
* the policy implemented here is to show only the first warning,
|
||||
* unless trace_level >= 3.
|
||||
*/
|
||||
if (zmerr->pub.num_warnings == 0 || zmerr->pub.trace_level >= 3) {
|
||||
zmerr->pub.format_message(cinfo, buffer);
|
||||
if (!strstr(buffer, "Corrupt JPEG data:"))
|
||||
Warning("%s", buffer);
|
||||
}
|
||||
/* Always count warnings in num_warnings. */
|
||||
zmerr->pub.num_warnings++;
|
||||
} else {
|
||||
/* It's a trace message. Show it if trace_level >= msg_level. */
|
||||
if (zmerr->pub.trace_level >= msg_level) {
|
||||
zmerr->pub.format_message(cinfo, buffer);
|
||||
Debug(msg_level, "%s", buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Expanded data destination object for memory */
|
||||
/* Expanded data destination object for memory */
|
||||
|
||||
typedef struct {
|
||||
struct jpeg_destination_mgr pub; /* public fields */
|
||||
typedef struct {
|
||||
struct jpeg_destination_mgr pub; /* public fields */
|
||||
|
||||
JOCTET *outbuffer; /* target buffer */
|
||||
int *outbuffer_size;
|
||||
JOCTET *buffer; /* start of buffer */
|
||||
} mem_destination_mgr;
|
||||
JOCTET *outbuffer; /* target buffer */
|
||||
int *outbuffer_size;
|
||||
JOCTET *buffer; /* start of buffer */
|
||||
} mem_destination_mgr;
|
||||
|
||||
typedef mem_destination_mgr * mem_dest_ptr;
|
||||
typedef mem_destination_mgr * mem_dest_ptr;
|
||||
|
||||
#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
|
||||
|
||||
/*
|
||||
* Initialize destination --- called by jpeg_start_compress
|
||||
* before any data is actually written.
|
||||
*/
|
||||
|
||||
static void init_destination (j_compress_ptr cinfo) {
|
||||
mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
|
||||
|
||||
/* Allocate the output buffer --- it will be released when done with image */
|
||||
dest->buffer = (JOCTET *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE * SIZEOF(JOCTET));
|
||||
|
||||
dest->pub.next_output_byte = dest->buffer;
|
||||
dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
|
||||
|
||||
*(dest->outbuffer_size) = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Empty the output buffer --- called whenever buffer fills up.
|
||||
*
|
||||
* In typical applications, this should write the entire output buffer
|
||||
* (ignoring the current state of next_output_byte & free_in_buffer),
|
||||
* reset the pointer & count to the start of the buffer, and return TRUE
|
||||
* indicating that the buffer has been dumped.
|
||||
*
|
||||
* In applications that need to be able to suspend compression due to output
|
||||
* overrun, a FALSE return indicates that the buffer cannot be emptied now.
|
||||
* In this situation, the compressor will return to its caller (possibly with
|
||||
* an indication that it has not accepted all the supplied scanlines). The
|
||||
* application should resume compression after it has made more room in the
|
||||
* output buffer. Note that there are substantial restrictions on the use of
|
||||
* suspension --- see the documentation.
|
||||
*
|
||||
* When suspending, the compressor will back up to a convenient restart point
|
||||
* (typically the start of the current MCU). next_output_byte & free_in_buffer
|
||||
* indicate where the restart point will be if the current call returns FALSE.
|
||||
* Data beyond this point will be regenerated after resumption, so do not
|
||||
* write it out when emptying the buffer externally.
|
||||
*/
|
||||
|
||||
static boolean empty_output_buffer(j_compress_ptr cinfo) {
|
||||
mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
|
||||
|
||||
memcpy(dest->outbuffer+*(dest->outbuffer_size), dest->buffer, OUTPUT_BUF_SIZE);
|
||||
*(dest->outbuffer_size) += OUTPUT_BUF_SIZE;
|
||||
|
||||
dest->pub.next_output_byte = dest->buffer;
|
||||
dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Terminate destination --- called by jpeg_finish_compress
|
||||
* after all data has been written. Usually needs to flush buffer.
|
||||
*
|
||||
* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
|
||||
* application must deal with any cleanup that should happen even
|
||||
* for error exit.
|
||||
*/
|
||||
|
||||
static void term_destination(j_compress_ptr cinfo) {
|
||||
mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
|
||||
size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
|
||||
|
||||
if ( datacount > 0 ) {
|
||||
memcpy(dest->outbuffer+*(dest->outbuffer_size), dest->buffer, datacount);
|
||||
*(dest->outbuffer_size) += datacount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Prepare for output to a stdio stream.
|
||||
* The caller must have already opened the stream, and is responsible
|
||||
* for closing it after finishing compression.
|
||||
*/
|
||||
|
||||
void zm_jpeg_mem_dest(j_compress_ptr cinfo, JOCTET *outbuffer, int *outbuffer_size) {
|
||||
mem_dest_ptr dest;
|
||||
|
||||
/* The destination object is made permanent so that multiple JPEG images
|
||||
* can be written to the same file without re-executing jpeg_stdio_dest.
|
||||
* This makes it dangerous to use this manager and a different destination
|
||||
* manager serially with the same JPEG object, because their private object
|
||||
* sizes may be different. Caveat programmer.
|
||||
/*
|
||||
* Initialize destination --- called by jpeg_start_compress
|
||||
* before any data is actually written.
|
||||
*/
|
||||
if ( cinfo->dest == nullptr ) {
|
||||
/* first time for this JPEG object? */
|
||||
cinfo->dest = (struct jpeg_destination_mgr *)(*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(mem_destination_mgr));
|
||||
|
||||
static void init_destination (j_compress_ptr cinfo) {
|
||||
mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
|
||||
|
||||
/* Allocate the output buffer --- it will be released when done with image */
|
||||
dest->buffer = (JOCTET *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE * SIZEOF(JOCTET));
|
||||
|
||||
dest->pub.next_output_byte = dest->buffer;
|
||||
dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
|
||||
|
||||
*(dest->outbuffer_size) = 0;
|
||||
}
|
||||
|
||||
dest = (mem_dest_ptr) cinfo->dest;
|
||||
dest->pub.init_destination = init_destination;
|
||||
dest->pub.empty_output_buffer = empty_output_buffer;
|
||||
dest->pub.term_destination = term_destination;
|
||||
dest->outbuffer = outbuffer;
|
||||
dest->outbuffer_size = outbuffer_size;
|
||||
}
|
||||
/*
|
||||
* Empty the output buffer --- called whenever buffer fills up.
|
||||
*
|
||||
* In typical applications, this should write the entire output buffer
|
||||
* (ignoring the current state of next_output_byte & free_in_buffer),
|
||||
* reset the pointer & count to the start of the buffer, and return TRUE
|
||||
* indicating that the buffer has been dumped.
|
||||
*
|
||||
* In applications that need to be able to suspend compression due to output
|
||||
* overrun, a FALSE return indicates that the buffer cannot be emptied now.
|
||||
* In this situation, the compressor will return to its caller (possibly with
|
||||
* an indication that it has not accepted all the supplied scanlines). The
|
||||
* application should resume compression after it has made more room in the
|
||||
* output buffer. Note that there are substantial restrictions on the use of
|
||||
* suspension --- see the documentation.
|
||||
*
|
||||
* When suspending, the compressor will back up to a convenient restart point
|
||||
* (typically the start of the current MCU). next_output_byte & free_in_buffer
|
||||
* indicate where the restart point will be if the current call returns FALSE.
|
||||
* Data beyond this point will be regenerated after resumption, so do not
|
||||
* write it out when emptying the buffer externally.
|
||||
*/
|
||||
|
||||
/* Expanded data source object for memory input */
|
||||
static boolean empty_output_buffer(j_compress_ptr cinfo) {
|
||||
mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
|
||||
|
||||
typedef struct {
|
||||
struct jpeg_source_mgr pub; /* public fields */
|
||||
memcpy(dest->outbuffer+*(dest->outbuffer_size), dest->buffer, OUTPUT_BUF_SIZE);
|
||||
*(dest->outbuffer_size) += OUTPUT_BUF_SIZE;
|
||||
|
||||
JOCTET * inbuffer; /* source stream */
|
||||
int inbuffer_size;
|
||||
int inbuffer_size_hwm; /* High water mark */
|
||||
dest->pub.next_output_byte = dest->buffer;
|
||||
dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
|
||||
|
||||
JOCTET * buffer; /* start of buffer */
|
||||
boolean start_of_data; /* have we gotten any data yet? */
|
||||
} mem_source_mgr;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef mem_source_mgr * mem_src_ptr;
|
||||
/*
|
||||
* Terminate destination --- called by jpeg_finish_compress
|
||||
* after all data has been written. Usually needs to flush buffer.
|
||||
*
|
||||
* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
|
||||
* application must deal with any cleanup that should happen even
|
||||
* for error exit.
|
||||
*/
|
||||
|
||||
static void term_destination(j_compress_ptr cinfo) {
|
||||
mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
|
||||
size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
|
||||
|
||||
if ( datacount > 0 ) {
|
||||
memcpy(dest->outbuffer+*(dest->outbuffer_size), dest->buffer, datacount);
|
||||
*(dest->outbuffer_size) += datacount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Prepare for output to a stdio stream.
|
||||
* The caller must have already opened the stream, and is responsible
|
||||
* for closing it after finishing compression.
|
||||
*/
|
||||
|
||||
void zm_jpeg_mem_dest(j_compress_ptr cinfo, JOCTET *outbuffer, int *outbuffer_size) {
|
||||
mem_dest_ptr dest;
|
||||
|
||||
/* The destination object is made permanent so that multiple JPEG images
|
||||
* can be written to the same file without re-executing jpeg_stdio_dest.
|
||||
* This makes it dangerous to use this manager and a different destination
|
||||
* manager serially with the same JPEG object, because their private object
|
||||
* sizes may be different. Caveat programmer.
|
||||
*/
|
||||
if ( cinfo->dest == nullptr ) {
|
||||
/* first time for this JPEG object? */
|
||||
cinfo->dest = (struct jpeg_destination_mgr *)(*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(mem_destination_mgr));
|
||||
}
|
||||
|
||||
dest = (mem_dest_ptr) cinfo->dest;
|
||||
dest->pub.init_destination = init_destination;
|
||||
dest->pub.empty_output_buffer = empty_output_buffer;
|
||||
dest->pub.term_destination = term_destination;
|
||||
dest->outbuffer = outbuffer;
|
||||
dest->outbuffer_size = outbuffer_size;
|
||||
}
|
||||
|
||||
/* Expanded data source object for memory input */
|
||||
|
||||
typedef struct {
|
||||
struct jpeg_source_mgr pub; /* public fields */
|
||||
|
||||
JOCTET * inbuffer; /* source stream */
|
||||
int inbuffer_size;
|
||||
int inbuffer_size_hwm; /* High water mark */
|
||||
|
||||
JOCTET * buffer; /* start of buffer */
|
||||
boolean start_of_data; /* have we gotten any data yet? */
|
||||
} mem_source_mgr;
|
||||
|
||||
typedef mem_source_mgr * mem_src_ptr;
|
||||
|
||||
#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
|
||||
|
||||
/*
|
||||
* Initialize source --- called by jpeg_read_header
|
||||
* before any data is actually read.
|
||||
*/
|
||||
|
||||
static void init_source (j_decompress_ptr cinfo) {
|
||||
mem_src_ptr src = (mem_src_ptr) cinfo->src;
|
||||
|
||||
/* We reset the empty-input-file flag for each image,
|
||||
* but we don't clear the input buffer.
|
||||
* This is correct behavior for reading a series of images from one source.
|
||||
/*
|
||||
* Initialize source --- called by jpeg_read_header
|
||||
* before any data is actually read.
|
||||
*/
|
||||
src->start_of_data = TRUE;
|
||||
src->pub.bytes_in_buffer = 0;
|
||||
}
|
||||
|
||||
static void init_source (j_decompress_ptr cinfo) {
|
||||
mem_src_ptr src = (mem_src_ptr) cinfo->src;
|
||||
|
||||
/*
|
||||
* Fill the input buffer --- called whenever buffer is emptied.
|
||||
*
|
||||
* In typical applications, this should read fresh data into the buffer
|
||||
* (ignoring the current state of next_input_byte & bytes_in_buffer),
|
||||
* reset the pointer & count to the start of the buffer, and return TRUE
|
||||
* indicating that the buffer has been reloaded. It is not necessary to
|
||||
* fill the buffer entirely, only to obtain at least one more byte.
|
||||
*
|
||||
* There is no such thing as an EOF return. If the end of the file has been
|
||||
* reached, the routine has a choice of ERREXIT() or inserting fake data into
|
||||
* the buffer. In most cases, generating a warning message and inserting a
|
||||
* fake EOI marker is the best course of action --- this will allow the
|
||||
* decompressor to output however much of the image is there. However,
|
||||
* the resulting error message is misleading if the real problem is an empty
|
||||
* input file, so we handle that case specially.
|
||||
*
|
||||
* In applications that need to be able to suspend compression due to input
|
||||
* not being available yet, a FALSE return indicates that no more data can be
|
||||
* obtained right now, but more may be forthcoming later. In this situation,
|
||||
* the decompressor will return to its caller (with an indication of the
|
||||
* number of scanlines it has read, if any). The application should resume
|
||||
* decompression after it has loaded more data into the input buffer. Note
|
||||
* that there are substantial restrictions on the use of suspension --- see
|
||||
* the documentation.
|
||||
*
|
||||
* When suspending, the decompressor will back up to a convenient restart point
|
||||
* (typically the start of the current MCU). next_input_byte & bytes_in_buffer
|
||||
* indicate where the restart point will be if the current call returns FALSE.
|
||||
* Data beyond this point must be rescanned after resumption, so move it to
|
||||
* the front of the buffer rather than discarding it.
|
||||
*/
|
||||
|
||||
static boolean fill_input_buffer (j_decompress_ptr cinfo) {
|
||||
mem_src_ptr src = (mem_src_ptr) cinfo->src;
|
||||
size_t nbytes;
|
||||
|
||||
memcpy(src->buffer, src->inbuffer, (size_t) src->inbuffer_size);
|
||||
nbytes = src->inbuffer_size;
|
||||
|
||||
if ( nbytes == 0 ) {
|
||||
if ( src->start_of_data ) /* Treat empty input file as fatal error */
|
||||
ERREXIT(cinfo, JERR_INPUT_EMPTY);
|
||||
WARNMS(cinfo, JWRN_JPEG_EOF);
|
||||
/* Insert a fake EOI marker */
|
||||
src->buffer[0] = (JOCTET) 0xFF;
|
||||
src->buffer[1] = (JOCTET) JPEG_EOI;
|
||||
nbytes = 2;
|
||||
/* We reset the empty-input-file flag for each image,
|
||||
* but we don't clear the input buffer.
|
||||
* This is correct behavior for reading a series of images from one source.
|
||||
*/
|
||||
src->start_of_data = TRUE;
|
||||
src->pub.bytes_in_buffer = 0;
|
||||
}
|
||||
|
||||
src->pub.next_input_byte = src->buffer;
|
||||
src->pub.bytes_in_buffer = nbytes;
|
||||
src->start_of_data = FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip data --- used to skip over a potentially large amount of
|
||||
* uninteresting data (such as an APPn marker).
|
||||
*
|
||||
* Writers of suspendable-input applications must note that skip_input_data
|
||||
* is not granted the right to give a suspension return. If the skip extends
|
||||
* beyond the data currently in the buffer, the buffer can be marked empty so
|
||||
* that the next read will cause a fill_input_buffer call that can suspend.
|
||||
* Arranging for additional bytes to be discarded before reloading the input
|
||||
* buffer is the application writer's problem.
|
||||
*/
|
||||
|
||||
static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
|
||||
mem_src_ptr src = (mem_src_ptr) cinfo->src;
|
||||
|
||||
/* Just a dumb implementation for now. Could use fseek() except
|
||||
* it doesn't work on pipes. Not clear that being smart is worth
|
||||
* any trouble anyway --- large skips are infrequent.
|
||||
/*
|
||||
* Fill the input buffer --- called whenever buffer is emptied.
|
||||
*
|
||||
* In typical applications, this should read fresh data into the buffer
|
||||
* (ignoring the current state of next_input_byte & bytes_in_buffer),
|
||||
* reset the pointer & count to the start of the buffer, and return TRUE
|
||||
* indicating that the buffer has been reloaded. It is not necessary to
|
||||
* fill the buffer entirely, only to obtain at least one more byte.
|
||||
*
|
||||
* There is no such thing as an EOF return. If the end of the file has been
|
||||
* reached, the routine has a choice of ERREXIT() or inserting fake data into
|
||||
* the buffer. In most cases, generating a warning message and inserting a
|
||||
* fake EOI marker is the best course of action --- this will allow the
|
||||
* decompressor to output however much of the image is there. However,
|
||||
* the resulting error message is misleading if the real problem is an empty
|
||||
* input file, so we handle that case specially.
|
||||
*
|
||||
* In applications that need to be able to suspend compression due to input
|
||||
* not being available yet, a FALSE return indicates that no more data can be
|
||||
* obtained right now, but more may be forthcoming later. In this situation,
|
||||
* the decompressor will return to its caller (with an indication of the
|
||||
* number of scanlines it has read, if any). The application should resume
|
||||
* decompression after it has loaded more data into the input buffer. Note
|
||||
* that there are substantial restrictions on the use of suspension --- see
|
||||
* the documentation.
|
||||
*
|
||||
* When suspending, the decompressor will back up to a convenient restart point
|
||||
* (typically the start of the current MCU). next_input_byte & bytes_in_buffer
|
||||
* indicate where the restart point will be if the current call returns FALSE.
|
||||
* Data beyond this point must be rescanned after resumption, so move it to
|
||||
* the front of the buffer rather than discarding it.
|
||||
*/
|
||||
if ( num_bytes > 0 ) {
|
||||
while ( num_bytes > (long) src->pub.bytes_in_buffer ) {
|
||||
num_bytes -= (long) src->pub.bytes_in_buffer;
|
||||
(void) fill_input_buffer(cinfo);
|
||||
/* note we assume that fill_input_buffer will never return FALSE,
|
||||
* so suspension need not be handled.
|
||||
*/
|
||||
|
||||
static boolean fill_input_buffer (j_decompress_ptr cinfo) {
|
||||
mem_src_ptr src = (mem_src_ptr) cinfo->src;
|
||||
size_t nbytes;
|
||||
|
||||
memcpy(src->buffer, src->inbuffer, (size_t) src->inbuffer_size);
|
||||
nbytes = src->inbuffer_size;
|
||||
|
||||
if ( nbytes == 0 ) {
|
||||
if ( src->start_of_data ) /* Treat empty input file as fatal error */
|
||||
ERREXIT(cinfo, JERR_INPUT_EMPTY);
|
||||
WARNMS(cinfo, JWRN_JPEG_EOF);
|
||||
/* Insert a fake EOI marker */
|
||||
src->buffer[0] = (JOCTET) 0xFF;
|
||||
src->buffer[1] = (JOCTET) JPEG_EOI;
|
||||
nbytes = 2;
|
||||
}
|
||||
src->pub.next_input_byte += (size_t) num_bytes;
|
||||
src->pub.bytes_in_buffer -= (size_t) num_bytes;
|
||||
|
||||
src->pub.next_input_byte = src->buffer;
|
||||
src->pub.bytes_in_buffer = nbytes;
|
||||
src->start_of_data = FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Terminate source --- called by jpeg_finish_decompress
|
||||
* after all data has been read. Often a no-op.
|
||||
*
|
||||
* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
|
||||
* application must deal with any cleanup that should happen even
|
||||
* for error exit.
|
||||
*/
|
||||
|
||||
static void term_source(j_decompress_ptr cinfo) {
|
||||
/* no work necessary here */
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare for input from a memory stream.
|
||||
* The caller must have already opened the stream, and is responsible
|
||||
* for closing it after finishing decompression.
|
||||
*/
|
||||
|
||||
void zm_jpeg_mem_src(j_decompress_ptr cinfo, const JOCTET *inbuffer, int inbuffer_size) {
|
||||
mem_src_ptr src;
|
||||
|
||||
/* The source object and input buffer are made permanent so that a series
|
||||
* of JPEG images can be read from the same file by calling zm_jpeg_mem_src
|
||||
* only before the first one. (If we discarded the buffer at the end of
|
||||
* one image, we'd likely lose the start of the next one.)
|
||||
* This makes it unsafe to use this manager and a different source
|
||||
* manager serially with the same JPEG object. Caveat programmer.
|
||||
/*
|
||||
* Skip data --- used to skip over a potentially large amount of
|
||||
* uninteresting data (such as an APPn marker).
|
||||
*
|
||||
* Writers of suspendable-input applications must note that skip_input_data
|
||||
* is not granted the right to give a suspension return. If the skip extends
|
||||
* beyond the data currently in the buffer, the buffer can be marked empty so
|
||||
* that the next read will cause a fill_input_buffer call that can suspend.
|
||||
* Arranging for additional bytes to be discarded before reloading the input
|
||||
* buffer is the application writer's problem.
|
||||
*/
|
||||
if ( cinfo->src == nullptr ) {
|
||||
|
||||
static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
|
||||
mem_src_ptr src = (mem_src_ptr) cinfo->src;
|
||||
|
||||
/* Just a dumb implementation for now. Could use fseek() except
|
||||
* it doesn't work on pipes. Not clear that being smart is worth
|
||||
* any trouble anyway --- large skips are infrequent.
|
||||
*/
|
||||
if ( num_bytes > 0 ) {
|
||||
while ( num_bytes > (long) src->pub.bytes_in_buffer ) {
|
||||
num_bytes -= (long) src->pub.bytes_in_buffer;
|
||||
(void) fill_input_buffer(cinfo);
|
||||
/* note we assume that fill_input_buffer will never return FALSE,
|
||||
* so suspension need not be handled.
|
||||
*/
|
||||
}
|
||||
src->pub.next_input_byte += (size_t) num_bytes;
|
||||
src->pub.bytes_in_buffer -= (size_t) num_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Terminate source --- called by jpeg_finish_decompress
|
||||
* after all data has been read. Often a no-op.
|
||||
*
|
||||
* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
|
||||
* application must deal with any cleanup that should happen even
|
||||
* for error exit.
|
||||
*/
|
||||
|
||||
static void term_source(j_decompress_ptr cinfo) {
|
||||
/* no work necessary here */
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare for input from a memory stream.
|
||||
* The caller must have already opened the stream, and is responsible
|
||||
* for closing it after finishing decompression.
|
||||
*/
|
||||
|
||||
void zm_jpeg_mem_src(j_decompress_ptr cinfo, const JOCTET *inbuffer, int inbuffer_size) {
|
||||
mem_src_ptr src;
|
||||
|
||||
/* The source object and input buffer are made permanent so that a series
|
||||
* of JPEG images can be read from the same file by calling zm_jpeg_mem_src
|
||||
* only before the first one. (If we discarded the buffer at the end of
|
||||
* one image, we'd likely lose the start of the next one.)
|
||||
* This makes it unsafe to use this manager and a different source
|
||||
* manager serially with the same JPEG object. Caveat programmer.
|
||||
*/
|
||||
if ( cinfo->src == nullptr ) {
|
||||
/* first time for this JPEG object? */
|
||||
cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(mem_source_mgr));
|
||||
src = (mem_src_ptr) cinfo->src;
|
||||
src->buffer = (JOCTET *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, inbuffer_size * SIZEOF(JOCTET));
|
||||
src->inbuffer_size_hwm = inbuffer_size;
|
||||
} else {
|
||||
src = (mem_src_ptr) cinfo->src;
|
||||
if ( src->inbuffer_size_hwm < inbuffer_size ) {
|
||||
cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(mem_source_mgr));
|
||||
src = (mem_src_ptr) cinfo->src;
|
||||
src->buffer = (JOCTET *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, inbuffer_size * SIZEOF(JOCTET));
|
||||
src->inbuffer_size_hwm = inbuffer_size;
|
||||
} else {
|
||||
src = (mem_src_ptr) cinfo->src;
|
||||
if ( src->inbuffer_size_hwm < inbuffer_size ) {
|
||||
src->buffer = (JOCTET *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, inbuffer_size * SIZEOF(JOCTET));
|
||||
src->inbuffer_size_hwm = inbuffer_size;
|
||||
}
|
||||
}
|
||||
|
||||
src = (mem_src_ptr) cinfo->src;
|
||||
src->pub.init_source = init_source;
|
||||
src->pub.fill_input_buffer = fill_input_buffer;
|
||||
src->pub.skip_input_data = skip_input_data;
|
||||
src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
|
||||
src->pub.term_source = term_source;
|
||||
src->inbuffer = (JOCTET *)inbuffer;
|
||||
src->inbuffer_size = inbuffer_size;
|
||||
src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
|
||||
src->pub.next_input_byte = nullptr; /* until buffer loaded */
|
||||
}
|
||||
|
||||
src = (mem_src_ptr) cinfo->src;
|
||||
src->pub.init_source = init_source;
|
||||
src->pub.fill_input_buffer = fill_input_buffer;
|
||||
src->pub.skip_input_data = skip_input_data;
|
||||
src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
|
||||
src->pub.term_source = term_source;
|
||||
src->inbuffer = (JOCTET *)inbuffer;
|
||||
src->inbuffer_size = inbuffer_size;
|
||||
src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
|
||||
src->pub.next_input_byte = nullptr; /* until buffer loaded */
|
||||
}
|
||||
void zm_use_std_huff_tables(j_decompress_ptr cinfo) {
|
||||
/* JPEG standard Huffman tables (cf. JPEG standard section K.3) */
|
||||
/* IMPORTANT: these are only valid for 8-bit data precision! */
|
||||
static const JHUFF_TBL dclumin = {
|
||||
{ /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 },
|
||||
FALSE
|
||||
};
|
||||
static const JHUFF_TBL dcchrome = {
|
||||
{ /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 },
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 },
|
||||
FALSE
|
||||
};
|
||||
static const JHUFF_TBL aclumin = {
|
||||
{ /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d },
|
||||
{
|
||||
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
|
||||
0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
|
||||
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
|
||||
0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
|
||||
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
|
||||
0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
|
||||
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
|
||||
0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
|
||||
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
|
||||
0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
|
||||
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
|
||||
0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
|
||||
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
|
||||
0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
|
||||
0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
|
||||
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
|
||||
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
|
||||
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
|
||||
0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
|
||||
0xf9, 0xfa
|
||||
},
|
||||
FALSE
|
||||
};
|
||||
static const JHUFF_TBL acchrome = {
|
||||
{ /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 },
|
||||
{
|
||||
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
|
||||
0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
|
||||
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
|
||||
0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
|
||||
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
|
||||
0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
|
||||
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
|
||||
0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
|
||||
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
||||
0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
|
||||
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
||||
0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
|
||||
0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
|
||||
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
|
||||
0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
|
||||
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
|
||||
0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
|
||||
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
|
||||
0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
|
||||
0xf9, 0xfa
|
||||
},
|
||||
FALSE
|
||||
};
|
||||
|
||||
void zm_use_std_huff_tables(j_decompress_ptr cinfo) {
|
||||
/* JPEG standard Huffman tables (cf. JPEG standard section K.3) */
|
||||
/* IMPORTANT: these are only valid for 8-bit data precision! */
|
||||
static const JHUFF_TBL dclumin = {
|
||||
{ /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 },
|
||||
FALSE
|
||||
};
|
||||
static const JHUFF_TBL dcchrome = {
|
||||
{ /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 },
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 },
|
||||
FALSE
|
||||
};
|
||||
static const JHUFF_TBL aclumin = {
|
||||
{ /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d },
|
||||
{ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
|
||||
0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
|
||||
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
|
||||
0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
|
||||
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
|
||||
0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
|
||||
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
|
||||
0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
|
||||
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
|
||||
0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
|
||||
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
|
||||
0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
|
||||
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
|
||||
0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
|
||||
0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
|
||||
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
|
||||
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
|
||||
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
|
||||
0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
|
||||
0xf9, 0xfa },
|
||||
FALSE
|
||||
};
|
||||
static const JHUFF_TBL acchrome = {
|
||||
{ /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 },
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
|
||||
0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
|
||||
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
|
||||
0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
|
||||
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
|
||||
0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
|
||||
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
|
||||
0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
|
||||
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
||||
0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
|
||||
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
||||
0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
|
||||
0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
|
||||
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
|
||||
0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
|
||||
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
|
||||
0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
|
||||
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
|
||||
0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
|
||||
0xf9, 0xfa },
|
||||
FALSE
|
||||
};
|
||||
|
||||
cinfo->dc_huff_tbl_ptrs[0] = (JHUFF_TBL*)&dclumin;
|
||||
cinfo->dc_huff_tbl_ptrs[1] = (JHUFF_TBL*)&dcchrome;
|
||||
cinfo->ac_huff_tbl_ptrs[0] = (JHUFF_TBL*)&aclumin;
|
||||
cinfo->ac_huff_tbl_ptrs[1] = (JHUFF_TBL*)&acchrome;
|
||||
}
|
||||
cinfo->dc_huff_tbl_ptrs[0] = (JHUFF_TBL*)&dclumin;
|
||||
cinfo->dc_huff_tbl_ptrs[1] = (JHUFF_TBL*)&dcchrome;
|
||||
cinfo->ac_huff_tbl_ptrs[0] = (JHUFF_TBL*)&aclumin;
|
||||
cinfo->ac_huff_tbl_ptrs[1] = (JHUFF_TBL*)&acchrome;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/*
|
||||
* ZoneMinder Jpeg Interface, $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.
|
||||
@@ -28,23 +28,22 @@
|
||||
|
||||
extern "C"
|
||||
{
|
||||
/* Stuff for overridden error handlers */
|
||||
struct zm_error_mgr
|
||||
{
|
||||
struct jpeg_error_mgr pub;
|
||||
jmp_buf setjmp_buffer;
|
||||
};
|
||||
/* Stuff for overridden error handlers */
|
||||
struct zm_error_mgr {
|
||||
struct jpeg_error_mgr pub;
|
||||
jmp_buf setjmp_buffer;
|
||||
};
|
||||
|
||||
typedef struct zm_error_mgr *zm_error_ptr;
|
||||
typedef struct zm_error_mgr *zm_error_ptr;
|
||||
|
||||
void zm_jpeg_error_silent( j_common_ptr cinfo );
|
||||
void zm_jpeg_emit_silence( j_common_ptr cinfo, int msg_level );
|
||||
void zm_jpeg_error_exit( j_common_ptr cinfo );
|
||||
void zm_jpeg_emit_message( j_common_ptr cinfo, int msg_level );
|
||||
void zm_jpeg_error_silent( j_common_ptr cinfo );
|
||||
void zm_jpeg_emit_silence( j_common_ptr cinfo, int msg_level );
|
||||
void zm_jpeg_error_exit( j_common_ptr cinfo );
|
||||
void zm_jpeg_emit_message( j_common_ptr cinfo, int msg_level );
|
||||
|
||||
// Prototypes for memory compress/decompression object */
|
||||
void zm_jpeg_mem_src(j_decompress_ptr cinfo, const JOCTET *inbuffer, int inbuffer_size );
|
||||
void zm_jpeg_mem_dest(j_compress_ptr cinfo, JOCTET *outbuffer, int *outbuffer_size );
|
||||
void zm_jpeg_mem_src(j_decompress_ptr cinfo, const JOCTET *inbuffer, int inbuffer_size );
|
||||
void zm_jpeg_mem_dest(j_compress_ptr cinfo, JOCTET *outbuffer, int *outbuffer_size );
|
||||
|
||||
void zm_use_std_huff_tables( j_decompress_ptr cinfo );
|
||||
void zm_use_std_huff_tables( j_decompress_ptr cinfo );
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/*
|
||||
* ZoneMinder Libvlc 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.
|
||||
@@ -27,24 +27,24 @@
|
||||
static void *libvlc_lib = nullptr;
|
||||
static void (*libvlc_media_player_release_f)(libvlc_media_player_t* ) = nullptr;
|
||||
static void (*libvlc_media_release_f)(libvlc_media_t* ) = nullptr;
|
||||
static void (*libvlc_release_f)(libvlc_instance_t* ) = nullptr;
|
||||
static void (*libvlc_release_f)(libvlc_instance_t* ) = nullptr;
|
||||
static void (*libvlc_media_player_stop_f)(libvlc_media_player_t* ) = nullptr;
|
||||
static libvlc_instance_t* (*libvlc_new_f)(int, const char* const *) = nullptr;
|
||||
static void (*libvlc_log_set_f)(libvlc_instance_t*, libvlc_log_cb, void *) = nullptr;
|
||||
static libvlc_media_t* (*libvlc_media_new_location_f)(libvlc_instance_t*, const char*) = nullptr;
|
||||
static libvlc_media_player_t* (*libvlc_media_player_new_from_media_f)(libvlc_media_t*) = nullptr;
|
||||
static void (*libvlc_video_set_format_f)(libvlc_media_player_t*, const char*, unsigned, unsigned, unsigned) = nullptr;
|
||||
static void (*libvlc_video_set_format_f)(libvlc_media_player_t*, const char*, unsigned, unsigned, unsigned) = nullptr;
|
||||
static void (*libvlc_video_set_callbacks_f)(libvlc_media_player_t*, libvlc_video_lock_cb, libvlc_video_unlock_cb, libvlc_video_display_cb, void*) = nullptr;
|
||||
static int (*libvlc_media_player_play_f)(libvlc_media_player_t *) = nullptr;
|
||||
static const char* (*libvlc_errmsg_f)(void) = nullptr;
|
||||
static const char* (*libvlc_get_version_f)(void) = nullptr;
|
||||
static const char* (*libvlc_get_version_f)(void) = nullptr;
|
||||
|
||||
void bind_libvlc_symbols() {
|
||||
if(libvlc_lib != nullptr) // Safe-check
|
||||
return;
|
||||
|
||||
|
||||
libvlc_lib = dlopen("libvlc.so", RTLD_LAZY | RTLD_GLOBAL);
|
||||
if(!libvlc_lib){
|
||||
if(!libvlc_lib) {
|
||||
Error("Error loading libvlc: %s", dlerror());
|
||||
return;
|
||||
}
|
||||
@@ -63,7 +63,7 @@ void bind_libvlc_symbols() {
|
||||
*(void**) (&libvlc_errmsg_f) = dlsym(libvlc_lib, "libvlc_errmsg");
|
||||
*(void**) (&libvlc_get_version_f) = dlsym(libvlc_lib, "libvlc_get_version");
|
||||
}
|
||||
// Do all the buffer checking work here to avoid unnecessary locking
|
||||
// Do all the buffer checking work here to avoid unnecessary locking
|
||||
void* LibvlcLockBuffer(void* opaque, void** planes) {
|
||||
LibvlcPrivateData* data = reinterpret_cast<LibvlcPrivateData*>(opaque);
|
||||
data->mutex.lock();
|
||||
@@ -102,42 +102,41 @@ void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) {
|
||||
}
|
||||
|
||||
LibvlcCamera::LibvlcCamera(
|
||||
const Monitor *monitor,
|
||||
const std::string &p_path,
|
||||
const std::string &p_user,
|
||||
const std::string &p_pass,
|
||||
const std::string &p_method,
|
||||
const std::string &p_options,
|
||||
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
|
||||
) :
|
||||
const Monitor *monitor,
|
||||
const std::string &p_path,
|
||||
const std::string &p_user,
|
||||
const std::string &p_pass,
|
||||
const std::string &p_method,
|
||||
const std::string &p_options,
|
||||
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
|
||||
) :
|
||||
Camera(
|
||||
monitor,
|
||||
LIBVLC_SRC,
|
||||
p_width,
|
||||
p_height,
|
||||
p_colours,
|
||||
ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours),
|
||||
p_brightness,
|
||||
p_contrast,
|
||||
p_hue,
|
||||
p_colour,
|
||||
p_capture,
|
||||
p_record_audio
|
||||
),
|
||||
monitor,
|
||||
LIBVLC_SRC,
|
||||
p_width,
|
||||
p_height,
|
||||
p_colours,
|
||||
ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours),
|
||||
p_brightness,
|
||||
p_contrast,
|
||||
p_hue,
|
||||
p_colour,
|
||||
p_capture,
|
||||
p_record_audio
|
||||
),
|
||||
mPath(p_path),
|
||||
mUser(UriEncode(p_user)),
|
||||
mPass(UriEncode(p_pass)),
|
||||
mMethod(p_method),
|
||||
mOptions(p_options)
|
||||
{
|
||||
mOptions(p_options) {
|
||||
mLibvlcInstance = nullptr;
|
||||
mLibvlcMedia = nullptr;
|
||||
mLibvlcMediaPlayer = nullptr;
|
||||
@@ -206,7 +205,7 @@ void LibvlcCamera::Terminate() {
|
||||
zm_freealigned(mLibvlcData.buffer);
|
||||
mLibvlcData.buffer = nullptr;
|
||||
}
|
||||
|
||||
|
||||
if ( mLibvlcData.prevBuffer ) {
|
||||
zm_freealigned(mLibvlcData.prevBuffer);
|
||||
mLibvlcData.prevBuffer = nullptr;
|
||||
@@ -287,16 +286,16 @@ int LibvlcCamera::PrimeCapture() {
|
||||
}
|
||||
|
||||
|
||||
int LibvlcCamera::PreCapture() {
|
||||
int LibvlcCamera::PreCapture() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Should not return -1 as cancels capture. Always wait for image if available.
|
||||
int LibvlcCamera::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
|
||||
int LibvlcCamera::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
|
||||
// newImage is a mutex/condition based flag to tell us when there is an image available
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(mLibvlcData.newImageMutex);
|
||||
mLibvlcData.newImageCv.wait(lck, [&]{ return mLibvlcData.newImage || zm_terminate; });
|
||||
mLibvlcData.newImageCv.wait(lck, [&] { return mLibvlcData.newImage || zm_terminate; });
|
||||
mLibvlcData.newImage = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* ZoneMinder Libvlc Camera Class Interface, $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.
|
||||
*/
|
||||
*/
|
||||
|
||||
#ifndef ZM_LIBVLC_CAMERA_H
|
||||
#define ZM_LIBVLC_CAMERA_H
|
||||
@@ -45,9 +45,9 @@ struct LibvlcPrivateData {
|
||||
};
|
||||
|
||||
class LibvlcCamera : public Camera {
|
||||
private:
|
||||
private:
|
||||
static void log_callback( void *ptr, int level, const libvlc_log_t *ctx, const char *format, va_list vargs );
|
||||
protected:
|
||||
protected:
|
||||
std::string mPath;
|
||||
std::string mUser;
|
||||
std::string mPass;
|
||||
@@ -63,7 +63,7 @@ protected:
|
||||
libvlc_media_t *mLibvlcMedia;
|
||||
libvlc_media_player_t *mLibvlcMediaPlayer;
|
||||
|
||||
public:
|
||||
public:
|
||||
LibvlcCamera( const Monitor *monitor, const std::string &path, const std::string &user,const std::string &pass, const std::string &p_method, const std::string &p_options, 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 );
|
||||
~LibvlcCamera();
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ static rfbBool (*HandleRFBServerMessage_f)(rfbClient*) = nullptr;
|
||||
void bind_libvnc_symbols() {
|
||||
if (libvnc_lib != nullptr) // Safe-check
|
||||
return;
|
||||
|
||||
|
||||
libvnc_lib = dlopen("libvncclient.so", RTLD_LAZY | RTLD_GLOBAL);
|
||||
if (!libvnc_lib) {
|
||||
Error("Error loading libvncclient.so: %s", dlerror());
|
||||
@@ -40,7 +40,7 @@ static void GotFrameBufferUpdateCallback(rfbClient *rfb, int x, int y, int w, in
|
||||
VncPrivateData *data = (VncPrivateData *)(*rfbClientGetClientData_f)(rfb, &TAG_0);
|
||||
data->buffer = rfb->frameBuffer;
|
||||
Debug(1, "GotFrameBufferUpdateallback x:%d y:%d w%d h:%d width: %d, height: %d, buffer %p",
|
||||
x,y,w,h, rfb->width, rfb->height, rfb->frameBuffer);
|
||||
x,y,w,h, rfb->width, rfb->height, rfb->frameBuffer);
|
||||
}
|
||||
|
||||
static char* GetPasswordCallback(rfbClient* cl) {
|
||||
@@ -48,9 +48,9 @@ static char* GetPasswordCallback(rfbClient* cl) {
|
||||
return strdup((const char *)(*rfbClientGetClientData_f)(cl, &TAG_1));
|
||||
}
|
||||
|
||||
static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){
|
||||
static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType) {
|
||||
if (credentialType != rfbCredentialTypeUser) {
|
||||
Debug(1, "credentialType != rfbCredentialTypeUser");
|
||||
Debug(1, "credentialType != rfbCredentialTypeUser");
|
||||
return nullptr;
|
||||
}
|
||||
rfbCredential *c = (rfbCredential *)malloc(sizeof(rfbCredential));
|
||||
@@ -73,47 +73,46 @@ static rfbBool resize(rfbClient* client) {
|
||||
// libVNC doesn't do alignment or padding in each line
|
||||
//SWScale::GetBufferSize(AV_PIX_FMT_RGBA, client->width, client->height);
|
||||
client->frameBuffer = (uint8_t *)av_malloc(bufferSize);
|
||||
Debug(1, "Allocing new frame buffer %dx%d = %d", client->width, client->height, bufferSize);
|
||||
Debug(1, "Allocing new frame buffer %dx%d = %d", client->width, client->height, bufferSize);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VncCamera::VncCamera(
|
||||
const Monitor *monitor,
|
||||
const std::string &host,
|
||||
const std::string &port,
|
||||
const std::string &user,
|
||||
const std::string &pass,
|
||||
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 ) :
|
||||
Camera(
|
||||
monitor,
|
||||
VNC_SRC,
|
||||
p_width,
|
||||
p_height,
|
||||
p_colours,
|
||||
ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours),
|
||||
p_brightness,
|
||||
p_contrast,
|
||||
p_hue,
|
||||
p_colour,
|
||||
p_capture,
|
||||
p_record_audio
|
||||
),
|
||||
mRfb(nullptr),
|
||||
mVncData({}),
|
||||
mHost(host),
|
||||
mPort(port),
|
||||
mUser(user),
|
||||
mPass(pass)
|
||||
{
|
||||
const Monitor *monitor,
|
||||
const std::string &host,
|
||||
const std::string &port,
|
||||
const std::string &user,
|
||||
const std::string &pass,
|
||||
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 ) :
|
||||
Camera(
|
||||
monitor,
|
||||
VNC_SRC,
|
||||
p_width,
|
||||
p_height,
|
||||
p_colours,
|
||||
ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours),
|
||||
p_brightness,
|
||||
p_contrast,
|
||||
p_hue,
|
||||
p_colour,
|
||||
p_capture,
|
||||
p_record_audio
|
||||
),
|
||||
mRfb(nullptr),
|
||||
mVncData({}),
|
||||
mHost(host),
|
||||
mPort(port),
|
||||
mUser(user),
|
||||
mPass(pass) {
|
||||
if (colours == ZM_COLOUR_RGB32) {
|
||||
subpixelorder = ZM_SUBPIX_ORDER_RGBA;
|
||||
mImgPixFmt = AV_PIX_FMT_RGBA;
|
||||
@@ -169,22 +168,22 @@ int VncCamera::PrimeCapture() {
|
||||
if (mRfb->serverHost) free(mRfb->serverHost);
|
||||
mRfb->serverHost = strdup(mHost.c_str());
|
||||
mRfb->serverPort = atoi(mPort.c_str());
|
||||
if (!mRfb->serverPort) {
|
||||
Debug(1, "Defaulting to port 5900");
|
||||
mRfb->serverPort = 5900;
|
||||
}
|
||||
if (!mRfb->serverPort) {
|
||||
Debug(1, "Defaulting to port 5900");
|
||||
mRfb->serverPort = 5900;
|
||||
}
|
||||
|
||||
} else {
|
||||
Debug(1, "mRfb already exists?");
|
||||
} else {
|
||||
Debug(1, "mRfb already exists?");
|
||||
}
|
||||
if (!(*rfbInitClient_f)(mRfb, 0, nullptr)) {
|
||||
/* IF rfbInitClient fails, it calls rdbClientCleanup which will free mRfb */
|
||||
mRfb = nullptr;
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
if (((unsigned int)mRfb->width != width) or ((unsigned int)mRfb->height != height)) {
|
||||
Warning("Specified dimensions do not match screen size monitor: (%dx%d) != vnc: (%dx%d)",
|
||||
width, height, mRfb->width, mRfb->height);
|
||||
width, height, mRfb->width, mRfb->height);
|
||||
}
|
||||
getVideoStream();
|
||||
|
||||
@@ -219,27 +218,27 @@ int VncCamera::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
|
||||
|
||||
uint8_t *directbuffer = zm_packet->image->WriteBuffer(width, height, colours, subpixelorder);
|
||||
Debug(1, "scale src %p, %d, dest %p %d %d %dx%d %dx%d", mVncData.buffer,
|
||||
mRfb->si.framebufferWidth * mRfb->si.framebufferHeight * 4,
|
||||
directbuffer,
|
||||
width * height * colours,
|
||||
mImgPixFmt,
|
||||
mRfb->si.framebufferWidth,
|
||||
mRfb->si.framebufferHeight,
|
||||
width,
|
||||
height);
|
||||
mRfb->si.framebufferWidth * mRfb->si.framebufferHeight * 4,
|
||||
directbuffer,
|
||||
width * height * colours,
|
||||
mImgPixFmt,
|
||||
mRfb->si.framebufferWidth,
|
||||
mRfb->si.framebufferHeight,
|
||||
width,
|
||||
height);
|
||||
|
||||
int rc = scale.Convert(
|
||||
mVncData.buffer,
|
||||
mRfb->si.framebufferWidth * mRfb->si.framebufferHeight * 4,
|
||||
//SWScale::GetBufferSize(AV_PIX_FMT_RGBA, mRfb->si.framebufferWidth, mRfb->si.framebufferHeight),
|
||||
directbuffer,
|
||||
width * height * colours,
|
||||
AV_PIX_FMT_RGBA,
|
||||
mImgPixFmt,
|
||||
mRfb->si.framebufferWidth,
|
||||
mRfb->si.framebufferHeight,
|
||||
width,
|
||||
height);
|
||||
mVncData.buffer,
|
||||
mRfb->si.framebufferWidth * mRfb->si.framebufferHeight * 4,
|
||||
//SWScale::GetBufferSize(AV_PIX_FMT_RGBA, mRfb->si.framebufferWidth, mRfb->si.framebufferHeight),
|
||||
directbuffer,
|
||||
width * height * colours,
|
||||
AV_PIX_FMT_RGBA,
|
||||
mImgPixFmt,
|
||||
mRfb->si.framebufferWidth,
|
||||
mRfb->si.framebufferHeight,
|
||||
width,
|
||||
height);
|
||||
return rc == 0 ? 1 : rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
// Used by vnc callbacks
|
||||
struct VncPrivateData {
|
||||
uint8_t *buffer;
|
||||
uint8_t width;
|
||||
uint8_t width;
|
||||
uint8_t height;
|
||||
};
|
||||
|
||||
class VncCamera : public Camera {
|
||||
protected:
|
||||
protected:
|
||||
rfbClient *mRfb;
|
||||
VncPrivateData mVncData;
|
||||
SWScale scale;
|
||||
@@ -33,23 +33,23 @@ protected:
|
||||
std::string mPort;
|
||||
std::string mUser;
|
||||
std::string mPass;
|
||||
public:
|
||||
public:
|
||||
VncCamera(
|
||||
const Monitor *monitor,
|
||||
const std::string &host,
|
||||
const std::string &port,
|
||||
const std::string &user,
|
||||
const std::string &pass,
|
||||
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);
|
||||
|
||||
const Monitor *monitor,
|
||||
const std::string &host,
|
||||
const std::string &port,
|
||||
const std::string &user,
|
||||
const std::string &pass,
|
||||
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);
|
||||
|
||||
~VncCamera();
|
||||
|
||||
int PreCapture() override;
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Local 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_local_camera.h"
|
||||
|
||||
@@ -48,128 +48,127 @@ static int vidioctl(int fd, int request, void *arg) {
|
||||
|
||||
static _AVPIXELFORMAT getFfPixFormatFromV4lPalette(int v4l_version, int palette) {
|
||||
_AVPIXELFORMAT pixFormat = AV_PIX_FMT_NONE;
|
||||
|
||||
|
||||
switch (palette) {
|
||||
#if defined(V4L2_PIX_FMT_RGB444) && defined(AV_PIX_FMT_RGB444)
|
||||
case V4L2_PIX_FMT_RGB444 :
|
||||
pixFormat = AV_PIX_FMT_RGB444;
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB444 :
|
||||
pixFormat = AV_PIX_FMT_RGB444;
|
||||
break;
|
||||
#endif // V4L2_PIX_FMT_RGB444
|
||||
case V4L2_PIX_FMT_RGB555 :
|
||||
pixFormat = AV_PIX_FMT_RGB555;
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB565 :
|
||||
pixFormat = AV_PIX_FMT_RGB565;
|
||||
break;
|
||||
case V4L2_PIX_FMT_BGR24 :
|
||||
pixFormat = AV_PIX_FMT_BGR24;
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB24 :
|
||||
pixFormat = AV_PIX_FMT_RGB24;
|
||||
break;
|
||||
case V4L2_PIX_FMT_BGR32 :
|
||||
pixFormat = AV_PIX_FMT_BGRA;
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB32 :
|
||||
pixFormat = AV_PIX_FMT_ARGB;
|
||||
break;
|
||||
case V4L2_PIX_FMT_GREY :
|
||||
pixFormat = AV_PIX_FMT_GRAY8;
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUYV :
|
||||
pixFormat = AV_PIX_FMT_YUYV422;
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUV422P :
|
||||
pixFormat = AV_PIX_FMT_YUV422P;
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUV411P :
|
||||
pixFormat = AV_PIX_FMT_YUV411P;
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB555 :
|
||||
pixFormat = AV_PIX_FMT_RGB555;
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB565 :
|
||||
pixFormat = AV_PIX_FMT_RGB565;
|
||||
break;
|
||||
case V4L2_PIX_FMT_BGR24 :
|
||||
pixFormat = AV_PIX_FMT_BGR24;
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB24 :
|
||||
pixFormat = AV_PIX_FMT_RGB24;
|
||||
break;
|
||||
case V4L2_PIX_FMT_BGR32 :
|
||||
pixFormat = AV_PIX_FMT_BGRA;
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB32 :
|
||||
pixFormat = AV_PIX_FMT_ARGB;
|
||||
break;
|
||||
case V4L2_PIX_FMT_GREY :
|
||||
pixFormat = AV_PIX_FMT_GRAY8;
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUYV :
|
||||
pixFormat = AV_PIX_FMT_YUYV422;
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUV422P :
|
||||
pixFormat = AV_PIX_FMT_YUV422P;
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUV411P :
|
||||
pixFormat = AV_PIX_FMT_YUV411P;
|
||||
break;
|
||||
#ifdef V4L2_PIX_FMT_YUV444
|
||||
case V4L2_PIX_FMT_YUV444 :
|
||||
pixFormat = AV_PIX_FMT_YUV444P;
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUV444 :
|
||||
pixFormat = AV_PIX_FMT_YUV444P;
|
||||
break;
|
||||
#endif // V4L2_PIX_FMT_YUV444
|
||||
case V4L2_PIX_FMT_YUV410 :
|
||||
pixFormat = AV_PIX_FMT_YUV410P;
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUV420 :
|
||||
pixFormat = AV_PIX_FMT_YUV420P;
|
||||
break;
|
||||
case V4L2_PIX_FMT_JPEG :
|
||||
case V4L2_PIX_FMT_MJPEG :
|
||||
pixFormat = AV_PIX_FMT_YUVJ444P;
|
||||
break;
|
||||
case V4L2_PIX_FMT_UYVY :
|
||||
pixFormat = AV_PIX_FMT_UYVY422;
|
||||
break;
|
||||
// These don't seem to have ffmpeg equivalents
|
||||
// See if you can match any of the ones in the default clause below!?
|
||||
case V4L2_PIX_FMT_RGB332 :
|
||||
case V4L2_PIX_FMT_RGB555X :
|
||||
case V4L2_PIX_FMT_RGB565X :
|
||||
//case V4L2_PIX_FMT_Y16 :
|
||||
//case V4L2_PIX_FMT_PAL8 :
|
||||
case V4L2_PIX_FMT_YVU410 :
|
||||
case V4L2_PIX_FMT_YVU420 :
|
||||
case V4L2_PIX_FMT_Y41P :
|
||||
//case V4L2_PIX_FMT_YUV555 :
|
||||
//case V4L2_PIX_FMT_YUV565 :
|
||||
//case V4L2_PIX_FMT_YUV32 :
|
||||
case V4L2_PIX_FMT_NV12 :
|
||||
case V4L2_PIX_FMT_NV21 :
|
||||
case V4L2_PIX_FMT_YYUV :
|
||||
case V4L2_PIX_FMT_HI240 :
|
||||
case V4L2_PIX_FMT_HM12 :
|
||||
//case V4L2_PIX_FMT_SBGGR8 :
|
||||
//case V4L2_PIX_FMT_SGBRG8 :
|
||||
//case V4L2_PIX_FMT_SBGGR16 :
|
||||
case V4L2_PIX_FMT_DV :
|
||||
case V4L2_PIX_FMT_MPEG :
|
||||
case V4L2_PIX_FMT_WNVA :
|
||||
case V4L2_PIX_FMT_SN9C10X :
|
||||
case V4L2_PIX_FMT_PWC1 :
|
||||
case V4L2_PIX_FMT_PWC2 :
|
||||
case V4L2_PIX_FMT_ET61X251 :
|
||||
//case V4L2_PIX_FMT_SPCA501 :
|
||||
//case V4L2_PIX_FMT_SPCA505 :
|
||||
//case V4L2_PIX_FMT_SPCA508 :
|
||||
//case V4L2_PIX_FMT_SPCA561 :
|
||||
//case V4L2_PIX_FMT_PAC207 :
|
||||
//case V4L2_PIX_FMT_PJPG :
|
||||
//case V4L2_PIX_FMT_YVYU :
|
||||
default :
|
||||
{
|
||||
Fatal("Can't find swscale format for palette %d", palette);
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUV410 :
|
||||
pixFormat = AV_PIX_FMT_YUV410P;
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUV420 :
|
||||
pixFormat = AV_PIX_FMT_YUV420P;
|
||||
break;
|
||||
case V4L2_PIX_FMT_JPEG :
|
||||
case V4L2_PIX_FMT_MJPEG :
|
||||
pixFormat = AV_PIX_FMT_YUVJ444P;
|
||||
break;
|
||||
case V4L2_PIX_FMT_UYVY :
|
||||
pixFormat = AV_PIX_FMT_UYVY422;
|
||||
break;
|
||||
// These don't seem to have ffmpeg equivalents
|
||||
// See if you can match any of the ones in the default clause below!?
|
||||
case V4L2_PIX_FMT_RGB332 :
|
||||
case V4L2_PIX_FMT_RGB555X :
|
||||
case V4L2_PIX_FMT_RGB565X :
|
||||
//case V4L2_PIX_FMT_Y16 :
|
||||
//case V4L2_PIX_FMT_PAL8 :
|
||||
case V4L2_PIX_FMT_YVU410 :
|
||||
case V4L2_PIX_FMT_YVU420 :
|
||||
case V4L2_PIX_FMT_Y41P :
|
||||
//case V4L2_PIX_FMT_YUV555 :
|
||||
//case V4L2_PIX_FMT_YUV565 :
|
||||
//case V4L2_PIX_FMT_YUV32 :
|
||||
case V4L2_PIX_FMT_NV12 :
|
||||
case V4L2_PIX_FMT_NV21 :
|
||||
case V4L2_PIX_FMT_YYUV :
|
||||
case V4L2_PIX_FMT_HI240 :
|
||||
case V4L2_PIX_FMT_HM12 :
|
||||
//case V4L2_PIX_FMT_SBGGR8 :
|
||||
//case V4L2_PIX_FMT_SGBRG8 :
|
||||
//case V4L2_PIX_FMT_SBGGR16 :
|
||||
case V4L2_PIX_FMT_DV :
|
||||
case V4L2_PIX_FMT_MPEG :
|
||||
case V4L2_PIX_FMT_WNVA :
|
||||
case V4L2_PIX_FMT_SN9C10X :
|
||||
case V4L2_PIX_FMT_PWC1 :
|
||||
case V4L2_PIX_FMT_PWC2 :
|
||||
case V4L2_PIX_FMT_ET61X251 :
|
||||
//case V4L2_PIX_FMT_SPCA501 :
|
||||
//case V4L2_PIX_FMT_SPCA505 :
|
||||
//case V4L2_PIX_FMT_SPCA508 :
|
||||
//case V4L2_PIX_FMT_SPCA561 :
|
||||
//case V4L2_PIX_FMT_PAC207 :
|
||||
//case V4L2_PIX_FMT_PJPG :
|
||||
//case V4L2_PIX_FMT_YVYU :
|
||||
default : {
|
||||
Fatal("Can't find swscale format for palette %d", palette);
|
||||
break;
|
||||
#if 0
|
||||
// These are all spare and may match some of the above
|
||||
pixFormat = AV_PIX_FMT_YUVJ420P;
|
||||
pixFormat = AV_PIX_FMT_YUVJ422P;
|
||||
pixFormat = AV_PIX_FMT_UYVY422;
|
||||
pixFormat = AV_PIX_FMT_UYYVYY411;
|
||||
pixFormat = AV_PIX_FMT_BGR565;
|
||||
pixFormat = AV_PIX_FMT_BGR555;
|
||||
pixFormat = AV_PIX_FMT_BGR8;
|
||||
pixFormat = AV_PIX_FMT_BGR4;
|
||||
pixFormat = AV_PIX_FMT_BGR4_BYTE;
|
||||
pixFormat = AV_PIX_FMT_RGB8;
|
||||
pixFormat = AV_PIX_FMT_RGB4;
|
||||
pixFormat = AV_PIX_FMT_RGB4_BYTE;
|
||||
pixFormat = AV_PIX_FMT_NV12;
|
||||
pixFormat = AV_PIX_FMT_NV21;
|
||||
pixFormat = AV_PIX_FMT_RGB32_1;
|
||||
pixFormat = AV_PIX_FMT_BGR32_1;
|
||||
pixFormat = AV_PIX_FMT_GRAY16BE;
|
||||
pixFormat = AV_PIX_FMT_GRAY16LE;
|
||||
pixFormat = AV_PIX_FMT_YUV440P;
|
||||
pixFormat = AV_PIX_FMT_YUVJ440P;
|
||||
pixFormat = AV_PIX_FMT_YUVA420P;
|
||||
//pixFormat = AV_PIX_FMT_VDPAU_H264;
|
||||
//pixFormat = AV_PIX_FMT_VDPAU_MPEG1;
|
||||
//pixFormat = AV_PIX_FMT_VDPAU_MPEG2;
|
||||
// These are all spare and may match some of the above
|
||||
pixFormat = AV_PIX_FMT_YUVJ420P;
|
||||
pixFormat = AV_PIX_FMT_YUVJ422P;
|
||||
pixFormat = AV_PIX_FMT_UYVY422;
|
||||
pixFormat = AV_PIX_FMT_UYYVYY411;
|
||||
pixFormat = AV_PIX_FMT_BGR565;
|
||||
pixFormat = AV_PIX_FMT_BGR555;
|
||||
pixFormat = AV_PIX_FMT_BGR8;
|
||||
pixFormat = AV_PIX_FMT_BGR4;
|
||||
pixFormat = AV_PIX_FMT_BGR4_BYTE;
|
||||
pixFormat = AV_PIX_FMT_RGB8;
|
||||
pixFormat = AV_PIX_FMT_RGB4;
|
||||
pixFormat = AV_PIX_FMT_RGB4_BYTE;
|
||||
pixFormat = AV_PIX_FMT_NV12;
|
||||
pixFormat = AV_PIX_FMT_NV21;
|
||||
pixFormat = AV_PIX_FMT_RGB32_1;
|
||||
pixFormat = AV_PIX_FMT_BGR32_1;
|
||||
pixFormat = AV_PIX_FMT_GRAY16BE;
|
||||
pixFormat = AV_PIX_FMT_GRAY16LE;
|
||||
pixFormat = AV_PIX_FMT_YUV440P;
|
||||
pixFormat = AV_PIX_FMT_YUVJ440P;
|
||||
pixFormat = AV_PIX_FMT_YUVA420P;
|
||||
//pixFormat = AV_PIX_FMT_VDPAU_H264;
|
||||
//pixFormat = AV_PIX_FMT_VDPAU_MPEG1;
|
||||
//pixFormat = AV_PIX_FMT_VDPAU_MPEG2;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} // end switch palette
|
||||
|
||||
return pixFormat;
|
||||
@@ -242,14 +241,13 @@ LocalCamera::LocalCamera(
|
||||
bool p_capture,
|
||||
bool p_record_audio,
|
||||
unsigned int p_extras) :
|
||||
Camera(monitor, LOCAL_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio),
|
||||
Camera(monitor, LOCAL_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio),
|
||||
device(p_device),
|
||||
channel(p_channel),
|
||||
standard(p_standard),
|
||||
palette(p_palette),
|
||||
channel_index(0),
|
||||
extras(p_extras)
|
||||
{
|
||||
extras(p_extras) {
|
||||
// If we are the first, or only, input on this device then
|
||||
// do the initial opening etc
|
||||
device_prime = (camera_count++ == 0);
|
||||
@@ -349,12 +347,12 @@ LocalCamera::LocalCamera(
|
||||
} else {
|
||||
if (capture) {
|
||||
Info(
|
||||
"No direct match for the selected palette (%d) and target colorspace (%02u). Format conversion is required, performance penalty expected",
|
||||
capturePixFormat,
|
||||
colours);
|
||||
"No direct match for the selected palette (%d) and target colorspace (%02u). Format conversion is required, performance penalty expected",
|
||||
capturePixFormat,
|
||||
colours);
|
||||
}
|
||||
/* Try using swscale for the conversion */
|
||||
conversion_type = 1;
|
||||
conversion_type = 1;
|
||||
Debug(2, "Using swscale for image conversion");
|
||||
if (colours == ZM_COLOUR_RGB32) {
|
||||
subpixelorder = ZM_SUBPIX_ORDER_RGBA;
|
||||
@@ -448,9 +446,9 @@ LocalCamera::LocalCamera(
|
||||
}
|
||||
|
||||
imgConversionContext = sws_getContext(
|
||||
width, height, capturePixFormat,
|
||||
width, height, imagePixFormat, SWS_BICUBIC,
|
||||
nullptr, nullptr, nullptr);
|
||||
width, height, capturePixFormat,
|
||||
width, height, imagePixFormat, SWS_BICUBIC,
|
||||
nullptr, nullptr, nullptr);
|
||||
|
||||
if (!imgConversionContext) {
|
||||
Fatal("Unable to initialise image scaling context");
|
||||
@@ -484,7 +482,7 @@ void LocalCamera::Initialise() {
|
||||
if ((vid_fd = open(device.c_str(), O_RDWR, 0)) < 0)
|
||||
Fatal("Failed to open video device %s: %s", device.c_str(), strerror(errno));
|
||||
|
||||
struct stat st;
|
||||
struct stat st;
|
||||
if (stat(device.c_str(), &st) < 0)
|
||||
Fatal("Failed to stat video device %s: %s", device.c_str(), strerror(errno));
|
||||
|
||||
@@ -512,28 +510,28 @@ void LocalCamera::Initialise() {
|
||||
Fatal("Failed to get video format: %s", strerror(errno));
|
||||
|
||||
Debug(4,
|
||||
" v4l2_data.fmt.type = %08x\n"
|
||||
" v4l2_data.fmt.fmt.pix.width = %d\n"
|
||||
" v4l2_data.fmt.fmt.pix.height = %d\n"
|
||||
" v4l2_data.fmt.fmt.pix.pixelformat = %08x\n"
|
||||
" v4l2_data.fmt.fmt.pix.field = %08x\n"
|
||||
" v4l2_data.fmt.fmt.pix.bytesperline = %d\n"
|
||||
" v4l2_data.fmt.fmt.pix.sizeimage = %d\n"
|
||||
" v4l2_data.fmt.fmt.pix.colorspace = %08x\n"
|
||||
" v4l2_data.fmt.fmt.pix.priv = %08x\n"
|
||||
, v4l2_data.fmt.type
|
||||
, v4l2_data.fmt.fmt.pix.width
|
||||
, v4l2_data.fmt.fmt.pix.height
|
||||
, v4l2_data.fmt.fmt.pix.pixelformat
|
||||
, v4l2_data.fmt.fmt.pix.field
|
||||
, v4l2_data.fmt.fmt.pix.bytesperline
|
||||
, v4l2_data.fmt.fmt.pix.sizeimage
|
||||
, v4l2_data.fmt.fmt.pix.colorspace
|
||||
, v4l2_data.fmt.fmt.pix.priv
|
||||
);
|
||||
" v4l2_data.fmt.type = %08x\n"
|
||||
" v4l2_data.fmt.fmt.pix.width = %d\n"
|
||||
" v4l2_data.fmt.fmt.pix.height = %d\n"
|
||||
" v4l2_data.fmt.fmt.pix.pixelformat = %08x\n"
|
||||
" v4l2_data.fmt.fmt.pix.field = %08x\n"
|
||||
" v4l2_data.fmt.fmt.pix.bytesperline = %d\n"
|
||||
" v4l2_data.fmt.fmt.pix.sizeimage = %d\n"
|
||||
" v4l2_data.fmt.fmt.pix.colorspace = %08x\n"
|
||||
" v4l2_data.fmt.fmt.pix.priv = %08x\n"
|
||||
, v4l2_data.fmt.type
|
||||
, v4l2_data.fmt.fmt.pix.width
|
||||
, v4l2_data.fmt.fmt.pix.height
|
||||
, v4l2_data.fmt.fmt.pix.pixelformat
|
||||
, v4l2_data.fmt.fmt.pix.field
|
||||
, v4l2_data.fmt.fmt.pix.bytesperline
|
||||
, v4l2_data.fmt.fmt.pix.sizeimage
|
||||
, v4l2_data.fmt.fmt.pix.colorspace
|
||||
, v4l2_data.fmt.fmt.pix.priv
|
||||
);
|
||||
|
||||
v4l2_data.fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
v4l2_data.fmt.fmt.pix.width = width;
|
||||
v4l2_data.fmt.fmt.pix.width = width;
|
||||
v4l2_data.fmt.fmt.pix.height = height;
|
||||
v4l2_data.fmt.fmt.pix.pixelformat = palette;
|
||||
|
||||
@@ -547,7 +545,7 @@ void LocalCamera::Initialise() {
|
||||
Fatal("Failed to set video format: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
if (vidioctl(vid_fd, VIDIOC_S_FMT, &v4l2_data.fmt) < 0) {
|
||||
Error("Failed to set video format: %s", strerror(errno));
|
||||
}
|
||||
@@ -555,25 +553,25 @@ void LocalCamera::Initialise() {
|
||||
|
||||
/* Note VIDIOC_S_FMT may change width and height. */
|
||||
Debug(4,
|
||||
" v4l2_data.fmt.type = %08x\n"
|
||||
" v4l2_data.fmt.fmt.pix.width = %d\n"
|
||||
" v4l2_data.fmt.fmt.pix.height = %d\n"
|
||||
" v4l2_data.fmt.fmt.pix.pixelformat = %08x\n"
|
||||
" v4l2_data.fmt.fmt.pix.field = %08x\n"
|
||||
" v4l2_data.fmt.fmt.pix.bytesperline = %d\n"
|
||||
" v4l2_data.fmt.fmt.pix.sizeimage = %d\n"
|
||||
" v4l2_data.fmt.fmt.pix.colorspace = %08x\n"
|
||||
" v4l2_data.fmt.fmt.pix.priv = %08x\n"
|
||||
, v4l2_data.fmt.type
|
||||
, v4l2_data.fmt.fmt.pix.width
|
||||
, v4l2_data.fmt.fmt.pix.height
|
||||
, v4l2_data.fmt.fmt.pix.pixelformat
|
||||
, v4l2_data.fmt.fmt.pix.field
|
||||
, v4l2_data.fmt.fmt.pix.bytesperline
|
||||
, v4l2_data.fmt.fmt.pix.sizeimage
|
||||
, v4l2_data.fmt.fmt.pix.colorspace
|
||||
, v4l2_data.fmt.fmt.pix.priv
|
||||
);
|
||||
" v4l2_data.fmt.type = %08x\n"
|
||||
" v4l2_data.fmt.fmt.pix.width = %d\n"
|
||||
" v4l2_data.fmt.fmt.pix.height = %d\n"
|
||||
" v4l2_data.fmt.fmt.pix.pixelformat = %08x\n"
|
||||
" v4l2_data.fmt.fmt.pix.field = %08x\n"
|
||||
" v4l2_data.fmt.fmt.pix.bytesperline = %d\n"
|
||||
" v4l2_data.fmt.fmt.pix.sizeimage = %d\n"
|
||||
" v4l2_data.fmt.fmt.pix.colorspace = %08x\n"
|
||||
" v4l2_data.fmt.fmt.pix.priv = %08x\n"
|
||||
, v4l2_data.fmt.type
|
||||
, v4l2_data.fmt.fmt.pix.width
|
||||
, v4l2_data.fmt.fmt.pix.height
|
||||
, v4l2_data.fmt.fmt.pix.pixelformat
|
||||
, v4l2_data.fmt.fmt.pix.field
|
||||
, v4l2_data.fmt.fmt.pix.bytesperline
|
||||
, v4l2_data.fmt.fmt.pix.sizeimage
|
||||
, v4l2_data.fmt.fmt.pix.colorspace
|
||||
, v4l2_data.fmt.fmt.pix.priv
|
||||
);
|
||||
|
||||
if (v4l2_data.fmt.fmt.pix.width != width) {
|
||||
Warning("Failed to set requested width");
|
||||
@@ -616,7 +614,7 @@ void LocalCamera::Initialise() {
|
||||
Debug(3,"Failed to get updated JPEG compression options: %s", strerror(errno));
|
||||
} else {
|
||||
Debug(4, "JPEG quality: %d, markers: %#x",
|
||||
jpeg_comp.quality, jpeg_comp.jpeg_markers);
|
||||
jpeg_comp.quality, jpeg_comp.jpeg_markers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -627,7 +625,7 @@ void LocalCamera::Initialise() {
|
||||
memset(&v4l2_data.reqbufs, 0, sizeof(v4l2_data.reqbufs));
|
||||
if (channel_count > 1) {
|
||||
Debug(3, "Channel count is %d", channel_count);
|
||||
if (v4l_multi_buffer){
|
||||
if (v4l_multi_buffer) {
|
||||
v4l2_data.reqbufs.count = 2*channel_count;
|
||||
} else {
|
||||
v4l2_data.reqbufs.count = 1;
|
||||
@@ -652,7 +650,7 @@ void LocalCamera::Initialise() {
|
||||
Fatal("Insufficient buffer memory %d on video device", v4l2_data.reqbufs.count);
|
||||
|
||||
Debug(3, "Setting up data buffers: Channels %d MultiBuffer %d Buffers: %d",
|
||||
channel_count, v4l_multi_buffer, v4l2_data.reqbufs.count);
|
||||
channel_count, v4l_multi_buffer, v4l2_data.reqbufs.count);
|
||||
|
||||
v4l2_data.buffers = new V4L2MappedBuffer[v4l2_data.reqbufs.count];
|
||||
capturePictures = new av_frame_ptr[v4l2_data.reqbufs.count];
|
||||
@@ -676,7 +674,7 @@ void LocalCamera::Initialise() {
|
||||
|
||||
if (v4l2_data.buffers[i].start == MAP_FAILED)
|
||||
Fatal("Can't map video buffer %u (%u bytes) to memory: %s(%d)",
|
||||
i, vid_buf.length, strerror(errno), errno);
|
||||
i, vid_buf.length, strerror(errno), errno);
|
||||
|
||||
capturePictures[i] = av_frame_ptr{zm_av_frame_alloc()};
|
||||
|
||||
@@ -684,13 +682,13 @@ void LocalCamera::Initialise() {
|
||||
Fatal("Could not allocate picture");
|
||||
|
||||
av_image_fill_arrays(
|
||||
capturePictures[i]->data,
|
||||
capturePictures[i]->linesize,
|
||||
(uint8_t*)v4l2_data.buffers[i].start,
|
||||
capturePixFormat,
|
||||
v4l2_data.fmt.fmt.pix.width,
|
||||
v4l2_data.fmt.fmt.pix.height,
|
||||
1);
|
||||
capturePictures[i]->data,
|
||||
capturePictures[i]->linesize,
|
||||
(uint8_t*)v4l2_data.buffers[i].start,
|
||||
capturePixFormat,
|
||||
v4l2_data.fmt.fmt.pix.width,
|
||||
v4l2_data.fmt.fmt.pix.height,
|
||||
1);
|
||||
} // end foreach request buf
|
||||
|
||||
Debug(3, "Configuring video source");
|
||||
@@ -759,7 +757,7 @@ uint32_t LocalCamera::AutoSelectFormat(int p_colours) {
|
||||
/* Open the device */
|
||||
if ( (enum_fd = open(device.c_str(), O_RDWR, 0)) < 0 ) {
|
||||
Error("Automatic format selection failed to open video device %s: %s",
|
||||
device.c_str(), strerror(errno));
|
||||
device.c_str(), strerror(errno));
|
||||
return selected_palette;
|
||||
}
|
||||
|
||||
@@ -784,7 +782,7 @@ uint32_t LocalCamera::AutoSelectFormat(int p_colours) {
|
||||
static_cast<uint8>((fmt_fcc[nIndex] >> 8) & 0xff),
|
||||
static_cast<uint8>((fmt_fcc[nIndex]) & 0xff),
|
||||
nIndex);
|
||||
|
||||
|
||||
/* Proceed to the next index */
|
||||
memset(&fmtinfo, 0, sizeof(fmtinfo));
|
||||
fmtinfo.index = ++nIndex;
|
||||
@@ -850,10 +848,10 @@ uint32_t LocalCamera::AutoSelectFormat(int p_colours) {
|
||||
(test) ? (prefix yesString " " capability "\n") : (prefix noString " " capability "\n")
|
||||
|
||||
bool LocalCamera::GetCurrentSettings(
|
||||
const std::string& device,
|
||||
char *output,
|
||||
int version,
|
||||
bool verbose) {
|
||||
const std::string& device,
|
||||
char *output,
|
||||
int version,
|
||||
bool verbose) {
|
||||
output[0] = 0;
|
||||
char *output_ptr = output;
|
||||
|
||||
@@ -904,40 +902,40 @@ bool LocalCamera::GetCurrentSettings(
|
||||
|
||||
if ( verbose ) {
|
||||
output_ptr += sprintf(output_ptr, "General Capabilities\n"
|
||||
" Driver: %s\n"
|
||||
" Card: %s\n"
|
||||
" Bus: %s\n"
|
||||
" Version: %u.%u.%u\n"
|
||||
" Type: 0x%x\n%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
vid_cap.driver, vid_cap.card, vid_cap.bus_info,
|
||||
(vid_cap.version>>16)&0xff, (vid_cap.version>>8)&0xff, vid_cap.version&0xff,
|
||||
vid_cap.capabilities,
|
||||
capString(vid_cap.capabilities&V4L2_CAP_VIDEO_CAPTURE, " ", "Supports", "Does not support", "video capture (X)"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_VIDEO_OUTPUT, " ", "Supports", "Does not support", "video output"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_VIDEO_OVERLAY, " ", "Supports", "Does not support", "frame buffer overlay"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_VBI_CAPTURE, " ", "Supports", "Does not support", "VBI capture"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_VBI_OUTPUT, " ", "Supports", "Does not support", "VBI output"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_SLICED_VBI_CAPTURE, " ", "Supports", "Does not support", "sliced VBI capture"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_SLICED_VBI_OUTPUT, " ", "Supports", "Does not support", "sliced VBI output"),
|
||||
" Driver: %s\n"
|
||||
" Card: %s\n"
|
||||
" Bus: %s\n"
|
||||
" Version: %u.%u.%u\n"
|
||||
" Type: 0x%x\n%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
vid_cap.driver, vid_cap.card, vid_cap.bus_info,
|
||||
(vid_cap.version>>16)&0xff, (vid_cap.version>>8)&0xff, vid_cap.version&0xff,
|
||||
vid_cap.capabilities,
|
||||
capString(vid_cap.capabilities&V4L2_CAP_VIDEO_CAPTURE, " ", "Supports", "Does not support", "video capture (X)"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_VIDEO_OUTPUT, " ", "Supports", "Does not support", "video output"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_VIDEO_OVERLAY, " ", "Supports", "Does not support", "frame buffer overlay"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_VBI_CAPTURE, " ", "Supports", "Does not support", "VBI capture"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_VBI_OUTPUT, " ", "Supports", "Does not support", "VBI output"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_SLICED_VBI_CAPTURE, " ", "Supports", "Does not support", "sliced VBI capture"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_SLICED_VBI_OUTPUT, " ", "Supports", "Does not support", "sliced VBI output"),
|
||||
#ifdef V4L2_CAP_VIDEO_OUTPUT_OVERLAY
|
||||
capString(vid_cap.capabilities&V4L2_CAP_VIDEO_OUTPUT_OVERLAY, " ", "Supports", "Does not support", "video output overlay"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_VIDEO_OUTPUT_OVERLAY, " ", "Supports", "Does not support", "video output overlay"),
|
||||
#else // V4L2_CAP_VIDEO_OUTPUT_OVERLAY
|
||||
"",
|
||||
"",
|
||||
#endif // V4L2_CAP_VIDEO_OUTPUT_OVERLAY
|
||||
capString(vid_cap.capabilities&V4L2_CAP_TUNER, " ", "Has", "Does not have", "tuner"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_AUDIO, " ", "Has", "Does not have", "audio in and/or out"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_RADIO, " ", "Has", "Does not have", "radio"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_READWRITE, " ", "Supports", "Does not support", "read/write i/o (X)"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_ASYNCIO, " ", "Supports", "Does not support", "async i/o"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_STREAMING, " ", "Supports", "Does not support", "streaming i/o (X)")
|
||||
);
|
||||
capString(vid_cap.capabilities&V4L2_CAP_TUNER, " ", "Has", "Does not have", "tuner"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_AUDIO, " ", "Has", "Does not have", "audio in and/or out"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_RADIO, " ", "Has", "Does not have", "radio"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_READWRITE, " ", "Supports", "Does not support", "read/write i/o (X)"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_ASYNCIO, " ", "Supports", "Does not support", "async i/o"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_STREAMING, " ", "Supports", "Does not support", "streaming i/o (X)")
|
||||
);
|
||||
} else {
|
||||
output_ptr += sprintf(output_ptr, "D:%s|C:%s|B:%s|V:%u.%u.%u|T:0x%x|"
|
||||
, vid_cap.driver
|
||||
, vid_cap.card
|
||||
, vid_cap.bus_info
|
||||
, (vid_cap.version>>16)&0xff, (vid_cap.version>>8)&0xff, vid_cap.version&0xff
|
||||
, vid_cap.capabilities);
|
||||
, vid_cap.driver
|
||||
, vid_cap.card
|
||||
, vid_cap.bus_info
|
||||
, (vid_cap.version>>16)&0xff, (vid_cap.version>>8)&0xff, vid_cap.version&0xff
|
||||
, vid_cap.capabilities);
|
||||
}
|
||||
|
||||
output_ptr += sprintf(output_ptr, verbose ? " Standards:\n" : "S:");
|
||||
@@ -992,26 +990,26 @@ bool LocalCamera::GetCurrentSettings(
|
||||
}
|
||||
if ( verbose )
|
||||
output_ptr += sprintf(
|
||||
output_ptr,
|
||||
" %s (0x%02x%02x%02x%02x)\n",
|
||||
format.description,
|
||||
(format.pixelformat >> 24) & 0xff,
|
||||
(format.pixelformat >> 16) & 0xff,
|
||||
(format.pixelformat >> 8) & 0xff,
|
||||
format.pixelformat & 0xff);
|
||||
output_ptr,
|
||||
" %s (0x%02x%02x%02x%02x)\n",
|
||||
format.description,
|
||||
(format.pixelformat >> 24) & 0xff,
|
||||
(format.pixelformat >> 16) & 0xff,
|
||||
(format.pixelformat >> 8) & 0xff,
|
||||
format.pixelformat & 0xff);
|
||||
else
|
||||
output_ptr += sprintf(
|
||||
output_ptr,
|
||||
"0x%02x%02x%02x%02x/",
|
||||
(format.pixelformat >> 24) & 0xff,
|
||||
(format.pixelformat >> 16) & 0xff,
|
||||
(format.pixelformat >> 8) & 0xff,
|
||||
format.pixelformat & 0xff);
|
||||
output_ptr,
|
||||
"0x%02x%02x%02x%02x/",
|
||||
(format.pixelformat >> 24) & 0xff,
|
||||
(format.pixelformat >> 16) & 0xff,
|
||||
(format.pixelformat >> 8) & 0xff,
|
||||
format.pixelformat & 0xff);
|
||||
} while ( formatIndex++ >= 0 );
|
||||
|
||||
if ( !verbose )
|
||||
*(output_ptr-1) = '|';
|
||||
else
|
||||
else
|
||||
output_ptr += sprintf(output_ptr, "Crop Capabilities\n");
|
||||
|
||||
v4l2_cropcap cropcap = {};
|
||||
@@ -1021,7 +1019,7 @@ bool LocalCamera::GetCurrentSettings(
|
||||
if ( errno != EINVAL ) {
|
||||
/* Failed querying crop capability, write error to the log and continue as if crop is not supported */
|
||||
Error("Failed to query crop capabilities for %s: %d, %s",
|
||||
device.c_str(), errno, strerror(errno));
|
||||
device.c_str(), errno, strerror(errno));
|
||||
}
|
||||
|
||||
if ( verbose ) {
|
||||
@@ -1033,7 +1031,7 @@ bool LocalCamera::GetCurrentSettings(
|
||||
} else {
|
||||
v4l2_crop crop = {};
|
||||
|
||||
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
|
||||
if ( vidioctl(vid_fd, VIDIOC_G_CROP, &crop) < 0 ) {
|
||||
if ( errno != EINVAL ) {
|
||||
@@ -1045,18 +1043,18 @@ bool LocalCamera::GetCurrentSettings(
|
||||
output_ptr += sprintf(output_ptr, " Cropping is not supported\n");
|
||||
} else {
|
||||
/* Send fake crop bounds to not confuse things parsing this, such as monitor probe */
|
||||
output_ptr += sprintf(output_ptr, "B:%dx%d|",0,0);
|
||||
output_ptr += sprintf(output_ptr, "B:%dx%d|",0,0);
|
||||
}
|
||||
} else {
|
||||
/* Cropping supported */
|
||||
if ( verbose ) {
|
||||
output_ptr += sprintf(output_ptr,
|
||||
" Bounds: %d x %d\n"
|
||||
" Default: %d x %d\n"
|
||||
" Current: %d x %d\n"
|
||||
, cropcap.bounds.width, cropcap.bounds.height
|
||||
, cropcap.defrect.width, cropcap.defrect.height
|
||||
, crop.c.width, crop.c.height);
|
||||
" Bounds: %d x %d\n"
|
||||
" Default: %d x %d\n"
|
||||
" Current: %d x %d\n"
|
||||
, cropcap.bounds.width, cropcap.bounds.height
|
||||
, cropcap.defrect.width, cropcap.defrect.height
|
||||
, crop.c.width, crop.c.height);
|
||||
} else {
|
||||
output_ptr += sprintf(output_ptr, "B:%dx%d|", cropcap.bounds.width, cropcap.bounds.height);
|
||||
}
|
||||
@@ -1072,9 +1070,9 @@ bool LocalCamera::GetCurrentSettings(
|
||||
if ( vidioctl(vid_fd, VIDIOC_ENUMINPUT, &input) < 0 ) {
|
||||
if ( errno == EINVAL ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Error("Failed to enumerate input for %s %d: %d %s",
|
||||
device.c_str(), input.index, errno, strerror(errno));
|
||||
device.c_str(), input.index, errno, strerror(errno));
|
||||
if ( verbose )
|
||||
output_ptr += sprintf(output_ptr, "Error, failed to enumerate input %d: %s\n", input.index, strerror(errno));
|
||||
else
|
||||
@@ -1114,35 +1112,35 @@ bool LocalCamera::GetCurrentSettings(
|
||||
|
||||
if ( verbose ) {
|
||||
output_ptr += sprintf( output,
|
||||
" Input %d\n"
|
||||
" Name: %s\n"
|
||||
" Type: %s\n"
|
||||
" Audioset: %08x\n"
|
||||
" Standards: 0x%" PRIx64"\n"
|
||||
, input.index
|
||||
, input.name
|
||||
, input.type==V4L2_INPUT_TYPE_TUNER?"Tuner":(input.type==V4L2_INPUT_TYPE_CAMERA?"Camera":"Unknown")
|
||||
, input.audioset
|
||||
, static_cast<uint64>(input.std));
|
||||
" Input %d\n"
|
||||
" Name: %s\n"
|
||||
" Type: %s\n"
|
||||
" Audioset: %08x\n"
|
||||
" Standards: 0x%" PRIx64"\n"
|
||||
, input.index
|
||||
, input.name
|
||||
, input.type==V4L2_INPUT_TYPE_TUNER?"Tuner":(input.type==V4L2_INPUT_TYPE_CAMERA?"Camera":"Unknown")
|
||||
, input.audioset
|
||||
, static_cast<uint64>(input.std));
|
||||
} else {
|
||||
output_ptr += sprintf( output_ptr, "i%d:%s|i%dT:%s|i%dS:%" PRIx64 "|"
|
||||
, input.index, input.name
|
||||
, input.index, input.type==V4L2_INPUT_TYPE_TUNER?"Tuner":(input.type==V4L2_INPUT_TYPE_CAMERA?"Camera":"Unknown")
|
||||
, input.index, static_cast<uint64>(input.std));
|
||||
, input.index, input.name
|
||||
, input.index, input.type==V4L2_INPUT_TYPE_TUNER?"Tuner":(input.type==V4L2_INPUT_TYPE_CAMERA?"Camera":"Unknown")
|
||||
, input.index, static_cast<uint64>(input.std));
|
||||
}
|
||||
|
||||
if ( verbose ) {
|
||||
output_ptr += sprintf( output_ptr, " %s %s %s %s"
|
||||
, capString(input.status&V4L2_IN_ST_NO_POWER, "Power ", "off", "on", " (X)")
|
||||
, capString(input.status&V4L2_IN_ST_NO_SIGNAL, "Signal ", "not detected", "detected", " (X)")
|
||||
, capString(input.status&V4L2_IN_ST_NO_COLOR, "Colour Signal ", "not detected", "detected", "")
|
||||
, capString(input.status&V4L2_IN_ST_NO_H_LOCK, "Horizontal Lock ", "not detected", "detected", ""));
|
||||
, capString(input.status&V4L2_IN_ST_NO_POWER, "Power ", "off", "on", " (X)")
|
||||
, capString(input.status&V4L2_IN_ST_NO_SIGNAL, "Signal ", "not detected", "detected", " (X)")
|
||||
, capString(input.status&V4L2_IN_ST_NO_COLOR, "Colour Signal ", "not detected", "detected", "")
|
||||
, capString(input.status&V4L2_IN_ST_NO_H_LOCK, "Horizontal Lock ", "not detected", "detected", ""));
|
||||
} else {
|
||||
output_ptr += sprintf( output_ptr, "i%dSP:%d|i%dSS:%d|i%dSC:%d|i%dHP:%d|"
|
||||
, input.index, (input.status&V4L2_IN_ST_NO_POWER)?0:1
|
||||
, input.index, (input.status&V4L2_IN_ST_NO_SIGNAL)?0:1
|
||||
, input.index, (input.status&V4L2_IN_ST_NO_COLOR)?0:1
|
||||
, input.index, (input.status&V4L2_IN_ST_NO_H_LOCK)?0:1 );
|
||||
, input.index, (input.status&V4L2_IN_ST_NO_POWER)?0:1
|
||||
, input.index, (input.status&V4L2_IN_ST_NO_SIGNAL)?0:1
|
||||
, input.index, (input.status&V4L2_IN_ST_NO_COLOR)?0:1
|
||||
, input.index, (input.status&V4L2_IN_ST_NO_H_LOCK)?0:1 );
|
||||
}
|
||||
} while ( inputIndex++ >= 0 );
|
||||
if ( !verbose )
|
||||
@@ -1253,7 +1251,7 @@ int LocalCamera::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
|
||||
if (captures_per_frame <= 0) {
|
||||
captures_per_frame = 1;
|
||||
Warning("Invalid Captures Per Frame setting: %d", captures_per_frame);
|
||||
}
|
||||
}
|
||||
|
||||
// Do the capture, unless we are the second or subsequent camera on a channel, in which case just reuse the buffer
|
||||
if (channel_prime) {
|
||||
@@ -1296,10 +1294,10 @@ int LocalCamera::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
|
||||
|
||||
if ((v4l2_data.fmt.fmt.pix.width * v4l2_data.fmt.fmt.pix.height) > (width * height)) {
|
||||
Fatal("Captured image dimensions larger than image buffer: V4L2: %dx%d monitor: %dx%d",
|
||||
v4l2_data.fmt.fmt.pix.width, v4l2_data.fmt.fmt.pix.height, width, height);
|
||||
v4l2_data.fmt.fmt.pix.width, v4l2_data.fmt.fmt.pix.height, width, height);
|
||||
} else if ((v4l2_data.fmt.fmt.pix.width * v4l2_data.fmt.fmt.pix.height) != (width * height)) {
|
||||
Error("Captured image dimensions differ: V4L2: %dx%d monitor: %dx%d",
|
||||
v4l2_data.fmt.fmt.pix.width, v4l2_data.fmt.fmt.pix.height, width, height);
|
||||
v4l2_data.fmt.fmt.pix.width, v4l2_data.fmt.fmt.pix.height, width, height);
|
||||
}
|
||||
|
||||
if (channel_count > 1) {
|
||||
@@ -1324,7 +1322,7 @@ int LocalCamera::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
|
||||
} else {
|
||||
Error("Unable to requeue buffer due to not v4l2_data");
|
||||
}
|
||||
} /* prime capture */
|
||||
} /* prime capture */
|
||||
|
||||
if (!zm_packet->image) {
|
||||
Debug(4, "Allocating image");
|
||||
@@ -1344,18 +1342,18 @@ int LocalCamera::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
|
||||
Debug(9, "Calling sws_scale to perform the conversion");
|
||||
/* Use swscale to convert the image directly into the shared memory */
|
||||
av_image_fill_arrays(tmpPicture->data,
|
||||
tmpPicture->linesize, directbuffer,
|
||||
imagePixFormat, width, height, 1);
|
||||
tmpPicture->linesize, directbuffer,
|
||||
imagePixFormat, width, height, 1);
|
||||
|
||||
sws_scale(
|
||||
imgConversionContext,
|
||||
capturePictures[capture_frame]->data,
|
||||
capturePictures[capture_frame]->linesize,
|
||||
0,
|
||||
height,
|
||||
tmpPicture->data,
|
||||
tmpPicture->linesize
|
||||
);
|
||||
imgConversionContext,
|
||||
capturePictures[capture_frame]->data,
|
||||
capturePictures[capture_frame]->linesize,
|
||||
0,
|
||||
height,
|
||||
tmpPicture->data,
|
||||
tmpPicture->linesize
|
||||
);
|
||||
} else if (conversion_type == 2) {
|
||||
Debug(9, "Calling the conversion function");
|
||||
/* Call the image conversion function and convert directly into the shared memory */
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Local Camera Class Interface, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_LOCAL_CAMERA_H
|
||||
#define ZM_LOCAL_CAMERA_H
|
||||
@@ -32,22 +32,22 @@
|
||||
// via a video interface.
|
||||
//
|
||||
class LocalCamera : public Camera {
|
||||
protected:
|
||||
struct V4L2MappedBuffer {
|
||||
void *start;
|
||||
size_t length;
|
||||
};
|
||||
protected:
|
||||
struct V4L2MappedBuffer {
|
||||
void *start;
|
||||
size_t length;
|
||||
};
|
||||
|
||||
struct V4L2Data {
|
||||
v4l2_cropcap cropcap;
|
||||
v4l2_crop crop;
|
||||
v4l2_format fmt;
|
||||
v4l2_requestbuffers reqbufs;
|
||||
V4L2MappedBuffer *buffers;
|
||||
v4l2_buffer *bufptr;
|
||||
};
|
||||
struct V4L2Data {
|
||||
v4l2_cropcap cropcap;
|
||||
v4l2_crop crop;
|
||||
v4l2_format fmt;
|
||||
v4l2_requestbuffers reqbufs;
|
||||
V4L2MappedBuffer *buffers;
|
||||
v4l2_buffer *bufptr;
|
||||
};
|
||||
|
||||
protected:
|
||||
protected:
|
||||
std::string device;
|
||||
int channel;
|
||||
int standard;
|
||||
@@ -56,10 +56,10 @@ protected:
|
||||
bool channel_prime;
|
||||
int channel_index;
|
||||
unsigned int extras;
|
||||
|
||||
|
||||
unsigned int conversion_type; /* 0 = no conversion needed, 1 = use libswscale, 2 = zm internal conversion, 3 = jpeg decoding */
|
||||
convert_fptr_t conversion_fptr; /* Pointer to conversion function used */
|
||||
|
||||
|
||||
uint32_t AutoSelectFormat(int p_colours);
|
||||
|
||||
static int camera_count;
|
||||
@@ -81,7 +81,7 @@ protected:
|
||||
|
||||
static LocalCamera *last_camera;
|
||||
|
||||
public:
|
||||
public:
|
||||
LocalCamera(
|
||||
const Monitor *monitor,
|
||||
const std::string &device,
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* ZoneMinder Logger 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_logger.h"
|
||||
|
||||
@@ -223,14 +223,14 @@ void Logger::initialise(const std::string &id, const Options &options) {
|
||||
mInitialised = true;
|
||||
|
||||
Debug(1, "LogOpts: level=%s effective=%s, screen=%s, database=%s, logfile=%s->%s, syslog=%s",
|
||||
smCodes[mLevel].c_str(),
|
||||
smCodes[mEffectiveLevel].c_str(),
|
||||
smCodes[mTerminalLevel].c_str(),
|
||||
smCodes[mDatabaseLevel].c_str(),
|
||||
smCodes[mFileLevel].c_str(),
|
||||
mLogFile.c_str(),
|
||||
smCodes[mSyslogLevel].c_str()
|
||||
);
|
||||
smCodes[mLevel].c_str(),
|
||||
smCodes[mEffectiveLevel].c_str(),
|
||||
smCodes[mTerminalLevel].c_str(),
|
||||
smCodes[mDatabaseLevel].c_str(),
|
||||
smCodes[mFileLevel].c_str(),
|
||||
mLogFile.c_str(),
|
||||
smCodes[mSyslogLevel].c_str()
|
||||
);
|
||||
}
|
||||
|
||||
void Logger::terminate() {
|
||||
@@ -420,7 +420,7 @@ void Logger::logPrint(bool hex, const char *filepath, int line, int level, const
|
||||
if (level > mEffectiveLevel) return;
|
||||
if (level < PANIC || level > DEBUG9)
|
||||
Panic("Invalid logger level %d", level);
|
||||
|
||||
|
||||
log_mutex.lock();
|
||||
// Can we save some cycles by having these as members and not allocate them on the fly? I think so.
|
||||
char timeString[64];
|
||||
@@ -434,7 +434,7 @@ void Logger::logPrint(bool hex, const char *filepath, int line, int level, const
|
||||
SystemTimePoint now = std::chrono::system_clock::now();
|
||||
time_t now_sec = std::chrono::system_clock::to_time_t(now);
|
||||
Microseconds now_frac = std::chrono::duration_cast<Microseconds>(
|
||||
now.time_since_epoch() - std::chrono::duration_cast<Seconds>(now.time_since_epoch()));
|
||||
now.time_since_epoch() - std::chrono::duration_cast<Seconds>(now.time_since_epoch()));
|
||||
|
||||
char *timePtr = timeString;
|
||||
tm now_tm = {};
|
||||
@@ -449,29 +449,29 @@ void Logger::logPrint(bool hex, const char *filepath, int line, int level, const
|
||||
|
||||
if ( tid < 0 ) // Thread/Process id
|
||||
#else
|
||||
#ifdef HAVE_SYSCALL
|
||||
#ifdef __FreeBSD_kernel__
|
||||
if ((syscall(SYS_thr_self, &tid)) < 0) // Thread/Process id
|
||||
#ifdef HAVE_SYSCALL
|
||||
#ifdef __FreeBSD_kernel__
|
||||
if ((syscall(SYS_thr_self, &tid)) < 0) // Thread/Process id
|
||||
|
||||
# else
|
||||
// SOLARIS doesn't have SYS_gettid; don't assume
|
||||
#ifdef SYS_gettid
|
||||
if ((tid = syscall(SYS_gettid)) < 0) // Thread/Process id
|
||||
#endif // SYS_gettid
|
||||
#endif
|
||||
#endif // HAVE_SYSCALL
|
||||
# else
|
||||
// SOLARIS doesn't have SYS_gettid; don't assume
|
||||
#ifdef SYS_gettid
|
||||
if ((tid = syscall(SYS_gettid)) < 0) // Thread/Process id
|
||||
#endif // SYS_gettid
|
||||
#endif
|
||||
#endif // HAVE_SYSCALL
|
||||
#endif
|
||||
tid = getpid(); // Process id
|
||||
|
||||
char *logPtr = logString;
|
||||
logPtr += snprintf(logPtr, sizeof(logString), "%s %s[%d].%s-%s/%d [",
|
||||
timeString,
|
||||
mId.c_str(),
|
||||
tid,
|
||||
classString,
|
||||
file,
|
||||
line
|
||||
);
|
||||
timeString,
|
||||
mId.c_str(),
|
||||
tid,
|
||||
classString,
|
||||
file,
|
||||
line
|
||||
);
|
||||
char *syslogStart = logPtr;
|
||||
|
||||
va_start(argPtr, fstring);
|
||||
@@ -526,12 +526,12 @@ void Logger::logPrint(bool hex, const char *filepath, int line, int level, const
|
||||
std::string escapedString = zmDbEscapeString({syslogStart, syslogEnd});
|
||||
|
||||
std::string sql_string = stringtf(
|
||||
"INSERT INTO `Logs` "
|
||||
"( `TimeKey`, `Component`, `ServerId`, `Pid`, `Level`, `Code`, `Message`, `File`, `Line` )"
|
||||
" VALUES "
|
||||
"( %ld.%06" PRIi64 ", '%s', %d, %d, %d, '%s', '%s', '%s', %d )",
|
||||
now_sec, static_cast<int64>(now_frac.count()), mId.c_str(), staticConfig.SERVER_ID, tid, level, classString,
|
||||
escapedString.c_str(), file, line);
|
||||
"INSERT INTO `Logs` "
|
||||
"( `TimeKey`, `Component`, `ServerId`, `Pid`, `Level`, `Code`, `Message`, `File`, `Line` )"
|
||||
" VALUES "
|
||||
"( %ld.%06" PRIi64 ", '%s', %d, %d, %d, '%s', '%s', '%s', %d )",
|
||||
now_sec, static_cast<int64>(now_frac.count()), mId.c_str(), staticConfig.SERVER_ID, tid, level, classString,
|
||||
escapedString.c_str(), file, line);
|
||||
dbQueue.push(std::move(sql_string));
|
||||
} else {
|
||||
puts("Db is closed");
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* ZoneMinder Logger Interface
|
||||
* 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.
|
||||
*/
|
||||
*/
|
||||
|
||||
#ifndef ZM_LOGGER_H
|
||||
#define ZM_LOGGER_H
|
||||
@@ -68,13 +68,13 @@ class Logger {
|
||||
std::string mLogFile;
|
||||
|
||||
Options(
|
||||
Level terminalLevel = NOOPT,
|
||||
Level databaseLevel = NOOPT,
|
||||
Level fileLevel = NOOPT,
|
||||
Level syslogLevel = NOOPT,
|
||||
const std::string &logPath = ".",
|
||||
const std::string &logFile = ""
|
||||
) :
|
||||
Level terminalLevel = NOOPT,
|
||||
Level databaseLevel = NOOPT,
|
||||
Level fileLevel = NOOPT,
|
||||
Level syslogLevel = NOOPT,
|
||||
const std::string &logPath = ".",
|
||||
const std::string &logFile = ""
|
||||
) :
|
||||
mTerminalLevel(terminalLevel),
|
||||
mDatabaseLevel(databaseLevel),
|
||||
mFileLevel(fileLevel),
|
||||
@@ -130,8 +130,8 @@ class Logger {
|
||||
bool boolEnv(const std::string &name, bool defaultValue = false);
|
||||
int intEnv(const std::string &name, bool defaultValue = 0);
|
||||
std::string strEnv(
|
||||
const std::string &name,
|
||||
const std::string &defaultValue = "");
|
||||
const std::string &name,
|
||||
const std::string &defaultValue = "");
|
||||
char *getTargettedEnv(const std::string &name);
|
||||
|
||||
void loadEnv();
|
||||
@@ -184,9 +184,9 @@ class Logger {
|
||||
};
|
||||
|
||||
void logInit(
|
||||
const char *name,
|
||||
const Logger::Options &options = Logger::Options()
|
||||
);
|
||||
const char *name,
|
||||
const Logger::Options &options = Logger::Options()
|
||||
);
|
||||
void logTerm();
|
||||
inline const std::string &logId() {
|
||||
return Logger::fetch()->id();
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Memory Utilities, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_MEM_UTILS_H
|
||||
#define ZM_MEM_UTILS_H
|
||||
@@ -27,23 +27,23 @@ inline void* zm_mallocaligned(unsigned int reqalignment, size_t reqsize) {
|
||||
#if HAVE_POSIX_MEMALIGN
|
||||
if ( posix_memalign((void**)&retptr, reqalignment, reqsize) != 0 )
|
||||
return nullptr;
|
||||
|
||||
|
||||
return retptr;
|
||||
#else
|
||||
uint8_t* alloc;
|
||||
retptr = (uint8_t*)malloc(reqsize+reqalignment+sizeof(void*));
|
||||
|
||||
|
||||
if ( retptr == nullptr )
|
||||
return nullptr;
|
||||
|
||||
|
||||
alloc = retptr + sizeof(void*);
|
||||
|
||||
|
||||
if ( ((long)alloc % reqalignment) != 0 )
|
||||
alloc = alloc + (reqalignment - ((long)alloc % reqalignment));
|
||||
|
||||
|
||||
/* Store a pointer before to the start of the block, just before returned aligned memory */
|
||||
*(void**)(alloc - sizeof(void*)) = retptr;
|
||||
|
||||
|
||||
return alloc;
|
||||
#endif
|
||||
}
|
||||
|
||||
1337
src/zm_monitor.cpp
1337
src/zm_monitor.cpp
File diff suppressed because it is too large
Load Diff
@@ -63,7 +63,7 @@ class Monitor : public std::enable_shared_from_this<Monitor> {
|
||||
friend class MonitorStream;
|
||||
friend class MonitorLinkExpression;
|
||||
|
||||
public:
|
||||
public:
|
||||
typedef enum {
|
||||
QUERY=0,
|
||||
CAPTURE,
|
||||
@@ -167,7 +167,7 @@ public:
|
||||
PASSTHROUGH,
|
||||
} VideoWriter;
|
||||
|
||||
protected:
|
||||
protected:
|
||||
typedef std::set<Zone *> ZoneSet;
|
||||
|
||||
typedef enum { GET_SETTINGS=0x1, SET_SETTINGS=0x2, RELOAD=0x4, SUSPEND=0x10, RESUME=0x20 } Action;
|
||||
@@ -205,7 +205,7 @@ protected:
|
||||
uint32_t audio_frequency; /* +68 */
|
||||
uint32_t audio_channels; /* +72 */
|
||||
uint32_t reserved3; /* +76 */
|
||||
/*
|
||||
/*
|
||||
** This keeps 32bit time_t and 64bit time_t identical and compatible as long as time is before 2038.
|
||||
** Shared memory layout should be identical for both 32bit and 64bit and is multiples of 16.
|
||||
** Because startup_time is 64bit it may be aligned to a 64bit boundary. So it's offset SHOULD be a multiple
|
||||
@@ -265,9 +265,9 @@ protected:
|
||||
timeval recording; // used as both bool and a pointer to the timestamp when recording should begin
|
||||
} VideoStoreData;
|
||||
|
||||
public:
|
||||
public:
|
||||
class MonitorLink {
|
||||
protected:
|
||||
protected:
|
||||
std::shared_ptr<Monitor> monitor;
|
||||
unsigned int zone_id;
|
||||
const Zone *zone;
|
||||
@@ -296,39 +296,39 @@ public:
|
||||
uint64_t last_event_id;
|
||||
std::vector<Zone> zones;
|
||||
|
||||
public:
|
||||
MonitorLink(std::shared_ptr<Monitor> p_monitor, unsigned int p_zone_id);
|
||||
~MonitorLink();
|
||||
public:
|
||||
MonitorLink(std::shared_ptr<Monitor> p_monitor, unsigned int p_zone_id);
|
||||
~MonitorLink();
|
||||
|
||||
inline unsigned int Id() const { return monitor->Id(); }
|
||||
inline const char *Name() const { return name.c_str(); }
|
||||
inline unsigned int Id() const { return monitor->Id(); }
|
||||
inline const char *Name() const { return name.c_str(); }
|
||||
|
||||
inline bool isConnected() const { return connected && shared_data->valid; }
|
||||
inline time_t getLastConnectTime() const { return last_connect_time; }
|
||||
inline bool isConnected() const { return connected && shared_data->valid; }
|
||||
inline time_t getLastConnectTime() const { return last_connect_time; }
|
||||
|
||||
inline uint32_t lastFrameScore() {
|
||||
return shared_data->last_frame_score;
|
||||
}
|
||||
inline uint32_t lastFrameScore() {
|
||||
return shared_data->last_frame_score;
|
||||
}
|
||||
|
||||
bool connect();
|
||||
bool disconnect();
|
||||
bool connect();
|
||||
bool disconnect();
|
||||
|
||||
bool isAlarmed();
|
||||
bool inAlarm();
|
||||
bool hasAlarmed();
|
||||
int score();
|
||||
bool isAlarmed();
|
||||
bool inAlarm();
|
||||
bool hasAlarmed();
|
||||
int score();
|
||||
};
|
||||
protected:
|
||||
protected:
|
||||
|
||||
class AmcrestAPI {
|
||||
protected:
|
||||
protected:
|
||||
Monitor *parent;
|
||||
std::string amcrest_response;
|
||||
CURLM *curl_multi = nullptr;
|
||||
CURL *Amcrest_handle = nullptr;
|
||||
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp);
|
||||
|
||||
public:
|
||||
public:
|
||||
explicit AmcrestAPI(Monitor *parent_);
|
||||
~AmcrestAPI();
|
||||
int API_Connect();
|
||||
@@ -338,7 +338,7 @@ protected:
|
||||
};
|
||||
|
||||
class RTSP2WebManager {
|
||||
protected:
|
||||
protected:
|
||||
Monitor *parent;
|
||||
CURL *curl = nullptr;
|
||||
//helper class for CURL
|
||||
@@ -350,7 +350,7 @@ protected:
|
||||
std::string rtsp_password;
|
||||
std::string rtsp_path;
|
||||
|
||||
public:
|
||||
public:
|
||||
explicit RTSP2WebManager(Monitor *parent_);
|
||||
~RTSP2WebManager();
|
||||
void load_from_monitor();
|
||||
@@ -360,7 +360,7 @@ protected:
|
||||
};
|
||||
|
||||
class JanusManager {
|
||||
protected:
|
||||
protected:
|
||||
Monitor *parent;
|
||||
CURL *curl = nullptr;
|
||||
//helper class for CURL
|
||||
@@ -378,7 +378,7 @@ protected:
|
||||
std::string profile_override;
|
||||
std::uint32_t rtsp_session_timeout;
|
||||
|
||||
public:
|
||||
public:
|
||||
explicit JanusManager(Monitor *parent_);
|
||||
~JanusManager();
|
||||
void load_from_monitor();
|
||||
@@ -498,7 +498,7 @@ protected:
|
||||
int fps_report_interval; // How many images should be captured/processed between reporting the current FPS
|
||||
int ref_blend_perc; // Percentage of new image going into reference image.
|
||||
int alarm_ref_blend_perc; // Percentage of new image going into reference image during alarm.
|
||||
bool track_motion; // Whether this monitor tries to track detected motion
|
||||
bool track_motion; // Whether this monitor tries to track detected motion
|
||||
int signal_check_points; // Number of points in the image to check for signal
|
||||
Rgb signal_check_colour; // The colour that the camera will emit when no video signal detected
|
||||
bool embed_exif; // Whether to embed Exif data into each image frame or not
|
||||
@@ -506,10 +506,10 @@ protected:
|
||||
double longitude;
|
||||
bool rtsp_server; // Whether to include this monitor as an rtsp server stream
|
||||
std::string rtsp_streamname; // path in the rtsp url for this monitor
|
||||
bool soap_wsa_compl; // Whether the camera supports soap_wsa or not.
|
||||
bool soap_wsa_compl; // Whether the camera supports soap_wsa or not.
|
||||
std::string onvif_alarm_txt; // def onvif_alarm_txt
|
||||
int importance; // Importance of this monitor, affects Connection logging errors.
|
||||
int startup_delay; // Seconds to sleep before connecting to camera
|
||||
int startup_delay; // Seconds to sleep before connecting to camera
|
||||
unsigned int zone_count;
|
||||
|
||||
int capture_max_fps;
|
||||
@@ -634,7 +634,7 @@ protected:
|
||||
Rgb colour_val; /* RGB32 color */
|
||||
int usedsubpixorder;
|
||||
|
||||
public:
|
||||
public:
|
||||
explicit Monitor();
|
||||
|
||||
~Monitor();
|
||||
@@ -674,7 +674,7 @@ public:
|
||||
return storage;
|
||||
}
|
||||
inline CameraType GetType() const { return type; }
|
||||
|
||||
|
||||
CapturingOption Capturing() const { return capturing; }
|
||||
AnalysingOption Analysing() const { return analysing; }
|
||||
RecordingOption Recording() const { return recording; }
|
||||
@@ -733,23 +733,23 @@ public:
|
||||
}
|
||||
void setLastViewed(SystemTimePoint new_time) {
|
||||
if (shared_data && shared_data->valid)
|
||||
shared_data->last_viewed_time =
|
||||
shared_data->last_viewed_time =
|
||||
static_cast<int64>(std::chrono::duration_cast<Seconds>(new_time.time_since_epoch()).count());
|
||||
}
|
||||
bool hasViewers() {
|
||||
if (shared_data && shared_data->valid) {
|
||||
SystemTimePoint now = std::chrono::system_clock::now();
|
||||
Debug(3, "Last viewed %" PRId64 " seconds ago",
|
||||
static_cast<int64>(std::chrono::duration_cast<Seconds>(now.time_since_epoch()).count())
|
||||
-
|
||||
shared_data->last_viewed_time
|
||||
);
|
||||
Debug(3, "Last viewed %" PRId64 " seconds ago",
|
||||
static_cast<int64>(std::chrono::duration_cast<Seconds>(now.time_since_epoch()).count())
|
||||
-
|
||||
shared_data->last_viewed_time
|
||||
);
|
||||
return (
|
||||
(
|
||||
static_cast<int64>(std::chrono::duration_cast<Seconds>(now.time_since_epoch()).count())
|
||||
-
|
||||
shared_data->last_viewed_time
|
||||
) > 1 ? false : true);
|
||||
(
|
||||
static_cast<int64>(std::chrono::duration_cast<Seconds>(now.time_since_epoch()).count())
|
||||
-
|
||||
shared_data->last_viewed_time
|
||||
) > 1 ? false : true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -864,8 +864,8 @@ public:
|
||||
void CheckAction();
|
||||
|
||||
unsigned int DetectMotion( const Image &comp_image, Event::StringSet &zoneSet );
|
||||
// DetectBlack seems to be unused. Check it on zm_monitor.cpp for more info.
|
||||
//unsigned int DetectBlack( const Image &comp_image, Event::StringSet &zoneSet );
|
||||
// DetectBlack seems to be unused. Check it on zm_monitor.cpp for more info.
|
||||
//unsigned int DetectBlack( const Image &comp_image, Event::StringSet &zoneSet );
|
||||
bool CheckSignal( const Image *image );
|
||||
bool Analyse();
|
||||
bool setupConvertContext(const AVFrame *input_frame, const Image *image);
|
||||
@@ -875,9 +875,9 @@ public:
|
||||
std::string Substitute(const std::string &format, SystemTimePoint ts_time) const;
|
||||
void TimestampImage(Image *ts_image, SystemTimePoint ts_time) const;
|
||||
Event *openEvent(
|
||||
const std::shared_ptr<ZMPacket> &snap,
|
||||
const std::string &cause,
|
||||
const Event::StringSetMap ¬eSetMap);
|
||||
const std::shared_ptr<ZMPacket> &snap,
|
||||
const std::string &cause,
|
||||
const Event::StringSetMap ¬eSetMap);
|
||||
void closeEvent();
|
||||
|
||||
void Reload();
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
|
||||
Monitor::AmcrestAPI::AmcrestAPI(Monitor *parent_) :
|
||||
parent(parent_),
|
||||
Amcrest_Alarmed(false)
|
||||
{
|
||||
Amcrest_Alarmed(false) {
|
||||
curl_multi = curl_multi_init();
|
||||
start_Amcrest();
|
||||
}
|
||||
@@ -49,7 +48,7 @@ int Monitor::AmcrestAPI::start_Amcrest() {
|
||||
if (full_url.back() != '/') full_url += '/';
|
||||
full_url += "eventManager.cgi?action=attach&codes=[VideoMotion]";
|
||||
Amcrest_handle = curl_easy_init();
|
||||
if (!Amcrest_handle){
|
||||
if (!Amcrest_handle) {
|
||||
Warning("Handle is null!");
|
||||
return -1;
|
||||
}
|
||||
@@ -82,7 +81,7 @@ int Monitor::AmcrestAPI::start_Amcrest() {
|
||||
} else {
|
||||
Warning("AMCREST Response: %s", amcrest_response.c_str());
|
||||
Warning("AMCREST Seeing %i streams, and error of %i, url: %s",
|
||||
running_handles, curl_error, full_url.c_str());
|
||||
running_handles, curl_error, full_url.c_str());
|
||||
curl_easy_getinfo(Amcrest_handle, CURLINFO_OS_ERRNO, &response_code);
|
||||
Warning("AMCREST Response code: %lu", response_code);
|
||||
}
|
||||
@@ -98,7 +97,7 @@ void Monitor::AmcrestAPI::WaitForMessage() {
|
||||
start_Amcrest(); // http transfer ended, need to restart.
|
||||
} else {
|
||||
// wait for max 5 seconds for event.
|
||||
curl_multi_wait(curl_multi, nullptr, 0, 5000, &transfers);
|
||||
curl_multi_wait(curl_multi, nullptr, 0, 5000, &transfers);
|
||||
if (transfers > 0) { // have data to deal with
|
||||
// actually grabs the data, populates amcrest_response
|
||||
curl_multi_perform(curl_multi, &open_handles);
|
||||
@@ -128,10 +127,10 @@ void Monitor::AmcrestAPI::WaitForMessage() {
|
||||
}
|
||||
|
||||
size_t Monitor::AmcrestAPI::WriteCallback(
|
||||
void *contents,
|
||||
size_t size,
|
||||
size_t nmemb,
|
||||
void *userp) {
|
||||
void *contents,
|
||||
size_t size,
|
||||
size_t nmemb,
|
||||
void *userp) {
|
||||
((std::string*)userp)->append((char*)contents, size * nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
@@ -27,8 +27,7 @@ std::string escape_json_string(std::string input);
|
||||
|
||||
Monitor::JanusManager::JanusManager(Monitor *parent_) :
|
||||
parent(parent_),
|
||||
Janus_Healthy(false)
|
||||
{
|
||||
Janus_Healthy(false) {
|
||||
load_from_monitor();
|
||||
}
|
||||
|
||||
@@ -66,22 +65,22 @@ void Monitor::JanusManager::load_from_monitor() {
|
||||
localtime_r(&now_t, &now_tm);
|
||||
if (parent->janus_rtsp_user) {
|
||||
std::string sql = "SELECT `Id`, `Username`, `Password`, `Enabled`,"
|
||||
" `Stream`+0, `Events`+0, `Control`+0, `Monitors`+0, `System`+0"
|
||||
" FROM `Users` WHERE `Enabled`=1 AND `Id`=" + std::to_string(parent->janus_rtsp_user);
|
||||
" `Stream`+0, `Events`+0, `Control`+0, `Monitors`+0, `System`+0"
|
||||
" FROM `Users` WHERE `Enabled`=1 AND `Id`=" + std::to_string(parent->janus_rtsp_user);
|
||||
|
||||
MYSQL_RES *result = zmDbFetch(sql);
|
||||
if (result) {
|
||||
MYSQL_ROW dbrow = mysql_fetch_row(result);
|
||||
|
||||
std::string auth_key = stringtf("%s%s%s%s%d%d%d%d",
|
||||
config.auth_hash_secret,
|
||||
dbrow[1], // username
|
||||
dbrow[2], // password
|
||||
(config.auth_hash_ips ? "127.0.0.1" : ""),
|
||||
now_tm.tm_hour,
|
||||
now_tm.tm_mday,
|
||||
now_tm.tm_mon,
|
||||
now_tm.tm_year);
|
||||
config.auth_hash_secret,
|
||||
dbrow[1], // username
|
||||
dbrow[2], // password
|
||||
(config.auth_hash_ips ? "127.0.0.1" : ""),
|
||||
now_tm.tm_hour,
|
||||
now_tm.tm_mday,
|
||||
now_tm.tm_mon,
|
||||
now_tm.tm_year);
|
||||
Debug(1, "Creating auth_key '%s'", auth_key.c_str());
|
||||
|
||||
zm::crypto::MD5::Digest md5_digest = zm::crypto::MD5::GetDigestOf(auth_key);
|
||||
@@ -162,7 +161,7 @@ int Monitor::JanusManager::check_janus() {
|
||||
}
|
||||
|
||||
//check for changed PIN
|
||||
if (response.find(parent->janus_pin) == std::string::npos){
|
||||
if (response.find(parent->janus_pin) == std::string::npos) {
|
||||
Warning("JANUS PIN changed, remounting.");
|
||||
return remove_from_janus();
|
||||
}
|
||||
@@ -195,14 +194,14 @@ int Monitor::JanusManager::add_to_janus() {
|
||||
postData += "\", \"pin\" : \"";
|
||||
postData += parent->janus_pin;
|
||||
if (profile_override[0] != '\0') {
|
||||
postData += "\", \"videofmtp\" : \"";
|
||||
postData += profile_override;
|
||||
postData += "\", \"videofmtp\" : \"";
|
||||
postData += profile_override;
|
||||
}
|
||||
if (!rtsp_username.empty()) {
|
||||
postData += "\", \"rtsp_user\" : \"";
|
||||
postData += rtsp_username;
|
||||
postData += "\", \"rtsp_pwd\" : \"";
|
||||
postData += rtsp_password;
|
||||
postData += "\", \"rtsp_user\" : \"";
|
||||
postData += rtsp_username;
|
||||
postData += "\", \"rtsp_pwd\" : \"";
|
||||
postData += rtsp_password;
|
||||
}
|
||||
|
||||
postData += "\", \"id\" : ";
|
||||
@@ -210,10 +209,10 @@ int Monitor::JanusManager::add_to_janus() {
|
||||
if (parent->janus_audio_enabled) postData += ", \"audio\" : true";
|
||||
// Add rtsp_session_timeout if not set to 0
|
||||
if (rtsp_session_timeout != 0) {
|
||||
// Add rtsp_session_timeout to postData, this works. Is there a better way?
|
||||
std::string rtsp_timeout = std::to_string(rtsp_session_timeout);
|
||||
postData += ", \"rtsp_session_timeout\" : ";
|
||||
postData += rtsp_timeout;
|
||||
// Add rtsp_session_timeout to postData, this works. Is there a better way?
|
||||
std::string rtsp_timeout = std::to_string(rtsp_session_timeout);
|
||||
postData += ", \"rtsp_session_timeout\" : ";
|
||||
postData += rtsp_timeout;
|
||||
}
|
||||
postData += ", \"video\" : true}}";
|
||||
Debug(1, "JANUS Sending %s to %s", postData.c_str(), endpoint.c_str());
|
||||
@@ -285,8 +284,7 @@ int Monitor::JanusManager::remove_from_janus() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t Monitor::JanusManager::WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
size_t Monitor::JanusManager::WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
|
||||
((std::string*)userp)->append((char*)contents, size * nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
@@ -38,8 +38,7 @@ Monitor::MonitorLink::MonitorLink(std::shared_ptr<Monitor>p_monitor, unsigned in
|
||||
shared_data(nullptr),
|
||||
trigger_data(nullptr),
|
||||
video_store_data(nullptr),
|
||||
zone_scores(nullptr)
|
||||
{
|
||||
zone_scores(nullptr) {
|
||||
name = monitor->Name();
|
||||
if (zone_id) {
|
||||
zones = Zone::Load(monitor);
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* ZoneMinder Monitor_Permission Class Interface
|
||||
* 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.
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -42,7 +42,8 @@ class Monitor_Permission {
|
||||
Monitor_Permission(const Monitor_Permission &mp) { Copy(mp); }
|
||||
void Copy(const Monitor_Permission &mp);
|
||||
Monitor_Permission& operator=(const Monitor_Permission &mp) {
|
||||
Copy(mp); return *this;
|
||||
Copy(mp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
int Id() const { return id; }
|
||||
|
||||
@@ -30,8 +30,7 @@ std::string escape_json_string(std::string input);
|
||||
|
||||
Monitor::RTSP2WebManager::RTSP2WebManager(Monitor *parent_) :
|
||||
parent(parent_),
|
||||
RTSP2Web_Healthy(false)
|
||||
{
|
||||
RTSP2Web_Healthy(false) {
|
||||
Use_RTSP_Restream = false;
|
||||
if ((config.rtsp2web_path != nullptr) && (config.rtsp2web_path[0] != '\0')) {
|
||||
RTSP2Web_endpoint = config.rtsp2web_path;
|
||||
|
||||
@@ -11,15 +11,15 @@ bool MonitorLinkExpression::parse() {
|
||||
// First we tokenize
|
||||
while (first != std::end(expression_)) {
|
||||
auto const second = std::find_first_of(
|
||||
first, std::cend(expression_),
|
||||
std::cbegin(delimiters_), std::cend(delimiters_)
|
||||
);
|
||||
first, std::cend(expression_),
|
||||
std::cbegin(delimiters_), std::cend(delimiters_)
|
||||
);
|
||||
|
||||
if (first != second) {
|
||||
std::string_view t = expression_.substr(
|
||||
std::distance(std::begin(expression_), first),
|
||||
std::distance(first, second)
|
||||
);
|
||||
std::distance(std::begin(expression_), first),
|
||||
std::distance(first, second)
|
||||
);
|
||||
Debug(1, "Have a token %s", std::string(t).c_str());
|
||||
|
||||
tokens.emplace_back(t);
|
||||
@@ -59,7 +59,7 @@ bool MonitorLinkExpression::evaluate() {
|
||||
if (!result.success) {
|
||||
Warning("%s", std::string(result.message).c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return result.score > 0;
|
||||
}
|
||||
|
||||
@@ -74,10 +74,10 @@ const MonitorLinkExpression::Result MonitorLinkExpression::result() {
|
||||
|
||||
MonitorLinkExpression::Result MonitorLinkExpression::visit(Node const & node) {
|
||||
Debug(1, "visit: Node: %p Token: %d value %s",
|
||||
&node,
|
||||
static_cast<int>(node.token.type()),
|
||||
std::string(node.token.value()).c_str()
|
||||
);
|
||||
&node,
|
||||
static_cast<int>(node.token.type()),
|
||||
std::string(node.token.value()).c_str()
|
||||
);
|
||||
if (node.token.type() == Token::TokenType::monitorlink) {
|
||||
Debug(1, "Have monitorlink, return true, value %d", node.token.score());
|
||||
return { true, "", node.token.score() };
|
||||
@@ -86,24 +86,23 @@ MonitorLinkExpression::Result MonitorLinkExpression::visit(Node const & node) {
|
||||
}
|
||||
|
||||
switch (node.token.type()) {
|
||||
case Token::TokenType::logical_and:
|
||||
Debug(1, "and");
|
||||
return visit_logical_and(node);
|
||||
case Token::TokenType::logical_or :
|
||||
Debug(1, "or");
|
||||
return visit_logical_or(node);
|
||||
case Token::TokenType::logical_comma :
|
||||
Debug(1, "comma");
|
||||
return visit_logical_or(node);
|
||||
default:
|
||||
Debug(1, "unknown");
|
||||
return { false, "Unknown token type" };
|
||||
case Token::TokenType::logical_and:
|
||||
Debug(1, "and");
|
||||
return visit_logical_and(node);
|
||||
case Token::TokenType::logical_or :
|
||||
Debug(1, "or");
|
||||
return visit_logical_or(node);
|
||||
case Token::TokenType::logical_comma :
|
||||
Debug(1, "comma");
|
||||
return visit_logical_or(node);
|
||||
default:
|
||||
Debug(1, "unknown");
|
||||
return { false, "Unknown token type" };
|
||||
}
|
||||
}
|
||||
|
||||
MonitorLinkExpression::Result
|
||||
MonitorLinkExpression::visit_logical_and(MonitorLinkExpression::Node const & node)
|
||||
{
|
||||
MonitorLinkExpression::visit_logical_and(MonitorLinkExpression::Node const & node) {
|
||||
auto const left { visit(*node.left) };
|
||||
auto const right { visit(*node.right) };
|
||||
|
||||
@@ -114,13 +113,12 @@ MonitorLinkExpression::visit_logical_and(MonitorLinkExpression::Node const & nod
|
||||
|
||||
Debug(1, "AND left score %d right score %d", left.score, right.score);
|
||||
return { left.success && right.success, message,
|
||||
((left.score and right.score) ? left.score + right.score : 0)
|
||||
};
|
||||
((left.score and right.score) ? left.score + right.score : 0)
|
||||
};
|
||||
}
|
||||
|
||||
MonitorLinkExpression::Result
|
||||
MonitorLinkExpression::visit_logical_or(MonitorLinkExpression::Node const & node)
|
||||
{
|
||||
MonitorLinkExpression::visit_logical_or(MonitorLinkExpression::Node const & node) {
|
||||
auto const left { visit(*node.left) };
|
||||
auto const right { visit(*node.right) };
|
||||
|
||||
@@ -132,12 +130,12 @@ MonitorLinkExpression::visit_logical_or(MonitorLinkExpression::Node const & node
|
||||
Debug(1, "Or left score %d right score %d", left.score, right.score);
|
||||
return {
|
||||
left.success || right.success,
|
||||
message,
|
||||
((left.score or right.score) ? left.score + right.score : 0)
|
||||
message,
|
||||
((left.score or right.score) ? left.score + right.score : 0)
|
||||
};
|
||||
}
|
||||
|
||||
std::unique_ptr<MonitorLinkExpression::Node>
|
||||
std::unique_ptr<MonitorLinkExpression::Node>
|
||||
MonitorLinkExpression::parse_expression( Tokens const & tokens, std::size_t & current ) {
|
||||
if (tokens.size() == 1) {
|
||||
Debug(1, "Special case monitorlink");
|
||||
@@ -146,16 +144,16 @@ MonitorLinkExpression::parse_expression( Tokens const & tokens, std::size_t & cu
|
||||
}
|
||||
|
||||
// First token could me a parenthesis or monitorlink. Otherwise invalid.
|
||||
|
||||
|
||||
auto left{ parse_and_operation(tokens, current) };
|
||||
|
||||
if (
|
||||
has_unused(tokens, current)
|
||||
and
|
||||
tokens[current].is_not(Token::TokenType::logical_or)
|
||||
and
|
||||
tokens[current].is_not(Token::TokenType::logical_comma)
|
||||
) {
|
||||
has_unused(tokens, current)
|
||||
and
|
||||
tokens[current].is_not(Token::TokenType::logical_or)
|
||||
and
|
||||
tokens[current].is_not(Token::TokenType::logical_comma)
|
||||
) {
|
||||
Debug(1, "parse_expression: not or, Returning left %s", std::string(left->token.value()).c_str());
|
||||
return left;
|
||||
}
|
||||
@@ -174,19 +172,19 @@ MonitorLinkExpression::parse_expression( Tokens const & tokens, std::size_t & cu
|
||||
*/
|
||||
|
||||
while (has_unused(tokens, current) and
|
||||
(
|
||||
tokens[current].is(Token::TokenType::logical_or)
|
||||
or
|
||||
tokens[current].is(Token::TokenType::logical_comma)
|
||||
)
|
||||
) {
|
||||
(
|
||||
tokens[current].is(Token::TokenType::logical_or)
|
||||
or
|
||||
tokens[current].is(Token::TokenType::logical_comma)
|
||||
)
|
||||
) {
|
||||
Debug(1, "Have or adding it");
|
||||
|
||||
auto logical_or{ std::make_unique<Node>( Token::TokenType::logical_or ) };
|
||||
current++;
|
||||
|
||||
auto right{ parse_and_operation( tokens, current ) };
|
||||
if (right == nullptr) {
|
||||
if (right == nullptr) {
|
||||
Debug(1, "null from right side");
|
||||
return nullptr;
|
||||
}
|
||||
@@ -199,7 +197,7 @@ MonitorLinkExpression::parse_expression( Tokens const & tokens, std::size_t & cu
|
||||
return left;
|
||||
}
|
||||
|
||||
std::unique_ptr<MonitorLinkExpression::Node>
|
||||
std::unique_ptr<MonitorLinkExpression::Node>
|
||||
MonitorLinkExpression::parse_and_operation( Tokens const & tokens, std::size_t & current ) {
|
||||
auto left{ parse_parentheses( tokens, current ) };
|
||||
|
||||
@@ -210,10 +208,10 @@ MonitorLinkExpression::parse_and_operation( Tokens const & tokens, std::size_t &
|
||||
}
|
||||
|
||||
while (
|
||||
has_unused(tokens, current)
|
||||
and
|
||||
tokens[current].is(Token::TokenType::logical_and)
|
||||
) {
|
||||
has_unused(tokens, current)
|
||||
and
|
||||
tokens[current].is(Token::TokenType::logical_and)
|
||||
) {
|
||||
++current;
|
||||
|
||||
auto logical_and{ std::make_unique< Node >(Token::TokenType::logical_and) };
|
||||
@@ -234,7 +232,7 @@ MonitorLinkExpression::parse_and_operation( Tokens const & tokens, std::size_t &
|
||||
return left;
|
||||
}
|
||||
|
||||
std::unique_ptr<MonitorLinkExpression::Node>
|
||||
std::unique_ptr<MonitorLinkExpression::Node>
|
||||
MonitorLinkExpression::parse_parentheses(Tokens const &tokens, std::size_t ¤t) {
|
||||
if (!has_unused(tokens, current)) {
|
||||
Debug(1, "No unused...");
|
||||
|
||||
@@ -28,78 +28,78 @@
|
||||
|
||||
class MonitorLinkExpression {
|
||||
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* struct node
|
||||
*
|
||||
* Represents the tree node containing references to left and right child nodes
|
||||
* as well as the token that the node represents in the actual expression tree.
|
||||
*/
|
||||
class Node {
|
||||
public:
|
||||
Token token{ Token::TokenType::unknown };
|
||||
|
||||
std::unique_ptr< Node > left { nullptr };
|
||||
std::unique_ptr< Node > right{ nullptr };
|
||||
|
||||
constexpr Node() noexcept = default;
|
||||
|
||||
Node( Node && rhs ) noexcept = default;
|
||||
Node( Node const & rhs ) noexcept = delete;
|
||||
|
||||
constexpr Node(Token::TokenType const type) noexcept : token(type) {}
|
||||
constexpr Node(Token const &token) noexcept : token(token) {}
|
||||
|
||||
Node & operator=( Node && rhs ) noexcept = default;
|
||||
Node & operator=( Node const & rhs ) noexcept = delete;
|
||||
|
||||
~Node() noexcept = default;
|
||||
};
|
||||
|
||||
struct Result {
|
||||
/**
|
||||
* struct node
|
||||
*
|
||||
* Represents the tree node containing references to left and right child nodes
|
||||
* as well as the token that the node represents in the actual expression tree.
|
||||
* True if evaluation process is successful. Otherwise, false.
|
||||
*/
|
||||
class Node {
|
||||
public:
|
||||
Token token{ Token::TokenType::unknown };
|
||||
bool success{ false };
|
||||
|
||||
std::unique_ptr< Node > left { nullptr };
|
||||
std::unique_ptr< Node > right{ nullptr };
|
||||
/**
|
||||
* Message in case of the fault.
|
||||
*/
|
||||
std::string_view message{};
|
||||
int score {-1};
|
||||
};
|
||||
|
||||
constexpr Node() noexcept = default;
|
||||
public:
|
||||
using Tokens = std::vector< Token >;
|
||||
private:
|
||||
std::unique_ptr<Node> tree_;
|
||||
int score_;
|
||||
|
||||
Node( Node && rhs ) noexcept = default;
|
||||
Node( Node const & rhs ) noexcept = delete;
|
||||
static std::unique_ptr< Node > parse_and_operation ( Tokens const & tokens, std::size_t & current );
|
||||
static std::unique_ptr< Node > parse_or_operation ( Tokens const & tokens, std::size_t & current );
|
||||
static std::unique_ptr< Node > parse_parentheses ( Tokens const & tokens, std::size_t & current );
|
||||
static std::unique_ptr< Node > parse_terminal ( Tokens const & tokens, std::size_t & current );
|
||||
static std::unique_ptr<Node> parse_expression( Tokens const & tokens, std::size_t & current );
|
||||
|
||||
constexpr Node(Token::TokenType const type) noexcept : token(type) {}
|
||||
constexpr Node(Token const &token) noexcept : token(token) {}
|
||||
static inline bool has_unused( Tokens const & tokens, std::size_t const current ) noexcept {
|
||||
return current < std::size( tokens );
|
||||
}
|
||||
|
||||
Node & operator=( Node && rhs ) noexcept = default;
|
||||
Node & operator=( Node const & rhs ) noexcept = delete;
|
||||
static Result visit(Node const &node);
|
||||
static Result visit_logical_and(Node const &node);
|
||||
static Result visit_logical_or(Node const &node);
|
||||
|
||||
~Node() noexcept = default;
|
||||
};
|
||||
|
||||
struct Result {
|
||||
/**
|
||||
* True if evaluation process is successful. Otherwise, false.
|
||||
*/
|
||||
bool success{ false };
|
||||
|
||||
/**
|
||||
* Message in case of the fault.
|
||||
*/
|
||||
std::string_view message{};
|
||||
int score {-1};
|
||||
};
|
||||
|
||||
public:
|
||||
using Tokens = std::vector< Token >;
|
||||
private:
|
||||
std::unique_ptr<Node> tree_;
|
||||
int score_;
|
||||
|
||||
static std::unique_ptr< Node > parse_and_operation ( Tokens const & tokens, std::size_t & current );
|
||||
static std::unique_ptr< Node > parse_or_operation ( Tokens const & tokens, std::size_t & current );
|
||||
static std::unique_ptr< Node > parse_parentheses ( Tokens const & tokens, std::size_t & current );
|
||||
static std::unique_ptr< Node > parse_terminal ( Tokens const & tokens, std::size_t & current );
|
||||
static std::unique_ptr<Node> parse_expression( Tokens const & tokens, std::size_t & current );
|
||||
|
||||
static inline bool has_unused( Tokens const & tokens, std::size_t const current ) noexcept {
|
||||
return current < std::size( tokens );
|
||||
}
|
||||
|
||||
static Result visit(Node const &node);
|
||||
static Result visit_logical_and(Node const &node);
|
||||
static Result visit_logical_or(Node const &node);
|
||||
|
||||
public:
|
||||
MonitorLinkExpression();
|
||||
MonitorLinkExpression(const std::string &expression) : expression_(expression) {
|
||||
};
|
||||
int score() { return score_; }
|
||||
bool evaluate();
|
||||
const Result result();
|
||||
bool parse();
|
||||
private:
|
||||
const std::string_view delimiters_ = "|&(),";
|
||||
std::string_view expression_;
|
||||
public:
|
||||
MonitorLinkExpression();
|
||||
MonitorLinkExpression(const std::string &expression) : expression_(expression) {
|
||||
};
|
||||
int score() { return score_; }
|
||||
bool evaluate();
|
||||
const Result result();
|
||||
bool parse();
|
||||
private:
|
||||
const std::string_view delimiters_ = "|&(),";
|
||||
std::string_view expression_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,202 +25,198 @@
|
||||
#include "zm_monitor.h"
|
||||
|
||||
class Token {
|
||||
public:
|
||||
/**
|
||||
* enum class token_type
|
||||
*
|
||||
* Represents a token type. Supported types are logical operators, relational operators, parentheses and monitorlink
|
||||
*/
|
||||
enum class [[ nodiscard ]] TokenType : std::uint8_t {
|
||||
unknown,
|
||||
monitorlink,
|
||||
logical_and,
|
||||
logical_or,
|
||||
logical_comma,
|
||||
lp,
|
||||
rp
|
||||
public:
|
||||
/**
|
||||
* enum class token_type
|
||||
*
|
||||
* Represents a token type. Supported types are logical operators, relational operators, parentheses and monitorlink
|
||||
*/
|
||||
enum class [[ nodiscard ]] TokenType : std::uint8_t {
|
||||
unknown,
|
||||
monitorlink,
|
||||
logical_and,
|
||||
logical_or,
|
||||
logical_comma,
|
||||
lp,
|
||||
rp
|
||||
};
|
||||
|
||||
/**
|
||||
* @class token
|
||||
*
|
||||
* Represents all tokens ('and', 'or', 'eq', ...).
|
||||
*/
|
||||
private:
|
||||
using token_type_pair = std::pair<std::string_view, TokenType>;
|
||||
constexpr static std::array symbols {
|
||||
token_type_pair{ "&", TokenType::logical_and },
|
||||
token_type_pair{ "|", TokenType::logical_or },
|
||||
token_type_pair{ ",", TokenType::logical_comma }, // or
|
||||
token_type_pair{ "(", TokenType::lp },
|
||||
token_type_pair{ ")", TokenType::rp }
|
||||
};
|
||||
|
||||
//constexpr TokenType to_token_type( std::string_view const value ) noexcept;
|
||||
constexpr TokenType to_token_type( std::string_view const value ) noexcept {
|
||||
auto find_matching {
|
||||
[ value ]( auto const & collection ) noexcept {
|
||||
return utils::find_if
|
||||
(
|
||||
std::cbegin( collection ),
|
||||
std::cend ( collection ),
|
||||
[ value ]( auto && item ) {
|
||||
return item.first == value;
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class token
|
||||
*
|
||||
* Represents all tokens ('and', 'or', 'eq', ...).
|
||||
*/
|
||||
private:
|
||||
using token_type_pair = std::pair<std::string_view, TokenType>;
|
||||
constexpr static std::array symbols {
|
||||
token_type_pair{ "&", TokenType::logical_and },
|
||||
token_type_pair{ "|", TokenType::logical_or },
|
||||
token_type_pair{ ",", TokenType::logical_comma }, // or
|
||||
token_type_pair{ "(", TokenType::lp },
|
||||
token_type_pair{ ")", TokenType::rp }
|
||||
};
|
||||
auto const symbol{ find_matching(symbols) };
|
||||
if (symbol != std::cend(symbols)) {
|
||||
return symbol->second;
|
||||
}
|
||||
|
||||
//constexpr TokenType to_token_type( std::string_view const value ) noexcept;
|
||||
constexpr TokenType to_token_type( std::string_view const value ) noexcept {
|
||||
auto find_matching {
|
||||
[ value ]( auto const & collection ) noexcept {
|
||||
return utils::find_if
|
||||
(
|
||||
std::cbegin( collection ),
|
||||
std::cend ( collection ),
|
||||
[ value ]( auto && item )
|
||||
{
|
||||
return item.first == value;
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
return TokenType::monitorlink;
|
||||
} // end constexpr TokenType to_token_type( std::string_view const value )
|
||||
|
||||
auto const symbol{ find_matching(symbols) };
|
||||
if (symbol != std::cend(symbols)) {
|
||||
return symbol->second;
|
||||
}
|
||||
public:
|
||||
|
||||
return TokenType::monitorlink;
|
||||
} // end constexpr TokenType to_token_type( std::string_view const value )
|
||||
Token(TokenType const type, std::string_view const value)
|
||||
: type_(type)
|
||||
, value_(value)
|
||||
, monitor_link_(nullptr) {
|
||||
if (type_ == TokenType::monitorlink) {
|
||||
auto colon_position = value_.find(':');
|
||||
unsigned int monitor_id = 0;
|
||||
unsigned int zone_id = 0;
|
||||
std::string monitor_name;
|
||||
std::string zone_name;
|
||||
|
||||
public:
|
||||
|
||||
Token(TokenType const type, std::string_view const value)
|
||||
: type_(type)
|
||||
, value_(value)
|
||||
, monitor_link_(nullptr)
|
||||
{
|
||||
if (type_ == TokenType::monitorlink) {
|
||||
auto colon_position = value_.find(':');
|
||||
unsigned int monitor_id = 0;
|
||||
unsigned int zone_id = 0;
|
||||
std::string monitor_name;
|
||||
std::string zone_name;
|
||||
|
||||
if (colon_position != std::string::npos) {
|
||||
// Has a zone specification
|
||||
monitor_id = std::stoul(std::string(value_.substr(0, colon_position)));
|
||||
zone_id = std::stoul(std::string(value_.substr(colon_position+1, std::string::npos)));
|
||||
} else {
|
||||
monitor_id = std::stoul(std::string(value_));
|
||||
}
|
||||
Debug(1, "Have linked monitor %d zone %d", monitor_id, zone_id);
|
||||
|
||||
std::shared_ptr<Monitor> monitor = Monitor::Load(monitor_id, false, Monitor::QUERY);
|
||||
monitor_link_ = new Monitor::MonitorLink(monitor, zone_id);
|
||||
if (colon_position != std::string::npos) {
|
||||
// Has a zone specification
|
||||
monitor_id = std::stoul(std::string(value_.substr(0, colon_position)));
|
||||
zone_id = std::stoul(std::string(value_.substr(colon_position+1, std::string::npos)));
|
||||
} else {
|
||||
Debug( 1, "Not a monitor link value is %s", std::string(value_).c_str());
|
||||
monitor_id = std::stoul(std::string(value_));
|
||||
}
|
||||
Debug(1, "Have linked monitor %d zone %d", monitor_id, zone_id);
|
||||
|
||||
std::shared_ptr<Monitor> monitor = Monitor::Load(monitor_id, false, Monitor::QUERY);
|
||||
monitor_link_ = new Monitor::MonitorLink(monitor, zone_id);
|
||||
} else {
|
||||
Debug( 1, "Not a monitor link value is %s", std::string(value_).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
constexpr Token() noexcept :
|
||||
type_(TokenType::unknown),
|
||||
value_(""),
|
||||
monitor_link_(nullptr)
|
||||
{ }
|
||||
//Token( TokenType const type, std::string_view const value );
|
||||
constexpr Token() noexcept :
|
||||
type_(TokenType::unknown),
|
||||
value_(""),
|
||||
monitor_link_(nullptr)
|
||||
{ }
|
||||
//Token( TokenType const type, std::string_view const value );
|
||||
|
||||
constexpr Token( Token && rhs ) noexcept = default;
|
||||
constexpr Token( Token const & rhs ) noexcept = default;
|
||||
constexpr Token( Token && rhs ) noexcept = default;
|
||||
constexpr Token( Token const & rhs ) noexcept = default;
|
||||
|
||||
constexpr Token( TokenType const type ) noexcept
|
||||
: type_ ( type )
|
||||
, value_("")
|
||||
, monitor_link_(nullptr)
|
||||
{}
|
||||
constexpr Token( TokenType const type ) noexcept
|
||||
: type_ ( type )
|
||||
, value_("")
|
||||
, monitor_link_(nullptr)
|
||||
{}
|
||||
|
||||
Token( std::string_view const value ) noexcept
|
||||
: type_ (to_token_type(value))
|
||||
, value_(value)
|
||||
, monitor_link_(nullptr)
|
||||
{
|
||||
if (type_ == TokenType::monitorlink) {
|
||||
auto colon_position = value_.find(':');
|
||||
unsigned int monitor_id = 0;
|
||||
unsigned int zone_id = 0;
|
||||
std::string monitor_name;
|
||||
std::string zone_name;
|
||||
Token( std::string_view const value ) noexcept
|
||||
: type_ (to_token_type(value))
|
||||
, value_(value)
|
||||
, monitor_link_(nullptr) {
|
||||
if (type_ == TokenType::monitorlink) {
|
||||
auto colon_position = value_.find(':');
|
||||
unsigned int monitor_id = 0;
|
||||
unsigned int zone_id = 0;
|
||||
std::string monitor_name;
|
||||
std::string zone_name;
|
||||
|
||||
if (colon_position != std::string::npos) {
|
||||
// Has a zone specification
|
||||
monitor_id = std::stoul(std::string(value_.substr(0, colon_position)));
|
||||
zone_id = std::stoul(std::string(value_.substr(colon_position+1, std::string::npos)));
|
||||
} else {
|
||||
monitor_id = std::stoul(std::string(value_));
|
||||
}
|
||||
Debug(1, "Have linked monitor %d zone %d", monitor_id, zone_id);
|
||||
|
||||
std::shared_ptr<Monitor> monitor = Monitor::Load(monitor_id, false, Monitor::QUERY);
|
||||
monitor_link_ = new Monitor::MonitorLink(monitor, zone_id);
|
||||
if (colon_position != std::string::npos) {
|
||||
// Has a zone specification
|
||||
monitor_id = std::stoul(std::string(value_.substr(0, colon_position)));
|
||||
zone_id = std::stoul(std::string(value_.substr(colon_position+1, std::string::npos)));
|
||||
} else {
|
||||
Debug( 1, "Not a monitor link value is %s", std::string(value_).c_str());
|
||||
}
|
||||
monitor_id = std::stoul(std::string(value_));
|
||||
}
|
||||
Debug(1, "Have linked monitor %d zone %d", monitor_id, zone_id);
|
||||
|
||||
Token & operator=( Token && rhs ) noexcept = default;
|
||||
Token & operator=( Token const & rhs ) noexcept = default;
|
||||
std::shared_ptr<Monitor> monitor = Monitor::Load(monitor_id, false, Monitor::QUERY);
|
||||
monitor_link_ = new Monitor::MonitorLink(monitor, zone_id);
|
||||
} else {
|
||||
Debug( 1, "Not a monitor link value is %s", std::string(value_).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
[[ nodiscard ]] constexpr bool operator==( Token const & rhs ) const noexcept {
|
||||
return type_ == rhs.type_ && value_ == rhs.value_;
|
||||
Token & operator=( Token && rhs ) noexcept = default;
|
||||
Token & operator=( Token const & rhs ) noexcept = default;
|
||||
|
||||
[[ nodiscard ]] constexpr bool operator==( Token const & rhs ) const noexcept {
|
||||
return type_ == rhs.type_ && value_ == rhs.value_;
|
||||
}
|
||||
|
||||
~Token() noexcept = default;
|
||||
constexpr void type( TokenType const type ) noexcept {
|
||||
if ( type != type_ ) {
|
||||
type_ = type;
|
||||
value_ = "";//to_token_keyword( type );
|
||||
}
|
||||
|
||||
~Token() noexcept = default;
|
||||
constexpr void type( TokenType const type ) noexcept {
|
||||
if ( type != type_ ) {
|
||||
type_ = type;
|
||||
value_ = "";//to_token_keyword( type );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
constexpr TokenType type() const noexcept { return type_; }
|
||||
|
||||
constexpr TokenType type() const noexcept { return type_; }
|
||||
constexpr void value( std::string_view const value ) noexcept {
|
||||
type_ = to_token_type( value );
|
||||
value_ = value;
|
||||
|
||||
constexpr void value( std::string_view const value ) noexcept {
|
||||
type_ = to_token_type( value );
|
||||
value_ = value;
|
||||
}
|
||||
|
||||
}
|
||||
[[ nodiscard ]] constexpr std::string_view value() const noexcept {
|
||||
return value_;
|
||||
}
|
||||
|
||||
[[ nodiscard ]] constexpr std::string_view value() const noexcept {
|
||||
return value_;
|
||||
}
|
||||
[[ nodiscard ]] constexpr bool is( TokenType const type ) const noexcept {
|
||||
return type_ == type;
|
||||
}
|
||||
|
||||
[[ nodiscard ]] constexpr bool is( TokenType const type ) const noexcept {
|
||||
return type_ == type;
|
||||
}
|
||||
[[ nodiscard ]] constexpr bool is_not( TokenType const type ) const noexcept {
|
||||
return type_ != type;
|
||||
}
|
||||
|
||||
[[ nodiscard ]] constexpr bool is_not( TokenType const type ) const noexcept {
|
||||
return type_ != type;
|
||||
}
|
||||
[[ nodiscard ]] constexpr bool is_one_of(
|
||||
TokenType const first,
|
||||
TokenType const second
|
||||
) const noexcept {
|
||||
return is(first) || is(second);
|
||||
}
|
||||
|
||||
[[ nodiscard ]] constexpr bool is_one_of(
|
||||
TokenType const first,
|
||||
TokenType const second
|
||||
) const noexcept
|
||||
{
|
||||
return is(first) || is(second);
|
||||
}
|
||||
[[ nodiscard ]] constexpr bool hasAlarmed() const {
|
||||
return (monitor_link_ && monitor_link_->connect() && monitor_link_->hasAlarmed());
|
||||
}
|
||||
|
||||
[[ nodiscard ]] constexpr bool hasAlarmed() const {
|
||||
return (monitor_link_ && monitor_link_->connect() && monitor_link_->hasAlarmed());
|
||||
}
|
||||
|
||||
[[ nodiscard ]] constexpr int score() const {
|
||||
if ( monitor_link_ ) {
|
||||
if (!monitor_link_->isConnected() ) {
|
||||
Debug(1, "connecting");
|
||||
if (!monitor_link_->connect()) {
|
||||
Debug(1, "failed");
|
||||
return 0;
|
||||
}
|
||||
[[ nodiscard ]] constexpr int score() const {
|
||||
if ( monitor_link_ ) {
|
||||
if (!monitor_link_->isConnected() ) {
|
||||
Debug(1, "connecting");
|
||||
if (!monitor_link_->connect()) {
|
||||
Debug(1, "failed");
|
||||
return 0;
|
||||
}
|
||||
int s = monitor_link_->score();
|
||||
Debug(1, "Score from monitor %s is %d", monitor_link_->Name(), s);
|
||||
return s;
|
||||
}
|
||||
return 0;
|
||||
int s = monitor_link_->score();
|
||||
Debug(1, "Score from monitor %s is %d", monitor_link_->Name(), s);
|
||||
return s;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
TokenType type_;
|
||||
std::string_view value_;
|
||||
Monitor::MonitorLink *monitor_link_;
|
||||
private:
|
||||
TokenType type_;
|
||||
std::string_view value_;
|
||||
Monitor::MonitorLink *monitor_link_;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -84,153 +84,152 @@ void MonitorStream::processCommand(const CmdMsg *msg) {
|
||||
Debug(2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0]);
|
||||
// Check for incoming command
|
||||
switch ((MsgCommand)msg->msg_data[0]) {
|
||||
case CMD_PAUSE :
|
||||
Debug(1, "Got PAUSE command");
|
||||
paused = true;
|
||||
delayed = true;
|
||||
last_frame_sent = now;
|
||||
break;
|
||||
case CMD_PLAY :
|
||||
Debug(1, "Got PLAY command");
|
||||
if (paused) {
|
||||
paused = false;
|
||||
delayed = true;
|
||||
}
|
||||
replay_rate = ZM_RATE_BASE;
|
||||
break;
|
||||
case CMD_VARPLAY :
|
||||
Debug(1, "Got VARPLAY command");
|
||||
if (paused) {
|
||||
paused = false;
|
||||
delayed = true;
|
||||
}
|
||||
replay_rate = ntohs(((unsigned char)msg->msg_data[2]<<8)|(unsigned char)msg->msg_data[1])-32768;
|
||||
break;
|
||||
case CMD_STOP :
|
||||
Debug(1, "Got STOP command");
|
||||
case CMD_PAUSE :
|
||||
Debug(1, "Got PAUSE command");
|
||||
paused = true;
|
||||
delayed = true;
|
||||
last_frame_sent = now;
|
||||
break;
|
||||
case CMD_PLAY :
|
||||
Debug(1, "Got PLAY command");
|
||||
if (paused) {
|
||||
paused = false;
|
||||
delayed = false;
|
||||
break;
|
||||
case CMD_FASTFWD :
|
||||
Debug(1, "Got FAST FWD command");
|
||||
if (paused) {
|
||||
paused = false;
|
||||
delayed = true;
|
||||
}
|
||||
// Set play rate
|
||||
switch (replay_rate) {
|
||||
case 2 * ZM_RATE_BASE :
|
||||
replay_rate = 5 * ZM_RATE_BASE;
|
||||
break;
|
||||
case 5 * ZM_RATE_BASE :
|
||||
replay_rate = 10 * ZM_RATE_BASE;
|
||||
break;
|
||||
case 10 * ZM_RATE_BASE :
|
||||
replay_rate = 25 * ZM_RATE_BASE;
|
||||
break;
|
||||
case 25 * ZM_RATE_BASE :
|
||||
case 50 * ZM_RATE_BASE :
|
||||
replay_rate = 50 * ZM_RATE_BASE;
|
||||
break;
|
||||
default :
|
||||
replay_rate = 2 * ZM_RATE_BASE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case CMD_MAXFPS :
|
||||
{
|
||||
double int_part = ((unsigned char) msg->msg_data[1] << 24) | ((unsigned char) msg->msg_data[2] << 16)
|
||||
| ((unsigned char) msg->msg_data[3] << 8) | (unsigned char) msg->msg_data[4];
|
||||
double dec_part = ((unsigned char) msg->msg_data[5] << 24) | ((unsigned char) msg->msg_data[6] << 16)
|
||||
| ((unsigned char) msg->msg_data[7] << 8) | (unsigned char) msg->msg_data[8];
|
||||
|
||||
maxfps = (int_part + dec_part / 1000000.0);
|
||||
|
||||
Debug(1, "Got MAXFPS %f", maxfps);
|
||||
break;
|
||||
}
|
||||
case CMD_SLOWFWD :
|
||||
Debug(1, "Got SLOW FWD command");
|
||||
paused = true;
|
||||
delayed = true;
|
||||
replay_rate = ZM_RATE_BASE;
|
||||
step = 1;
|
||||
break;
|
||||
case CMD_SLOWREV :
|
||||
Debug(1, "Got SLOW REV command");
|
||||
paused = true;
|
||||
}
|
||||
replay_rate = ZM_RATE_BASE;
|
||||
break;
|
||||
case CMD_VARPLAY :
|
||||
Debug(1, "Got VARPLAY command");
|
||||
if (paused) {
|
||||
paused = false;
|
||||
delayed = true;
|
||||
replay_rate = ZM_RATE_BASE;
|
||||
step = -1;
|
||||
}
|
||||
replay_rate = ntohs(((unsigned char)msg->msg_data[2]<<8)|(unsigned char)msg->msg_data[1])-32768;
|
||||
break;
|
||||
case CMD_STOP :
|
||||
Debug(1, "Got STOP command");
|
||||
paused = false;
|
||||
delayed = false;
|
||||
break;
|
||||
case CMD_FASTFWD :
|
||||
Debug(1, "Got FAST FWD command");
|
||||
if (paused) {
|
||||
paused = false;
|
||||
delayed = true;
|
||||
}
|
||||
// Set play rate
|
||||
switch (replay_rate) {
|
||||
case 2 * ZM_RATE_BASE :
|
||||
replay_rate = 5 * ZM_RATE_BASE;
|
||||
break;
|
||||
case CMD_FASTREV :
|
||||
Debug(1, "Got FAST REV command");
|
||||
if (paused) {
|
||||
paused = false;
|
||||
delayed = true;
|
||||
}
|
||||
// Set play rate
|
||||
switch (replay_rate) {
|
||||
case -2 * ZM_RATE_BASE :
|
||||
replay_rate = -5 * ZM_RATE_BASE;
|
||||
break;
|
||||
case -5 * ZM_RATE_BASE :
|
||||
replay_rate = -10 * ZM_RATE_BASE;
|
||||
break;
|
||||
case -10 * ZM_RATE_BASE :
|
||||
replay_rate = -25 * ZM_RATE_BASE;
|
||||
break;
|
||||
case -25 * ZM_RATE_BASE :
|
||||
case -50 * ZM_RATE_BASE :
|
||||
replay_rate = -50 * ZM_RATE_BASE;
|
||||
break;
|
||||
default :
|
||||
replay_rate = -2 * ZM_RATE_BASE;
|
||||
break;
|
||||
}
|
||||
case 5 * ZM_RATE_BASE :
|
||||
replay_rate = 10 * ZM_RATE_BASE;
|
||||
break;
|
||||
case CMD_ZOOMIN :
|
||||
x = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2];
|
||||
y = ((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4];
|
||||
zoom += 10;
|
||||
Debug(1, "Got ZOOM IN command, to %d,%d zoom value %d%%", x, y, zoom);
|
||||
case 10 * ZM_RATE_BASE :
|
||||
replay_rate = 25 * ZM_RATE_BASE;
|
||||
break;
|
||||
case CMD_ZOOMOUT :
|
||||
zoom -= 10;
|
||||
if (zoom < 100) zoom = 100;
|
||||
Debug(1, "Got ZOOM OUT command resulting zoom %d%%", zoom);
|
||||
break;
|
||||
case CMD_ZOOMSTOP :
|
||||
zoom = 100;
|
||||
Debug(1, "Got ZOOM OUT FULL command resulting zoom %d%%", zoom);
|
||||
break;
|
||||
case CMD_PAN :
|
||||
x = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2];
|
||||
y = ((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4];
|
||||
Debug(1, "Got PAN command, to %d,%d", x, y);
|
||||
break;
|
||||
case CMD_SCALE :
|
||||
scale = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2];
|
||||
Debug(1, "Got SCALE command, to %d", scale);
|
||||
break;
|
||||
case CMD_QUIT :
|
||||
Info("User initiated exit - CMD_QUIT");
|
||||
zm_terminate = true;
|
||||
break;
|
||||
case CMD_ANALYZE_ON :
|
||||
frame_type = FRAME_ANALYSIS;
|
||||
Debug(1, "ANALYSIS on");
|
||||
break;
|
||||
case CMD_ANALYZE_OFF :
|
||||
frame_type = FRAME_NORMAL;
|
||||
Debug(1, "ANALYSIS off");
|
||||
break;
|
||||
case CMD_QUERY :
|
||||
Debug(1, "Got QUERY command, sending STATUS");
|
||||
case 25 * ZM_RATE_BASE :
|
||||
case 50 * ZM_RATE_BASE :
|
||||
replay_rate = 50 * ZM_RATE_BASE;
|
||||
break;
|
||||
default :
|
||||
Error("Got unexpected command %d", msg->msg_data[0]);
|
||||
replay_rate = 2 * ZM_RATE_BASE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case CMD_MAXFPS : {
|
||||
double int_part = ((unsigned char) msg->msg_data[1] << 24) | ((unsigned char) msg->msg_data[2] << 16)
|
||||
| ((unsigned char) msg->msg_data[3] << 8) | (unsigned char) msg->msg_data[4];
|
||||
double dec_part = ((unsigned char) msg->msg_data[5] << 24) | ((unsigned char) msg->msg_data[6] << 16)
|
||||
| ((unsigned char) msg->msg_data[7] << 8) | (unsigned char) msg->msg_data[8];
|
||||
|
||||
maxfps = (int_part + dec_part / 1000000.0);
|
||||
|
||||
Debug(1, "Got MAXFPS %f", maxfps);
|
||||
break;
|
||||
}
|
||||
case CMD_SLOWFWD :
|
||||
Debug(1, "Got SLOW FWD command");
|
||||
paused = true;
|
||||
delayed = true;
|
||||
replay_rate = ZM_RATE_BASE;
|
||||
step = 1;
|
||||
break;
|
||||
case CMD_SLOWREV :
|
||||
Debug(1, "Got SLOW REV command");
|
||||
paused = true;
|
||||
delayed = true;
|
||||
replay_rate = ZM_RATE_BASE;
|
||||
step = -1;
|
||||
break;
|
||||
case CMD_FASTREV :
|
||||
Debug(1, "Got FAST REV command");
|
||||
if (paused) {
|
||||
paused = false;
|
||||
delayed = true;
|
||||
}
|
||||
// Set play rate
|
||||
switch (replay_rate) {
|
||||
case -2 * ZM_RATE_BASE :
|
||||
replay_rate = -5 * ZM_RATE_BASE;
|
||||
break;
|
||||
case -5 * ZM_RATE_BASE :
|
||||
replay_rate = -10 * ZM_RATE_BASE;
|
||||
break;
|
||||
case -10 * ZM_RATE_BASE :
|
||||
replay_rate = -25 * ZM_RATE_BASE;
|
||||
break;
|
||||
case -25 * ZM_RATE_BASE :
|
||||
case -50 * ZM_RATE_BASE :
|
||||
replay_rate = -50 * ZM_RATE_BASE;
|
||||
break;
|
||||
default :
|
||||
replay_rate = -2 * ZM_RATE_BASE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case CMD_ZOOMIN :
|
||||
x = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2];
|
||||
y = ((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4];
|
||||
zoom += 10;
|
||||
Debug(1, "Got ZOOM IN command, to %d,%d zoom value %d%%", x, y, zoom);
|
||||
break;
|
||||
case CMD_ZOOMOUT :
|
||||
zoom -= 10;
|
||||
if (zoom < 100) zoom = 100;
|
||||
Debug(1, "Got ZOOM OUT command resulting zoom %d%%", zoom);
|
||||
break;
|
||||
case CMD_ZOOMSTOP :
|
||||
zoom = 100;
|
||||
Debug(1, "Got ZOOM OUT FULL command resulting zoom %d%%", zoom);
|
||||
break;
|
||||
case CMD_PAN :
|
||||
x = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2];
|
||||
y = ((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4];
|
||||
Debug(1, "Got PAN command, to %d,%d", x, y);
|
||||
break;
|
||||
case CMD_SCALE :
|
||||
scale = ((unsigned char)msg->msg_data[1]<<8)|(unsigned char)msg->msg_data[2];
|
||||
Debug(1, "Got SCALE command, to %d", scale);
|
||||
break;
|
||||
case CMD_QUIT :
|
||||
Info("User initiated exit - CMD_QUIT");
|
||||
zm_terminate = true;
|
||||
break;
|
||||
case CMD_ANALYZE_ON :
|
||||
frame_type = FRAME_ANALYSIS;
|
||||
Debug(1, "ANALYSIS on");
|
||||
break;
|
||||
case CMD_ANALYZE_OFF :
|
||||
frame_type = FRAME_NORMAL;
|
||||
Debug(1, "ANALYSIS off");
|
||||
break;
|
||||
case CMD_QUERY :
|
||||
Debug(1, "Got QUERY command, sending STATUS");
|
||||
break;
|
||||
default :
|
||||
Error("Got unexpected command %d", msg->msg_data[0]);
|
||||
break;
|
||||
} // end switch command
|
||||
|
||||
struct {
|
||||
@@ -262,7 +261,7 @@ void MonitorStream::processCommand(const CmdMsg *msg) {
|
||||
status_data.buffer_level = 0;
|
||||
} else {
|
||||
FPSeconds elapsed = now - last_fps_update;
|
||||
if (elapsed.count()) {
|
||||
if (elapsed.count()) {
|
||||
actual_fps = (actual_fps + (frame_count - last_frame_count) / elapsed.count())/2;
|
||||
last_frame_count = frame_count;
|
||||
last_fps_update = now;
|
||||
@@ -287,18 +286,18 @@ void MonitorStream::processCommand(const CmdMsg *msg) {
|
||||
status_data.zoom = zoom;
|
||||
status_data.scale = scale;
|
||||
Debug(2, "viewing fps: %.2f capture_fps: %.2f analysis_fps: %.2f Buffer Level:%d, Delayed:%d, Paused:%d, Rate:%d, delay:%.3f, Zoom:%d, Enabled:%d Forced:%d",
|
||||
status_data.fps,
|
||||
status_data.capture_fps,
|
||||
status_data.analysis_fps,
|
||||
status_data.buffer_level,
|
||||
status_data.delayed,
|
||||
status_data.paused,
|
||||
status_data.rate,
|
||||
status_data.delay,
|
||||
status_data.zoom,
|
||||
status_data.enabled,
|
||||
status_data.forced
|
||||
);
|
||||
status_data.fps,
|
||||
status_data.capture_fps,
|
||||
status_data.analysis_fps,
|
||||
status_data.buffer_level,
|
||||
status_data.delayed,
|
||||
status_data.paused,
|
||||
status_data.rate,
|
||||
status_data.delay,
|
||||
status_data.zoom,
|
||||
status_data.enabled,
|
||||
status_data.forced
|
||||
);
|
||||
|
||||
DataMsg status_msg;
|
||||
status_msg.msg_type = MSG_DATA_WATCH;
|
||||
@@ -314,10 +313,10 @@ bool MonitorStream::sendFrame(const std::string &filepath, SystemTimePoint times
|
||||
bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE));
|
||||
|
||||
if (
|
||||
(type != STREAM_JPEG)
|
||||
||
|
||||
(!config.timestamp_on_capture)
|
||||
)
|
||||
(type != STREAM_JPEG)
|
||||
||
|
||||
(!config.timestamp_on_capture)
|
||||
)
|
||||
send_raw = false;
|
||||
|
||||
if (!send_raw) {
|
||||
@@ -339,11 +338,11 @@ bool MonitorStream::sendFrame(const std::string &filepath, SystemTimePoint times
|
||||
TimePoint send_start_time = std::chrono::steady_clock::now();
|
||||
|
||||
if (
|
||||
(0 > fprintf(stdout, "Content-Length: %d\r\nX-Timestamp: %.6f\r\n\r\n",
|
||||
img_buffer_size, std::chrono::duration_cast<FPSeconds>(timestamp.time_since_epoch()).count()))
|
||||
||
|
||||
(fwrite(img_buffer, img_buffer_size, 1, stdout) != 1)
|
||||
) {
|
||||
(0 > fprintf(stdout, "Content-Length: %d\r\nX-Timestamp: %.6f\r\n\r\n",
|
||||
img_buffer_size, std::chrono::duration_cast<FPSeconds>(timestamp.time_since_epoch()).count()))
|
||||
||
|
||||
(fwrite(img_buffer, img_buffer_size, 1, stdout) != 1)
|
||||
) {
|
||||
if (!zm_terminate)
|
||||
Warning("Unable to send stream frame: %s", strerror(errno));
|
||||
return false;
|
||||
@@ -357,8 +356,8 @@ bool MonitorStream::sendFrame(const std::string &filepath, SystemTimePoint times
|
||||
|
||||
if (frame_send_time > Milliseconds(lround(Milliseconds::period::den / maxfps))) {
|
||||
Info("Frame send time %" PRIi64 " ms too slow, throttling maxfps to %.2f",
|
||||
static_cast<int64>(std::chrono::duration_cast<Milliseconds>(frame_send_time).count()),
|
||||
maxfps);
|
||||
static_cast<int64>(std::chrono::duration_cast<Milliseconds>(frame_send_time).count()),
|
||||
maxfps);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,36 +399,36 @@ bool MonitorStream::sendFrame(Image *image, SystemTimePoint timestamp) {
|
||||
unsigned char *img_buffer = temp_img_buffer;
|
||||
|
||||
switch (type) {
|
||||
case STREAM_JPEG :
|
||||
send_image->EncodeJpeg(img_buffer, &img_buffer_size);
|
||||
fputs("Content-Type: image/jpeg\r\n", stdout);
|
||||
break;
|
||||
case STREAM_RAW :
|
||||
fputs("Content-Type: image/x-rgb\r\n", stdout);
|
||||
img_buffer = send_image->Buffer();
|
||||
img_buffer_size = send_image->Size();
|
||||
break;
|
||||
case STREAM_ZIP :
|
||||
case STREAM_JPEG :
|
||||
send_image->EncodeJpeg(img_buffer, &img_buffer_size);
|
||||
fputs("Content-Type: image/jpeg\r\n", stdout);
|
||||
break;
|
||||
case STREAM_RAW :
|
||||
fputs("Content-Type: image/x-rgb\r\n", stdout);
|
||||
img_buffer = send_image->Buffer();
|
||||
img_buffer_size = send_image->Size();
|
||||
break;
|
||||
case STREAM_ZIP :
|
||||
#if HAVE_ZLIB_H
|
||||
fputs("Content-Type: image/x-rgbz\r\n", stdout);
|
||||
unsigned long zip_buffer_size;
|
||||
send_image->Zip(img_buffer, &zip_buffer_size);
|
||||
img_buffer_size = zip_buffer_size;
|
||||
fputs("Content-Type: image/x-rgbz\r\n", stdout);
|
||||
unsigned long zip_buffer_size;
|
||||
send_image->Zip(img_buffer, &zip_buffer_size);
|
||||
img_buffer_size = zip_buffer_size;
|
||||
#else
|
||||
Error("zlib is required for zipped images. Falling back to raw image");
|
||||
type = STREAM_RAW;
|
||||
Error("zlib is required for zipped images. Falling back to raw image");
|
||||
type = STREAM_RAW;
|
||||
#endif // HAVE_ZLIB_H
|
||||
break;
|
||||
default :
|
||||
Error("Unexpected frame type %d", type);
|
||||
return false;
|
||||
break;
|
||||
default :
|
||||
Error("Unexpected frame type %d", type);
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
(0 > fprintf(stdout, "Content-Length: %d\r\nX-Timestamp: %.6f\r\n\r\n",
|
||||
img_buffer_size, std::chrono::duration_cast<FPSeconds>(timestamp.time_since_epoch()).count()))
|
||||
||
|
||||
(fwrite(img_buffer, img_buffer_size, 1, stdout) != 1)
|
||||
) {
|
||||
(0 > fprintf(stdout, "Content-Length: %d\r\nX-Timestamp: %.6f\r\n\r\n",
|
||||
img_buffer_size, std::chrono::duration_cast<FPSeconds>(timestamp.time_since_epoch()).count()))
|
||||
||
|
||||
(fwrite(img_buffer, img_buffer_size, 1, stdout) != 1)
|
||||
) {
|
||||
// If the pipe was closed, we will get signalled SIGPIPE to exit, which will set zm_terminate
|
||||
Debug(1, "Unable to send stream frame: %s, zm_terminate: %d", strerror(errno), zm_terminate);
|
||||
return false;
|
||||
@@ -447,9 +446,9 @@ bool MonitorStream::sendFrame(Image *image, SystemTimePoint timestamp) {
|
||||
if (frame_send_time > maxfps_milliseconds) {
|
||||
//maxfps /= 1.5;
|
||||
Debug(1, "Frame send time %" PRIi64 " msec too slow (> %" PRIi64 ", %.3f",
|
||||
static_cast<int64>(std::chrono::duration_cast<Milliseconds>(frame_send_time).count()),
|
||||
static_cast<int64>(std::chrono::duration_cast<Milliseconds>(maxfps_milliseconds).count()),
|
||||
maxfps);
|
||||
static_cast<int64>(std::chrono::duration_cast<Milliseconds>(frame_send_time).count()),
|
||||
static_cast<int64>(std::chrono::duration_cast<Milliseconds>(maxfps_milliseconds).count()),
|
||||
maxfps);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -473,7 +472,7 @@ void MonitorStream::runStream() {
|
||||
sendTextFrame("Unable to stream");
|
||||
}
|
||||
} else {
|
||||
// Not yet migrated over to stream class
|
||||
// Not yet migrated over to stream class
|
||||
SingleImage(scale);
|
||||
}
|
||||
zm_terminate = true;
|
||||
@@ -547,7 +546,7 @@ void MonitorStream::runStream() {
|
||||
} else {
|
||||
Debug(2, "Not using playback_buffer");
|
||||
} // end if connkey && playback_buffer
|
||||
|
||||
|
||||
std::thread command_processor;
|
||||
if (connkey) {
|
||||
command_processor = std::thread(&MonitorStream::checkCommandQueue, this);
|
||||
@@ -649,7 +648,7 @@ void MonitorStream::runStream() {
|
||||
if (!sendFrame(
|
||||
temp_image_buffer[temp_read_index].file_name,
|
||||
temp_image_buffer[temp_read_index].timestamp)
|
||||
) {
|
||||
) {
|
||||
zm_terminate = true;
|
||||
}
|
||||
frame_count++;
|
||||
@@ -693,16 +692,16 @@ void MonitorStream::runStream() {
|
||||
if (!paused && !delayed) {
|
||||
last_read_index = monitor->shared_data->last_write_index;
|
||||
Debug(2, "Sending frame index: %d: frame_mod: %d frame count: %d paused(%d) delayed(%d)",
|
||||
index, frame_mod, frame_count, paused, delayed);
|
||||
index, frame_mod, frame_count, paused, delayed);
|
||||
// Send the next frame
|
||||
//
|
||||
// Perhaps we should use NOW instead.
|
||||
// Perhaps we should use NOW instead.
|
||||
last_frame_timestamp =
|
||||
SystemTimePoint(zm::chrono::duration_cast<Microseconds>(monitor->shared_timestamps[index]));
|
||||
SystemTimePoint(zm::chrono::duration_cast<Microseconds>(monitor->shared_timestamps[index]));
|
||||
|
||||
Image *send_image = nullptr;
|
||||
/*
|
||||
if ((frame_type == FRAME_ANALYSIS) &&
|
||||
if ((frame_type == FRAME_ANALYSIS) &&
|
||||
(monitor->Analysing() != Monitor::ANALYSING_NONE)) {
|
||||
Debug(1, "Sending analysis image");
|
||||
send_image = monitor->GetAlarmImage();
|
||||
@@ -763,7 +762,7 @@ void MonitorStream::runStream() {
|
||||
} // end if actual_delta_time > 5
|
||||
} // end if change in zoom
|
||||
} // end if paused or not
|
||||
//} else {
|
||||
//} else {
|
||||
//frame_count++;
|
||||
} // end if should send frame now > when_to_send_next_frame
|
||||
|
||||
@@ -778,7 +777,7 @@ void MonitorStream::runStream() {
|
||||
}
|
||||
|
||||
temp_image_buffer[temp_index].timestamp =
|
||||
SystemTimePoint(zm::chrono::duration_cast<Microseconds>(monitor->shared_timestamps[index]));
|
||||
SystemTimePoint(zm::chrono::duration_cast<Microseconds>(monitor->shared_timestamps[index]));
|
||||
monitor->image_buffer[index]->WriteJpeg(temp_image_buffer[temp_index].file_name, config.jpeg_file_quality);
|
||||
temp_write_index = MOD_ADD(temp_write_index, 1, temp_image_buffer_count);
|
||||
if (temp_write_index == temp_read_index) {
|
||||
@@ -797,8 +796,8 @@ void MonitorStream::runStream() {
|
||||
} // end if buffered playback
|
||||
} else {
|
||||
Debug(3, "Waiting for capture last_write_index=%u == last_read_index=%u",
|
||||
monitor->shared_data->last_write_index,
|
||||
last_read_index);
|
||||
monitor->shared_data->last_write_index,
|
||||
last_read_index);
|
||||
|
||||
if (now - last_frame_sent > Seconds(5)) {
|
||||
if (last_read_index == monitor->GetImageBufferCount()) {
|
||||
@@ -816,7 +815,7 @@ void MonitorStream::runStream() {
|
||||
double capture_fps = monitor->GetFPS();
|
||||
double fps = ((maxfps > 0.0) && (capture_fps > maxfps)) ? maxfps : capture_fps;
|
||||
double sleep_time_seconds = (1 / ((fps ? fps : 1))) // 1 second / fps
|
||||
* (replay_rate ? abs(replay_rate)/ZM_RATE_BASE : 1); // replay_rate is 100 for 1x
|
||||
* (replay_rate ? abs(replay_rate)/ZM_RATE_BASE : 1); // replay_rate is 100 for 1x
|
||||
Debug(3, "Using %f for maxfps. capture_fps: %f maxfps %f * replay_rate: %d = %f", fps, capture_fps, maxfps, replay_rate, sleep_time_seconds);
|
||||
|
||||
sleep_time = FPSeconds(sleep_time_seconds);
|
||||
@@ -912,7 +911,7 @@ void MonitorStream::SingleImage(int scale) {
|
||||
int count = 10; // Give it 1 second to connect or else send text frame.
|
||||
while (count and (monitor->shared_data->last_write_index >= monitor->image_buffer_count) and !zm_terminate) {
|
||||
Debug(1, "Waiting for capture to begin. last write index %d >=? %d",
|
||||
monitor->shared_data->last_write_index, monitor->image_buffer_count);
|
||||
monitor->shared_data->last_write_index, monitor->image_buffer_count);
|
||||
std::this_thread::sleep_for(Milliseconds(100));
|
||||
count--;
|
||||
}
|
||||
@@ -938,9 +937,9 @@ void MonitorStream::SingleImage(int scale) {
|
||||
snap_image->EncodeJpeg(img_buffer, &img_buffer_size);
|
||||
|
||||
fprintf(stdout,
|
||||
"Content-Length: %d\r\n"
|
||||
"Content-Type: image/jpeg\r\n\r\n",
|
||||
img_buffer_size);
|
||||
"Content-Length: %d\r\n"
|
||||
"Content-Type: image/jpeg\r\n\r\n",
|
||||
img_buffer_size);
|
||||
fwrite(img_buffer, img_buffer_size, 1, stdout);
|
||||
} // end void MonitorStream::SingleImage(int scale)
|
||||
|
||||
@@ -959,9 +958,9 @@ void MonitorStream::SingleImageRaw(int scale) {
|
||||
}
|
||||
|
||||
fprintf(stdout,
|
||||
"Content-Length: %u\r\n"
|
||||
"Content-Type: image/x-rgb\r\n\r\n",
|
||||
snap_image->Size());
|
||||
"Content-Length: %u\r\n"
|
||||
"Content-Type: image/x-rgb\r\n\r\n",
|
||||
snap_image->Size());
|
||||
fwrite(snap_image->Buffer(), snap_image->Size(), 1, stdout);
|
||||
} // end void MonitorStream::SingleImageRaw(int scale)
|
||||
|
||||
@@ -985,9 +984,9 @@ void MonitorStream::SingleImageZip(int scale) {
|
||||
snap_image->Zip(img_buffer, &img_buffer_size);
|
||||
|
||||
fprintf(stdout,
|
||||
"Content-Length: %lu\r\n"
|
||||
"Content-Type: image/x-rgbz\r\n\r\n",
|
||||
img_buffer_size);
|
||||
"Content-Length: %lu\r\n"
|
||||
"Content-Type: image/x-rgbz\r\n\r\n",
|
||||
img_buffer_size);
|
||||
fwrite(img_buffer, img_buffer_size, 1, stdout);
|
||||
} // end void MonitorStream::SingleImageZip(int scale)
|
||||
#endif // HAVE_ZLIB_H
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder MonitorStream Class Interfaces, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_MONITORSTREAM_H
|
||||
#define ZM_MONITORSTREAM_H
|
||||
@@ -23,56 +23,56 @@
|
||||
#include "zm_stream.h"
|
||||
|
||||
class MonitorStream : public StreamBase {
|
||||
protected:
|
||||
struct SwapImage {
|
||||
bool valid = false;
|
||||
SystemTimePoint timestamp;
|
||||
std::string file_name;
|
||||
};
|
||||
protected:
|
||||
struct SwapImage {
|
||||
bool valid = false;
|
||||
SystemTimePoint timestamp;
|
||||
std::string file_name;
|
||||
};
|
||||
|
||||
private:
|
||||
SwapImage *temp_image_buffer;
|
||||
int temp_image_buffer_count;
|
||||
int temp_read_index;
|
||||
int temp_write_index;
|
||||
private:
|
||||
SwapImage *temp_image_buffer;
|
||||
int temp_image_buffer_count;
|
||||
int temp_read_index;
|
||||
int temp_write_index;
|
||||
|
||||
protected:
|
||||
Microseconds ttl;
|
||||
int playback_buffer;
|
||||
bool delayed;
|
||||
protected:
|
||||
Microseconds ttl;
|
||||
int playback_buffer;
|
||||
bool delayed;
|
||||
|
||||
protected:
|
||||
bool checkSwapPath(const char *path, bool create_path);
|
||||
bool sendFrame(const std::string &filepath, SystemTimePoint timestamp);
|
||||
bool sendFrame(Image *image, SystemTimePoint timestamp);
|
||||
void processCommand(const CmdMsg *msg) override;
|
||||
void SingleImage(int scale=100);
|
||||
void SingleImageRaw(int scale=100);
|
||||
protected:
|
||||
bool checkSwapPath(const char *path, bool create_path);
|
||||
bool sendFrame(const std::string &filepath, SystemTimePoint timestamp);
|
||||
bool sendFrame(Image *image, SystemTimePoint timestamp);
|
||||
void processCommand(const CmdMsg *msg) override;
|
||||
void SingleImage(int scale=100);
|
||||
void SingleImageRaw(int scale=100);
|
||||
#ifdef HAVE_ZLIB_H
|
||||
void SingleImageZip(int scale=100);
|
||||
void SingleImageZip(int scale=100);
|
||||
#endif
|
||||
|
||||
public:
|
||||
MonitorStream() :
|
||||
temp_image_buffer(nullptr),
|
||||
temp_image_buffer_count(0),
|
||||
temp_read_index(0),
|
||||
temp_write_index(0),
|
||||
ttl(0),
|
||||
playback_buffer(0),
|
||||
delayed(false)
|
||||
public:
|
||||
MonitorStream() :
|
||||
temp_image_buffer(nullptr),
|
||||
temp_image_buffer_count(0),
|
||||
temp_read_index(0),
|
||||
temp_write_index(0),
|
||||
ttl(0),
|
||||
playback_buffer(0),
|
||||
delayed(false)
|
||||
{}
|
||||
|
||||
void setStreamBuffer(int p_playback_buffer) {
|
||||
playback_buffer = p_playback_buffer;
|
||||
}
|
||||
void setStreamTTL(time_t p_ttl) {
|
||||
ttl = Seconds(p_ttl);
|
||||
}
|
||||
bool setStreamStart(int monitor_id) {
|
||||
return loadMonitor(monitor_id);
|
||||
}
|
||||
void runStream() override;
|
||||
void setStreamBuffer(int p_playback_buffer) {
|
||||
playback_buffer = p_playback_buffer;
|
||||
}
|
||||
void setStreamTTL(time_t p_ttl) {
|
||||
ttl = Seconds(p_ttl);
|
||||
}
|
||||
bool setStreamStart(int monitor_id) {
|
||||
return loadMonitor(monitor_id);
|
||||
}
|
||||
void runStream() override;
|
||||
};
|
||||
|
||||
#endif // ZM_MONITORSTREAM_H
|
||||
|
||||
549
src/zm_mpeg.cpp
549
src/zm_mpeg.cpp
@@ -26,81 +26,81 @@
|
||||
bool VideoStream::initialised = false;
|
||||
|
||||
VideoStream::MimeData VideoStream::mime_data[] = {
|
||||
{ "asf", "video/x-ms-asf" },
|
||||
{ "swf", "application/x-shockwave-flash" },
|
||||
{ "flv", "video/x-flv" },
|
||||
{ "mov", "video/quicktime" }
|
||||
{ "asf", "video/x-ms-asf" },
|
||||
{ "swf", "application/x-shockwave-flash" },
|
||||
{ "flv", "video/x-flv" },
|
||||
{ "mov", "video/quicktime" }
|
||||
};
|
||||
|
||||
void VideoStream::Initialise( ) {
|
||||
FFMPEGInit();
|
||||
initialised = true;
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
void VideoStream::SetupFormat( ) {
|
||||
/* allocate the output media context */
|
||||
ofc = nullptr;
|
||||
avformat_alloc_output_context2(&ofc, nullptr, format, filename);
|
||||
/* allocate the output media context */
|
||||
ofc = nullptr;
|
||||
avformat_alloc_output_context2(&ofc, nullptr, format, filename);
|
||||
|
||||
if (!ofc) {
|
||||
Fatal("avformat_alloc_..._context failed");
|
||||
}
|
||||
if (!ofc) {
|
||||
Fatal("avformat_alloc_..._context failed");
|
||||
}
|
||||
|
||||
of = ofc->oformat;
|
||||
of = ofc->oformat;
|
||||
Debug(1, "Using output format: %s (%s)", of->name, of->long_name);
|
||||
}
|
||||
|
||||
int VideoStream::SetupCodec(
|
||||
int colours,
|
||||
int subpixelorder,
|
||||
int width,
|
||||
int height,
|
||||
int bitrate,
|
||||
double frame_rate
|
||||
) {
|
||||
/* ffmpeg format matching */
|
||||
switch (colours) {
|
||||
case ZM_COLOUR_RGB24:
|
||||
if (subpixelorder == ZM_SUBPIX_ORDER_BGR) {
|
||||
/* BGR subpixel order */
|
||||
pf = AV_PIX_FMT_BGR24;
|
||||
} else {
|
||||
/* Assume RGB subpixel order */
|
||||
pf = AV_PIX_FMT_RGB24;
|
||||
}
|
||||
break;
|
||||
case ZM_COLOUR_RGB32:
|
||||
if (subpixelorder == ZM_SUBPIX_ORDER_ARGB) {
|
||||
/* ARGB subpixel order */
|
||||
pf = AV_PIX_FMT_ARGB;
|
||||
} else if (subpixelorder == ZM_SUBPIX_ORDER_ABGR) {
|
||||
/* ABGR subpixel order */
|
||||
pf = AV_PIX_FMT_ABGR;
|
||||
} else if (subpixelorder == ZM_SUBPIX_ORDER_BGRA) {
|
||||
/* BGRA subpixel order */
|
||||
pf = AV_PIX_FMT_BGRA;
|
||||
} else {
|
||||
/* Assume RGBA subpixel order */
|
||||
pf = AV_PIX_FMT_RGBA;
|
||||
}
|
||||
break;
|
||||
case ZM_COLOUR_GRAY8:
|
||||
pf = AV_PIX_FMT_GRAY8;
|
||||
break;
|
||||
default:
|
||||
Panic("Unexpected colours: %d",colours);
|
||||
break;
|
||||
}
|
||||
int colours,
|
||||
int subpixelorder,
|
||||
int width,
|
||||
int height,
|
||||
int bitrate,
|
||||
double frame_rate
|
||||
) {
|
||||
/* ffmpeg format matching */
|
||||
switch (colours) {
|
||||
case ZM_COLOUR_RGB24:
|
||||
if (subpixelorder == ZM_SUBPIX_ORDER_BGR) {
|
||||
/* BGR subpixel order */
|
||||
pf = AV_PIX_FMT_BGR24;
|
||||
} else {
|
||||
/* Assume RGB subpixel order */
|
||||
pf = AV_PIX_FMT_RGB24;
|
||||
}
|
||||
break;
|
||||
case ZM_COLOUR_RGB32:
|
||||
if (subpixelorder == ZM_SUBPIX_ORDER_ARGB) {
|
||||
/* ARGB subpixel order */
|
||||
pf = AV_PIX_FMT_ARGB;
|
||||
} else if (subpixelorder == ZM_SUBPIX_ORDER_ABGR) {
|
||||
/* ABGR subpixel order */
|
||||
pf = AV_PIX_FMT_ABGR;
|
||||
} else if (subpixelorder == ZM_SUBPIX_ORDER_BGRA) {
|
||||
/* BGRA subpixel order */
|
||||
pf = AV_PIX_FMT_BGRA;
|
||||
} else {
|
||||
/* Assume RGBA subpixel order */
|
||||
pf = AV_PIX_FMT_RGBA;
|
||||
}
|
||||
break;
|
||||
case ZM_COLOUR_GRAY8:
|
||||
pf = AV_PIX_FMT_GRAY8;
|
||||
break;
|
||||
default:
|
||||
Panic("Unexpected colours: %d",colours);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcmp("rtp", of->name) == 0) {
|
||||
// RTP must have a packet_size.
|
||||
// Not sure what this value should be really...
|
||||
ofc->packet_size = width*height;
|
||||
if (strcmp("rtp", of->name) == 0) {
|
||||
// RTP must have a packet_size.
|
||||
// Not sure what this value should be really...
|
||||
ofc->packet_size = width*height;
|
||||
Debug(1,"Setting packet_size to %d", ofc->packet_size);
|
||||
}
|
||||
}
|
||||
|
||||
_AVCODECID codec_id = of->video_codec;
|
||||
if (codec_name) {
|
||||
_AVCODECID codec_id = of->video_codec;
|
||||
if (codec_name) {
|
||||
const AVCodec *a = avcodec_find_encoder_by_name(codec_name);
|
||||
if (a) {
|
||||
codec_id = a->id;
|
||||
@@ -108,66 +108,66 @@ int VideoStream::SetupCodec(
|
||||
} else {
|
||||
Debug(1, "Could not find codec \"%s\". Using default \"%s\"", codec_name, avcodec_get_name(codec_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* add the video streams using the default format codecs
|
||||
and initialize the codecs */
|
||||
ost = nullptr;
|
||||
if (codec_id != AV_CODEC_ID_NONE) {
|
||||
codec = avcodec_find_encoder(codec_id);
|
||||
if (!codec) {
|
||||
Error("Could not find encoder for '%s'", avcodec_get_name(codec_id));
|
||||
/* add the video streams using the default format codecs
|
||||
and initialize the codecs */
|
||||
ost = nullptr;
|
||||
if (codec_id != AV_CODEC_ID_NONE) {
|
||||
codec = avcodec_find_encoder(codec_id);
|
||||
if (!codec) {
|
||||
Error("Could not find encoder for '%s'", avcodec_get_name(codec_id));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Debug(1, "Found encoder for '%s'", avcodec_get_name(codec_id));
|
||||
ost = avformat_new_stream(ofc, codec);
|
||||
if (!ost) {
|
||||
Error("Could not alloc stream");
|
||||
Debug(1, "Found encoder for '%s'", avcodec_get_name(codec_id));
|
||||
ost = avformat_new_stream(ofc, codec);
|
||||
if (!ost) {
|
||||
Error("Could not alloc stream");
|
||||
return -1;
|
||||
}
|
||||
Debug(1, "Allocated stream (%d) !=? (%d)", ost->id , ofc->nb_streams - 1);
|
||||
ost->id = ofc->nb_streams - 1;
|
||||
}
|
||||
Debug(1, "Allocated stream (%d) !=? (%d)", ost->id, ofc->nb_streams - 1);
|
||||
ost->id = ofc->nb_streams - 1;
|
||||
|
||||
codec_context = avcodec_alloc_context3(nullptr);
|
||||
//avcodec_parameters_to_context(codec_context, ost->codecpar);
|
||||
codec_context->codec_id = codec->id;
|
||||
codec_context->codec_type = codec->type;
|
||||
codec_context->codec_id = codec->id;
|
||||
codec_context->codec_type = codec->type;
|
||||
|
||||
codec_context->pix_fmt = strcmp("mjpeg", ofc->oformat->name) == 0 ? AV_PIX_FMT_YUVJ422P : AV_PIX_FMT_YUV420P;
|
||||
if (bitrate <= 100) {
|
||||
// Quality based bitrate control (VBR). Scale is 1..31 where 1 is best.
|
||||
// This gets rid of artifacts in the beginning of the movie; and well, even quality.
|
||||
codec_context->flags |= AV_CODEC_FLAG_QSCALE;
|
||||
codec_context->global_quality = FF_QP2LAMBDA * (31 - (31 * (bitrate / 100.0)));
|
||||
} else {
|
||||
codec_context->bit_rate = bitrate;
|
||||
}
|
||||
codec_context->pix_fmt = strcmp("mjpeg", ofc->oformat->name) == 0 ? AV_PIX_FMT_YUVJ422P : AV_PIX_FMT_YUV420P;
|
||||
if (bitrate <= 100) {
|
||||
// Quality based bitrate control (VBR). Scale is 1..31 where 1 is best.
|
||||
// This gets rid of artifacts in the beginning of the movie; and well, even quality.
|
||||
codec_context->flags |= AV_CODEC_FLAG_QSCALE;
|
||||
codec_context->global_quality = FF_QP2LAMBDA * (31 - (31 * (bitrate / 100.0)));
|
||||
} else {
|
||||
codec_context->bit_rate = bitrate;
|
||||
}
|
||||
|
||||
/* resolution must be a multiple of two */
|
||||
codec_context->width = width;
|
||||
codec_context->height = height;
|
||||
/* time base: this is the fundamental unit of time (in seconds) in terms
|
||||
of which frame timestamps are represented. for fixed-fps content,
|
||||
timebase should be 1/framerate and timestamp increments should be
|
||||
identically 1. */
|
||||
codec_context->time_base.den = frame_rate;
|
||||
codec_context->time_base.num = 1;
|
||||
/* resolution must be a multiple of two */
|
||||
codec_context->width = width;
|
||||
codec_context->height = height;
|
||||
/* time base: this is the fundamental unit of time (in seconds) in terms
|
||||
of which frame timestamps are represented. for fixed-fps content,
|
||||
timebase should be 1/framerate and timestamp increments should be
|
||||
identically 1. */
|
||||
codec_context->time_base.den = frame_rate;
|
||||
codec_context->time_base.num = 1;
|
||||
ost->time_base.den = frame_rate;
|
||||
ost->time_base.num = 1;
|
||||
Debug( 1, "Will encode in %d fps. %dx%d", codec_context->time_base.den, width, height );
|
||||
ost->time_base.num = 1;
|
||||
Debug( 1, "Will encode in %d fps. %dx%d", codec_context->time_base.den, width, height );
|
||||
|
||||
/* emit one intra frame every second */
|
||||
codec_context->gop_size = frame_rate;
|
||||
/* emit one intra frame every second */
|
||||
codec_context->gop_size = frame_rate;
|
||||
|
||||
// some formats want stream headers to be separate
|
||||
if (of->flags & AVFMT_GLOBALHEADER)
|
||||
codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
||||
// some formats want stream headers to be separate
|
||||
if (of->flags & AVFMT_GLOBALHEADER)
|
||||
codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
||||
|
||||
avcodec_parameters_from_context(ost->codecpar, codec_context);
|
||||
zm_dump_codecpar(ost->codecpar);
|
||||
} else {
|
||||
Error("of->video_codec == AV_CODEC_ID_NONE");
|
||||
} else {
|
||||
Error("of->video_codec == AV_CODEC_ID_NONE");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -177,43 +177,43 @@ void VideoStream::SetParameters( ) {
|
||||
}
|
||||
|
||||
const char *VideoStream::MimeType() const {
|
||||
for ( unsigned int i = 0; i < sizeof (mime_data) / sizeof (*mime_data); i++ ) {
|
||||
if ( strcmp(format, mime_data[i].format) == 0 ) {
|
||||
Debug(1, "MimeType is \"%s\"", mime_data[i].mime_type);
|
||||
return mime_data[i].mime_type;
|
||||
}
|
||||
}
|
||||
const char *mime_type = of->mime_type;
|
||||
if ( !mime_type ) {
|
||||
std::string mime = std::string("video/") + format;
|
||||
mime_type = strdup(mime.c_str()); // mem leak
|
||||
Warning( "Unable to determine mime type for '%s' format, using '%s' as default", format, mime_type);
|
||||
}
|
||||
for ( unsigned int i = 0; i < sizeof (mime_data) / sizeof (*mime_data); i++ ) {
|
||||
if ( strcmp(format, mime_data[i].format) == 0 ) {
|
||||
Debug(1, "MimeType is \"%s\"", mime_data[i].mime_type);
|
||||
return mime_data[i].mime_type;
|
||||
}
|
||||
}
|
||||
const char *mime_type = of->mime_type;
|
||||
if ( !mime_type ) {
|
||||
std::string mime = std::string("video/") + format;
|
||||
mime_type = strdup(mime.c_str()); // mem leak
|
||||
Warning( "Unable to determine mime type for '%s' format, using '%s' as default", format, mime_type);
|
||||
}
|
||||
|
||||
Debug(1, "MimeType is \"%s\"", mime_type);
|
||||
Debug(1, "MimeType is \"%s\"", mime_type);
|
||||
|
||||
return mime_type;
|
||||
return mime_type;
|
||||
}
|
||||
|
||||
bool VideoStream::OpenStream( ) {
|
||||
int ret;
|
||||
int ret;
|
||||
|
||||
/* now that all the parameters are set, we can open the
|
||||
video codecs and allocate the necessary encode buffers */
|
||||
if ( ost ) {
|
||||
/* now that all the parameters are set, we can open the
|
||||
video codecs and allocate the necessary encode buffers */
|
||||
if ( ost ) {
|
||||
Debug(1,"Opening codec");
|
||||
|
||||
/* open the codec */
|
||||
/* open the codec */
|
||||
|
||||
if ((ret = avcodec_open2(codec_context, codec, nullptr)) < 0) {
|
||||
Error("Could not open codec. Error code %d \"%s\"", ret, av_err2str(ret));
|
||||
if ((ret = avcodec_open2(codec_context, codec, nullptr)) < 0) {
|
||||
Error("Could not open codec. Error code %d \"%s\"", ret, av_err2str(ret));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Debug( 1, "Opened codec" );
|
||||
Debug( 1, "Opened codec" );
|
||||
|
||||
/* allocate the encoded raw picture */
|
||||
opicture = av_frame_ptr{zm_av_frame_alloc()};
|
||||
/* allocate the encoded raw picture */
|
||||
opicture = av_frame_ptr{zm_av_frame_alloc()};
|
||||
if (!opicture) {
|
||||
Error("Could not allocate opicture");
|
||||
return false;
|
||||
@@ -230,7 +230,7 @@ bool VideoStream::OpenStream( ) {
|
||||
return false;
|
||||
}
|
||||
av_image_fill_arrays(opicture->data, opicture->linesize,
|
||||
opicture->buf[0]->data, codec_context->pix_fmt, codec_context->width, codec_context->height, 1);
|
||||
opicture->buf[0]->data, codec_context->pix_fmt, codec_context->width, codec_context->height, 1);
|
||||
|
||||
/* if the output format is not identical to the input format, then a temporary
|
||||
picture is needed too. It is then converted to the required
|
||||
@@ -250,40 +250,40 @@ bool VideoStream::OpenStream( ) {
|
||||
}
|
||||
|
||||
av_image_fill_arrays(tmp_opicture->data,
|
||||
tmp_opicture->linesize, tmp_opicture->buf[0]->data, pf,
|
||||
codec_context->width, codec_context->height, 1);
|
||||
tmp_opicture->linesize, tmp_opicture->buf[0]->data, pf,
|
||||
codec_context->width, codec_context->height, 1);
|
||||
}
|
||||
} // end if ost
|
||||
|
||||
/* open the output file, if needed */
|
||||
if ( !(of->flags & AVFMT_NOFILE) ) {
|
||||
ret = avio_open2( &ofc->pb, filename, AVIO_FLAG_WRITE, nullptr, nullptr );
|
||||
ret = avio_open2( &ofc->pb, filename, AVIO_FLAG_WRITE, nullptr, nullptr );
|
||||
|
||||
if ( ret < 0 ) {
|
||||
Error("Could not open '%s'", filename);
|
||||
if ( ret < 0 ) {
|
||||
Error("Could not open '%s'", filename);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Debug(1, "Opened output \"%s\"", filename);
|
||||
} else {
|
||||
Error( "of->flags & AVFMT_NOFILE" );
|
||||
Debug(1, "Opened output \"%s\"", filename);
|
||||
} else {
|
||||
Error( "of->flags & AVFMT_NOFILE" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
video_outbuf = nullptr;
|
||||
video_outbuf = nullptr;
|
||||
if (codec_context->codec_type == AVMEDIA_TYPE_VIDEO &&
|
||||
codec_context->codec_id == AV_CODEC_ID_RAWVIDEO) {
|
||||
/* allocate output buffer */
|
||||
/* XXX: API change will be done */
|
||||
// TODO: Make buffer dynamic.
|
||||
video_outbuf_size = 4000000;
|
||||
video_outbuf = (uint8_t *)malloc( video_outbuf_size );
|
||||
if ( video_outbuf == nullptr ) {
|
||||
Fatal("Unable to malloc memory for outbuf");
|
||||
}
|
||||
}
|
||||
/* allocate output buffer */
|
||||
/* XXX: API change will be done */
|
||||
// TODO: Make buffer dynamic.
|
||||
video_outbuf_size = 4000000;
|
||||
video_outbuf = (uint8_t *)malloc( video_outbuf_size );
|
||||
if ( video_outbuf == nullptr ) {
|
||||
Fatal("Unable to malloc memory for outbuf");
|
||||
}
|
||||
}
|
||||
|
||||
av_dump_format(ofc, 0, filename, 1);
|
||||
av_dump_format(ofc, 0, filename, 1);
|
||||
|
||||
ret = avformat_write_header(ofc, nullptr);
|
||||
|
||||
@@ -295,167 +295,166 @@ bool VideoStream::OpenStream( ) {
|
||||
}
|
||||
|
||||
VideoStream::VideoStream( const char *in_filename, const char *in_format, int bitrate, double frame_rate, int colours, int subpixelorder, int width, int height ) :
|
||||
filename(in_filename),
|
||||
format(in_format),
|
||||
video_outbuf(nullptr),
|
||||
video_outbuf_size(0),
|
||||
last_pts( -1 ),
|
||||
streaming_thread(0),
|
||||
do_streaming(true),
|
||||
add_timestamp(false),
|
||||
timestamp(0),
|
||||
buffer_copy(nullptr),
|
||||
buffer_copy_lock(new pthread_mutex_t),
|
||||
buffer_copy_size(0),
|
||||
buffer_copy_used(0),
|
||||
packet_index(0)
|
||||
{
|
||||
if ( !initialised ) {
|
||||
Initialise( );
|
||||
}
|
||||
filename(in_filename),
|
||||
format(in_format),
|
||||
video_outbuf(nullptr),
|
||||
video_outbuf_size(0),
|
||||
last_pts( -1 ),
|
||||
streaming_thread(0),
|
||||
do_streaming(true),
|
||||
add_timestamp(false),
|
||||
timestamp(0),
|
||||
buffer_copy(nullptr),
|
||||
buffer_copy_lock(new pthread_mutex_t),
|
||||
buffer_copy_size(0),
|
||||
buffer_copy_used(0),
|
||||
packet_index(0) {
|
||||
if ( !initialised ) {
|
||||
Initialise( );
|
||||
}
|
||||
|
||||
if ( format ) {
|
||||
int length = strlen(format);
|
||||
codec_and_format = new char[length+1];;
|
||||
strcpy( codec_and_format, format );
|
||||
format = codec_and_format;
|
||||
codec_name = nullptr;
|
||||
char *f = strchr(codec_and_format, '/');
|
||||
if (f != nullptr) {
|
||||
*f = 0;
|
||||
codec_name = f+1;
|
||||
}
|
||||
}
|
||||
if ( format ) {
|
||||
int length = strlen(format);
|
||||
codec_and_format = new char[length+1];;
|
||||
strcpy( codec_and_format, format );
|
||||
format = codec_and_format;
|
||||
codec_name = nullptr;
|
||||
char *f = strchr(codec_and_format, '/');
|
||||
if (f != nullptr) {
|
||||
*f = 0;
|
||||
codec_name = f+1;
|
||||
}
|
||||
}
|
||||
|
||||
codec_context = nullptr;
|
||||
SetupFormat( );
|
||||
SetupCodec( colours, subpixelorder, width, height, bitrate, frame_rate );
|
||||
SetParameters( );
|
||||
SetupFormat( );
|
||||
SetupCodec( colours, subpixelorder, width, height, bitrate, frame_rate );
|
||||
SetParameters( );
|
||||
|
||||
// Allocate buffered packets.
|
||||
for (auto &pkt : packet_buffers)
|
||||
pkt = av_packet_ptr{av_packet_alloc()};
|
||||
|
||||
// Initialize mutex used by streaming thread.
|
||||
if ( pthread_mutex_init( buffer_copy_lock, nullptr ) != 0 ) {
|
||||
Fatal("pthread_mutex_init failed");
|
||||
}
|
||||
// Initialize mutex used by streaming thread.
|
||||
if ( pthread_mutex_init( buffer_copy_lock, nullptr ) != 0 ) {
|
||||
Fatal("pthread_mutex_init failed");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VideoStream::~VideoStream( ) {
|
||||
Debug( 1, "VideoStream destructor." );
|
||||
Debug( 1, "VideoStream destructor." );
|
||||
|
||||
// Stop streaming thread.
|
||||
if ( streaming_thread ) {
|
||||
do_streaming = false;
|
||||
void* thread_exit_code;
|
||||
// Stop streaming thread.
|
||||
if ( streaming_thread ) {
|
||||
do_streaming = false;
|
||||
void* thread_exit_code;
|
||||
|
||||
Debug( 1, "Asking streaming thread to exit." );
|
||||
Debug( 1, "Asking streaming thread to exit." );
|
||||
|
||||
// Wait for thread to exit.
|
||||
pthread_join(streaming_thread, &thread_exit_code);
|
||||
}
|
||||
// Wait for thread to exit.
|
||||
pthread_join(streaming_thread, &thread_exit_code);
|
||||
}
|
||||
|
||||
if ( buffer_copy != nullptr ) {
|
||||
av_free( buffer_copy );
|
||||
}
|
||||
if ( buffer_copy != nullptr ) {
|
||||
av_free( buffer_copy );
|
||||
}
|
||||
|
||||
if ( buffer_copy_lock ) {
|
||||
if ( pthread_mutex_destroy( buffer_copy_lock ) != 0 ) {
|
||||
Error( "pthread_mutex_destroy failed" );
|
||||
}
|
||||
delete buffer_copy_lock;
|
||||
}
|
||||
if ( buffer_copy_lock ) {
|
||||
if ( pthread_mutex_destroy( buffer_copy_lock ) != 0 ) {
|
||||
Error( "pthread_mutex_destroy failed" );
|
||||
}
|
||||
delete buffer_copy_lock;
|
||||
}
|
||||
|
||||
/* close each codec */
|
||||
if ( ost ) {
|
||||
avcodec_close( codec_context );
|
||||
av_free( video_outbuf );
|
||||
}
|
||||
/* close each codec */
|
||||
if ( ost ) {
|
||||
avcodec_close( codec_context );
|
||||
av_free( video_outbuf );
|
||||
}
|
||||
|
||||
/* write the trailer, if any */
|
||||
av_write_trailer( ofc );
|
||||
/* write the trailer, if any */
|
||||
av_write_trailer( ofc );
|
||||
|
||||
/* free the streams */
|
||||
for ( unsigned int i = 0; i < ofc->nb_streams; i++ ) {
|
||||
av_freep( &ofc->streams[i] );
|
||||
}
|
||||
/* free the streams */
|
||||
for ( unsigned int i = 0; i < ofc->nb_streams; i++ ) {
|
||||
av_freep( &ofc->streams[i] );
|
||||
}
|
||||
|
||||
if ( !(of->flags & AVFMT_NOFILE) ) {
|
||||
/* close the output file */
|
||||
avio_close( ofc->pb );
|
||||
}
|
||||
if ( !(of->flags & AVFMT_NOFILE) ) {
|
||||
/* close the output file */
|
||||
avio_close( ofc->pb );
|
||||
}
|
||||
|
||||
/* free the stream */
|
||||
av_free( ofc );
|
||||
/* free the stream */
|
||||
av_free( ofc );
|
||||
|
||||
/* free format and codec_name data. */
|
||||
if ( codec_and_format ) {
|
||||
delete codec_and_format;
|
||||
}
|
||||
/* free format and codec_name data. */
|
||||
if ( codec_and_format ) {
|
||||
delete codec_and_format;
|
||||
}
|
||||
}
|
||||
|
||||
double VideoStream::EncodeFrame( const uint8_t *buffer, int buffer_size, bool _add_timestamp, unsigned int _timestamp ) {
|
||||
if ( pthread_mutex_lock(buffer_copy_lock) != 0 ) {
|
||||
Fatal( "EncodeFrame: pthread_mutex_lock failed." );
|
||||
}
|
||||
if ( pthread_mutex_lock(buffer_copy_lock) != 0 ) {
|
||||
Fatal( "EncodeFrame: pthread_mutex_lock failed." );
|
||||
}
|
||||
|
||||
if (buffer_copy_size < buffer_size) {
|
||||
if ( buffer_copy ) {
|
||||
av_free(buffer_copy);
|
||||
}
|
||||
if (buffer_copy_size < buffer_size) {
|
||||
if ( buffer_copy ) {
|
||||
av_free(buffer_copy);
|
||||
}
|
||||
|
||||
// Allocate a buffer to store source images for the streaming thread to encode.
|
||||
buffer_copy = (uint8_t *)av_malloc(buffer_size);
|
||||
if ( !buffer_copy ) {
|
||||
Error( "Could not allocate buffer_copy" );
|
||||
// Allocate a buffer to store source images for the streaming thread to encode.
|
||||
buffer_copy = (uint8_t *)av_malloc(buffer_size);
|
||||
if ( !buffer_copy ) {
|
||||
Error( "Could not allocate buffer_copy" );
|
||||
pthread_mutex_unlock(buffer_copy_lock);
|
||||
return 0;
|
||||
}
|
||||
buffer_copy_size = buffer_size;
|
||||
}
|
||||
}
|
||||
buffer_copy_size = buffer_size;
|
||||
}
|
||||
|
||||
add_timestamp = _add_timestamp;
|
||||
timestamp = _timestamp;
|
||||
buffer_copy_used = buffer_size;
|
||||
memcpy(buffer_copy, buffer, buffer_size);
|
||||
add_timestamp = _add_timestamp;
|
||||
timestamp = _timestamp;
|
||||
buffer_copy_used = buffer_size;
|
||||
memcpy(buffer_copy, buffer, buffer_size);
|
||||
|
||||
if ( pthread_mutex_unlock(buffer_copy_lock) != 0 ) {
|
||||
Fatal( "EncodeFrame: pthread_mutex_unlock failed." );
|
||||
}
|
||||
if ( pthread_mutex_unlock(buffer_copy_lock) != 0 ) {
|
||||
Fatal( "EncodeFrame: pthread_mutex_unlock failed." );
|
||||
}
|
||||
|
||||
if ( streaming_thread == 0 ) {
|
||||
Debug( 1, "Starting streaming thread" );
|
||||
if ( streaming_thread == 0 ) {
|
||||
Debug( 1, "Starting streaming thread" );
|
||||
|
||||
// Start a thread for streaming encoded video.
|
||||
if (pthread_create( &streaming_thread, nullptr, StreamingThreadCallback, (void*) this) != 0){
|
||||
// Log a fatal error and exit the process.
|
||||
Fatal( "VideoStream failed to create streaming thread." );
|
||||
}
|
||||
}
|
||||
// Start a thread for streaming encoded video.
|
||||
if (pthread_create( &streaming_thread, nullptr, StreamingThreadCallback, (void*) this) != 0) {
|
||||
// Log a fatal error and exit the process.
|
||||
Fatal( "VideoStream failed to create streaming thread." );
|
||||
}
|
||||
}
|
||||
|
||||
//return ActuallyEncodeFrame( buffer, buffer_size, add_timestamp, timestamp);
|
||||
//return ActuallyEncodeFrame( buffer, buffer_size, add_timestamp, timestamp);
|
||||
|
||||
return _timestamp;
|
||||
return _timestamp;
|
||||
}
|
||||
|
||||
double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, bool add_timestamp, unsigned int timestamp ) {
|
||||
if ( codec_context->pix_fmt != pf ) {
|
||||
if ( codec_context->pix_fmt != pf ) {
|
||||
static struct SwsContext *img_convert_ctx = nullptr;
|
||||
memcpy( tmp_opicture->data[0], buffer, buffer_size );
|
||||
if ( !img_convert_ctx ) {
|
||||
img_convert_ctx = sws_getCachedContext( nullptr, codec_context->width, codec_context->height, pf, codec_context->width, codec_context->height, codec_context->pix_fmt, SWS_BICUBIC, nullptr, nullptr, nullptr );
|
||||
if ( !img_convert_ctx )
|
||||
Panic( "Unable to initialise image scaling context" );
|
||||
}
|
||||
sws_scale( img_convert_ctx, tmp_opicture->data, tmp_opicture->linesize, 0, codec_context->height, opicture->data, opicture->linesize );
|
||||
} else {
|
||||
memcpy( opicture->data[0], buffer, buffer_size );
|
||||
}
|
||||
memcpy( tmp_opicture->data[0], buffer, buffer_size );
|
||||
if ( !img_convert_ctx ) {
|
||||
img_convert_ctx = sws_getCachedContext( nullptr, codec_context->width, codec_context->height, pf, codec_context->width, codec_context->height, codec_context->pix_fmt, SWS_BICUBIC, nullptr, nullptr, nullptr );
|
||||
if ( !img_convert_ctx )
|
||||
Panic( "Unable to initialise image scaling context" );
|
||||
}
|
||||
sws_scale( img_convert_ctx, tmp_opicture->data, tmp_opicture->linesize, 0, codec_context->height, opicture->data, opicture->linesize );
|
||||
} else {
|
||||
memcpy( opicture->data[0], buffer, buffer_size );
|
||||
}
|
||||
|
||||
AVFrame *opicture_ptr = opicture.get();
|
||||
AVPacket *pkt = packet_buffers[packet_index].get();
|
||||
AVFrame *opicture_ptr = opicture.get();
|
||||
AVPacket *pkt = packet_buffers[packet_index].get();
|
||||
|
||||
if (codec_context->codec_type == AVMEDIA_TYPE_VIDEO &&
|
||||
codec_context->codec_id == AV_CODEC_ID_RAWVIDEO) {
|
||||
@@ -463,9 +462,9 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size,
|
||||
pkt->stream_index = ost->index;
|
||||
pkt->data = (uint8_t *)opicture_ptr;
|
||||
pkt->size = buffer_size;
|
||||
} else {
|
||||
opicture_ptr->pts = codec_context->frame_number;
|
||||
opicture_ptr->quality = codec_context->global_quality;
|
||||
} else {
|
||||
opicture_ptr->pts = codec_context->frame_number;
|
||||
opicture_ptr->quality = codec_context->global_quality;
|
||||
|
||||
avcodec_send_frame(codec_context, opicture_ptr);
|
||||
int ret = avcodec_receive_packet(codec_context, pkt);
|
||||
@@ -512,7 +511,7 @@ void *VideoStream::StreamingThreadCallback(void *ctx) {
|
||||
VideoStream *videoStream = reinterpret_cast<VideoStream *>(ctx);
|
||||
|
||||
TimePoint::duration target_interval = std::chrono::duration_cast<TimePoint::duration>(FPSeconds(
|
||||
videoStream->codec_context->time_base.num / static_cast<double>(videoStream->codec_context->time_base.den)));
|
||||
videoStream->codec_context->time_base.num / static_cast<double>(videoStream->codec_context->time_base.den)));
|
||||
|
||||
uint64_t frame_count = 0;
|
||||
TimePoint start_time = std::chrono::steady_clock::now();
|
||||
|
||||
@@ -25,17 +25,17 @@
|
||||
#include <array>
|
||||
|
||||
class VideoStream {
|
||||
protected:
|
||||
protected:
|
||||
struct MimeData {
|
||||
const char *format;
|
||||
const char *mime_type;
|
||||
};
|
||||
|
||||
protected:
|
||||
protected:
|
||||
static bool initialised;
|
||||
static struct MimeData mime_data[];
|
||||
|
||||
protected:
|
||||
protected:
|
||||
char *codec_and_format;
|
||||
const char *filename;
|
||||
const char *format;
|
||||
@@ -65,7 +65,7 @@ protected:
|
||||
int SendPacket(AVPacket *packet);
|
||||
static void* StreamingThreadCallback(void *ctx);
|
||||
|
||||
protected:
|
||||
protected:
|
||||
static void Initialise();
|
||||
|
||||
void SetupFormat( );
|
||||
@@ -74,7 +74,7 @@ protected:
|
||||
void ActuallyOpenStream();
|
||||
double ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, bool add_timestamp=false, unsigned int timestamp=0 );
|
||||
|
||||
public:
|
||||
public:
|
||||
VideoStream( const char *filename, const char *format, int bitrate, double frame_rate, int colours, int subpixelorder, int width, int height );
|
||||
~VideoStream();
|
||||
const char *MimeType() const;
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
MQTT::MQTT(Monitor *monitor) :
|
||||
mosquittopp("ZoneMinder"),
|
||||
monitor_(monitor),
|
||||
connected_(false)
|
||||
{
|
||||
connected_(false) {
|
||||
mosqpp::lib_init();
|
||||
connect();
|
||||
}
|
||||
@@ -52,7 +51,7 @@ void MQTT::on_connect(int rc) {
|
||||
}
|
||||
|
||||
void MQTT::on_message(const struct mosquitto_message *message) {
|
||||
Debug(1, "MQTT: Have message %s: %s", message->topic, message->payload);
|
||||
Debug(1, "MQTT: Have message %s: %s", message->topic, message->payload);
|
||||
}
|
||||
|
||||
void MQTT::on_subscribe(int mid, int qos_count, const int *granted_qos) {
|
||||
@@ -102,8 +101,8 @@ void MQTT::addValue(std::string name, double value) {
|
||||
// }
|
||||
// valuesList.insert ( std::pair<std::string,double>(name, value));
|
||||
std::chrono::milliseconds ms = std::chrono::duration_cast< std::chrono::milliseconds >(
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch()
|
||||
);
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch()
|
||||
);
|
||||
sensorListIterator->second.insert(std::pair<std::chrono::milliseconds, double>(ms, value));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,34 +16,34 @@
|
||||
class Monitor;
|
||||
|
||||
class MQTT : public mosqpp::mosquittopp {
|
||||
public:
|
||||
MQTT(Monitor *);
|
||||
~MQTT();
|
||||
void autoconfigure();
|
||||
void connect();
|
||||
void disconnect();
|
||||
void send(const std::string &message);
|
||||
void addSensor(std::string name, std::string type);
|
||||
void add_subscription(const std::string &name);
|
||||
public:
|
||||
MQTT(Monitor *);
|
||||
~MQTT();
|
||||
void autoconfigure();
|
||||
void connect();
|
||||
void disconnect();
|
||||
void send(const std::string &message);
|
||||
void addSensor(std::string name, std::string type);
|
||||
void add_subscription(const std::string &name);
|
||||
|
||||
void addValue(std::string name, double value);
|
||||
void listValues(const std::string &sensor_name);
|
||||
void on_connect(int rc);
|
||||
void on_message(const struct mosquitto_message *message);
|
||||
void on_subscribe(int mid, int qos_count, const int *granted_qos);
|
||||
void on_publish();
|
||||
enum sensorTypes {
|
||||
NUMERIC = 0,
|
||||
DIGITAL
|
||||
};
|
||||
void addValue(std::string name, double value);
|
||||
void listValues(const std::string &sensor_name);
|
||||
void on_connect(int rc);
|
||||
void on_message(const struct mosquitto_message *message);
|
||||
void on_subscribe(int mid, int qos_count, const int *granted_qos);
|
||||
void on_publish();
|
||||
enum sensorTypes {
|
||||
NUMERIC = 0,
|
||||
DIGITAL
|
||||
};
|
||||
|
||||
private:
|
||||
std::map<std::string, std::map<std::chrono::milliseconds, double>> sensorList;
|
||||
std::map<std::string, std::map<std::chrono::milliseconds, double>>::iterator sensorListIterator;
|
||||
std::map<std::string, int> actuatorList;
|
||||
private:
|
||||
std::map<std::string, std::map<std::chrono::milliseconds, double>> sensorList;
|
||||
std::map<std::string, std::map<std::chrono::milliseconds, double>>::iterator sensorListIterator;
|
||||
std::map<std::string, int> actuatorList;
|
||||
|
||||
Monitor *monitor_;
|
||||
bool connected_;
|
||||
Monitor *monitor_;
|
||||
bool connected_;
|
||||
};
|
||||
#endif // MOSQUITTOPP_FOUND
|
||||
|
||||
|
||||
@@ -36,8 +36,7 @@ ZMPacket::ZMPacket() :
|
||||
image_index(-1),
|
||||
codec_imgsize(0),
|
||||
pts(0),
|
||||
decoded(false)
|
||||
{
|
||||
decoded(false) {
|
||||
packet = av_packet_ptr{av_packet_alloc()};
|
||||
}
|
||||
|
||||
@@ -53,8 +52,7 @@ ZMPacket::ZMPacket(Image *i, SystemTimePoint tv) :
|
||||
image_index(-1),
|
||||
codec_imgsize(0),
|
||||
pts(0),
|
||||
decoded(false)
|
||||
{
|
||||
decoded(false) {
|
||||
packet = av_packet_ptr{av_packet_alloc()};
|
||||
}
|
||||
|
||||
@@ -70,8 +68,7 @@ ZMPacket::ZMPacket(ZMPacket &p) :
|
||||
image_index(-1),
|
||||
codec_imgsize(0),
|
||||
pts(0),
|
||||
decoded(false)
|
||||
{
|
||||
decoded(false) {
|
||||
packet = av_packet_ptr{av_packet_alloc()};
|
||||
|
||||
if (zm_av_packet_ref(packet.get(), p.packet.get()) < 0) {
|
||||
@@ -87,16 +84,16 @@ ZMPacket::~ZMPacket() {
|
||||
|
||||
ssize_t ZMPacket::ram() {
|
||||
return packet->size +
|
||||
(in_frame ? in_frame->linesize[0] * in_frame->height : 0) +
|
||||
(out_frame ? out_frame->linesize[0] * out_frame->height : 0) +
|
||||
(image ? image->Size() : 0) +
|
||||
(analysis_image ? analysis_image->Size() : 0);
|
||||
(in_frame ? in_frame->linesize[0] * in_frame->height : 0) +
|
||||
(out_frame ? out_frame->linesize[0] * out_frame->height : 0) +
|
||||
(image ? image->Size() : 0) +
|
||||
(analysis_image ? analysis_image->Size() : 0);
|
||||
}
|
||||
|
||||
/* returns < 0 on error, 0 on not ready, int bytes consumed on success
|
||||
/* returns < 0 on error, 0 on not ready, int bytes consumed on success
|
||||
* This functions job is to populate in_frame with the image in an appropriate
|
||||
* format. It MAY also populate image if able to. In this case in_frame is populated
|
||||
* by the image buffer.
|
||||
* by the image buffer.
|
||||
*/
|
||||
int ZMPacket::decode(AVCodecContext *ctx) {
|
||||
Debug(4, "about to decode video, image_index is (%d)", image_index);
|
||||
@@ -114,7 +111,7 @@ int ZMPacket::decode(AVCodecContext *ctx) {
|
||||
if (ret < 0) {
|
||||
if (AVERROR(EAGAIN) != ret) {
|
||||
Warning("Unable to receive frame : code %d %s.",
|
||||
ret, av_make_error_string(ret).c_str());
|
||||
ret, av_make_error_string(ret).c_str());
|
||||
}
|
||||
in_frame = nullptr;
|
||||
return 0;
|
||||
@@ -128,28 +125,28 @@ int ZMPacket::decode(AVCodecContext *ctx) {
|
||||
|
||||
if ((ctx->sw_pix_fmt != AV_PIX_FMT_NONE) and (fix_deprecated_pix_fmt(ctx->sw_pix_fmt) != fix_deprecated_pix_fmt(static_cast<AVPixelFormat>(in_frame->format)))) {
|
||||
Debug(3, "Have different format ctx->pix_fmt %d %s ?= ctx->sw_pix_fmt %d %s in_frame->format %d %s.",
|
||||
ctx->pix_fmt,
|
||||
av_get_pix_fmt_name(ctx->pix_fmt),
|
||||
ctx->sw_pix_fmt,
|
||||
av_get_pix_fmt_name(ctx->sw_pix_fmt),
|
||||
in_frame->format,
|
||||
av_get_pix_fmt_name(static_cast<AVPixelFormat>(in_frame->format))
|
||||
);
|
||||
ctx->pix_fmt,
|
||||
av_get_pix_fmt_name(ctx->pix_fmt),
|
||||
ctx->sw_pix_fmt,
|
||||
av_get_pix_fmt_name(ctx->sw_pix_fmt),
|
||||
in_frame->format,
|
||||
av_get_pix_fmt_name(static_cast<AVPixelFormat>(in_frame->format))
|
||||
);
|
||||
#if 0
|
||||
if ( target_format == AV_PIX_FMT_NONE and ctx->hw_frames_ctx and (image->Colours() == 4) ) {
|
||||
// Look for rgb0 in list of supported formats
|
||||
enum AVPixelFormat *formats;
|
||||
if ( 0 <= av_hwframe_transfer_get_formats(
|
||||
ctx->hw_frames_ctx,
|
||||
AV_HWFRAME_TRANSFER_DIRECTION_FROM,
|
||||
&formats,
|
||||
0
|
||||
) ) {
|
||||
ctx->hw_frames_ctx,
|
||||
AV_HWFRAME_TRANSFER_DIRECTION_FROM,
|
||||
&formats,
|
||||
0
|
||||
) ) {
|
||||
for (int i = 0; formats[i] != AV_PIX_FMT_NONE; i++) {
|
||||
Debug(1, "Available dest formats %d %s",
|
||||
formats[i],
|
||||
av_get_pix_fmt_name(formats[i])
|
||||
);
|
||||
Debug(1, "Available dest formats %d %s",
|
||||
formats[i],
|
||||
av_get_pix_fmt_name(formats[i])
|
||||
);
|
||||
if ( formats[i] == AV_PIX_FMT_RGB0 ) {
|
||||
target_format = formats[i];
|
||||
break;
|
||||
@@ -179,14 +176,14 @@ int ZMPacket::decode(AVCodecContext *ctx) {
|
||||
ret = av_hwframe_transfer_data(new_frame.get(), in_frame.get(), 0);
|
||||
if (ret < 0) {
|
||||
Error("Unable to transfer frame: %s, continuing",
|
||||
av_make_error_string(ret).c_str());
|
||||
av_make_error_string(ret).c_str());
|
||||
in_frame = nullptr;
|
||||
return 0;
|
||||
}
|
||||
ret = av_frame_copy_props(new_frame.get(), in_frame.get());
|
||||
if (ret < 0) {
|
||||
Error("Unable to copy props: %s, continuing",
|
||||
av_make_error_string(ret).c_str());
|
||||
av_make_error_string(ret).c_str());
|
||||
}
|
||||
|
||||
zm_dump_video_frame(new_frame.get(), "After hwtransfer");
|
||||
@@ -201,9 +198,9 @@ int ZMPacket::decode(AVCodecContext *ctx) {
|
||||
#endif
|
||||
#endif
|
||||
Debug(3, "Same pix format %s so not hwtransferring. sw_pix_fmt is %s",
|
||||
av_get_pix_fmt_name(ctx->pix_fmt),
|
||||
av_get_pix_fmt_name(ctx->sw_pix_fmt)
|
||||
);
|
||||
av_get_pix_fmt_name(ctx->pix_fmt),
|
||||
av_get_pix_fmt_name(ctx->sw_pix_fmt)
|
||||
);
|
||||
#if 0
|
||||
if ( image ) {
|
||||
image->Assign(in_frame);
|
||||
@@ -222,7 +219,7 @@ Image *ZMPacket::get_image(Image *i) {
|
||||
if (!i) {
|
||||
Error("Need a pre-allocated image buffer");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
image = i;
|
||||
}
|
||||
image->Assign(in_frame.get());
|
||||
@@ -254,9 +251,9 @@ AVFrame *ZMPacket::get_out_frame(int width, int height, AVPixelFormat format) {
|
||||
|
||||
int alignment = 32;
|
||||
if (width%alignment) alignment = 1;
|
||||
|
||||
|
||||
codec_imgsize = av_image_get_buffer_size(
|
||||
format, width, height, alignment);
|
||||
format, width, height, alignment);
|
||||
Debug(1, "buffer size %u from %s %dx%d", codec_imgsize, av_get_pix_fmt_name(format), width, height);
|
||||
out_frame->buf[0] = av_buffer_alloc(codec_imgsize);
|
||||
if (!out_frame->buf[0]) {
|
||||
@@ -266,13 +263,13 @@ AVFrame *ZMPacket::get_out_frame(int width, int height, AVPixelFormat format) {
|
||||
}
|
||||
int ret;
|
||||
if ((ret=av_image_fill_arrays(
|
||||
out_frame->data,
|
||||
out_frame->linesize,
|
||||
out_frame->buf[0]->data,
|
||||
format,
|
||||
width,
|
||||
height,
|
||||
alignment))<0) {
|
||||
out_frame->data,
|
||||
out_frame->linesize,
|
||||
out_frame->buf[0]->data,
|
||||
format,
|
||||
width,
|
||||
height,
|
||||
alignment))<0) {
|
||||
Error("Failed to fill_arrays %s", av_make_error_string(ret).c_str());
|
||||
out_frame = nullptr;
|
||||
return nullptr;
|
||||
|
||||
160
src/zm_packet.h
160
src/zm_packet.h
@@ -36,99 +36,99 @@ extern "C" {
|
||||
class Image;
|
||||
|
||||
class ZMPacket {
|
||||
public:
|
||||
|
||||
std::mutex mutex_;
|
||||
// The condition has to be in the packet because it is shared between locks
|
||||
std::condition_variable condition_;
|
||||
public:
|
||||
|
||||
int keyframe;
|
||||
AVStream *stream; // Input stream
|
||||
av_packet_ptr packet; // Input packet, undecoded
|
||||
av_frame_ptr in_frame; // Input image, decoded Theoretically only filled if needed.
|
||||
av_frame_ptr out_frame; // output image, Only filled if needed.
|
||||
SystemTimePoint timestamp;
|
||||
Image *image;
|
||||
Image *y_image;
|
||||
Image *analysis_image;
|
||||
int score;
|
||||
AVMediaType codec_type;
|
||||
int image_index;
|
||||
int codec_imgsize;
|
||||
int64_t pts; // pts in the packet can be in another time base. This MUST be in AV_TIME_BASE_Q
|
||||
bool decoded;
|
||||
std::vector<ZoneStats> zone_stats;
|
||||
std::string alarm_cause;
|
||||
std::mutex mutex_;
|
||||
// The condition has to be in the packet because it is shared between locks
|
||||
std::condition_variable condition_;
|
||||
|
||||
public:
|
||||
AVPacket *av_packet() { return packet.get(); }
|
||||
AVPacket *set_packet(AVPacket *p) ;
|
||||
AVFrame *av_frame() { return out_frame.get(); }
|
||||
Image *get_image(Image *i=nullptr);
|
||||
Image *set_image(Image *);
|
||||
ssize_t ram();
|
||||
int keyframe;
|
||||
AVStream *stream; // Input stream
|
||||
av_packet_ptr packet; // Input packet, undecoded
|
||||
av_frame_ptr in_frame; // Input image, decoded Theoretically only filled if needed.
|
||||
av_frame_ptr out_frame; // output image, Only filled if needed.
|
||||
SystemTimePoint timestamp;
|
||||
Image *image;
|
||||
Image *y_image;
|
||||
Image *analysis_image;
|
||||
int score;
|
||||
AVMediaType codec_type;
|
||||
int image_index;
|
||||
int codec_imgsize;
|
||||
int64_t pts; // pts in the packet can be in another time base. This MUST be in AV_TIME_BASE_Q
|
||||
bool decoded;
|
||||
std::vector<ZoneStats> zone_stats;
|
||||
std::string alarm_cause;
|
||||
|
||||
int is_keyframe() { return keyframe; };
|
||||
int decode(AVCodecContext *ctx);
|
||||
explicit ZMPacket(Image *image, SystemTimePoint tv);
|
||||
explicit ZMPacket(ZMPacket &packet);
|
||||
ZMPacket();
|
||||
~ZMPacket();
|
||||
public:
|
||||
AVPacket *av_packet() { return packet.get(); }
|
||||
AVPacket *set_packet(AVPacket *p) ;
|
||||
AVFrame *av_frame() { return out_frame.get(); }
|
||||
Image *get_image(Image *i=nullptr);
|
||||
Image *set_image(Image *);
|
||||
ssize_t ram();
|
||||
|
||||
//AVFrame *get_out_frame(const AVCodecContext *ctx);
|
||||
AVFrame *get_out_frame(int width, int height, AVPixelFormat format);
|
||||
int get_codec_imgsize() { return codec_imgsize; };
|
||||
void notify_all() {
|
||||
this->condition_.notify_all();
|
||||
}
|
||||
int is_keyframe() { return keyframe; };
|
||||
int decode(AVCodecContext *ctx);
|
||||
explicit ZMPacket(Image *image, SystemTimePoint tv);
|
||||
explicit ZMPacket(ZMPacket &packet);
|
||||
ZMPacket();
|
||||
~ZMPacket();
|
||||
|
||||
//AVFrame *get_out_frame(const AVCodecContext *ctx);
|
||||
AVFrame *get_out_frame(int width, int height, AVPixelFormat format);
|
||||
int get_codec_imgsize() { return codec_imgsize; };
|
||||
void notify_all() {
|
||||
this->condition_.notify_all();
|
||||
}
|
||||
};
|
||||
|
||||
class ZMLockedPacket {
|
||||
public:
|
||||
std::shared_ptr<ZMPacket> packet_;
|
||||
std::unique_lock<std::mutex> lck_;
|
||||
bool locked;
|
||||
public:
|
||||
std::shared_ptr<ZMPacket> packet_;
|
||||
std::unique_lock<std::mutex> lck_;
|
||||
bool locked;
|
||||
|
||||
explicit ZMLockedPacket(std::shared_ptr<ZMPacket> p) :
|
||||
packet_(p),
|
||||
lck_(packet_->mutex_, std::defer_lock),
|
||||
locked(false) {
|
||||
}
|
||||
explicit ZMLockedPacket(std::shared_ptr<ZMPacket> p) :
|
||||
packet_(p),
|
||||
lck_(packet_->mutex_, std::defer_lock),
|
||||
locked(false) {
|
||||
}
|
||||
|
||||
~ZMLockedPacket() {
|
||||
if (locked) unlock();
|
||||
}
|
||||
~ZMLockedPacket() {
|
||||
if (locked) unlock();
|
||||
}
|
||||
|
||||
void lock() {
|
||||
Debug(4, "locking packet %d %p %d owns %d", packet_->image_index, packet_.get(), locked, lck_.owns_lock());
|
||||
lck_.lock();
|
||||
locked = true;
|
||||
Debug(4, "packet %d locked", packet_->image_index);
|
||||
};
|
||||
void lock() {
|
||||
Debug(4, "locking packet %d %p %d owns %d", packet_->image_index, packet_.get(), locked, lck_.owns_lock());
|
||||
lck_.lock();
|
||||
locked = true;
|
||||
Debug(4, "packet %d locked", packet_->image_index);
|
||||
};
|
||||
|
||||
bool trylock() {
|
||||
Debug(4, "TryLocking packet %d %p locked: %d owns: %d", packet_->image_index, packet_.get(), locked, lck_.owns_lock());
|
||||
locked = lck_.try_lock();
|
||||
Debug(4, "TryLocking packet %d %p %d, owns: %d", packet_->image_index, packet_.get(), locked, lck_.owns_lock());
|
||||
return locked;
|
||||
};
|
||||
bool trylock() {
|
||||
Debug(4, "TryLocking packet %d %p locked: %d owns: %d", packet_->image_index, packet_.get(), locked, lck_.owns_lock());
|
||||
locked = lck_.try_lock();
|
||||
Debug(4, "TryLocking packet %d %p %d, owns: %d", packet_->image_index, packet_.get(), locked, lck_.owns_lock());
|
||||
return locked;
|
||||
};
|
||||
|
||||
void unlock() {
|
||||
Debug(4, "packet %d unlocked, %p, locked %d, owns %d", packet_->image_index, packet_.get(), locked, lck_.owns_lock());
|
||||
locked = false;
|
||||
lck_.unlock();
|
||||
Debug(4, "packet %d unlocked, %p, locked %d, owns %d", packet_->image_index, packet_.get(), locked, lck_.owns_lock());
|
||||
packet_->condition_.notify_all();
|
||||
};
|
||||
void unlock() {
|
||||
Debug(4, "packet %d unlocked, %p, locked %d, owns %d", packet_->image_index, packet_.get(), locked, lck_.owns_lock());
|
||||
locked = false;
|
||||
lck_.unlock();
|
||||
Debug(4, "packet %d unlocked, %p, locked %d, owns %d", packet_->image_index, packet_.get(), locked, lck_.owns_lock());
|
||||
packet_->condition_.notify_all();
|
||||
};
|
||||
|
||||
void wait() {
|
||||
Debug(4, "packet %d waiting", packet_->image_index);
|
||||
packet_->condition_.wait(lck_);
|
||||
}
|
||||
void notify_all() {
|
||||
packet_->notify_all();
|
||||
}
|
||||
|
||||
void wait() {
|
||||
Debug(4, "packet %d waiting", packet_->image_index);
|
||||
packet_->condition_.wait(lck_);
|
||||
}
|
||||
void notify_all() {
|
||||
packet_->notify_all();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif /* ZM_PACKET_H */
|
||||
|
||||
@@ -35,8 +35,7 @@ PacketQueue::PacketQueue():
|
||||
keep_keyframes(false),
|
||||
warned_count(0),
|
||||
has_out_of_order_packets_(false),
|
||||
max_keyframe_interval_(0)
|
||||
{
|
||||
max_keyframe_interval_(0) {
|
||||
}
|
||||
|
||||
/* Assumes queue is empty when adding streams
|
||||
@@ -108,7 +107,7 @@ bool PacketQueue::queuePacket(std::shared_ptr<ZMPacket> add_packet) {
|
||||
rit++;
|
||||
} // end while
|
||||
}
|
||||
|
||||
|
||||
if (!max_keyframe_interval_ and add_packet->keyframe and (video_stream_id==add_packet->packet->stream_index)) {
|
||||
auto rit = pktQueue.rbegin();
|
||||
int packet_count = 0;
|
||||
@@ -128,10 +127,10 @@ bool PacketQueue::queuePacket(std::shared_ptr<ZMPacket> add_packet) {
|
||||
|
||||
/* Any iterators that are pointing to the end will now point to the newly pushed packet */
|
||||
for (
|
||||
auto iterators_it = iterators.begin();
|
||||
iterators_it != iterators.end();
|
||||
++iterators_it
|
||||
) {
|
||||
auto iterators_it = iterators.begin();
|
||||
iterators_it != iterators.end();
|
||||
++iterators_it
|
||||
) {
|
||||
packetqueue_iterator *iterator_it = *iterators_it;
|
||||
if (*iterator_it == pktQueue.end()) {
|
||||
--(*iterator_it);
|
||||
@@ -140,30 +139,30 @@ bool PacketQueue::queuePacket(std::shared_ptr<ZMPacket> add_packet) {
|
||||
|
||||
packet_counts[add_packet->packet->stream_index] += 1;
|
||||
Debug(2, "packet counts for %d is %d",
|
||||
add_packet->packet->stream_index,
|
||||
packet_counts[add_packet->packet->stream_index]);
|
||||
add_packet->packet->stream_index,
|
||||
packet_counts[add_packet->packet->stream_index]);
|
||||
|
||||
if (
|
||||
(add_packet->packet->stream_index == video_stream_id)
|
||||
and
|
||||
(max_video_packet_count > 0)
|
||||
and
|
||||
(packet_counts[video_stream_id] > max_video_packet_count)
|
||||
) {
|
||||
(add_packet->packet->stream_index == video_stream_id)
|
||||
and
|
||||
(max_video_packet_count > 0)
|
||||
and
|
||||
(packet_counts[video_stream_id] > max_video_packet_count)
|
||||
) {
|
||||
if (!warned_count) {
|
||||
warned_count++;
|
||||
Warning("You have set the max video packets in the queue to %u."
|
||||
" The queue is full. Either Analysis is not keeping up or"
|
||||
" your camera's keyframe interval %d is larger than this setting."
|
||||
, max_video_packet_count, max_keyframe_interval_);
|
||||
" The queue is full. Either Analysis is not keeping up or"
|
||||
" your camera's keyframe interval %d is larger than this setting."
|
||||
, max_video_packet_count, max_keyframe_interval_);
|
||||
}
|
||||
|
||||
for (
|
||||
// Start at second packet because the first is always a keyframe
|
||||
auto it = ++pktQueue.begin();
|
||||
//it != pktQueue.end() and // can't hit end because we added our packet
|
||||
(*it != add_packet) && !(deleting or zm_terminate);
|
||||
// iterator is incremented by erase
|
||||
// Start at second packet because the first is always a keyframe
|
||||
auto it = ++pktQueue.begin();
|
||||
//it != pktQueue.end() and // can't hit end because we added our packet
|
||||
(*it != add_packet) && !(deleting or zm_terminate);
|
||||
// iterator is incremented by erase
|
||||
) {
|
||||
std::shared_ptr <ZMPacket>zm_packet = *it;
|
||||
|
||||
@@ -179,10 +178,10 @@ bool PacketQueue::queuePacket(std::shared_ptr<ZMPacket> add_packet) {
|
||||
}
|
||||
|
||||
for (
|
||||
auto iterators_it = iterators.begin();
|
||||
iterators_it != iterators.end();
|
||||
++iterators_it
|
||||
) {
|
||||
auto iterators_it = iterators.begin();
|
||||
iterators_it != iterators.end();
|
||||
++iterators_it
|
||||
) {
|
||||
auto iterator_it = *iterators_it;
|
||||
// Have to check each iterator and make sure it doesn't point to the packet we are about to delete
|
||||
if (*(*iterator_it) == zm_packet) {
|
||||
@@ -197,13 +196,13 @@ bool PacketQueue::queuePacket(std::shared_ptr<ZMPacket> add_packet) {
|
||||
it = pktQueue.erase(it);
|
||||
packet_counts[zm_packet->packet->stream_index] -= 1;
|
||||
Debug(1,
|
||||
"Deleting a packet with stream index:%d image_index:%d with keyframe:%d, video frames in queue:%d max: %d, queuesize:%zu",
|
||||
zm_packet->packet->stream_index,
|
||||
zm_packet->image_index,
|
||||
zm_packet->keyframe,
|
||||
packet_counts[video_stream_id],
|
||||
max_video_packet_count,
|
||||
pktQueue.size());
|
||||
"Deleting a packet with stream index:%d image_index:%d with keyframe:%d, video frames in queue:%d max: %d, queuesize:%zu",
|
||||
zm_packet->packet->stream_index,
|
||||
zm_packet->image_index,
|
||||
zm_packet->keyframe,
|
||||
packet_counts[video_stream_id],
|
||||
max_video_packet_count,
|
||||
pktQueue.size());
|
||||
|
||||
if (zm_packet->packet->stream_index == video_stream_id)
|
||||
break;
|
||||
@@ -216,18 +215,18 @@ bool PacketQueue::queuePacket(std::shared_ptr<ZMPacket> add_packet) {
|
||||
Debug(4, "packetqueue queuepacket, unlocked signalling");
|
||||
condition.notify_all();
|
||||
|
||||
return true;
|
||||
return true;
|
||||
} // end bool PacketQueue::queuePacket(ZMPacket* zm_packet)
|
||||
|
||||
void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
|
||||
// Only do queueCleaning if we are adding a video keyframe, so that we guarantee that there is one.
|
||||
// No good. Have to satisfy two conditions:
|
||||
// No good. Have to satisfy two conditions:
|
||||
// 1. packetqueue starts with a video keyframe
|
||||
// 2. Have minimum # of video packets
|
||||
// 3. No packets can be locked
|
||||
// 4. No iterator can point to one of the packets
|
||||
//
|
||||
// So start at the beginning, counting video packets until the next keyframe.
|
||||
// So start at the beginning, counting video packets until the next keyframe.
|
||||
// Then if deleting those packets doesn't break 1 and 2, then go ahead and delete them.
|
||||
//
|
||||
// One assumption that we can make is that there will be packets in the queue. Because we call it while holding a locked packet
|
||||
@@ -239,14 +238,14 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
|
||||
add_packet->keyframe
|
||||
and
|
||||
(packet_counts[video_stream_id] > pre_event_video_packet_count)
|
||||
and
|
||||
and
|
||||
*(pktQueue.begin()) != add_packet
|
||||
)
|
||||
)
|
||||
) {
|
||||
Debug(3, "stream index %d ?= video_stream_id %d, keyframe %d, keep_keyframes %d, counts %d > pre_event_count %d at begin %d",
|
||||
add_packet->packet->stream_index, video_stream_id, add_packet->keyframe, keep_keyframes, packet_counts[video_stream_id], pre_event_video_packet_count,
|
||||
( *(pktQueue.begin()) != add_packet )
|
||||
);
|
||||
add_packet->packet->stream_index, video_stream_id, add_packet->keyframe, keep_keyframes, packet_counts[video_stream_id], pre_event_video_packet_count,
|
||||
( *(pktQueue.begin()) != add_packet )
|
||||
);
|
||||
return;
|
||||
}
|
||||
std::unique_lock<std::mutex> lck(mutex);
|
||||
@@ -268,7 +267,7 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
|
||||
if ((*it)->packet->stream_index == video_stream_id)
|
||||
++tail_count;
|
||||
}
|
||||
|
||||
|
||||
--it;
|
||||
}
|
||||
}
|
||||
@@ -319,7 +318,7 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
|
||||
delete lp;
|
||||
return;
|
||||
} // end if first packet not locked
|
||||
|
||||
|
||||
int video_packets_to_delete = 0; // This is a count of how many packets we will delete so we know when to stop looking
|
||||
++it;
|
||||
delete lp;
|
||||
@@ -357,7 +356,7 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
|
||||
++video_packets_to_delete;
|
||||
if (packet_counts[video_stream_id] - video_packets_to_delete <= pre_event_video_packet_count + tail_count) {
|
||||
Debug(3, "Counted %d video packets. Which would leave %d in packetqueue tail count is %d",
|
||||
video_packets_to_delete, packet_counts[video_stream_id]-video_packets_to_delete, tail_count);
|
||||
video_packets_to_delete, packet_counts[video_stream_id]-video_packets_to_delete, tail_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -365,10 +364,10 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
|
||||
} // end while
|
||||
|
||||
Debug(1, "Resulting it pointing at latest packet? %d, next front points to begin? %d, Keyframe interval %d",
|
||||
( *it == add_packet ),
|
||||
( next_front == pktQueue.begin() ),
|
||||
keyframe_interval_count
|
||||
);
|
||||
( *it == add_packet ),
|
||||
( next_front == pktQueue.begin() ),
|
||||
keyframe_interval_count
|
||||
);
|
||||
if (next_front != pktQueue.begin()) {
|
||||
while (pktQueue.begin() != next_front) {
|
||||
zm_packet = *pktQueue.begin();
|
||||
@@ -390,7 +389,7 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
|
||||
}
|
||||
} // end if have at least max_video_packet_count video packets remaining
|
||||
|
||||
return;
|
||||
return;
|
||||
} // end voidPacketQueue::clearPackets(ZMPacket* zm_packet)
|
||||
|
||||
void PacketQueue::stop() {
|
||||
@@ -416,13 +415,13 @@ void PacketQueue::clear() {
|
||||
ZMLockedPacket *lp = new ZMLockedPacket(packet);
|
||||
lp->lock();
|
||||
Debug(1,
|
||||
"Deleting a packet with stream index:%d image_index:%d with keyframe:%d, video frames in queue:%d max: %d, queuesize:%zu",
|
||||
packet->packet->stream_index,
|
||||
packet->image_index,
|
||||
packet->keyframe,
|
||||
packet_counts[video_stream_id],
|
||||
pre_event_video_packet_count,
|
||||
pktQueue.size());
|
||||
"Deleting a packet with stream index:%d image_index:%d with keyframe:%d, video frames in queue:%d max: %d, queuesize:%zu",
|
||||
packet->packet->stream_index,
|
||||
packet->image_index,
|
||||
packet->keyframe,
|
||||
packet_counts[video_stream_id],
|
||||
pre_event_video_packet_count,
|
||||
pktQueue.size());
|
||||
packet_counts[packet->packet->stream_index] -= 1;
|
||||
pktQueue.pop_front();
|
||||
delete lp;
|
||||
@@ -430,10 +429,10 @@ void PacketQueue::clear() {
|
||||
Debug(1, "Packetqueue is clear, deleting iterators");
|
||||
|
||||
for (
|
||||
std::list<packetqueue_iterator *>::iterator iterators_it = iterators.begin();
|
||||
iterators_it != iterators.end();
|
||||
++iterators_it
|
||||
) {
|
||||
std::list<packetqueue_iterator *>::iterator iterators_it = iterators.begin();
|
||||
iterators_it != iterators.end();
|
||||
++iterators_it
|
||||
) {
|
||||
packetqueue_iterator *iterator_it = *iterators_it;
|
||||
*iterator_it = pktQueue.begin();
|
||||
} // end foreach iterator
|
||||
@@ -467,7 +466,8 @@ ZMLockedPacket *PacketQueue::get_packet(packetqueue_iterator *it) {
|
||||
std::addressof(*it), (*it == pktQueue.end()));
|
||||
|
||||
ZMLockedPacket *lp = nullptr;
|
||||
{ // scope for lock
|
||||
{
|
||||
// scope for lock
|
||||
std::unique_lock<std::mutex> lck(mutex);
|
||||
Debug(4, "Have Lock in get_packet");
|
||||
while (!lp) {
|
||||
@@ -483,7 +483,7 @@ ZMLockedPacket *PacketQueue::get_packet(packetqueue_iterator *it) {
|
||||
return nullptr;
|
||||
}
|
||||
Debug(3, "get_packet using it %p locking index %d",
|
||||
std::addressof(*it), p->image_index);
|
||||
std::addressof(*it), p->image_index);
|
||||
|
||||
lp = new ZMLockedPacket(p);
|
||||
if (lp->trylock()) {
|
||||
@@ -513,7 +513,8 @@ ZMLockedPacket *PacketQueue::get_packet_and_increment_it(packetqueue_iterator *i
|
||||
std::addressof(*it), (*it == pktQueue.end()));
|
||||
|
||||
ZMLockedPacket *lp = nullptr;
|
||||
{ // scope for lock
|
||||
{
|
||||
// scope for lock
|
||||
std::unique_lock<std::mutex> lck(mutex);
|
||||
Debug(4, "Have Lock in get_packet");
|
||||
while (!lp) {
|
||||
@@ -529,7 +530,7 @@ ZMLockedPacket *PacketQueue::get_packet_and_increment_it(packetqueue_iterator *i
|
||||
return nullptr;
|
||||
}
|
||||
Debug(3, "get_packet using it %p locking index %d",
|
||||
std::addressof(*it), p->image_index);
|
||||
std::addressof(*it), p->image_index);
|
||||
|
||||
lp = new ZMLockedPacket(p);
|
||||
if (lp->trylock()) {
|
||||
@@ -591,9 +592,9 @@ bool PacketQueue::increment_it(packetqueue_iterator *it, int stream_id) {
|
||||
} // end bool PacketQueue::increment_it(packetqueue_iterator *it)
|
||||
|
||||
packetqueue_iterator *PacketQueue::get_event_start_packet_it(
|
||||
packetqueue_iterator snapshot_it,
|
||||
unsigned int pre_event_count
|
||||
) {
|
||||
packetqueue_iterator snapshot_it,
|
||||
unsigned int pre_event_count
|
||||
) {
|
||||
std::unique_lock<std::mutex> lck(mutex);
|
||||
|
||||
packetqueue_iterator *it = new packetqueue_iterator;
|
||||
@@ -685,7 +686,7 @@ packetqueue_iterator * PacketQueue::get_video_it(bool wait) {
|
||||
return nullptr;
|
||||
}
|
||||
Debug(1, "Packet keyframe %d for stream %d, so returning the it to it",
|
||||
zm_packet->keyframe, zm_packet->packet->stream_index);
|
||||
zm_packet->keyframe, zm_packet->packet->stream_index);
|
||||
if (zm_packet->keyframe and ( zm_packet->packet->stream_index == video_stream_id )) {
|
||||
Debug(1, "Found a keyframe for stream %d, so returning the it to it", video_stream_id);
|
||||
return it;
|
||||
@@ -698,10 +699,10 @@ packetqueue_iterator * PacketQueue::get_video_it(bool wait) {
|
||||
|
||||
void PacketQueue::free_it(packetqueue_iterator *it) {
|
||||
for (
|
||||
std::list<packetqueue_iterator *>::iterator iterators_it = iterators.begin();
|
||||
iterators_it != iterators.end();
|
||||
++iterators_it
|
||||
) {
|
||||
std::list<packetqueue_iterator *>::iterator iterators_it = iterators.begin();
|
||||
iterators_it != iterators.end();
|
||||
++iterators_it
|
||||
) {
|
||||
if ( *iterators_it == it ) {
|
||||
iterators.erase(iterators_it);
|
||||
break;
|
||||
@@ -711,10 +712,10 @@ void PacketQueue::free_it(packetqueue_iterator *it) {
|
||||
|
||||
bool PacketQueue::is_there_an_iterator_pointing_to_packet(const std::shared_ptr<ZMPacket> &zm_packet) {
|
||||
for (
|
||||
std::list<packetqueue_iterator *>::iterator iterators_it = iterators.begin();
|
||||
iterators_it != iterators.end();
|
||||
++iterators_it
|
||||
) {
|
||||
std::list<packetqueue_iterator *>::iterator iterators_it = iterators.begin();
|
||||
iterators_it != iterators.end();
|
||||
++iterators_it
|
||||
) {
|
||||
packetqueue_iterator *iterator_it = *iterators_it;
|
||||
if (*iterator_it == pktQueue.end()) {
|
||||
continue;
|
||||
|
||||
@@ -30,66 +30,66 @@ class ZMLockedPacket;
|
||||
typedef std::list<std::shared_ptr<ZMPacket>>::iterator packetqueue_iterator;
|
||||
|
||||
class PacketQueue {
|
||||
private: // For now just to ease development
|
||||
std::list<std::shared_ptr<ZMPacket>> pktQueue;
|
||||
std::list<std::shared_ptr<ZMPacket>>::iterator analysis_it;
|
||||
private: // For now just to ease development
|
||||
std::list<std::shared_ptr<ZMPacket>> pktQueue;
|
||||
std::list<std::shared_ptr<ZMPacket>>::iterator analysis_it;
|
||||
|
||||
int video_stream_id;
|
||||
int max_video_packet_count; // allow a negative value to someday mean unlimited
|
||||
// This is now a hard limit on the # of video packets to keep in the queue so that we can limit ram
|
||||
int pre_event_video_packet_count; // Was max_video_packet_count
|
||||
int max_stream_id;
|
||||
int *packet_counts; /* packet count for each stream_id, to keep track of how many video vs audio packets are in the queue */
|
||||
bool deleting;
|
||||
bool keep_keyframes;
|
||||
std::list<packetqueue_iterator *> iterators;
|
||||
int video_stream_id;
|
||||
int max_video_packet_count; // allow a negative value to someday mean unlimited
|
||||
// This is now a hard limit on the # of video packets to keep in the queue so that we can limit ram
|
||||
int pre_event_video_packet_count; // Was max_video_packet_count
|
||||
int max_stream_id;
|
||||
int *packet_counts; /* packet count for each stream_id, to keep track of how many video vs audio packets are in the queue */
|
||||
bool deleting;
|
||||
bool keep_keyframes;
|
||||
std::list<packetqueue_iterator *> iterators;
|
||||
|
||||
std::mutex mutex;
|
||||
std::condition_variable condition;
|
||||
int warned_count;
|
||||
bool has_out_of_order_packets_;
|
||||
int max_keyframe_interval_;
|
||||
std::mutex mutex;
|
||||
std::condition_variable condition;
|
||||
int warned_count;
|
||||
bool has_out_of_order_packets_;
|
||||
int max_keyframe_interval_;
|
||||
|
||||
public:
|
||||
PacketQueue();
|
||||
virtual ~PacketQueue();
|
||||
std::list<std::shared_ptr<ZMPacket>>::const_iterator end() const { return pktQueue.end(); }
|
||||
std::list<std::shared_ptr<ZMPacket>>::const_iterator begin() const { return pktQueue.begin(); }
|
||||
public:
|
||||
PacketQueue();
|
||||
virtual ~PacketQueue();
|
||||
std::list<std::shared_ptr<ZMPacket>>::const_iterator end() const { return pktQueue.end(); }
|
||||
std::list<std::shared_ptr<ZMPacket>>::const_iterator begin() const { return pktQueue.begin(); }
|
||||
|
||||
int addStream();
|
||||
void setMaxVideoPackets(int p);
|
||||
void setPreEventVideoPackets(int p);
|
||||
void setKeepKeyframes(bool k) { keep_keyframes = k; };
|
||||
int addStream();
|
||||
void setMaxVideoPackets(int p);
|
||||
void setPreEventVideoPackets(int p);
|
||||
void setKeepKeyframes(bool k) { keep_keyframes = k; };
|
||||
|
||||
bool queuePacket(std::shared_ptr<ZMPacket> packet);
|
||||
void stop();
|
||||
bool stopping() const { return deleting; };
|
||||
void clear();
|
||||
void dumpQueue();
|
||||
unsigned int size();
|
||||
unsigned int get_packet_count(int stream_id) const { return packet_counts[stream_id]; };
|
||||
bool has_out_of_order_packets() const { return has_out_of_order_packets_; };
|
||||
int get_max_keyframe_interval() const { return max_keyframe_interval_; };
|
||||
bool queuePacket(std::shared_ptr<ZMPacket> packet);
|
||||
void stop();
|
||||
bool stopping() const { return deleting; };
|
||||
void clear();
|
||||
void dumpQueue();
|
||||
unsigned int size();
|
||||
unsigned int get_packet_count(int stream_id) const { return packet_counts[stream_id]; };
|
||||
bool has_out_of_order_packets() const { return has_out_of_order_packets_; };
|
||||
int get_max_keyframe_interval() const { return max_keyframe_interval_; };
|
||||
|
||||
void clearPackets(const std::shared_ptr<ZMPacket> &packet);
|
||||
int packet_count(int stream_id);
|
||||
void clearPackets(const std::shared_ptr<ZMPacket> &packet);
|
||||
int packet_count(int stream_id);
|
||||
|
||||
bool increment_it(packetqueue_iterator *it);
|
||||
bool increment_it(packetqueue_iterator *it, int stream_id);
|
||||
ZMLockedPacket *get_packet(packetqueue_iterator *);
|
||||
ZMLockedPacket *get_packet_and_increment_it(packetqueue_iterator *);
|
||||
packetqueue_iterator *get_video_it(bool wait);
|
||||
packetqueue_iterator *get_stream_it(int stream_id);
|
||||
void free_it(packetqueue_iterator *);
|
||||
bool increment_it(packetqueue_iterator *it);
|
||||
bool increment_it(packetqueue_iterator *it, int stream_id);
|
||||
ZMLockedPacket *get_packet(packetqueue_iterator *);
|
||||
ZMLockedPacket *get_packet_and_increment_it(packetqueue_iterator *);
|
||||
packetqueue_iterator *get_video_it(bool wait);
|
||||
packetqueue_iterator *get_stream_it(int stream_id);
|
||||
void free_it(packetqueue_iterator *);
|
||||
|
||||
packetqueue_iterator *get_event_start_packet_it(
|
||||
packetqueue_iterator snapshot_it,
|
||||
unsigned int pre_event_count
|
||||
);
|
||||
bool is_there_an_iterator_pointing_to_packet(const std::shared_ptr<ZMPacket> &zm_packet);
|
||||
void unlock(ZMLockedPacket *lp);
|
||||
void notify_all();
|
||||
void wait();
|
||||
packetqueue_iterator *get_event_start_packet_it(
|
||||
packetqueue_iterator snapshot_it,
|
||||
unsigned int pre_event_count
|
||||
);
|
||||
bool is_there_an_iterator_pointing_to_packet(const std::shared_ptr<ZMPacket> &zm_packet);
|
||||
void unlock(ZMLockedPacket *lp);
|
||||
void notify_all();
|
||||
void wait();
|
||||
};
|
||||
|
||||
#endif /* ZM_PACKETQUEUE_H */
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "zm_time.h"
|
||||
|
||||
PollThread::PollThread(Monitor *monitor) :
|
||||
monitor_(monitor), terminate_(false) {
|
||||
monitor_(monitor), terminate_(false) {
|
||||
thread_ = std::thread(&PollThread::Run, this);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Polygon 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_poly.h"
|
||||
|
||||
@@ -64,9 +64,9 @@ void Polygon::UpdateCentre() {
|
||||
double float_y = 0.0;
|
||||
for (size_t i = 0, j = vertices_.size() - 1; i < vertices_.size(); j = i++) {
|
||||
float_x += ((vertices_[i].y_ - vertices_[j].y_)
|
||||
* ((vertices_[i].x_ * 2) + (vertices_[i].x_ * vertices_[j].x_) + (vertices_[j].x_ * 2)));
|
||||
* ((vertices_[i].x_ * 2) + (vertices_[i].x_ * vertices_[j].x_) + (vertices_[j].x_ * 2)));
|
||||
float_y += ((vertices_[j].x_ - vertices_[i].x_)
|
||||
* ((vertices_[i].y_ * 2) + (vertices_[i].y_ * vertices_[j].y_) + (vertices_[j].y_ * 2)));
|
||||
* ((vertices_[i].y_ * 2) + (vertices_[i].y_ * vertices_[j].y_) + (vertices_[j].y_ * 2)));
|
||||
}
|
||||
float_x /= (6 * area);
|
||||
float_y /= (6 * area);
|
||||
@@ -78,7 +78,7 @@ bool Polygon::Contains(const Vector2 &coord) const {
|
||||
bool inside = false;
|
||||
for (size_t i = 0, j = vertices_.size() - 1; i < vertices_.size(); j = i++) {
|
||||
if ((((vertices_[i].y_ <= coord.y_) && (coord.y_ < vertices_[j].y_)) || ((vertices_[j].y_ <= coord.y_) && (coord.y_ < vertices_[i].y_)))
|
||||
&& (coord.x_ < (vertices_[j].x_ - vertices_[i].x_) * (coord.y_ - vertices_[i].y_) / (vertices_[j].y_ - vertices_[i].y_) + vertices_[i].x_)) {
|
||||
&& (coord.x_ < (vertices_[j].x_ - vertices_[i].x_) * (coord.y_ - vertices_[i].y_) / (vertices_[j].y_ - vertices_[i].y_) + vertices_[i].x_)) {
|
||||
inside = !inside;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Polygon Class Interfaces, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_POLY_H
|
||||
#define ZM_POLY_H
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/*
|
||||
* ZoneMinder regular expression 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.
|
||||
@@ -24,23 +24,19 @@
|
||||
|
||||
#if HAVE_LIBPCRE
|
||||
|
||||
RegExpr::RegExpr( const char *pattern, int flags, int p_max_matches ) : max_matches( p_max_matches ), match_buffers( nullptr ), match_lengths( nullptr ), match_valid( nullptr )
|
||||
{
|
||||
RegExpr::RegExpr( const char *pattern, int flags, int p_max_matches ) : max_matches( p_max_matches ), match_buffers( nullptr ), match_lengths( nullptr ), match_valid( nullptr ) {
|
||||
const char *errstr;
|
||||
int erroffset = 0;
|
||||
if ( !(regex = pcre_compile( pattern, flags, &errstr, &erroffset, 0 )) )
|
||||
{
|
||||
if ( !(regex = pcre_compile( pattern, flags, &errstr, &erroffset, 0 )) ) {
|
||||
Panic( "pcre_compile(%s): %s at %d", pattern, errstr, erroffset );
|
||||
}
|
||||
|
||||
regextra = pcre_study( regex, 0, &errstr );
|
||||
if ( errstr )
|
||||
{
|
||||
if ( errstr ) {
|
||||
Panic( "pcre_study(%s): %s", pattern, errstr );
|
||||
}
|
||||
|
||||
if ( (ok = (bool)regex) )
|
||||
{
|
||||
if ( (ok = (bool)regex) ) {
|
||||
match_vectors = new int[3*max_matches];
|
||||
memset( match_vectors, 0, sizeof(*match_vectors)*3*max_matches );
|
||||
match_buffers = new char *[max_matches];
|
||||
@@ -56,12 +52,9 @@ RegExpr::RegExpr( const char *pattern, int flags, int p_max_matches ) : max_matc
|
||||
n_matches = 0;
|
||||
}
|
||||
|
||||
RegExpr::~RegExpr()
|
||||
{
|
||||
for ( int i = 0; i < max_matches; i++ )
|
||||
{
|
||||
if ( match_buffers[i] )
|
||||
{
|
||||
RegExpr::~RegExpr() {
|
||||
for ( int i = 0; i < max_matches; i++ ) {
|
||||
if ( match_buffers[i] ) {
|
||||
delete[] match_buffers[i];
|
||||
}
|
||||
}
|
||||
@@ -71,39 +64,31 @@ RegExpr::~RegExpr()
|
||||
delete[] match_vectors;
|
||||
}
|
||||
|
||||
int RegExpr::Match( const char *subject_string, int subject_length, int flags )
|
||||
{
|
||||
int RegExpr::Match( const char *subject_string, int subject_length, int flags ) {
|
||||
match_string = subject_string;
|
||||
|
||||
n_matches = pcre_exec( regex, regextra, subject_string, subject_length, 0, flags, match_vectors, 2*max_matches );
|
||||
|
||||
if ( n_matches <= 0 )
|
||||
{
|
||||
if ( n_matches < PCRE_ERROR_NOMATCH )
|
||||
{
|
||||
if ( n_matches <= 0 ) {
|
||||
if ( n_matches < PCRE_ERROR_NOMATCH ) {
|
||||
Error( "Error %d executing regular expression", n_matches );
|
||||
}
|
||||
return( n_matches = 0 );
|
||||
}
|
||||
|
||||
for( int i = 0; i < max_matches; i++ )
|
||||
{
|
||||
for( int i = 0; i < max_matches; i++ ) {
|
||||
match_valid[i] = false;
|
||||
}
|
||||
return( n_matches );
|
||||
}
|
||||
|
||||
const char *RegExpr::MatchString( int match_index ) const
|
||||
{
|
||||
if ( match_index > n_matches )
|
||||
{
|
||||
const char *RegExpr::MatchString( int match_index ) const {
|
||||
if ( match_index > n_matches ) {
|
||||
return( 0 );
|
||||
}
|
||||
if ( !match_valid[match_index] )
|
||||
{
|
||||
if ( !match_valid[match_index] ) {
|
||||
int match_len = match_vectors[(2*match_index)+1]-match_vectors[2*match_index];
|
||||
if ( match_lengths[match_index] < (match_len+1) )
|
||||
{
|
||||
if ( match_lengths[match_index] < (match_len+1) ) {
|
||||
delete[] match_buffers[match_index];
|
||||
match_buffers[match_index] = new char[match_len+1];
|
||||
match_lengths[match_index] = match_len+1;
|
||||
@@ -115,10 +100,8 @@ const char *RegExpr::MatchString( int match_index ) const
|
||||
return( match_buffers[match_index] );
|
||||
}
|
||||
|
||||
int RegExpr::MatchLength( int match_index ) const
|
||||
{
|
||||
if ( match_index > n_matches )
|
||||
{
|
||||
int RegExpr::MatchLength( int match_index ) const {
|
||||
if ( match_index > n_matches ) {
|
||||
return( 0 );
|
||||
}
|
||||
return( match_vectors[(2*match_index)+1]-match_vectors[2*match_index] );
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* ZoneMinder Regular Expression Interface, $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.
|
||||
*/
|
||||
*/
|
||||
|
||||
#ifndef ZM_REGEXP_H
|
||||
#define ZM_REGEXP_H
|
||||
@@ -32,9 +32,8 @@
|
||||
#error Unable to locate pcre.h, please do 'locate pcre.h' and report location to zoneminder.com
|
||||
#endif
|
||||
|
||||
class RegExpr
|
||||
{
|
||||
protected:
|
||||
class RegExpr {
|
||||
protected:
|
||||
pcre *regex;
|
||||
pcre_extra *regextra;
|
||||
int max_matches;
|
||||
@@ -43,14 +42,14 @@ protected:
|
||||
int *match_lengths;
|
||||
bool *match_valid;
|
||||
|
||||
protected:
|
||||
protected:
|
||||
const char *match_string;
|
||||
int n_matches;
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
bool ok;
|
||||
|
||||
public:
|
||||
public:
|
||||
explicit RegExpr( const char *pattern, int cflags=0, int p_max_matches=32 );
|
||||
~RegExpr();
|
||||
bool Ok() const { return( ok ); }
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// 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.h"
|
||||
|
||||
@@ -41,20 +41,19 @@ RemoteCamera::RemoteCamera(
|
||||
int p_colour,
|
||||
bool p_capture,
|
||||
bool p_record_audio
|
||||
) :
|
||||
Camera(monitor, REMOTE_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio),
|
||||
protocol(p_protocol),
|
||||
host(p_host),
|
||||
port(p_port),
|
||||
path(p_path),
|
||||
username(p_user),
|
||||
password(p_pass),
|
||||
hp(nullptr),
|
||||
mNeedAuth(false),
|
||||
mAuthenticator(nullptr)
|
||||
{
|
||||
if (path[0] != '/')
|
||||
path = '/'+path;
|
||||
) :
|
||||
Camera(monitor, REMOTE_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio),
|
||||
protocol(p_protocol),
|
||||
host(p_host),
|
||||
port(p_port),
|
||||
path(p_path),
|
||||
username(p_user),
|
||||
password(p_pass),
|
||||
hp(nullptr),
|
||||
mNeedAuth(false),
|
||||
mAuthenticator(nullptr) {
|
||||
if (path[0] != '/')
|
||||
path = '/'+path;
|
||||
}
|
||||
|
||||
RemoteCamera::~RemoteCamera() {
|
||||
@@ -62,21 +61,21 @@ RemoteCamera::~RemoteCamera() {
|
||||
freeaddrinfo(hp);
|
||||
hp = nullptr;
|
||||
}
|
||||
delete mAuthenticator;
|
||||
delete mAuthenticator;
|
||||
}
|
||||
|
||||
void RemoteCamera::Initialise() {
|
||||
if (protocol.empty())
|
||||
Fatal("No protocol specified for remote camera");
|
||||
|
||||
if (host.empty())
|
||||
Fatal("No host specified for remote camera");
|
||||
if (host.empty())
|
||||
Fatal("No host specified for remote camera");
|
||||
|
||||
if (port.empty())
|
||||
Fatal("No port specified for remote camera");
|
||||
if (port.empty())
|
||||
Fatal("No port specified for remote camera");
|
||||
|
||||
|
||||
// Cache as much as we can to speed things up
|
||||
// Cache as much as we can to speed things up
|
||||
std::string::size_type authIndex = host.rfind('@');
|
||||
|
||||
if (authIndex != std::string::npos) {
|
||||
@@ -94,12 +93,12 @@ void RemoteCamera::Initialise() {
|
||||
}
|
||||
|
||||
mNeedAuth = false;
|
||||
mAuthenticator = new zm::Authenticator(username, password);
|
||||
mAuthenticator = new zm::Authenticator(username, password);
|
||||
|
||||
struct addrinfo hints;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
struct addrinfo hints;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
int ret = getaddrinfo(host.c_str(), port.c_str(), &hints, &hp);
|
||||
if (ret != 0) {
|
||||
@@ -119,7 +118,7 @@ int RemoteCamera::Read( int fd, char *buf, int size ) {
|
||||
while ( ReceivedBytes < size ) {
|
||||
// recv blocks until we get data, but it may be of ARBITRARY LENGTH and INCOMPLETE
|
||||
int bytes_to_recv = size - ReceivedBytes;
|
||||
if ( SOCKET_BUF_SIZE < bytes_to_recv )
|
||||
if ( SOCKET_BUF_SIZE < bytes_to_recv )
|
||||
bytes_to_recv = SOCKET_BUF_SIZE;
|
||||
//Debug(3, "Aiming to receive %d of %d bytes", bytes_to_recv, size );
|
||||
int bytes = recv(fd, &buf[ReceivedBytes], bytes_to_recv, 0); //socket, buffer, len, flags
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Remote Camera Class Interface, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_REMOTE_CAMERA_H
|
||||
#define ZM_REMOTE_CAMERA_H
|
||||
@@ -31,7 +31,7 @@
|
||||
// accessed over a network connection.
|
||||
//
|
||||
class RemoteCamera : public Camera {
|
||||
protected:
|
||||
protected:
|
||||
std::string protocol;
|
||||
std::string host;
|
||||
std::string port;
|
||||
@@ -50,7 +50,7 @@ protected:
|
||||
bool mNeedAuth;
|
||||
zm::Authenticator* mAuthenticator;
|
||||
|
||||
public:
|
||||
public:
|
||||
RemoteCamera(
|
||||
const Monitor *monitor,
|
||||
const std::string &p_proto,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Remote HTTP Camera Class Interface, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_REMOTE_CAMERA_HTTP_H
|
||||
#define ZM_REMOTE_CAMERA_HTTP_H
|
||||
@@ -28,7 +28,7 @@
|
||||
// accessed over a network connection using http
|
||||
//
|
||||
class RemoteCameraHttp : public RemoteCamera {
|
||||
protected:
|
||||
protected:
|
||||
std::string request;
|
||||
struct timeval timeout;
|
||||
//struct hostent *hp;
|
||||
@@ -40,25 +40,25 @@ protected:
|
||||
enum { HEADER, HEADERCONT, SUBHEADER, SUBHEADERCONT, CONTENT } state;
|
||||
enum { SIMPLE, REGEXP } method;
|
||||
|
||||
public:
|
||||
public:
|
||||
RemoteCameraHttp(
|
||||
const Monitor *monitor,
|
||||
const std::string &method,
|
||||
const std::string &host,
|
||||
const std::string &port,
|
||||
const std::string &path,
|
||||
const std::string &p_user,
|
||||
const std::string &p_pass,
|
||||
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
|
||||
);
|
||||
const Monitor *monitor,
|
||||
const std::string &method,
|
||||
const std::string &host,
|
||||
const std::string &port,
|
||||
const std::string &path,
|
||||
const std::string &p_user,
|
||||
const std::string &p_pass,
|
||||
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
|
||||
);
|
||||
~RemoteCameraHttp();
|
||||
|
||||
void Initialise() override;
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
int Disconnect() override;
|
||||
int SendRequest();
|
||||
int ReadData( Buffer &buffer, unsigned int bytes_expected=0 );
|
||||
int GetData();
|
||||
int GetData();
|
||||
int GetResponse();
|
||||
int PrimeCapture() override;
|
||||
int PreCapture() override;
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// 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"
|
||||
|
||||
@@ -63,8 +63,7 @@ RemoteCameraNVSocket::RemoteCameraNVSocket(
|
||||
p_hue,
|
||||
p_colour,
|
||||
p_capture,
|
||||
p_record_audio )
|
||||
{
|
||||
p_record_audio ) {
|
||||
sd = -1;
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
@@ -87,7 +86,7 @@ void RemoteCameraNVSocket::Initialise() {
|
||||
RemoteCamera::Initialise();
|
||||
|
||||
if ( !timeout.tv_sec ) {
|
||||
timeout.tv_sec = config.http_timeout/1000;
|
||||
timeout.tv_sec = config.http_timeout/1000;
|
||||
timeout.tv_usec = (config.http_timeout%1000)*1000;
|
||||
}
|
||||
|
||||
@@ -115,7 +114,7 @@ int RemoteCameraNVSocket::Connect() {
|
||||
}
|
||||
|
||||
//if ( connect( sd, p->ai_addr, p->ai_addrlen ) < 0 ) {
|
||||
if ( connect( sd, (struct sockaddr *)&servaddr , sizeof(servaddr) ) < 0 ) {
|
||||
if ( connect( sd, (struct sockaddr *)&servaddr, sizeof(servaddr) ) < 0 ) {
|
||||
close(sd);
|
||||
sd = -1;
|
||||
|
||||
@@ -191,13 +190,13 @@ int RemoteCameraNVSocket::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
|
||||
Warning("Unable to capture image, retrying");
|
||||
return 0;
|
||||
}
|
||||
int bytes_read = Read(sd, buffer, imagesize);
|
||||
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) {
|
||||
if (Read(sd, (char *) &end, sizeof(end)) < 0) {
|
||||
Warning("Unable to capture image, retrying");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Remote NVSOCKET Camera Class Interface, $Date$, $Revision$
|
||||
// Copyright (C) 2017 ZoneMinder LLC
|
||||
//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_REMOTE_CAMERA_NVSOCKET_H
|
||||
#define ZM_REMOTE_CAMERA_NVSOCKET_H
|
||||
@@ -24,27 +24,27 @@
|
||||
#include "zm_remote_camera.h"
|
||||
|
||||
class RemoteCameraNVSocket : public RemoteCamera {
|
||||
protected:
|
||||
protected:
|
||||
std::string request;
|
||||
struct timeval timeout;
|
||||
int sd;
|
||||
Buffer buffer;
|
||||
|
||||
public:
|
||||
public:
|
||||
RemoteCameraNVSocket(
|
||||
const Monitor *monitor,
|
||||
const std::string &host,
|
||||
const std::string &port,
|
||||
const std::string &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 );
|
||||
const Monitor *monitor,
|
||||
const std::string &host,
|
||||
const std::string &port,
|
||||
const std::string &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 );
|
||||
~RemoteCameraNVSocket();
|
||||
|
||||
void Initialise() override;
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// 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_rtsp.h"
|
||||
|
||||
@@ -25,35 +25,34 @@
|
||||
#include "zm_signal.h"
|
||||
|
||||
RemoteCameraRtsp::RemoteCameraRtsp(
|
||||
const Monitor *monitor,
|
||||
const std::string &p_method,
|
||||
const std::string &p_host,
|
||||
const std::string &p_port,
|
||||
const std::string &p_path,
|
||||
const std::string &p_user,
|
||||
const std::string &p_pass,
|
||||
int p_width,
|
||||
int p_height,
|
||||
bool p_rtsp_describe,
|
||||
int p_colours,
|
||||
int p_brightness,
|
||||
int p_contrast,
|
||||
int p_hue,
|
||||
int p_colour,
|
||||
bool p_capture,
|
||||
bool p_record_audio ) :
|
||||
const Monitor *monitor,
|
||||
const std::string &p_method,
|
||||
const std::string &p_host,
|
||||
const std::string &p_port,
|
||||
const std::string &p_path,
|
||||
const std::string &p_user,
|
||||
const std::string &p_pass,
|
||||
int p_width,
|
||||
int p_height,
|
||||
bool p_rtsp_describe,
|
||||
int p_colours,
|
||||
int p_brightness,
|
||||
int p_contrast,
|
||||
int p_hue,
|
||||
int p_colour,
|
||||
bool p_capture,
|
||||
bool p_record_audio ) :
|
||||
RemoteCamera(
|
||||
monitor, "rtsp",
|
||||
p_host, p_port, p_path,
|
||||
p_user, p_pass,
|
||||
p_width, p_height, p_colours,
|
||||
p_brightness, p_contrast, p_hue, p_colour,
|
||||
p_capture, p_record_audio),
|
||||
monitor, "rtsp",
|
||||
p_host, p_port, p_path,
|
||||
p_user, p_pass,
|
||||
p_width, p_height, p_colours,
|
||||
p_brightness, p_contrast, p_hue, p_colour,
|
||||
p_capture, p_record_audio),
|
||||
rtsp_describe(p_rtsp_describe),
|
||||
user(p_user),
|
||||
pass(p_pass),
|
||||
frameCount(0)
|
||||
{
|
||||
frameCount(0) {
|
||||
if ( p_method == "rtpUni" )
|
||||
method = RtspThread::RTP_UNICAST;
|
||||
else if ( p_method == "rtpMulti" )
|
||||
@@ -68,7 +67,7 @@ RemoteCameraRtsp::RemoteCameraRtsp(
|
||||
if ( capture ) {
|
||||
Initialise();
|
||||
}
|
||||
|
||||
|
||||
/* Has to be located inside the constructor so other components such as zma will receive correct colours and subpixel order */
|
||||
if ( colours == ZM_COLOUR_RGB32 ) {
|
||||
subpixelorder = ZM_SUBPIX_ORDER_RGBA;
|
||||
@@ -87,8 +86,8 @@ RemoteCameraRtsp::RemoteCameraRtsp(
|
||||
RemoteCameraRtsp::~RemoteCameraRtsp() {
|
||||
|
||||
if ( mVideoCodecContext ) {
|
||||
avcodec_close(mVideoCodecContext);
|
||||
mVideoCodecContext = nullptr; // Freed by avformat_free_context in the destructor of RtspThread class
|
||||
avcodec_close(mVideoCodecContext);
|
||||
mVideoCodecContext = nullptr; // Freed by avformat_free_context in the destructor of RtspThread class
|
||||
}
|
||||
// Is allocated in RTSPThread and is free there as well
|
||||
mFormatContext = nullptr;
|
||||
@@ -150,7 +149,7 @@ int RemoteCameraRtsp::PrimeCapture() {
|
||||
mVideoStreamId = -1;
|
||||
mAudioStreamId = -1;
|
||||
|
||||
// Find the first video stream.
|
||||
// Find the first video stream.
|
||||
for ( unsigned int i = 0; i < mFormatContext->nb_streams; i++ ) {
|
||||
if ( is_video_stream(mFormatContext->streams[i]) ) {
|
||||
if ( mVideoStreamId == -1 ) {
|
||||
@@ -238,20 +237,20 @@ int RemoteCameraRtsp::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
|
||||
if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H264 ) {
|
||||
// SPS and PPS frames should be saved and appended to IDR frames
|
||||
int nalType = (buffer.head()[3] & 0x1f);
|
||||
|
||||
|
||||
// SPS The SPS NAL unit contains parameters that apply to a series of consecutive coded video pictures
|
||||
if ( nalType == 1 ) {
|
||||
} else if ( nalType == 7 ) {
|
||||
lastSps = buffer;
|
||||
continue;
|
||||
} else if ( nalType == 8 ) {
|
||||
// PPS The PPS NAL unit contains parameters that apply to the decoding of one or more individual pictures inside a coded video sequence
|
||||
// PPS The PPS NAL unit contains parameters that apply to the decoding of one or more individual pictures inside a coded video sequence
|
||||
lastPps = buffer;
|
||||
continue;
|
||||
} else if ( nalType == 5 ) {
|
||||
packet->flags |= AV_PKT_FLAG_KEY;
|
||||
zm_packet->keyframe = 1;
|
||||
// IDR
|
||||
// IDR
|
||||
buffer += lastSps;
|
||||
buffer += lastPps;
|
||||
} else {
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder Remote RTSP Camera Class Interface, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_REMOTE_CAMERA_RTSP_H
|
||||
#define ZM_REMOTE_CAMERA_RTSP_H
|
||||
@@ -30,7 +30,7 @@
|
||||
// (Real Time Streaming Protocol)
|
||||
//
|
||||
class RemoteCameraRtsp : public RemoteCamera {
|
||||
protected:
|
||||
protected:
|
||||
struct sockaddr_in rtsp_sa;
|
||||
struct sockaddr_in rtcp_sa;
|
||||
int rtsp_sd;
|
||||
@@ -53,25 +53,25 @@ protected:
|
||||
|
||||
_AVPIXELFORMAT imagePixFormat;
|
||||
|
||||
public:
|
||||
public:
|
||||
RemoteCameraRtsp(
|
||||
const Monitor *monitor,
|
||||
const std::string &method,
|
||||
const std::string &host,
|
||||
const std::string &port,
|
||||
const std::string &path,
|
||||
const std::string &user,
|
||||
const std::string &pass,
|
||||
int p_width,
|
||||
int p_height,
|
||||
bool p_rtsp_describe,
|
||||
int p_colours,
|
||||
int p_brightness,
|
||||
int p_contrast,
|
||||
int p_hue,
|
||||
int p_colour,
|
||||
bool p_capture,
|
||||
bool p_record_audio);
|
||||
const Monitor *monitor,
|
||||
const std::string &method,
|
||||
const std::string &host,
|
||||
const std::string &port,
|
||||
const std::string &path,
|
||||
const std::string &user,
|
||||
const std::string &pass,
|
||||
int p_width,
|
||||
int p_height,
|
||||
bool p_rtsp_describe,
|
||||
int p_colours,
|
||||
int p_brightness,
|
||||
int p_contrast,
|
||||
int p_hue,
|
||||
int p_colour,
|
||||
bool p_capture,
|
||||
bool p_record_audio);
|
||||
~RemoteCameraRtsp();
|
||||
|
||||
void Initialise() override;
|
||||
@@ -85,7 +85,7 @@ public:
|
||||
int PostCapture() override;
|
||||
int Close() override { return 0; };
|
||||
|
||||
AVStream *get_VideoStream() {
|
||||
AVStream *get_VideoStream() {
|
||||
if ( mVideoStreamId != -1 )
|
||||
return mFormatContext->streams[mVideoStreamId];
|
||||
return nullptr;
|
||||
|
||||
56
src/zm_rgb.h
56
src/zm_rgb.h
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder RGB Interface, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_RGB_H
|
||||
#define ZM_RGB_H
|
||||
@@ -120,31 +120,31 @@ constexpr Rgb kRGBTransparent = 0x01000000;
|
||||
/* Convert RGB colour value into BGR\ARGB\ABGR */
|
||||
inline Rgb rgb_convert(Rgb p_col, int p_subpixorder) {
|
||||
Rgb result = 0;
|
||||
|
||||
|
||||
switch (p_subpixorder) {
|
||||
case ZM_SUBPIX_ORDER_BGR:
|
||||
case ZM_SUBPIX_ORDER_BGRA:
|
||||
BLUE_PTR_BGRA(&result) = BLUE_VAL_RGBA(p_col);
|
||||
GREEN_PTR_BGRA(&result) = GREEN_VAL_RGBA(p_col);
|
||||
RED_PTR_BGRA(&result) = RED_VAL_RGBA(p_col);
|
||||
break;
|
||||
case ZM_SUBPIX_ORDER_ARGB:
|
||||
BLUE_PTR_ARGB(&result) = BLUE_VAL_RGBA(p_col);
|
||||
GREEN_PTR_ARGB(&result) = GREEN_VAL_RGBA(p_col);
|
||||
RED_PTR_ARGB(&result) = RED_VAL_RGBA(p_col);
|
||||
break;
|
||||
case ZM_SUBPIX_ORDER_ABGR:
|
||||
BLUE_PTR_ABGR(&result) = BLUE_VAL_RGBA(p_col);
|
||||
GREEN_PTR_ABGR(&result) = GREEN_VAL_RGBA(p_col);
|
||||
RED_PTR_ABGR(&result) = RED_VAL_RGBA(p_col);
|
||||
break;
|
||||
/* Grayscale */
|
||||
case ZM_SUBPIX_ORDER_NONE:
|
||||
result = p_col & 0xff;
|
||||
break;
|
||||
default:
|
||||
result = p_col;
|
||||
break;
|
||||
case ZM_SUBPIX_ORDER_BGR:
|
||||
case ZM_SUBPIX_ORDER_BGRA:
|
||||
BLUE_PTR_BGRA(&result) = BLUE_VAL_RGBA(p_col);
|
||||
GREEN_PTR_BGRA(&result) = GREEN_VAL_RGBA(p_col);
|
||||
RED_PTR_BGRA(&result) = RED_VAL_RGBA(p_col);
|
||||
break;
|
||||
case ZM_SUBPIX_ORDER_ARGB:
|
||||
BLUE_PTR_ARGB(&result) = BLUE_VAL_RGBA(p_col);
|
||||
GREEN_PTR_ARGB(&result) = GREEN_VAL_RGBA(p_col);
|
||||
RED_PTR_ARGB(&result) = RED_VAL_RGBA(p_col);
|
||||
break;
|
||||
case ZM_SUBPIX_ORDER_ABGR:
|
||||
BLUE_PTR_ABGR(&result) = BLUE_VAL_RGBA(p_col);
|
||||
GREEN_PTR_ABGR(&result) = GREEN_VAL_RGBA(p_col);
|
||||
RED_PTR_ABGR(&result) = RED_VAL_RGBA(p_col);
|
||||
break;
|
||||
/* Grayscale */
|
||||
case ZM_SUBPIX_ORDER_NONE:
|
||||
result = p_col & 0xff;
|
||||
break;
|
||||
default:
|
||||
result = p_col;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder RTP/RTCP 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_rtp.h"
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder RTP/RTCP Class Interface, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_RTP_H
|
||||
#define ZM_RTP_H
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
//
|
||||
// ZoneMinder RTCP 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.
|
||||
@@ -24,8 +24,7 @@
|
||||
#include "zm_rtsp.h"
|
||||
|
||||
RtpCtrlThread::RtpCtrlThread(RtspThread &rtspThread, RtpSource &rtpSource)
|
||||
: mRtspThread(rtspThread), mRtpSource(rtpSource), mTerminate(false)
|
||||
{
|
||||
: mRtspThread(rtspThread), mRtpSource(rtpSource), mTerminate(false) {
|
||||
mThread = std::thread(&RtpCtrlThread::Run, this);
|
||||
}
|
||||
|
||||
@@ -43,7 +42,7 @@ int RtpCtrlThread::recvPacket( const unsigned char *packet, ssize_t packetLen )
|
||||
|
||||
//printf( "C: " );
|
||||
//for ( int i = 0; i < packetLen; i++ )
|
||||
//printf( "%02x ", (unsigned char)packet[i] );
|
||||
//printf( "%02x ", (unsigned char)packet[i] );
|
||||
//printf( "\n" );
|
||||
int ver = rtcpPacket->header.version;
|
||||
int count = rtcpPacket->header.count;
|
||||
@@ -53,92 +52,89 @@ int RtpCtrlThread::recvPacket( const unsigned char *packet, ssize_t packetLen )
|
||||
Debug( 5, "RTCP Ver: %d Count: %d Pt: %d len: %d", ver, count, pt, len);
|
||||
|
||||
switch( pt ) {
|
||||
case RTCP_SR :
|
||||
{
|
||||
uint32_t ssrc = ntohl(rtcpPacket->body.sr.ssrcN);
|
||||
case RTCP_SR : {
|
||||
uint32_t ssrc = ntohl(rtcpPacket->body.sr.ssrcN);
|
||||
|
||||
Debug( 5, "RTCP Got SR (%x)", ssrc );
|
||||
if ( mRtpSource.getSsrc() ) {
|
||||
if ( ssrc != mRtpSource.getSsrc() ) {
|
||||
Warning( "Discarding packet for unrecognised ssrc %x", ssrc );
|
||||
return( -1 );
|
||||
}
|
||||
} else if ( ssrc ) {
|
||||
mRtpSource.setSsrc( ssrc );
|
||||
Debug( 5, "RTCP Got SR (%x)", ssrc );
|
||||
if ( mRtpSource.getSsrc() ) {
|
||||
if ( ssrc != mRtpSource.getSsrc() ) {
|
||||
Warning( "Discarding packet for unrecognised ssrc %x", ssrc );
|
||||
return( -1 );
|
||||
}
|
||||
} else if ( ssrc ) {
|
||||
mRtpSource.setSsrc( ssrc );
|
||||
}
|
||||
|
||||
if ( len > 1 ) {
|
||||
//printf( "NTPts:%d.%d, RTPts:%d\n", $ntptsmsb, $ntptslsb, $rtpts );
|
||||
uint16_t ntptsmsb = ntohl(rtcpPacket->body.sr.ntpSecN);
|
||||
uint16_t ntptslsb = ntohl(rtcpPacket->body.sr.ntpFracN);
|
||||
//printf( "NTPts:%x.%04x, RTPts:%x\n", $ntptsmsb, $ntptslsb, $rtpts );
|
||||
//printf( "Pkts:$sendpkts, Octs:$sendocts\n" );
|
||||
uint32_t rtpTime = ntohl(rtcpPacket->body.sr.rtpTsN);
|
||||
|
||||
mRtpSource.updateRtcpData( ntptsmsb, ntptslsb, rtpTime );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RTCP_SDES : {
|
||||
ssize_t contentLen = packetLen - sizeof(rtcpPacket->header);
|
||||
while ( contentLen ) {
|
||||
Debug( 5, "RTCP CL: %zd", contentLen );
|
||||
uint32_t ssrc = ntohl(rtcpPacket->body.sdes.srcN);
|
||||
|
||||
Debug( 5, "RTCP Got SDES (%x), %d items", ssrc, count );
|
||||
if ( mRtpSource.getSsrc() && (ssrc != mRtpSource.getSsrc()) ) {
|
||||
Warning( "Discarding packet for unrecognised ssrc %x", ssrc );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if ( len > 1 ) {
|
||||
//printf( "NTPts:%d.%d, RTPts:%d\n", $ntptsmsb, $ntptslsb, $rtpts );
|
||||
uint16_t ntptsmsb = ntohl(rtcpPacket->body.sr.ntpSecN);
|
||||
uint16_t ntptslsb = ntohl(rtcpPacket->body.sr.ntpFracN);
|
||||
//printf( "NTPts:%x.%04x, RTPts:%x\n", $ntptsmsb, $ntptslsb, $rtpts );
|
||||
//printf( "Pkts:$sendpkts, Octs:$sendocts\n" );
|
||||
uint32_t rtpTime = ntohl(rtcpPacket->body.sr.rtpTsN);
|
||||
|
||||
mRtpSource.updateRtcpData( ntptsmsb, ntptslsb, rtpTime );
|
||||
unsigned char *sdesPtr = (unsigned char *)&rtcpPacket->body.sdes.item;
|
||||
for ( int i = 0; i < count; i++ ) {
|
||||
RtcpSdesItem *item = (RtcpSdesItem *)sdesPtr;
|
||||
Debug( 5, "RTCP Item length %d", item->len );
|
||||
switch( item->type ) {
|
||||
case RTCP_SDES_CNAME : {
|
||||
std::string cname( item->data, item->len );
|
||||
Debug( 5, "RTCP Got CNAME %s", cname.c_str() );
|
||||
break;
|
||||
}
|
||||
case RTCP_SDES_END :
|
||||
case RTCP_SDES_NAME :
|
||||
case RTCP_SDES_EMAIL :
|
||||
case RTCP_SDES_PHONE :
|
||||
case RTCP_SDES_LOC :
|
||||
case RTCP_SDES_TOOL :
|
||||
case RTCP_SDES_NOTE :
|
||||
case RTCP_SDES_PRIV :
|
||||
default :
|
||||
Error( "Received unexpected SDES item type %d, ignoring", item->type );
|
||||
return -1;
|
||||
}
|
||||
int paddedLen = 4+2+item->len+1; // Add null byte
|
||||
paddedLen = (((paddedLen-1)/4)+1)*4; // Round to nearest multiple of 4
|
||||
Debug(5, "RTCP PL:%d", paddedLen);
|
||||
sdesPtr += paddedLen;
|
||||
contentLen = ( paddedLen <= contentLen ) ? ( contentLen - paddedLen ) : 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RTCP_SDES :
|
||||
{
|
||||
ssize_t contentLen = packetLen - sizeof(rtcpPacket->header);
|
||||
while ( contentLen ) {
|
||||
Debug( 5, "RTCP CL: %zd", contentLen );
|
||||
uint32_t ssrc = ntohl(rtcpPacket->body.sdes.srcN);
|
||||
|
||||
Debug( 5, "RTCP Got SDES (%x), %d items", ssrc, count );
|
||||
if ( mRtpSource.getSsrc() && (ssrc != mRtpSource.getSsrc()) ) {
|
||||
Warning( "Discarding packet for unrecognised ssrc %x", ssrc );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
unsigned char *sdesPtr = (unsigned char *)&rtcpPacket->body.sdes.item;
|
||||
for ( int i = 0; i < count; i++ ) {
|
||||
RtcpSdesItem *item = (RtcpSdesItem *)sdesPtr;
|
||||
Debug( 5, "RTCP Item length %d", item->len );
|
||||
switch( item->type ) {
|
||||
case RTCP_SDES_CNAME :
|
||||
{
|
||||
std::string cname( item->data, item->len );
|
||||
Debug( 5, "RTCP Got CNAME %s", cname.c_str() );
|
||||
break;
|
||||
}
|
||||
case RTCP_SDES_END :
|
||||
case RTCP_SDES_NAME :
|
||||
case RTCP_SDES_EMAIL :
|
||||
case RTCP_SDES_PHONE :
|
||||
case RTCP_SDES_LOC :
|
||||
case RTCP_SDES_TOOL :
|
||||
case RTCP_SDES_NOTE :
|
||||
case RTCP_SDES_PRIV :
|
||||
default :
|
||||
Error( "Received unexpected SDES item type %d, ignoring", item->type );
|
||||
return -1;
|
||||
}
|
||||
int paddedLen = 4+2+item->len+1; // Add null byte
|
||||
paddedLen = (((paddedLen-1)/4)+1)*4; // Round to nearest multiple of 4
|
||||
Debug(5, "RTCP PL:%d", paddedLen);
|
||||
sdesPtr += paddedLen;
|
||||
contentLen = ( paddedLen <= contentLen ) ? ( contentLen - paddedLen ) : 0;
|
||||
}
|
||||
} // end whiel contentLen
|
||||
break;
|
||||
}
|
||||
case RTCP_BYE :
|
||||
Debug(5, "RTCP Got BYE");
|
||||
Stop();
|
||||
break;
|
||||
case RTCP_APP :
|
||||
// Ignoring as per RFC 3550
|
||||
Debug(5, "Received RTCP_APP packet, ignoring.");
|
||||
break;
|
||||
case RTCP_RR :
|
||||
Error("Received RTCP_RR packet.");
|
||||
return -1;
|
||||
default :
|
||||
// Ignore unknown packet types. Some cameras do this by design.
|
||||
Debug(5, "Received unexpected packet type %d, ignoring", pt);
|
||||
break;
|
||||
} // end whiel contentLen
|
||||
break;
|
||||
}
|
||||
case RTCP_BYE :
|
||||
Debug(5, "RTCP Got BYE");
|
||||
Stop();
|
||||
break;
|
||||
case RTCP_APP :
|
||||
// Ignoring as per RFC 3550
|
||||
Debug(5, "Received RTCP_APP packet, ignoring.");
|
||||
break;
|
||||
case RTCP_RR :
|
||||
Error("Received RTCP_RR packet.");
|
||||
return -1;
|
||||
default :
|
||||
// Ignore unknown packet types. Some cameras do this by design.
|
||||
Debug(5, "Received unexpected packet type %d, ignoring", pt);
|
||||
break;
|
||||
}
|
||||
consumed = sizeof(uint32_t)*(len+1);
|
||||
return consumed;
|
||||
@@ -159,12 +155,12 @@ int RtpCtrlThread::generateRr( const unsigned char *packet, ssize_t packetLen )
|
||||
mRtpSource.updateRtcpStats();
|
||||
|
||||
Debug(5, "Ssrc = %d Ssrc_1 = %d Last Seq = %d Jitter = %d Last SR = %d",
|
||||
mRtspThread.getSsrc()+1,
|
||||
mRtpSource.getSsrc(),
|
||||
mRtpSource.getMaxSeq(),
|
||||
mRtpSource.getJitter(),
|
||||
mRtpSource.getLastSrTimestamp()
|
||||
);
|
||||
mRtspThread.getSsrc()+1,
|
||||
mRtpSource.getSsrc(),
|
||||
mRtpSource.getMaxSeq(),
|
||||
mRtpSource.getJitter(),
|
||||
mRtpSource.getLastSrTimestamp()
|
||||
);
|
||||
|
||||
rtcpPacket->body.rr.ssrcN = htonl(mRtspThread.getSsrc()+1);
|
||||
rtcpPacket->body.rr.rr[0].ssrcN = htonl(mRtpSource.getSsrc());
|
||||
@@ -225,7 +221,7 @@ int RtpCtrlThread::recvPackets( unsigned char *buffer, ssize_t nBytes ) {
|
||||
// rtcp_t *end; /* end of compound RTCP packet */
|
||||
|
||||
// if ((*(u_int16 *)r & RTCP_VALID_MASK) != RTCP_VALID_VALUE) {
|
||||
// /* something wrong with packet format */
|
||||
// /* something wrong with packet format */
|
||||
// }
|
||||
// end = (rtcp_t *)((u_int32 *)r + len);
|
||||
|
||||
@@ -233,7 +229,7 @@ int RtpCtrlThread::recvPackets( unsigned char *buffer, ssize_t nBytes ) {
|
||||
// while (r < end && r->common.version == 2);
|
||||
|
||||
// if (r != end) {
|
||||
// /* something wrong with packet format */
|
||||
// /* something wrong with packet format */
|
||||
// }
|
||||
|
||||
while ( nBytes > 0 ) {
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder RTCP Class Interface, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_RTP_CTRL_H
|
||||
#define ZM_RTP_CTRL_H
|
||||
@@ -35,9 +35,9 @@ class RtspThread;
|
||||
class RtpSource;
|
||||
|
||||
class RtpCtrlThread {
|
||||
friend class RtspThread;
|
||||
friend class RtspThread;
|
||||
|
||||
private:
|
||||
private:
|
||||
typedef enum {
|
||||
RTCP_SR = 200,
|
||||
RTCP_RR = 201,
|
||||
@@ -63,7 +63,7 @@ private:
|
||||
uint8_t p:1; // padding flag
|
||||
uint8_t version:2; // protocol version
|
||||
uint8_t pt; // RTCP packet type
|
||||
uint16_t lenN; // pkt len in words, w/o this word, network order
|
||||
uint16_t lenN; // pkt len in words, w/o this word, network order
|
||||
};
|
||||
|
||||
// Reception report block
|
||||
@@ -116,10 +116,10 @@ private:
|
||||
uint32_t srcN[]; // list of sources
|
||||
// can't express trailing text for reason (what does this mean? it's not even english!)
|
||||
} bye;
|
||||
} body;
|
||||
} body;
|
||||
};
|
||||
|
||||
private:
|
||||
private:
|
||||
RtspThread &mRtspThread;
|
||||
RtpSource &mRtpSource;
|
||||
int mPort;
|
||||
@@ -127,7 +127,7 @@ private:
|
||||
std::atomic<bool> mTerminate;
|
||||
std::thread mThread;
|
||||
|
||||
private:
|
||||
private:
|
||||
int recvPacket( const unsigned char *packet, ssize_t packetLen );
|
||||
int generateRr( const unsigned char *packet, ssize_t packetLen );
|
||||
int generateSdes( const unsigned char *packet, ssize_t packetLen );
|
||||
@@ -135,7 +135,7 @@ private:
|
||||
int recvPackets( unsigned char *buffer, ssize_t nBytes );
|
||||
void Run();
|
||||
|
||||
public:
|
||||
public:
|
||||
RtpCtrlThread( RtspThread &rtspThread, RtpSource &rtpSource );
|
||||
~RtpCtrlThread();
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder RTP Data 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_rtp_data.h"
|
||||
|
||||
@@ -24,8 +24,7 @@
|
||||
#include "zm_signal.h"
|
||||
|
||||
RtpDataThread::RtpDataThread(RtspThread &rtspThread, RtpSource &rtpSource) :
|
||||
mRtspThread(rtspThread), mRtpSource(rtpSource), mTerminate(false)
|
||||
{
|
||||
mRtspThread(rtspThread), mRtpSource(rtpSource), mTerminate(false) {
|
||||
mThread = std::thread(&RtpDataThread::Run, this);
|
||||
}
|
||||
|
||||
@@ -40,20 +39,20 @@ bool RtpDataThread::recvPacket(const unsigned char *packet, size_t packetLen) {
|
||||
rtpHeader = (RtpDataHeader *)packet;
|
||||
|
||||
Debug(5, "Ver: %d P: %d Pt: %d Mk: %d Seq: %d T/S: %x SSRC: %x",
|
||||
rtpHeader->version,
|
||||
rtpHeader->p,
|
||||
rtpHeader->pt,
|
||||
rtpHeader->m,
|
||||
ntohs(rtpHeader->seqN),
|
||||
ntohl(rtpHeader->timestampN),
|
||||
ntohl(rtpHeader->ssrcN));
|
||||
rtpHeader->version,
|
||||
rtpHeader->p,
|
||||
rtpHeader->pt,
|
||||
rtpHeader->m,
|
||||
ntohs(rtpHeader->seqN),
|
||||
ntohl(rtpHeader->timestampN),
|
||||
ntohl(rtpHeader->ssrcN));
|
||||
|
||||
//unsigned short seq = ntohs(rtpHeader->seqN);
|
||||
unsigned long ssrc = ntohl(rtpHeader->ssrcN);
|
||||
|
||||
if ( mRtpSource.getSsrc() && (ssrc != mRtpSource.getSsrc()) ) {
|
||||
Warning("Discarding packet for unrecognised ssrc %lx", ssrc);
|
||||
return false;
|
||||
Warning("Discarding packet for unrecognised ssrc %lx", ssrc);
|
||||
return false;
|
||||
}
|
||||
|
||||
return mRtpSource.handlePacket(packet, packetLen);
|
||||
@@ -61,7 +60,7 @@ bool RtpDataThread::recvPacket(const unsigned char *packet, size_t packetLen) {
|
||||
|
||||
void RtpDataThread::Run() {
|
||||
Debug(2, "Starting data thread %d on port %d",
|
||||
mRtpSource.getSsrc(), mRtpSource.getLocalDataPort());
|
||||
mRtpSource.getSsrc(), mRtpSource.getLocalDataPort());
|
||||
|
||||
zm::SockAddrInet localAddr;
|
||||
zm::UdpInetServer rtpDataSocket;
|
||||
@@ -70,8 +69,8 @@ void RtpDataThread::Run() {
|
||||
Fatal("Failed to bind RTP server");
|
||||
} else {
|
||||
if ( !rtpDataSocket.bind(
|
||||
mRtspThread.getAddressFamily() == AF_INET6 ? "::" : "0.0.0.0",
|
||||
mRtpSource.getLocalDataPort() ) )
|
||||
mRtspThread.getAddressFamily() == AF_INET6 ? "::" : "0.0.0.0",
|
||||
mRtpSource.getLocalDataPort() ) )
|
||||
Fatal("Failed to bind RTP server");
|
||||
}
|
||||
Debug(3, "Bound to %s:%d", mRtpSource.getLocalHost().c_str(), mRtpSource.getLocalDataPort());
|
||||
@@ -82,25 +81,25 @@ void RtpDataThread::Run() {
|
||||
unsigned char buffer[ZM_NETWORK_BUFSIZ];
|
||||
while ( !zm_terminate && !mTerminate && (select.wait() >= 0) ) {
|
||||
zm::Select::CommsList readable = select.getReadable();
|
||||
if ( readable.size() == 0 ) {
|
||||
Error("RTP timed out");
|
||||
Stop();
|
||||
break;
|
||||
}
|
||||
for (zm::Select::CommsList::iterator iter = readable.begin(); iter != readable.end(); ++iter ) {
|
||||
if ( zm::UdpInetServer *socket = dynamic_cast<zm::UdpInetServer *>(*iter) ) {
|
||||
int nBytes = socket->recv(buffer, sizeof(buffer));
|
||||
Debug(4, "Got %d bytes on sd %d", nBytes, socket->getReadDesc());
|
||||
if ( nBytes ) {
|
||||
recvPacket(buffer, nBytes);
|
||||
} else {
|
||||
if ( readable.size() == 0 ) {
|
||||
Error("RTP timed out");
|
||||
Stop();
|
||||
break;
|
||||
}
|
||||
for (zm::Select::CommsList::iterator iter = readable.begin(); iter != readable.end(); ++iter ) {
|
||||
if ( zm::UdpInetServer *socket = dynamic_cast<zm::UdpInetServer *>(*iter) ) {
|
||||
int nBytes = socket->recv(buffer, sizeof(buffer));
|
||||
Debug(4, "Got %d bytes on sd %d", nBytes, socket->getReadDesc());
|
||||
if ( nBytes ) {
|
||||
recvPacket(buffer, nBytes);
|
||||
} else {
|
||||
Stop();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
Panic("Barfed");
|
||||
}
|
||||
} // end foreach commsList
|
||||
}
|
||||
} else {
|
||||
Panic("Barfed");
|
||||
}
|
||||
} // end foreach commsList
|
||||
}
|
||||
rtpDataSocket.close();
|
||||
mRtspThread.Stop();
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
//
|
||||
// ZoneMinder RTP Data Class Interface, $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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef ZM_RTP_DATA_H
|
||||
#define ZM_RTP_DATA_H
|
||||
@@ -27,8 +27,7 @@
|
||||
class RtspThread;
|
||||
class RtpSource;
|
||||
|
||||
struct RtpDataHeader
|
||||
{
|
||||
struct RtpDataHeader {
|
||||
uint8_t cc:4; // CSRC count
|
||||
uint8_t x:1; // header extension flag
|
||||
uint8_t p:1; // padding flag
|
||||
@@ -41,22 +40,21 @@ struct RtpDataHeader
|
||||
uint32_t csrc[]; // optional CSRC list
|
||||
};
|
||||
|
||||
class RtpDataThread
|
||||
{
|
||||
friend class RtspThread;
|
||||
class RtpDataThread {
|
||||
friend class RtspThread;
|
||||
|
||||
private:
|
||||
private:
|
||||
RtspThread &mRtspThread;
|
||||
RtpSource &mRtpSource;
|
||||
|
||||
std::atomic<bool> mTerminate;
|
||||
std::thread mThread;
|
||||
|
||||
private:
|
||||
private:
|
||||
bool recvPacket( const unsigned char *packet, size_t packetLen );
|
||||
void Run();
|
||||
|
||||
public:
|
||||
public:
|
||||
RtpDataThread( RtspThread &rtspThread, RtpSource &rtpSource );
|
||||
~RtpDataThread();
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user