Merge branch 'master' of github.com:zoneminder/ZoneMinder

This commit is contained in:
Isaac Connor 2020-05-11 08:34:19 -04:00
commit 81cd338545
21 changed files with 345 additions and 355 deletions

View File

@ -41,6 +41,7 @@ env:
- SMPFLAGS=-j4 OS=ubuntu DIST=bionic DOCKER_REPO=iconzm/packpack - SMPFLAGS=-j4 OS=ubuntu DIST=bionic DOCKER_REPO=iconzm/packpack
- SMPFLAGS=-j4 OS=ubuntu DIST=disco DOCKER_REPO=iconzm/packpack - SMPFLAGS=-j4 OS=ubuntu DIST=disco DOCKER_REPO=iconzm/packpack
- SMPFLAGS=-j4 OS=ubuntu DIST=eoan DOCKER_REPO=iconzm/packpack - SMPFLAGS=-j4 OS=ubuntu DIST=eoan DOCKER_REPO=iconzm/packpack
- SMPFLAGS=-j4 OS=ubuntu DIST=focal DOCKER_REPO=iconzm/packpack
- SMPFLAGS=-j4 OS=debian DIST=jessie DOCKER_REPO=iconzm/packpack - SMPFLAGS=-j4 OS=debian DIST=jessie DOCKER_REPO=iconzm/packpack
- SMPFLAGS=-j4 OS=debian DIST=stretch DOCKER_REPO=iconzm/packpack - SMPFLAGS=-j4 OS=debian DIST=stretch DOCKER_REPO=iconzm/packpack
- SMPFLAGS=-j4 OS=debian DIST=buster DOCKER_REPO=iconzm/packpack - SMPFLAGS=-j4 OS=debian DIST=buster DOCKER_REPO=iconzm/packpack

View File

@ -19,6 +19,10 @@ if [ "$1" = "configure" ]; then
echo "The cgi module is not enabled in apache2. I am enabling it using a2enmod cgi." echo "The cgi module is not enabled in apache2. I am enabling it using a2enmod cgi."
a2enmod cgi a2enmod cgi
fi fi
if [ ! -e "/etc/apache2/mods-enabled/rewrite.load" ] && [ "$(command -v a2enmod)" != "" ]; then
echo "The rewrite module is not enabled in apache2. I am enabling it using a2enmod rewrite."
a2enmod rewrite
fi
if [ "$ZM_DB_HOST" = "localhost" ]; then if [ "$ZM_DB_HOST" = "localhost" ]; then
@ -61,11 +65,10 @@ if [ "$1" = "configure" ]; then
exit 1; exit 1;
fi fi
# This creates the user. # This creates the user.
echo "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql echo "CREATE USER '${ZM_DB_USER}'@localhost IDENTIFIED BY '${ZM_DB_PASS}';" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
else fi
echo "Updating permissions" echo "Updating permissions"
echo "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql echo "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
fi
zmupdate.pl --nointeractive zmupdate.pl --nointeractive
zmupdate.pl --nointeractive -f zmupdate.pl --nointeractive -f

View File

@ -46,7 +46,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
,javascript-common ,javascript-common
,libmp4v2-2, libx264-155 ,libmp4v2-2, libx264-155
,libswscale5 ,libswscale5
,libswresample4 ,libswresample3
,ffmpeg ,ffmpeg
,libdate-manip-perl, libmime-lite-perl, libmime-tools-perl ,libdate-manip-perl, libmime-lite-perl, libmime-tools-perl
,libdbd-mysql-perl ,libdbd-mysql-perl

View File

@ -61,11 +61,10 @@ if [ "$1" = "configure" ]; then
exit 1; exit 1;
fi fi
# This creates the user. # This creates the user.
echo "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql echo "CREATE USER '${ZM_DB_USER}'@localhost IDENTIFIED BY '${ZM_DB_PASS}';" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
else fi
echo "Updating permissions" echo "Updating permissions"
echo "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql echo "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
fi
zmupdate.pl --nointeractive zmupdate.pl --nointeractive
zmupdate.pl --nointeractive -f zmupdate.pl --nointeractive -f

View File

@ -69,7 +69,7 @@ sub sendCmd {
my $result = undef; my $result = undef;
printMsg($cmd, 'Tx'); $self->printMsg($cmd, 'Tx');
my $req = HTTP::Request->new(POST=>"http://$self->{Monitor}->{ControlAddress}/$cgi.cgi"); my $req = HTTP::Request->new(POST=>"http://$self->{Monitor}->{ControlAddress}/$cgi.cgi");
$req->content($cmd); $req->content($cmd);

View File

@ -185,16 +185,12 @@ sub discover {
push @responses, $response; push @responses, $response;
}; };
## try both soap versions
my $uuid_gen = Data::UUID->new(); my $uuid_gen = Data::UUID->new();
if ( ( ! $soap_version ) or ( $soap_version eq '1.1' ) ) { if ( ( ! $soap_version ) or ( $soap_version eq '1.1' ) ) {
my %services; my %services;
if ( $verbose ) { print "Probing for SOAP 1.1\n" if $verbose;
print "Probing for SOAP 1.1\n";
}
my $svc_discover = WSDiscovery10::Interfaces::WSDiscovery::WSDiscoveryPort->new({ my $svc_discover = WSDiscovery10::Interfaces::WSDiscovery::WSDiscoveryPort->new({
# no_dispatch => '1', # no_dispatch => '1',
}); });
@ -226,9 +222,7 @@ sub discover {
if ( ( ! $soap_version ) or ( $soap_version eq '1.2' ) ) { if ( ( ! $soap_version ) or ( $soap_version eq '1.2' ) ) {
my %services; my %services;
if ( $verbose ) { print "Probing for SOAP 1.2\n" if $verbose;
print "Probing for SOAP 1.2\n";
}
my $svc_discover = WSDiscovery10::Interfaces::WSDiscovery::WSDiscoveryPort->new({ my $svc_discover = WSDiscovery10::Interfaces::WSDiscovery::WSDiscoveryPort->new({
# no_dispatch => '1', # no_dispatch => '1',
}); });
@ -281,19 +275,16 @@ sub profiles {
} }
my @profiles; my @profiles;
foreach my $profile ( @{ $result->get_Profiles() } ) { foreach my $profile ( @{ $result->get_Profiles() } ) {
my $token = $profile->attr()->get_token() ;
my $Name = $profile->get_Name();
my $VideoEncoderConfiguration = $profile->get_VideoEncoderConfiguration(); my $VideoEncoderConfiguration = $profile->get_VideoEncoderConfiguration();
if ( ! $VideoEncoderConfiguration ) { if ( ! $VideoEncoderConfiguration ) {
print "Unknown profile $token $Name.\n"; print "No VideoEncoderConfiguration in profile $token $Name.\n";
next; next;
} }
my $token = $profile->attr()->get_token() ;
my $Name = $profile->get_Name();
# Specification gives conflicting values for unicast stream types, try both. # Specification gives conflicting values for unicast stream types, try both.
# http://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl#op.GetStreamUri # http://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl#op.GetStreamUri
foreach my $streamtype ( 'RTP_unicast', 'RTP-Unicast', 'RTP-multicast', 'RTP-Multicast' ) { foreach my $streamtype ( 'RTP_unicast', 'RTP-Unicast', 'RTP-multicast', 'RTP-Multicast' ) {
@ -315,15 +306,15 @@ sub profiles {
my $Width = $Resolution ? $Resolution->get_Width() : 0; my $Width = $Resolution ? $Resolution->get_Width() : 0;
my $Height = $Resolution ? $Resolution->get_Height() : 0; my $Height = $Resolution ? $Resolution->get_Height() : 0;
push @profiles, { push @profiles, [
print join(', ', $token, $token,
$Name, $Name,
$VideoEncoderConfiguration->get_Encoding(), $VideoEncoderConfiguration->get_Encoding(),
$Width, $Width,
$Height, $Height,
$VideoEncoderConfiguration->get_RateControl()->get_FrameRateLimit(), $VideoEncoderConfiguration->get_RateControl()->get_FrameRateLimit(),
$Uri, $Uri,
) . "\n"; ];
} # end foreach streamtype } # end foreach streamtype
} # end foreach profile } # end foreach profile

View File

@ -22,6 +22,7 @@
#define ZM_H #define ZM_H
#include "zm_config.h" #include "zm_config.h"
#include "zm_signal.h"
#ifdef SOLARIS #ifdef SOLARIS
#undef DEFAULT_TYPE // pthread defines this which breaks StreamType DEFAULT_TYPE #undef DEFAULT_TYPE // pthread defines this which breaks StreamType DEFAULT_TYPE
#include <string.h> // define strerror() and friends #include <string.h> // define strerror() and friends

View File

@ -468,7 +468,7 @@ void av_packet_rescale_ts(
} }
#endif #endif
bool is_video_stream( AVStream * stream ) { bool is_video_stream(const AVStream * stream) {
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
if ( stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ) { if ( stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ) {
#else #else
@ -480,10 +480,14 @@ bool is_video_stream( AVStream * stream ) {
#endif #endif
return true; return true;
} }
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
Debug(2, "Not a video type %d != %d", stream->codecpar->codec_type, AVMEDIA_TYPE_VIDEO);
#endif
return false; return false;
} }
bool is_video_context( AVCodecContext *codec_context ) { bool is_video_context(const AVCodecContext *codec_context ) {
return return
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
( codec_context->codec_type == AVMEDIA_TYPE_VIDEO ); ( codec_context->codec_type == AVMEDIA_TYPE_VIDEO );
@ -492,7 +496,7 @@ bool is_video_context( AVCodecContext *codec_context ) {
#endif #endif
} }
bool is_audio_stream( AVStream * stream ) { bool is_audio_stream(const AVStream * stream ) {
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
if ( stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO ) { if ( stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO ) {
#else #else
@ -507,7 +511,7 @@ bool is_audio_stream( AVStream * stream ) {
return false; return false;
} }
bool is_audio_context( AVCodecContext *codec_context ) { bool is_audio_context(const AVCodecContext *codec_context ) {
return return
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
( codec_context->codec_type == AVMEDIA_TYPE_AUDIO ); ( codec_context->codec_type == AVMEDIA_TYPE_AUDIO );

View File

@ -372,10 +372,10 @@ void zm_dump_codecpar(const AVCodecParameters *par);
int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt); int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt);
bool is_video_stream(AVStream *); bool is_video_stream(const AVStream *);
bool is_audio_stream(AVStream *); bool is_audio_stream(const AVStream *);
bool is_video_context(AVCodec *); bool is_video_context(const AVCodec *);
bool is_audio_context(AVCodec *); bool is_audio_context(const AVCodec *);
int zm_receive_packet(AVCodecContext *context, AVPacket &packet); int zm_receive_packet(AVCodecContext *context, AVPacket &packet);

View File

@ -151,11 +151,13 @@ int RemoteCameraRtsp::Disconnect() {
int RemoteCameraRtsp::PrimeCapture() { int RemoteCameraRtsp::PrimeCapture() {
Debug(2, "Waiting for sources"); Debug(2, "Waiting for sources");
for ( int i = 0; i < 100 && !rtspThread->hasSources(); i++ ) { for ( int i = 0; (i < 100) && !rtspThread->hasSources(); i++ ) {
usleep(100000); usleep(100000);
} }
if ( !rtspThread->hasSources() ) if ( !rtspThread->hasSources() ) {
Fatal("No RTSP sources"); Error("No RTSP sources");
return -1;
}
Debug(2, "Got sources"); Debug(2, "Got sources");
@ -167,38 +169,21 @@ int RemoteCameraRtsp::PrimeCapture() {
// Find the first video stream. // Find the first video stream.
for ( unsigned int i = 0; i < mFormatContext->nb_streams; i++ ) { for ( unsigned int i = 0; i < mFormatContext->nb_streams; i++ ) {
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) if ( is_video_stream(mFormatContext->streams[i]) ) {
AVMediaType codec_type = mFormatContext->streams[i]->codecpar->codec_type;
#else
AVMediaType codec_type = mFormatContext->streams[i]->codec->codec_type;
#endif
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
if ( codec_type == AVMEDIA_TYPE_VIDEO )
#else
if ( codec_type == CODEC_TYPE_VIDEO )
#endif
{
if ( mVideoStreamId == -1 ) { if ( mVideoStreamId == -1 ) {
mVideoStreamId = i; mVideoStreamId = i;
continue; continue;
} else { } else {
Debug(2, "Have another video stream."); Debug(2, "Have another video stream.");
} }
} else } else if ( is_audio_stream(mFormatContext->streams[i]) ) {
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
if ( codec_type == AVMEDIA_TYPE_AUDIO )
#else
if ( codec_type == CODEC_TYPE_AUDIO )
#endif
{
if ( mAudioStreamId == -1 ) { if ( mAudioStreamId == -1 ) {
mAudioStreamId = i; mAudioStreamId = i;
} else { } else {
Debug(2, "Have another audio stream."); Debug(2, "Have another audio stream.");
} }
} else { } else {
Debug(1, "Have unknown codec type in stream %d : %d", i, codec_type); Debug(1, "Have unknown codec type in stream %d", i);
} }
} // end foreach stream } // end foreach stream
@ -288,7 +273,6 @@ int RemoteCameraRtsp::Capture( Image &image ) {
if ( rtspThread->getFrame(buffer) ) { if ( rtspThread->getFrame(buffer) ) {
Debug(3, "Read frame %d bytes", buffer.size()); Debug(3, "Read frame %d bytes", buffer.size());
Debug(4, "Address %p", buffer.head());
Hexdump(4, buffer.head(), 16); Hexdump(4, buffer.head(), 16);
if ( !buffer.size() ) if ( !buffer.size() )
@ -310,14 +294,15 @@ int RemoteCameraRtsp::Capture( Image &image ) {
// IDR // IDR
buffer += lastSps; buffer += lastSps;
buffer += lastPps; buffer += lastPps;
} else {
Debug(2, "Unknown nalType %d", nalType);
} }
} else { } else {
Debug(3, "Not an h264 packet"); Debug(3, "Not an h264 packet");
} }
av_init_packet(&packet); av_init_packet(&packet);
while ( (!frameComplete) && (buffer.size() > 0) ) {
while ( !frameComplete && (buffer.size() > 0) ) {
packet.data = buffer.head(); packet.data = buffer.head();
packet.size = buffer.size(); packet.size = buffer.size();
bytes += packet.size; bytes += packet.size;
@ -330,6 +315,7 @@ int RemoteCameraRtsp::Capture( Image &image ) {
buffer.clear(); buffer.clear();
continue; continue;
} }
frameComplete = true;
Debug(2, "Frame: %d - %d/%d", frameCount, len, buffer.size()); Debug(2, "Frame: %d - %d/%d", frameCount, len, buffer.size());
//if ( buffer.size() < 400 ) //if ( buffer.size() < 400 )
//Hexdump( 0, buffer.head(), buffer.size() ); //Hexdump( 0, buffer.head(), buffer.size() );

View File

@ -27,98 +27,81 @@
#include <arpa/inet.h> #include <arpa/inet.h>
RtpDataThread::RtpDataThread( RtspThread &rtspThread, RtpSource &rtpSource ) : mRtspThread( rtspThread ), mRtpSource( rtpSource ), mStop( false ) RtpDataThread::RtpDataThread(RtspThread &rtspThread, RtpSource &rtpSource) :
mRtspThread(rtspThread), mRtpSource(rtpSource), mStop(false)
{ {
} }
bool RtpDataThread::recvPacket( const unsigned char *packet, size_t packetLen ) bool RtpDataThread::recvPacket(const unsigned char *packet, size_t packetLen) {
{
const RtpDataHeader *rtpHeader; const RtpDataHeader *rtpHeader;
rtpHeader = (RtpDataHeader *)packet; rtpHeader = (RtpDataHeader *)packet;
//printf( "D: " ); Debug(5, "Ver: %d P: %d Pt: %d Mk: %d Seq: %d T/S: %x SSRC: %x",
//for ( int i = 0; i < 32; i++ ) rtpHeader->version,
//printf( "%02x ", (unsigned char)packet[i] ); rtpHeader->p,
//printf( "\n" ); rtpHeader->pt,
rtpHeader->m,
Debug( 5, "Ver: %d", rtpHeader->version ); ntohs(rtpHeader->seqN),
Debug( 5, "P: %d", rtpHeader->p ); ntohl(rtpHeader->timestampN),
Debug( 5, "Pt: %d", rtpHeader->pt ); ntohl(rtpHeader->ssrcN));
Debug( 5, "Mk: %d", rtpHeader->m );
Debug( 5, "Seq: %d", ntohs(rtpHeader->seqN) );
Debug( 5, "T/S: %x", ntohl(rtpHeader->timestampN) );
Debug( 5, "SSRC: %x", ntohl(rtpHeader->ssrcN) );
//unsigned short seq = ntohs(rtpHeader->seqN); //unsigned short seq = ntohs(rtpHeader->seqN);
unsigned long ssrc = ntohl(rtpHeader->ssrcN); unsigned long ssrc = ntohl(rtpHeader->ssrcN);
if ( mRtpSource.getSsrc() && (ssrc != mRtpSource.getSsrc()) ) if ( mRtpSource.getSsrc() && (ssrc != mRtpSource.getSsrc()) ) {
{
Warning("Discarding packet for unrecognised ssrc %lx", ssrc); Warning("Discarding packet for unrecognised ssrc %lx", ssrc);
return( false ); return false;
} }
return( mRtpSource.handlePacket( packet, packetLen ) ); return mRtpSource.handlePacket(packet, packetLen);
} }
int RtpDataThread::run() int RtpDataThread::run() {
{ Debug(2, "Starting data thread %d on port %d",
Debug( 2, "Starting data thread %d on port %d", mRtpSource.getSsrc(), mRtpSource.getLocalDataPort() ); mRtpSource.getSsrc(), mRtpSource.getLocalDataPort());
SockAddrInet localAddr; SockAddrInet localAddr;
UdpInetServer rtpDataSocket; UdpInetServer rtpDataSocket;
if ( mRtpSource.getLocalHost() != "" ) { if ( mRtpSource.getLocalHost() != "" ) {
if ( !rtpDataSocket.bind(mRtpSource.getLocalHost().c_str(), mRtpSource.getLocalDataPort()) ) if ( !rtpDataSocket.bind(mRtpSource.getLocalHost().c_str(), mRtpSource.getLocalDataPort()) )
Fatal("Failed to bind RTP server"); Fatal("Failed to bind RTP server");
Debug( 3, "Bound to %s:%d", mRtpSource.getLocalHost().c_str(), mRtpSource.getLocalDataPort() ); } else {
} if ( !rtpDataSocket.bind(
else mRtspThread.getAddressFamily() == AF_INET6 ? "::" : "0.0.0.0",
{ mRtpSource.getLocalDataPort() ) )
if ( !rtpDataSocket.bind( mRtspThread.getAddressFamily() == AF_INET6 ? "::" : "0.0.0.0", mRtpSource.getLocalDataPort() ) )
Fatal("Failed to bind RTP server"); Fatal("Failed to bind RTP server");
Debug( 3, "Bound to %s:%d", mRtpSource.getLocalHost().c_str(), mRtpSource.getLocalDataPort() );
} }
Debug(3, "Bound to %s:%d", mRtpSource.getLocalHost().c_str(), mRtpSource.getLocalDataPort());
Select select(3); Select select(3);
select.addReader(&rtpDataSocket); select.addReader(&rtpDataSocket);
unsigned char buffer[ZM_NETWORK_BUFSIZ]; unsigned char buffer[ZM_NETWORK_BUFSIZ];
while ( !mStop && select.wait() >= 0 ) while ( !zm_terminate && !mStop && (select.wait() >= 0) ) {
{
if ( mStop )
break;
Select::CommsList readable = select.getReadable(); Select::CommsList readable = select.getReadable();
if ( readable.size() == 0 ) if ( readable.size() == 0 ) {
{
Error("RTP timed out"); Error("RTP timed out");
mStop = true; mStop = true;
break; break;
} }
for ( Select::CommsList::iterator iter = readable.begin(); iter != readable.end(); ++iter ) for ( Select::CommsList::iterator iter = readable.begin(); iter != readable.end(); ++iter ) {
{ if ( UdpInetServer *socket = dynamic_cast<UdpInetServer *>(*iter) ) {
if ( UdpInetServer *socket = dynamic_cast<UdpInetServer *>(*iter) )
{
int nBytes = socket->recv(buffer, sizeof(buffer)); int nBytes = socket->recv(buffer, sizeof(buffer));
Debug(4, "Got %d bytes on sd %d", nBytes, socket->getReadDesc()); Debug(4, "Got %d bytes on sd %d", nBytes, socket->getReadDesc());
if ( nBytes ) if ( nBytes ) {
{
recvPacket(buffer, nBytes); recvPacket(buffer, nBytes);
} } else {
else
{
mStop = true; mStop = true;
break; break;
} }
} } else {
else
{
Panic("Barfed"); Panic("Barfed");
} }
} } // end foreach commsList
} }
rtpDataSocket.close(); rtpDataSocket.close();
mRtspThread.stop(); mRtspThread.stop();
return( 0 ); return 0;
} }
#endif // HAVE_LIBAVFORMAT #endif // HAVE_LIBAVFORMAT

View File

@ -109,15 +109,15 @@ bool RtpSource::updateSeq( uint16_t seq ) {
if ( mProbation == 0 ) { if ( mProbation == 0 ) {
init(seq); init(seq);
mReceivedPackets++; mReceivedPackets++;
return( true ); return true;
} }
} else { } else {
Warning("Sequence in probation %d, out of sequence", mProbation); Warning("Sequence in probation %d, out of sequence", mProbation);
mProbation = MIN_SEQUENTIAL - 1; mProbation = MIN_SEQUENTIAL - 1;
mMaxSeq = seq; mMaxSeq = seq;
return( false ); return false;
} }
return( true ); return true;
} else if ( uDelta < MAX_DROPOUT ) { } else if ( uDelta < MAX_DROPOUT ) {
if ( uDelta == 1 ) { if ( uDelta == 1 ) {
Debug(4, "Packet in sequence, gap %d", uDelta); Debug(4, "Packet in sequence, gap %d", uDelta);
@ -142,12 +142,12 @@ bool RtpSource::updateSeq( uint16_t seq ) {
init(seq); init(seq);
} else { } else {
mBadSeq = (seq + 1) & (RTP_SEQ_MOD-1); mBadSeq = (seq + 1) & (RTP_SEQ_MOD-1);
return( false ); return false;
} }
} else { } else {
Warning("Packet duplicate or reordered, gap %d", uDelta); Warning("Packet duplicate or reordered, gap %d", uDelta);
// duplicate or reordered packet // duplicate or reordered packet
return( false ); return false;
} }
mReceivedPackets++; mReceivedPackets++;
return( uDelta==1?true:false ); return( uDelta==1?true:false );
@ -155,12 +155,17 @@ bool RtpSource::updateSeq( uint16_t seq ) {
void RtpSource::updateJitter( const RtpDataHeader *header ) { void RtpSource::updateJitter( const RtpDataHeader *header ) {
if ( mRtpFactor > 0 ) { if ( mRtpFactor > 0 ) {
Debug( 5, "Delta rtp = %.6f", tvDiffSec( mBaseTimeReal ) );
uint32_t localTimeRtp = mBaseTimeRtp + uint32_t(tvDiffSec(mBaseTimeReal) * mRtpFactor); uint32_t localTimeRtp = mBaseTimeRtp + uint32_t(tvDiffSec(mBaseTimeReal) * mRtpFactor);
Debug( 5, "Local RTP time = %x", localTimeRtp );
Debug( 5, "Packet RTP time = %x", ntohl(header->timestampN) );
uint32_t packetTransit = localTimeRtp - ntohl(header->timestampN); uint32_t packetTransit = localTimeRtp - ntohl(header->timestampN);
Debug( 5, "Packet transit RTP time = %x", packetTransit );
Debug(5, "Delta rtp = %.6f\n"
"Local RTP time = %x",
"Packet RTP time = %x",
"Packet transit RTP time = %x",
tvDiffSec(mBaseTimeReal),
localTimeRtp,
ntohl(header->timestampN),
packetTransit);
if ( mTransit > 0 ) { if ( mTransit > 0 ) {
// Jitter // Jitter
@ -178,7 +183,10 @@ void RtpSource::updateJitter( const RtpDataHeader *header ) {
Debug(5, "RTP Jitter: %d", mJitter); Debug(5, "RTP Jitter: %d", mJitter);
} }
void RtpSource::updateRtcpData( uint32_t ntpTimeSecs, uint32_t ntpTimeFrac, uint32_t rtpTime ) { void RtpSource::updateRtcpData(
uint32_t ntpTimeSecs,
uint32_t ntpTimeFrac,
uint32_t rtpTime) {
struct timeval ntpTime = tvMake(ntpTimeSecs, suseconds_t((USEC_PER_SEC*(ntpTimeFrac>>16))/(1<<16))); struct timeval ntpTime = tvMake(ntpTimeSecs, suseconds_t((USEC_PER_SEC*(ntpTimeFrac>>16))/(1<<16)));
Debug(5, "ntpTime: %ld.%06ld, rtpTime: %x", ntpTime.tv_sec, ntpTime.tv_usec, rtpTime); Debug(5, "ntpTime: %ld.%06ld, rtpTime: %x", ntpTime.tv_sec, ntpTime.tv_usec, rtpTime);
@ -188,19 +196,17 @@ void RtpSource::updateRtcpData( uint32_t ntpTimeSecs, uint32_t ntpTimeFrac, uint
mBaseTimeNtp = ntpTime; mBaseTimeNtp = ntpTime;
mBaseTimeRtp = rtpTime; mBaseTimeRtp = rtpTime;
} else if ( !mRtpClock ) { } else if ( !mRtpClock ) {
Debug( 5, "lastSrNtpTime: %ld.%06ld, rtpTime: %x", mLastSrTimeNtp.tv_sec, mLastSrTimeNtp.tv_usec, rtpTime ); Debug(5, "lastSrNtpTime: %ld.%06ld, rtpTime: %x"
Debug( 5, "ntpTime: %ld.%06ld, rtpTime: %x", ntpTime.tv_sec, ntpTime.tv_usec, rtpTime ); "ntpTime: %ld.%06ld, rtpTime: %x",
mLastSrTimeNtp.tv_sec, mLastSrTimeNtp.tv_usec, rtpTime,
ntpTime.tv_sec, ntpTime.tv_usec, rtpTime);
double diffNtpTime = tvDiffSec( mBaseTimeNtp, ntpTime ); double diffNtpTime = tvDiffSec( mBaseTimeNtp, ntpTime );
uint32_t diffRtpTime = rtpTime - mBaseTimeRtp; uint32_t diffRtpTime = rtpTime - mBaseTimeRtp;
//Debug( 5, "Real-diff: %.6f", diffRealTime );
Debug( 5, "NTP-diff: %.6f", diffNtpTime );
Debug( 5, "RTP-diff: %d", diffRtpTime );
mRtpFactor = (uint32_t)(diffRtpTime / diffNtpTime); mRtpFactor = (uint32_t)(diffRtpTime / diffNtpTime);
Debug( 5, "RTPfactor: %d", mRtpFactor ); Debug( 5, "NTP-diff: %.6f RTP-diff: %d RTPfactor: %d",
diffNtpTime, diffRtpTime, mRtpFactor);
} }
mLastSrTimeNtpSecs = ntpTimeSecs; mLastSrTimeNtpSecs = ntpTimeSecs;
mLastSrTimeNtpFrac = ntpTimeFrac; mLastSrTimeNtpFrac = ntpTimeFrac;
@ -211,28 +217,34 @@ void RtpSource::updateRtcpData( uint32_t ntpTimeSecs, uint32_t ntpTimeFrac, uint
void RtpSource::updateRtcpStats() { void RtpSource::updateRtcpStats() {
uint32_t extendedMax = mCycles + mMaxSeq; uint32_t extendedMax = mCycles + mMaxSeq;
mExpectedPackets = extendedMax - mBaseSeq + 1; mExpectedPackets = extendedMax - mBaseSeq + 1;
Debug( 5, "Expected packets = %d", mExpectedPackets );
// The number of packets lost is defined to be the number of packets // The number of packets lost is defined to be the number of packets
// expected less the number of packets actually received: // expected less the number of packets actually received:
mLostPackets = mExpectedPackets - mReceivedPackets; mLostPackets = mExpectedPackets - mReceivedPackets;
Debug( 5, "Lost packets = %d", mLostPackets );
uint32_t expectedInterval = mExpectedPackets - mExpectedPrior; uint32_t expectedInterval = mExpectedPackets - mExpectedPrior;
Debug( 5, "Expected interval = %d", expectedInterval );
mExpectedPrior = mExpectedPackets; mExpectedPrior = mExpectedPackets;
uint32_t receivedInterval = mReceivedPackets - mReceivedPrior; uint32_t receivedInterval = mReceivedPackets - mReceivedPrior;
Debug( 5, "Received interval = %d", receivedInterval );
mReceivedPrior = mReceivedPackets; mReceivedPrior = mReceivedPackets;
uint32_t lostInterval = expectedInterval - receivedInterval; uint32_t lostInterval = expectedInterval - receivedInterval;
Debug( 5, "Lost interval = %d", lostInterval );
if ( expectedInterval == 0 || lostInterval <= 0 ) if ( expectedInterval == 0 || lostInterval <= 0 )
mLostFraction = 0; mLostFraction = 0;
else else
mLostFraction = (lostInterval << 8) / expectedInterval; mLostFraction = (lostInterval << 8) / expectedInterval;
Debug( 5, "Lost fraction = %d", mLostFraction );
Debug(5,
"Expected packets = %d\n",
"Lost packets = %d\n",
"Expected interval = %d\n",
"Received interval = %d\n",
"Lost interval = %d\n",
"Lost fraction = %d\n",
mExpectedPackets,
mLostPackets,
expectedInterval,
receivedInterval,
lostInterval,
mLostFraction);
} }
bool RtpSource::handlePacket(const unsigned char *packet, size_t packetLen) { bool RtpSource::handlePacket(const unsigned char *packet, size_t packetLen) {
@ -288,7 +300,8 @@ bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen ) {
if ( !mFrame.size() ) if ( !mFrame.size() )
mFrame.append("\x0\x0\x1", 3); mFrame.append("\x0\x0\x1", 3);
} // end if H264 } // end if H264
mFrame.append( packet+rtpHeaderSize+extraHeader, packetLen-rtpHeaderSize-extraHeader ); mFrame.append(packet+rtpHeaderSize+extraHeader,
packetLen-rtpHeaderSize-extraHeader);
} else { } else {
Debug(3, "NOT H264 frame: type is %d", mCodecId); Debug(3, "NOT H264 frame: type is %d", mCodecId);
} }
@ -307,7 +320,7 @@ bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen ) {
for ( int count = 0; !mFrameProcessed.getUpdatedValue( 1 ); count++ ) for ( int count = 0; !mFrameProcessed.getUpdatedValue( 1 ); count++ )
if ( count > 1 ) if ( count > 1 )
return( false ); return false;
} }
mFrameCount++; mFrameCount++;
} else { } else {

View File

@ -88,13 +88,13 @@ bool RtspThread::recvResponse( std::string &response ) {
return false; return false;
} }
return true; return true;
} // end RtspThread::recResponse } // end RtspThread::recvResponse
int RtspThread::requestPorts() { int RtspThread::requestPorts() {
if ( !smMinDataPort ) { if ( !smMinDataPort ) {
char sql[ZM_SQL_SML_BUFSIZ]; char sql[ZM_SQL_SML_BUFSIZ];
//FIXME Why not load specifically by Id? This will get ineffeicient with a lot of monitors //FIXME Why not load specifically by Id? This will get ineffeicient with a lot of monitors
strncpy( sql, "select Id from Monitors where Function != 'None' and Type = 'Remote' and Protocol = 'rtsp' and Method = 'rtpUni' order by Id asc", sizeof(sql) ); strncpy(sql, "SELECT `Id` FROM `Monitors` WHERE `Function` != 'None' AND `Type` = 'Remote' AND `Protocol` = 'rtsp' AND `Method` = 'rtpUni' ORDER BY `Id` ASC", sizeof(sql));
if ( mysql_query(&dbconn, sql) ) { if ( mysql_query(&dbconn, sql) ) {
Error("Can't run query: %s", mysql_error(&dbconn)); Error("Can't run query: %s", mysql_error(&dbconn));
exit(mysql_errno(&dbconn)); exit(mysql_errno(&dbconn));
@ -177,13 +177,14 @@ RtspThread::RtspThread(
mSsrc = rand(); mSsrc = rand();
Debug(2, "RTSP Local SSRC is %x", mSsrc); Debug(2, "RTSP Local SSRC is %x, url is %s", mSsrc, mUrl.c_str());
if ( mMethod == RTP_RTSP_HTTP ) if ( mMethod == RTP_RTSP_HTTP )
mHttpSession = stringtf("%d", rand()); mHttpSession = stringtf("%d", rand());
mNeedAuth = false; mNeedAuth = false;
StringVector parts = split(auth, ":"); StringVector parts = split(auth, ":");
Debug(2, "# of auth parts %d", parts.size());
if ( parts.size() > 1 ) if ( parts.size() > 1 )
mAuthenticator = new zm::Authenticator(parts[0], parts[1]); mAuthenticator = new zm::Authenticator(parts[0], parts[1]);
else else
@ -204,6 +205,7 @@ RtspThread::~RtspThread() {
mSessDesc = NULL; mSessDesc = NULL;
} }
delete mAuthenticator; delete mAuthenticator;
mAuthenticator = NULL;
} }
int RtspThread::run() { int RtspThread::run() {
@ -222,7 +224,6 @@ int RtspThread::run() {
//Debug( 4, "Drained %d bytes from RTSP socket", response.size() ); //Debug( 4, "Drained %d bytes from RTSP socket", response.size() );
//} //}
bool authTried = false; bool authTried = false;
if ( mMethod == RTP_RTSP_HTTP ) { if ( mMethod == RTP_RTSP_HTTP ) {
if ( !mRtspSocket2.connect(mHost.c_str(), mPort.c_str()) ) if ( !mRtspSocket2.connect(mHost.c_str(), mPort.c_str()) )
@ -245,8 +246,7 @@ int RtspThread::run() {
message += mAuthenticator->getAuthHeader("GET", mPath); message += mAuthenticator->getAuthHeader("GET", mPath);
authTried = true; authTried = true;
} }
message += "Accept: application/x-rtsp-tunnelled\r\n"; message += "Accept: application/x-rtsp-tunnelled\r\n\r\n";
message += "\r\n";
Debug(2, "Sending HTTP message: %s", message.c_str()); Debug(2, "Sending HTTP message: %s", message.c_str());
if ( mRtspSocket.send(message.c_str(), message.size()) != (int)message.length() ) { if ( mRtspSocket.send(message.c_str(), message.size()) != (int)message.length() ) {
Error("Unable to send message '%s': %s", message.c_str(), strerror(errno)); Error("Unable to send message '%s': %s", message.c_str(), strerror(errno));
@ -299,9 +299,9 @@ int RtspThread::run() {
Debug(2, "Sending HTTP message: %s", message.c_str()); Debug(2, "Sending HTTP message: %s", message.c_str());
if ( mRtspSocket2.send(message.c_str(), message.size()) != (int)message.length() ) { if ( mRtspSocket2.send(message.c_str(), message.size()) != (int)message.length() ) {
Error("Unable to send message '%s': %s", message.c_str(), strerror(errno)); Error("Unable to send message '%s': %s", message.c_str(), strerror(errno));
return( -1 ); return -1;
}
} }
} // end if ( mMethod == RTP_RTSP_HTTP )
std::string localHost = ""; std::string localHost = "";
int localPorts[2] = { 0, 0 }; int localPorts[2] = { 0, 0 };
@ -341,8 +341,8 @@ int RtspThread::run() {
if ( mNeedAuth ) if ( mNeedAuth )
authTried = true; authTried = true;
sendCommand(message); sendCommand(message);
// FIXME WHy sleep 1? // FIXME Why sleep 1?
sleep(1); usleep(10000);
res = recvResponse(response); res = recvResponse(response);
if ( !res && respCode==401 ) if ( !res && respCode==401 )
mNeedAuth = true; mNeedAuth = true;
@ -600,7 +600,8 @@ int RtspThread::run() {
while( !mStop ) { while( !mStop ) {
now = time(NULL); now = time(NULL);
// Send a keepalive message if the server supports this feature and we are close to the timeout expiration // Send a keepalive message if the server supports this feature and we are close to the timeout expiration
Debug(5, "sendkeepalive %d, timeout %d, now: %d last: %d since: %d", sendKeepalive, timeout, now, lastKeepalive, (now-lastKeepalive) ); Debug(5, "sendkeepalive %d, timeout %d, now: %d last: %d since: %d",
sendKeepalive, timeout, now, lastKeepalive, (now-lastKeepalive) );
if ( sendKeepalive && (timeout > 0) && ((now-lastKeepalive) > (timeout-5)) ) { if ( sendKeepalive && (timeout > 0) && ((now-lastKeepalive) > (timeout-5)) ) {
if ( !sendCommand( message ) ) if ( !sendCommand( message ) )
return( -1 ); return( -1 );
@ -681,7 +682,6 @@ Debug(5, "sendkeepalive %d, timeout %d, now: %d last: %d since: %d", sendKeepali
Debug(4, "Got %d bytes on data channel %d, packet length is %d", buffer.size(), channel, len); Debug(4, "Got %d bytes on data channel %d, packet length is %d", buffer.size(), channel, len);
Hexdump(4, (char *)buffer, 16); Hexdump(4, (char *)buffer, 16);
rtpDataThread.recvPacket(buffer+4, len); rtpDataThread.recvPacket(buffer+4, len);
Debug( 4, "Received" );
} else if ( channel == remoteChannels[1] ) { } else if ( channel == remoteChannels[1] ) {
// len = ntohs( *((unsigned short *)(buffer+2)) ); // len = ntohs( *((unsigned short *)(buffer+2)) );
// Debug( 4, "Got %d bytes on control channel %d", nBytes, channel ); // Debug( 4, "Got %d bytes on control channel %d", nBytes, channel );

View File

@ -56,8 +56,7 @@ void Authenticator::reset() {
fAuthMethod = AUTH_UNDEFINED; fAuthMethod = AUTH_UNDEFINED;
} }
void Authenticator::authHandleHeader(std::string headerData) void Authenticator::authHandleHeader(std::string headerData) {
{
const char* basic_match = "Basic "; const char* basic_match = "Basic ";
const char* digest_match = "Digest "; const char* digest_match = "Digest ";
size_t digest_match_len = strlen(digest_match); size_t digest_match_len = strlen(digest_match);
@ -92,7 +91,7 @@ void Authenticator::authHandleHeader(std::string headerData)
Debug(2, "Auth data completed. User: %s, realm: %s, nonce: %s, qop: %s", Debug(2, "Auth data completed. User: %s, realm: %s, nonce: %s, qop: %s",
username().c_str(), fRealm.c_str(), fNonce.c_str(), fQop.c_str()); username().c_str(), fRealm.c_str(), fNonce.c_str(), fQop.c_str());
} }
} } // end void Authenticator::authHandleHeader(std::string headerData)
std::string Authenticator::quote( const std::string &src ) { std::string Authenticator::quote( const std::string &src ) {
return replaceAll(replaceAll(src, "\\", "\\\\"), "\"", "\\\""); return replaceAll(replaceAll(src, "\\", "\\\\"), "\"", "\\\"");
@ -208,8 +207,8 @@ void Authenticator::checkAuthResponse(std::string &response) {
if ( strncasecmp(lines[i].c_str(), authenticate_match, authenticate_match_len) == 0 ) { if ( strncasecmp(lines[i].c_str(), authenticate_match, authenticate_match_len) == 0 ) {
authLine = lines[i]; authLine = lines[i];
Debug( 2, "Found auth line at %d", i); Debug(2, "Found auth line at %d:", i);
break; //break;
} }
} }
if ( !authLine.empty() ) { if ( !authLine.empty() ) {
@ -218,6 +217,6 @@ void Authenticator::checkAuthResponse(std::string &response) {
} else { } else {
Debug(2, "Didn't find auth line in %s", authLine.c_str()); Debug(2, "Didn't find auth line in %s", authLine.c_str());
} }
} } // end void Authenticator::checkAuthResponse(std::string &response)
} // namespace zm } // namespace zm

View File

@ -376,6 +376,9 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const {
#endif #endif
else else
Warning("Unknown media_type %s", type.c_str()); Warning("Unknown media_type %s", type.c_str());
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
stream->codecpar->codec_type = codec_context->codec_type;
#endif
#if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) #if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103)
std::string codec_name; std::string codec_name;

View File

@ -124,17 +124,24 @@ bool Condition::wait( int secs ) {
// Locking done outside of this function // Locking done outside of this function
Debug(8, "Waiting for %d seconds", secs); Debug(8, "Waiting for %d seconds", secs);
struct timespec timeout = getTimeout(secs); struct timespec timeout = getTimeout(secs);
if ( pthread_cond_timedwait( &mCondition, mMutex.getMutex(), &timeout ) < 0 && errno != ETIMEDOUT ) if (
( pthread_cond_timedwait(&mCondition, mMutex.getMutex(), &timeout) < 0 )
&&
( errno != ETIMEDOUT )
)
throw ThreadException(stringtf("Unable to timedwait pthread condition: %s", strerror(errno))); throw ThreadException(stringtf("Unable to timedwait pthread condition: %s", strerror(errno)));
return( errno != ETIMEDOUT ); return errno != ETIMEDOUT;
} }
bool Condition::wait( double secs ) { bool Condition::wait( double secs ) {
// Locking done outside of this function // Locking done outside of this function
struct timespec timeout = getTimeout( secs ); struct timespec timeout = getTimeout( secs );
if ( pthread_cond_timedwait( &mCondition, mMutex.getMutex(), &timeout ) < 0 && errno != ETIMEDOUT ) if (
(pthread_cond_timedwait( &mCondition, mMutex.getMutex(), &timeout ) < 0)
&&
(errno != ETIMEDOUT) )
throw ThreadException( stringtf( "Unable to timedwait pthread condition: %s", strerror(errno) ) ); throw ThreadException( stringtf( "Unable to timedwait pthread condition: %s", strerror(errno) ) );
return( errno != ETIMEDOUT ); return errno != ETIMEDOUT;
} }
void Condition::signal() { void Condition::signal() {

View File

@ -57,7 +57,9 @@ private:
pthread_t pid() { return( pthread_self() ); } pthread_t pid() { return( pthread_self() ); }
#endif #endif
public: public:
explicit ThreadException( const std::string &message ) : Exception( stringtf("(%d) ", (long int)pid())+message ) { explicit ThreadException(const std::string &message) :
Exception(stringtf("(%d) ", (long int)pid())+message)
{
} }
}; };
@ -169,30 +171,28 @@ private:
mutable Condition mCondition; mutable Condition mCondition;
public: public:
__attribute__((used)) ThreadData() : mValue(0), mCondition( mMutex ) { __attribute__((used)) ThreadData() :
mValue(0), mCondition(mMutex)
{
mChanged = false; mChanged = false;
} }
explicit __attribute__((used)) ThreadData( T value ) : mValue( value ), mCondition( mMutex ) { explicit __attribute__((used)) ThreadData(T value) :
mValue(value), mCondition(mMutex) {
mChanged = false; mChanged = false;
} }
//~ThreadData() {}
__attribute__((used)) operator T() const __attribute__((used)) operator T() const {
{ return getValue();
return( getValue() );
} }
__attribute__((used)) const T operator=( const T value ) __attribute__((used)) const T operator=( const T value ) {
{ return setValue(value);
return( setValue( value ) );
} }
__attribute__((used)) const T getValueImmediate() const __attribute__((used)) const T getValueImmediate() const {
{ return mValue;
return( mValue );
} }
__attribute__((used)) T setValueImmediate( const T value ) __attribute__((used)) T setValueImmediate( const T value ) {
{ return mValue = value;
return( mValue = value );
} }
__attribute__((used)) const T getValue() const; __attribute__((used)) const T getValue() const;
__attribute__((used)) T setValue( const T value ); __attribute__((used)) T setValue( const T value );

View File

@ -19,7 +19,7 @@ $statusData = array(
'limit' => 1, 'limit' => 1,
'elements' => array( 'elements' => array(
'MonitorCount' => array( 'sql' => 'count(*)' ), 'MonitorCount' => array( 'sql' => 'count(*)' ),
'ActiveMonitorCount' => array( 'sql' => 'count(if(Function != \'None\',1,NULL))' ), 'ActiveMonitorCount' => array( 'sql' => 'count(if(`Function` != \'None\',1,NULL))' ),
'State' => array( 'func' => 'daemonCheck()?'.translate('Running').':'.translate('Stopped') ), 'State' => array( 'func' => 'daemonCheck()?'.translate('Running').':'.translate('Stopped') ),
'Load' => array( 'func' => 'getLoad()' ), 'Load' => array( 'func' => 'getLoad()' ),
'Disk' => array( 'func' => 'getDiskPercent()' ), 'Disk' => array( 'func' => 'getDiskPercent()' ),
@ -246,7 +246,7 @@ function collectData() {
if ( isset($elementData['sql']) ) if ( isset($elementData['sql']) )
$fieldSql[] = $elementData['sql'].' as '.$element; $fieldSql[] = $elementData['sql'].' as '.$element;
else else
$fieldSql[] = $element; $fieldSql[] = '`'.$element.'`';
if ( isset($elementData['table']) && isset($elementData['join']) ) { if ( isset($elementData['table']) && isset($elementData['join']) ) {
$joinSql[] = 'left join '.$elementData['table'].' on '.$elementData['join']; $joinSql[] = 'left join '.$elementData['table'].' on '.$elementData['join'];
} }
@ -296,7 +296,7 @@ function collectData() {
$sql .= ' '.strtoupper($matches[3]); $sql .= ' '.strtoupper($matches[3]);
} }
} else { } else {
ZM\Error("Sort field didn't match regexp $sort_field"); ZM\Error('Sort field didn\'t match regexp '.$sort_field);
} }
} # end foreach sort field } # end foreach sort field
} # end if has sort } # end if has sort

View File

@ -32,7 +32,7 @@ if ( !empty($_REQUEST['group']) ) {
$mid = !empty($_REQUEST['mid']) ? validInt($_REQUEST['mid']) : 0; $mid = !empty($_REQUEST['mid']) ? validInt($_REQUEST['mid']) : 0;
$sql = "SELECT m.* FROM Monitors m WHERE m.Function != 'None' AND m.Controllable = 1$groupSql ORDER BY Sequence"; $sql = "SELECT m.* FROM Monitors m WHERE m.`Function` != 'None' AND m.`Controllable` = 1$groupSql ORDER BY `Sequence`";
$mids = array(); $mids = array();
foreach ( dbFetchAll($sql, false, $params) as $row ) { foreach ( dbFetchAll($sql, false, $params) as $row ) {
if ( !visibleMonitor($row['Id']) ) { if ( !visibleMonitor($row['Id']) ) {

View File

@ -71,7 +71,7 @@ if ( canView('Control') && $monitor->Type() == 'Local' ) {
<?php <?php
} }
?> ?>
<div id="scaleControl"><?php echo translate('Scale') ?>: <?php echo htmlSelect('scale', $scales, $scale); ?></div> <div id="scaleControl"><?php echo translate('Scale').': '.htmlSelect('scale', $scales, $scale); ?></div>
</div> </div>
<div id="closeControl"><a href="#" data-on-click="<?php echo $popup ? 'closeWindow' : 'backWindow' ?>"><?php echo $popup ? translate('Close') : translate('Back') ?></a></div> <div id="closeControl"><a href="#" data-on-click="<?php echo $popup ? 'closeWindow' : 'backWindow' ?>"><?php echo $popup ? translate('Close') : translate('Back') ?></a></div>
</div> </div>