diff --git a/.travis.yml b/.travis.yml index b085414b5..7a51c271c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,6 +41,7 @@ env: - 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=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=stretch DOCKER_REPO=iconzm/packpack - SMPFLAGS=-j4 OS=debian DIST=buster DOCKER_REPO=iconzm/packpack diff --git a/distros/ubuntu1604/zoneminder.postinst b/distros/ubuntu1604/zoneminder.postinst index d3983950b..7b7af708b 100644 --- a/distros/ubuntu1604/zoneminder.postinst +++ b/distros/ubuntu1604/zoneminder.postinst @@ -19,6 +19,10 @@ if [ "$1" = "configure" ]; then echo "The cgi module is not enabled in apache2. I am enabling it using a2enmod cgi." a2enmod cgi 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 @@ -61,11 +65,10 @@ if [ "$1" = "configure" ]; then exit 1; fi # 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 - else - 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 "CREATE USER '${ZM_DB_USER}'@localhost IDENTIFIED BY '${ZM_DB_PASS}';" | mysql --defaults-file=/etc/mysql/debian.cnf mysql fi + 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 zmupdate.pl --nointeractive zmupdate.pl --nointeractive -f diff --git a/distros/ubuntu2004/control b/distros/ubuntu2004/control index 4e7c53503..7304d34fb 100644 --- a/distros/ubuntu2004/control +++ b/distros/ubuntu2004/control @@ -46,7 +46,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} ,javascript-common ,libmp4v2-2, libx264-155 ,libswscale5 - ,libswresample4 + ,libswresample3 ,ffmpeg ,libdate-manip-perl, libmime-lite-perl, libmime-tools-perl ,libdbd-mysql-perl diff --git a/distros/ubuntu2004/zoneminder.postinst b/distros/ubuntu2004/zoneminder.postinst index d3983950b..a7f8f3131 100644 --- a/distros/ubuntu2004/zoneminder.postinst +++ b/distros/ubuntu2004/zoneminder.postinst @@ -61,11 +61,10 @@ if [ "$1" = "configure" ]; then exit 1; fi # 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 - else - 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 "CREATE USER '${ZM_DB_USER}'@localhost IDENTIFIED BY '${ZM_DB_PASS}';" | mysql --defaults-file=/etc/mysql/debian.cnf mysql fi + 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 zmupdate.pl --nointeractive zmupdate.pl --nointeractive -f diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/DCS5020L.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/DCS5020L.pm index 4f14e787a..2b2cf3fd2 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/DCS5020L.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/DCS5020L.pm @@ -69,9 +69,9 @@ sub sendCmd { 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); my $res = $self->{ua}->request($req); diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in index b2824ced1..a801fea1d 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in @@ -185,16 +185,12 @@ sub discover { push @responses, $response; }; -## try both soap versions - my $uuid_gen = Data::UUID->new(); if ( ( ! $soap_version ) or ( $soap_version eq '1.1' ) ) { my %services; - if ( $verbose ) { - print "Probing for SOAP 1.1\n"; - } + print "Probing for SOAP 1.1\n" if $verbose; my $svc_discover = WSDiscovery10::Interfaces::WSDiscovery::WSDiscoveryPort->new({ # no_dispatch => '1', }); @@ -218,7 +214,7 @@ sub discover { To => { value => 'urn:schemas-xmlsoap-org:ws:2005:04:discovery' }, }) ); - print $result . "\n" if $verbose; + print $result."\n" if $verbose; push @results, interpret_messages($svc_discover, \%services, @responses); @responses = (); @@ -226,9 +222,7 @@ sub discover { if ( ( ! $soap_version ) or ( $soap_version eq '1.2' ) ) { my %services; - if ( $verbose ) { - print "Probing for SOAP 1.2\n"; - } + print "Probing for SOAP 1.2\n" if $verbose; my $svc_discover = WSDiscovery10::Interfaces::WSDiscovery::WSDiscoveryPort->new({ # no_dispatch => '1', }); @@ -256,7 +250,7 @@ sub discover { To => { value => 'urn:schemas-xmlsoap-org:ws:2005:04:discovery' }, }) ); - print $result . "\n" if $verbose; + print $result."\n" if $verbose; push @results, interpret_messages($svc_discover, \%services, @responses); } # end if doing soap 1.2 return @results; @@ -281,19 +275,16 @@ sub profiles { } my @profiles; - foreach my $profile ( @{ $result->get_Profiles() } ) { - + my $token = $profile->attr()->get_token() ; + my $Name = $profile->get_Name(); my $VideoEncoderConfiguration = $profile->get_VideoEncoderConfiguration(); if ( ! $VideoEncoderConfiguration ) { - print "Unknown profile $token $Name.\n"; + print "No VideoEncoderConfiguration in profile $token $Name.\n"; next; } - my $token = $profile->attr()->get_token() ; - my $Name = $profile->get_Name(); - # Specification gives conflicting values for unicast stream types, try both. # http://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl#op.GetStreamUri foreach my $streamtype ( 'RTP_unicast', 'RTP-Unicast', 'RTP-multicast', 'RTP-Multicast' ) { @@ -305,25 +296,25 @@ sub profiles { }, }, ProfileToken => $token, # ReferenceToken - } ); - next if ! ( $StreamUri and $StreamUri->can('get_MediaUri') ); - my $MediaUri = $StreamUri->get_MediaUri(); - next if ! $MediaUri; - my $Uri = $MediaUri->get_Uri(); - next if ! $Uri; - my $Resolution = $VideoEncoderConfiguration->get_Resolution(); - my $Width = $Resolution ? $Resolution->get_Width() : 0; - my $Height = $Resolution ? $Resolution->get_Height() : 0; + } ); + next if ! ( $StreamUri and $StreamUri->can('get_MediaUri') ); + my $MediaUri = $StreamUri->get_MediaUri(); + next if ! $MediaUri; + my $Uri = $MediaUri->get_Uri(); + next if ! $Uri; + my $Resolution = $VideoEncoderConfiguration->get_Resolution(); + my $Width = $Resolution ? $Resolution->get_Width() : 0; + my $Height = $Resolution ? $Resolution->get_Height() : 0; -push @profiles, { - print join(', ', $token, - $Name, - $VideoEncoderConfiguration->get_Encoding(), - $Width, - $Height, - $VideoEncoderConfiguration->get_RateControl()->get_FrameRateLimit(), - $Uri, - ) . "\n"; + push @profiles, [ + $token, + $Name, + $VideoEncoderConfiguration->get_Encoding(), + $Width, + $Height, + $VideoEncoderConfiguration->get_RateControl()->get_FrameRateLimit(), + $Uri, + ]; } # end foreach streamtype } # end foreach profile diff --git a/src/zm.h b/src/zm.h index ad0f89584..60fa67711 100644 --- a/src/zm.h +++ b/src/zm.h @@ -22,6 +22,7 @@ #define ZM_H #include "zm_config.h" +#include "zm_signal.h" #ifdef SOLARIS #undef DEFAULT_TYPE // pthread defines this which breaks StreamType DEFAULT_TYPE #include // define strerror() and friends diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 1631749fb..a92f38652 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -468,7 +468,7 @@ void av_packet_rescale_ts( } #endif -bool is_video_stream( AVStream * stream ) { +bool is_video_stream(const AVStream * stream) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) if ( stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ) { #else @@ -480,10 +480,14 @@ bool is_video_stream( AVStream * stream ) { #endif 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; } -bool is_video_context( AVCodecContext *codec_context ) { +bool is_video_context(const AVCodecContext *codec_context ) { return #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) ( codec_context->codec_type == AVMEDIA_TYPE_VIDEO ); @@ -492,7 +496,7 @@ bool is_video_context( AVCodecContext *codec_context ) { #endif } -bool is_audio_stream( AVStream * stream ) { +bool is_audio_stream(const AVStream * stream ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) if ( stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO ) { #else @@ -507,7 +511,7 @@ bool is_audio_stream( AVStream * stream ) { return false; } -bool is_audio_context( AVCodecContext *codec_context ) { +bool is_audio_context(const AVCodecContext *codec_context ) { return #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) ( codec_context->codec_type == AVMEDIA_TYPE_AUDIO ); diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index 73afff3e3..4705b707c 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -372,10 +372,10 @@ void zm_dump_codecpar(const AVCodecParameters *par); int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt); -bool is_video_stream(AVStream *); -bool is_audio_stream(AVStream *); -bool is_video_context(AVCodec *); -bool is_audio_context(AVCodec *); +bool is_video_stream(const AVStream *); +bool is_audio_stream(const AVStream *); +bool is_video_context(const AVCodec *); +bool is_audio_context(const AVCodec *); int zm_receive_packet(AVCodecContext *context, AVPacket &packet); diff --git a/src/zm_remote_camera_rtsp.cpp b/src/zm_remote_camera_rtsp.cpp index ee308c30e..b011c742d 100644 --- a/src/zm_remote_camera_rtsp.cpp +++ b/src/zm_remote_camera_rtsp.cpp @@ -151,11 +151,13 @@ int RemoteCameraRtsp::Disconnect() { int RemoteCameraRtsp::PrimeCapture() { 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); } - if ( !rtspThread->hasSources() ) - Fatal("No RTSP sources"); + if ( !rtspThread->hasSources() ) { + Error("No RTSP sources"); + return -1; + } Debug(2, "Got sources"); @@ -167,38 +169,21 @@ int RemoteCameraRtsp::PrimeCapture() { // Find the first video stream. for ( unsigned int i = 0; i < mFormatContext->nb_streams; i++ ) { -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - 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 ( is_video_stream(mFormatContext->streams[i]) ) { if ( mVideoStreamId == -1 ) { mVideoStreamId = i; continue; } else { Debug(2, "Have another video stream."); } - } else -#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 - { + } else if ( is_audio_stream(mFormatContext->streams[i]) ) { if ( mAudioStreamId == -1 ) { mAudioStreamId = i; } else { Debug(2, "Have another audio stream."); } } 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 @@ -288,7 +273,6 @@ int RemoteCameraRtsp::Capture( Image &image ) { if ( rtspThread->getFrame(buffer) ) { Debug(3, "Read frame %d bytes", buffer.size()); - Debug(4, "Address %p", buffer.head()); Hexdump(4, buffer.head(), 16); if ( !buffer.size() ) @@ -310,14 +294,15 @@ int RemoteCameraRtsp::Capture( Image &image ) { // IDR buffer += lastSps; buffer += lastPps; + } else { + Debug(2, "Unknown nalType %d", nalType); } } else { Debug(3, "Not an h264 packet"); } av_init_packet(&packet); - - while ( !frameComplete && (buffer.size() > 0) ) { + while ( (!frameComplete) && (buffer.size() > 0) ) { packet.data = buffer.head(); packet.size = buffer.size(); bytes += packet.size; @@ -330,6 +315,7 @@ int RemoteCameraRtsp::Capture( Image &image ) { buffer.clear(); continue; } + frameComplete = true; Debug(2, "Frame: %d - %d/%d", frameCount, len, buffer.size()); //if ( buffer.size() < 400 ) //Hexdump( 0, buffer.head(), buffer.size() ); diff --git a/src/zm_rtp_data.cpp b/src/zm_rtp_data.cpp index 4fbf0cd04..de7c732d3 100644 --- a/src/zm_rtp_data.cpp +++ b/src/zm_rtp_data.cpp @@ -27,98 +27,81 @@ #include -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; rtpHeader = (RtpDataHeader *)packet; - //printf( "D: " ); - //for ( int i = 0; i < 32; i++ ) - //printf( "%02x ", (unsigned char)packet[i] ); - //printf( "\n" ); - - Debug( 5, "Ver: %d", rtpHeader->version ); - Debug( 5, "P: %d", rtpHeader->p ); - Debug( 5, "Pt: %d", rtpHeader->pt ); - 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) ); + 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)); //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 ); + if ( mRtpSource.getSsrc() && (ssrc != mRtpSource.getSsrc()) ) { + Warning("Discarding packet for unrecognised ssrc %lx", ssrc); + return false; } - return( mRtpSource.handlePacket( packet, packetLen ) ); + return mRtpSource.handlePacket(packet, packetLen); } -int RtpDataThread::run() -{ - Debug( 2, "Starting data thread %d on port %d", mRtpSource.getSsrc(), mRtpSource.getLocalDataPort() ); +int RtpDataThread::run() { + Debug(2, "Starting data thread %d on port %d", + mRtpSource.getSsrc(), mRtpSource.getLocalDataPort()); SockAddrInet localAddr; UdpInetServer rtpDataSocket; if ( mRtpSource.getLocalHost() != "" ) { - if ( !rtpDataSocket.bind( mRtpSource.getLocalHost().c_str(), mRtpSource.getLocalDataPort() ) ) - Fatal( "Failed to bind RTP server" ); - Debug( 3, "Bound to %s:%d", mRtpSource.getLocalHost().c_str(), mRtpSource.getLocalDataPort() ); - } - else - { - if ( !rtpDataSocket.bind( 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() ); + if ( !rtpDataSocket.bind(mRtpSource.getLocalHost().c_str(), mRtpSource.getLocalDataPort()) ) + Fatal("Failed to bind RTP server"); + } else { + if ( !rtpDataSocket.bind( + 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()); - Select select( 3 ); - select.addReader( &rtpDataSocket ); + Select select(3); + select.addReader(&rtpDataSocket); unsigned char buffer[ZM_NETWORK_BUFSIZ]; - while ( !mStop && select.wait() >= 0 ) - { - if ( mStop ) - break; + while ( !zm_terminate && !mStop && (select.wait() >= 0) ) { Select::CommsList readable = select.getReadable(); - if ( readable.size() == 0 ) - { - Error( "RTP timed out" ); + if ( readable.size() == 0 ) { + Error("RTP timed out"); mStop = true; break; } - for ( Select::CommsList::iterator iter = readable.begin(); iter != readable.end(); ++iter ) - { - if ( UdpInetServer *socket = dynamic_cast(*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 - { + for ( Select::CommsList::iterator iter = readable.begin(); iter != readable.end(); ++iter ) { + if ( UdpInetServer *socket = dynamic_cast(*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 { mStop = true; break; } + } else { + Panic("Barfed"); } - else - { - Panic( "Barfed" ); - } - } + } // end foreach commsList } rtpDataSocket.close(); mRtspThread.stop(); - return( 0 ); + return 0; } #endif // HAVE_LIBAVFORMAT diff --git a/src/zm_rtp_source.cpp b/src/zm_rtp_source.cpp index 131d32d7e..0ac963947 100644 --- a/src/zm_rtp_source.cpp +++ b/src/zm_rtp_source.cpp @@ -37,25 +37,25 @@ RtpSource::RtpSource( uint32_t rtpClock, uint32_t rtpTime, _AVCODECID codecId ) : - mId( id ), - mSsrc( ssrc ), - mLocalHost( localHost ), - mRemoteHost( remoteHost ), - mRtpClock( rtpClock ), - mCodecId( codecId ), - mFrame( 65536 ), - mFrameCount( 0 ), - mFrameGood( true ), - mFrameReady( false ), - mFrameProcessed( false ) + mId(id), + mSsrc(ssrc), + mLocalHost(localHost), + mRemoteHost(remoteHost), + mRtpClock(rtpClock), + mCodecId(codecId), + mFrame(65536), + mFrameCount(0), + mFrameGood(true), + mFrameReady(false), + mFrameProcessed(false) { char hostname[256] = ""; - gethostname( hostname, sizeof(hostname) ); + gethostname(hostname, sizeof(hostname)); - mCname = stringtf( "zm-%d@%s", mId, hostname ); - Debug( 3, "RTP CName = %s", mCname.c_str() ); + mCname = stringtf("zm-%d@%s", mId, hostname); + Debug(3, "RTP CName = %s", mCname.c_str()); - init( seq ); + init(seq); mMaxSeq = seq - 1; mProbation = MIN_SEQUENTIAL; @@ -79,7 +79,7 @@ RtpSource::RtpSource( Warning("The device is using a codec (%d) that may not be supported. Do not be surprised if things don't work.", mCodecId); } -void RtpSource::init( uint16_t seq ) { +void RtpSource::init(uint16_t seq) { Debug(3, "Initialising sequence"); mBaseSeq = seq; mMaxSeq = seq; @@ -93,36 +93,36 @@ void RtpSource::init( uint16_t seq ) { mTransit = 0; } -bool RtpSource::updateSeq( uint16_t seq ) { +bool RtpSource::updateSeq(uint16_t seq) { uint16_t uDelta = seq - mMaxSeq; // Source is not valid until MIN_SEQUENTIAL packets with // sequential sequence numbers have been received. - Debug( 5, "Seq: %d", seq ); + Debug(5, "Seq: %d", seq); if ( mProbation) { // packet is in sequence - if ( seq == mMaxSeq + 1) { - Debug( 3, "Sequence in probation %d, in sequence", mProbation ); + if ( seq == mMaxSeq + 1 ) { + Debug(3, "Sequence in probation %d, in sequence", mProbation); mProbation--; mMaxSeq = seq; if ( mProbation == 0 ) { - init( seq ); + init(seq); mReceivedPackets++; - return( true ); + return true; } } else { - Warning( "Sequence in probation %d, out of sequence", mProbation ); + Warning("Sequence in probation %d, out of sequence", mProbation); mProbation = MIN_SEQUENTIAL - 1; mMaxSeq = seq; - return( false ); + return false; } - return( true ); + return true; } else if ( uDelta < MAX_DROPOUT ) { if ( uDelta == 1 ) { - Debug( 4, "Packet in sequence, gap %d", uDelta ); + Debug(4, "Packet in sequence, gap %d", uDelta); } else { - Warning( "Packet in sequence, gap %d", uDelta ); + Warning("Packet in sequence, gap %d", uDelta); } // in order, with permissible gap @@ -132,22 +132,22 @@ bool RtpSource::updateSeq( uint16_t seq ) { } mMaxSeq = seq; } else if ( uDelta <= RTP_SEQ_MOD - MAX_MISORDER ) { - Warning( "Packet out of sequence, gap %d", uDelta ); + Warning("Packet out of sequence, gap %d", uDelta); // the sequence number made a very large jump if ( seq == mBadSeq ) { - Debug( 3, "Restarting sequence" ); + Debug(3, "Restarting sequence"); // Two sequential packets -- assume that the other side // restarted without telling us so just re-sync // (i.e., pretend this was the first packet). - init( seq ); + init(seq); } else { mBadSeq = (seq + 1) & (RTP_SEQ_MOD-1); - return( false ); + return false; } } else { - Warning( "Packet duplicate or reordered, gap %d", uDelta ); + Warning("Packet duplicate or reordered, gap %d", uDelta); // duplicate or reordered packet - return( false ); + return false; } mReceivedPackets++; return( uDelta==1?true:false ); @@ -155,17 +155,22 @@ bool RtpSource::updateSeq( uint16_t seq ) { void RtpSource::updateJitter( const RtpDataHeader *header ) { if ( mRtpFactor > 0 ) { - Debug( 5, "Delta rtp = %.6f", tvDiffSec( mBaseTimeReal ) ); - 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 localTimeRtp = mBaseTimeRtp + uint32_t(tvDiffSec(mBaseTimeReal) * mRtpFactor); 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 ) { // Jitter int d = packetTransit - mTransit; - Debug( 5, "Jitter D = %d", d ); + Debug(5, "Jitter D = %d", d); if ( d < 0 ) d = -d; //mJitter += (1./16.) * ((double)d - mJitter); @@ -175,32 +180,33 @@ void RtpSource::updateJitter( const RtpDataHeader *header ) { } else { mJitter = 0; } - Debug( 5, "RTP Jitter: %d", mJitter ); + Debug(5, "RTP Jitter: %d", mJitter); } -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)) ); +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))); - 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); if ( mBaseTimeNtp.tv_sec == 0 ) { mBaseTimeReal = tvNow(); mBaseTimeNtp = ntpTime; mBaseTimeRtp = rtpTime; } else if ( !mRtpClock ) { - Debug( 5, "lastSrNtpTime: %ld.%06ld, rtpTime: %x", mLastSrTimeNtp.tv_sec, mLastSrTimeNtp.tv_usec, rtpTime ); - Debug( 5, "ntpTime: %ld.%06ld, rtpTime: %x", ntpTime.tv_sec, ntpTime.tv_usec, rtpTime ); + Debug(5, "lastSrNtpTime: %ld.%06ld, rtpTime: %x" + "ntpTime: %ld.%06ld, rtpTime: %x", + mLastSrTimeNtp.tv_sec, mLastSrTimeNtp.tv_usec, rtpTime, + ntpTime.tv_sec, ntpTime.tv_usec, rtpTime); double diffNtpTime = tvDiffSec( mBaseTimeNtp, ntpTime ); 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); - Debug( 5, "RTPfactor: %d", mRtpFactor ); + Debug( 5, "NTP-diff: %.6f RTP-diff: %d RTPfactor: %d", + diffNtpTime, diffRtpTime, mRtpFactor); } mLastSrTimeNtpSecs = ntpTimeSecs; mLastSrTimeNtpFrac = ntpTimeFrac; @@ -211,31 +217,37 @@ void RtpSource::updateRtcpData( uint32_t ntpTimeSecs, uint32_t ntpTimeFrac, uint void RtpSource::updateRtcpStats() { uint32_t extendedMax = mCycles + mMaxSeq; mExpectedPackets = extendedMax - mBaseSeq + 1; - - Debug( 5, "Expected packets = %d", mExpectedPackets ); - // The number of packets lost is defined to be the number of packets // expected less the number of packets actually received: mLostPackets = mExpectedPackets - mReceivedPackets; - Debug( 5, "Lost packets = %d", mLostPackets ); - uint32_t expectedInterval = mExpectedPackets - mExpectedPrior; - Debug( 5, "Expected interval = %d", expectedInterval ); mExpectedPrior = mExpectedPackets; uint32_t receivedInterval = mReceivedPackets - mReceivedPrior; - Debug( 5, "Received interval = %d", receivedInterval ); mReceivedPrior = mReceivedPackets; uint32_t lostInterval = expectedInterval - receivedInterval; - Debug( 5, "Lost interval = %d", lostInterval ); if ( expectedInterval == 0 || lostInterval <= 0 ) mLostFraction = 0; else 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) { const RtpDataHeader *rtpHeader; rtpHeader = (RtpDataHeader *)packet; int rtpHeaderSize = 12 + rtpHeader->cc * 4; @@ -248,15 +260,15 @@ bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen ) { // that there is no marker bit by changing the number of bits in the payload type field. bool thisM = rtpHeader->m || h264FragmentEnd; - if ( updateSeq( ntohs(rtpHeader->seqN) ) ) { - Hexdump( 4, packet+rtpHeaderSize, 16 ); + if ( updateSeq(ntohs(rtpHeader->seqN)) ) { + Hexdump(4, packet+rtpHeaderSize, 16); if ( mFrameGood ) { int extraHeader = 0; if ( mCodecId == AV_CODEC_ID_H264 ) { int nalType = (packet[rtpHeaderSize] & 0x1f); - Debug( 3, "Have H264 frame: nal type is %d", nalType ); + Debug(3, "Have H264 frame: nal type is %d", nalType); switch (nalType) { case 24: // STAP-A @@ -281,45 +293,46 @@ bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen ) { extraHeader = 2; break; default: - Debug(3, "Unhandled nalType %d", nalType ); + Debug(3, "Unhandled nalType %d", nalType); } // Append NAL frame start code if ( !mFrame.size() ) - mFrame.append( "\x0\x0\x1", 3 ); + mFrame.append("\x0\x0\x1", 3); } // end if H264 - mFrame.append( packet+rtpHeaderSize+extraHeader, packetLen-rtpHeaderSize-extraHeader ); + mFrame.append(packet+rtpHeaderSize+extraHeader, + packetLen-rtpHeaderSize-extraHeader); } else { - Debug( 3, "NOT H264 frame: type is %d", mCodecId ); + Debug(3, "NOT H264 frame: type is %d", mCodecId); } - Hexdump( 4, mFrame.head(), 16 ); + Hexdump(4, mFrame.head(), 16); if ( thisM ) { if ( mFrameGood ) { - Debug( 3, "Got new frame %d, %d bytes", mFrameCount, mFrame.size() ); + Debug(3, "Got new frame %d, %d bytes", mFrameCount, mFrame.size()); - mFrameProcessed.setValueImmediate( false ); - mFrameReady.updateValueSignal( true ); + mFrameProcessed.setValueImmediate(false); + mFrameReady.updateValueSignal(true); if ( !mFrameProcessed.getValueImmediate() ) { // What is the point of this for loop? Is it just me, or will it call getUpdatedValue once or twice? Could it not be better written as // if ( ! mFrameProcessed.getUpdatedValue( 1 ) && mFrameProcessed.getUpdatedValue( 1 ) ) return false; for ( int count = 0; !mFrameProcessed.getUpdatedValue( 1 ); count++ ) - if( count > 1 ) - return( false ); + if ( count > 1 ) + return false; } mFrameCount++; } else { - Warning( "Discarding incomplete frame %d, %d bytes", mFrameCount, mFrame.size() ); + Warning("Discarding incomplete frame %d, %d bytes", mFrameCount, mFrame.size()); } mFrame.clear(); } } else { if ( mFrame.size() ) { - Warning( "Discarding partial frame %d, %d bytes", mFrameCount, mFrame.size() ); + Warning("Discarding partial frame %d, %d bytes", mFrameCount, mFrame.size()); } else { - Warning( "Discarding frame %d", mFrameCount ); + Warning("Discarding frame %d", mFrameCount); } mFrameGood = false; mFrame.clear(); @@ -335,7 +348,7 @@ bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen ) { return true; } -bool RtpSource::getFrame( Buffer &buffer ) { +bool RtpSource::getFrame(Buffer &buffer) { if ( !mFrameReady.getValueImmediate() ) { Debug(3, "Getting frame but not ready"); // Allow for a couple of spurious returns diff --git a/src/zm_rtp_source.h b/src/zm_rtp_source.h index b53fb975b..f91ba20f7 100644 --- a/src/zm_rtp_source.h +++ b/src/zm_rtp_source.h @@ -94,7 +94,7 @@ private: ThreadData mFrameProcessed; private: - void init( uint16_t seq ); + void init(uint16_t seq); public: RtpSource( int id, const std::string &localHost, int localPortBase, const std::string &remoteHost, int remotePortBase, uint32_t ssrc, uint16_t seq, uint32_t rtpClock, uint32_t rtpTime, _AVCODECID codecId ); diff --git a/src/zm_rtsp.cpp b/src/zm_rtsp.cpp index 5e2858e4f..59d8ab171 100644 --- a/src/zm_rtsp.cpp +++ b/src/zm_rtsp.cpp @@ -34,17 +34,17 @@ int RtspThread::smMinDataPort = 0; int RtspThread::smMaxDataPort = 0; -RtspThread::PortSet RtspThread::smAssignedPorts; +RtspThread::PortSet RtspThread::smAssignedPorts; -bool RtspThread::sendCommand( std::string message ) { +bool RtspThread::sendCommand(std::string message) { if ( mNeedAuth ) { - StringVector parts = split( message, " " ); - if (parts.size() > 1) + StringVector parts = split(message, " "); + if ( parts.size() > 1 ) message += mAuthenticator->getAuthHeader(parts[0], parts[1]); } - message += stringtf( "User-Agent: ZoneMinder/%s\r\n", ZM_VERSION ); - message += stringtf( "CSeq: %d\r\n\r\n", ++mSeq ); - Debug( 2, "Sending RTSP message: %s", message.c_str() ); + message += stringtf("User-Agent: ZoneMinder/%s\r\n", ZM_VERSION); + message += stringtf("CSeq: %d\r\n\r\n", ++mSeq); + Debug(2, "Sending RTSP message: %s", message.c_str()); if ( mMethod == RTP_RTSP_HTTP ) { message = base64Encode(message); Debug(2, "Sending encoded RTSP message: %s", message.c_str()); @@ -61,8 +61,8 @@ bool RtspThread::sendCommand( std::string message ) { return true; } -bool RtspThread::recvResponse( std::string &response ) { - if ( mRtspSocket.recv( response ) < 0 ) +bool RtspThread::recvResponse(std::string &response) { + if ( mRtspSocket.recv(response) < 0 ) Error("Recv failed; %s", strerror(errno)); Debug(2, "Received RTSP response: %s (%zd bytes)", response.c_str(), response.size()); float respVer = 0; @@ -74,12 +74,12 @@ bool RtspThread::recvResponse( std::string &response ) { } else { Error("Response parse failure, %zd bytes follow", response.size()); if ( response.size() ) - Hexdump( Logger::ERROR, response.data(), min(response.size(),16) ); + Hexdump(Logger::ERROR, response.data(), min(response.size(),16)); } return false; } if ( respCode == 401 ) { - Debug( 2, "Got 401 access denied response code, check WWW-Authenticate header and retry"); + Debug(2, "Got 401 access denied response code, check WWW-Authenticate header and retry"); mAuthenticator->checkAuthResponse(response); mNeedAuth = true; return false; @@ -88,24 +88,24 @@ bool RtspThread::recvResponse( std::string &response ) { return false; } return true; -} // end RtspThread::recResponse +} // end RtspThread::recvResponse int RtspThread::requestPorts() { if ( !smMinDataPort ) { char sql[ZM_SQL_SML_BUFSIZ]; //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) ); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + 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) ) { + Error("Can't run query: %s", mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); } - MYSQL_RES *result = mysql_store_result( &dbconn ); + MYSQL_RES *result = mysql_store_result(&dbconn); if ( !result ) { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + Error("Can't use query result: %s", mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); } - int nMonitors = mysql_num_rows( result ); + int nMonitors = mysql_num_rows(result); int position = 0; if ( nMonitors ) { for ( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) { @@ -124,7 +124,7 @@ int RtspThread::requestPorts() { int portRange = int(((config.max_rtp_port-config.min_rtp_port)+1)/nMonitors); smMinDataPort = config.min_rtp_port + (position * portRange); smMaxDataPort = smMinDataPort + portRange - 1; - Debug( 2, "Assigned RTP port range is %d-%d", smMinDataPort, smMaxDataPort ); + Debug(2, "Assigned RTP port range is %d-%d", smMinDataPort, smMaxDataPort); } for ( int i = smMinDataPort; i <= smMaxDataPort; i++ ) { PortSet::const_iterator iter = smAssignedPorts.find(i); @@ -137,7 +137,7 @@ int RtspThread::requestPorts() { return -1; } -void RtspThread::releasePorts( int port ) { +void RtspThread::releasePorts(int port) { if ( port > 0 ) smAssignedPorts.erase(port); } @@ -151,21 +151,21 @@ RtspThread::RtspThread( const std::string &path, const std::string &auth, bool rtsp_describe) : - mId( id ), - mMethod( method ), - mProtocol( protocol ), - mHost( host ), - mPort( port ), - mPath( path ), - mRtspDescribe( rtsp_describe ), - mSessDesc( 0 ), - mFormatContext( 0 ), - mSeq( 0 ), - mSession( 0 ), - mSsrc( 0 ), - mDist( UNDEFINED ), - mRtpTime( 0 ), - mStop( false ) + mId(id), + mMethod(method), + mProtocol(protocol), + mHost(host), + mPort(port), + mPath(path), + mRtspDescribe(rtsp_describe), + mSessDesc(0), + mFormatContext(0), + mSeq(0), + mSession(0), + mSsrc(0), + mDist(UNDEFINED), + mRtpTime(0), + mStop(false) { mUrl = mProtocol+"://"+mHost+":"+mPort; if ( !mPath.empty() ) { @@ -177,14 +177,15 @@ RtspThread::RtspThread( 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 ) mHttpSession = stringtf("%d", rand()); mNeedAuth = false; - StringVector parts = split(auth,":"); - if (parts.size() > 1) + StringVector parts = split(auth, ":"); + Debug(2, "# of auth parts %d", parts.size()); + if ( parts.size() > 1 ) mAuthenticator = new zm::Authenticator(parts[0], parts[1]); else mAuthenticator = new zm::Authenticator(parts[0], ""); @@ -193,9 +194,9 @@ RtspThread::RtspThread( RtspThread::~RtspThread() { if ( mFormatContext ) { #if LIBAVFORMAT_VERSION_CHECK(52, 96, 0, 96, 0) - avformat_free_context( mFormatContext ); + avformat_free_context(mFormatContext); #else - av_free_format_context( mFormatContext ); + av_free_format_context(mFormatContext); #endif mFormatContext = NULL; } @@ -204,16 +205,17 @@ RtspThread::~RtspThread() { mSessDesc = NULL; } delete mAuthenticator; + mAuthenticator = NULL; } int RtspThread::run() { std::string message; std::string response; - response.reserve( ZM_NETWORK_BUFSIZ ); + response.reserve(ZM_NETWORK_BUFSIZ); - if ( !mRtspSocket.connect( mHost.c_str(), mPort.c_str() ) ) - Fatal( "Unable to connect RTSP socket" ); + if ( !mRtspSocket.connect(mHost.c_str(), mPort.c_str()) ) + Fatal("Unable to connect RTSP socket"); //Select select( 0.25 ); //select.addReader( &mRtspSocket ); //while ( select.wait() ) @@ -221,7 +223,6 @@ int RtspThread::run() { //mRtspSocket.recv( response ); //Debug( 4, "Drained %d bytes from RTSP socket", response.size() ); //} - bool authTried = false; if ( mMethod == RTP_RTSP_HTTP ) { @@ -245,14 +246,13 @@ int RtspThread::run() { message += mAuthenticator->getAuthHeader("GET", mPath); authTried = true; } - message += "Accept: application/x-rtsp-tunnelled\r\n"; - message += "\r\n"; - Debug( 2, "Sending HTTP message: %s", message.c_str() ); - if ( mRtspSocket.send( message.c_str(), message.size() ) != (int)message.length() ) { + message += "Accept: application/x-rtsp-tunnelled\r\n\r\n"; + Debug(2, "Sending HTTP message: %s", message.c_str()); + if ( mRtspSocket.send(message.c_str(), message.size()) != (int)message.length() ) { Error("Unable to send message '%s': %s", message.c_str(), strerror(errno)); return -1; } - if ( mRtspSocket.recv( response ) < 0 ) { + if ( mRtspSocket.recv(response) < 0 ) { Error("Recv failed; %s", strerror(errno)); return -1; } @@ -260,13 +260,13 @@ int RtspThread::run() { Debug(2, "Received HTTP response: %s (%zd bytes)", response.c_str(), response.size()); float respVer = 0; respCode = -1; - if ( sscanf( response.c_str(), "HTTP/%f %3d %[^\r\n]\r\n", &respVer, &respCode, respText ) != 3 ) { + if ( sscanf(response.c_str(), "HTTP/%f %3d %[^\r\n]\r\n", &respVer, &respCode, respText) != 3 ) { if ( isalnum(response[0]) ) { - Error( "Response parse failure in '%s'", response.c_str() ); + Error("Response parse failure in '%s'", response.c_str()); } else { - Error( "Response parse failure, %zd bytes follow", response.size() ); + Error("Response parse failure, %zd bytes follow", response.size()); if ( response.size() ) - Hexdump( Logger::ERROR, response.data(), min(response.size(),16) ); + Hexdump(Logger::ERROR, response.data(), min(response.size(),16)); } return -1; } @@ -296,25 +296,25 @@ int RtspThread::run() { message += "Content-Length: 32767\r\n"; message += "Content-Type: application/x-rtsp-tunnelled\r\n"; message += "\r\n"; - Debug( 2, "Sending HTTP message: %s", message.c_str() ); - if ( mRtspSocket2.send( message.c_str(), message.size() ) != (int)message.length() ) { - Error( "Unable to send message '%s': %s", message.c_str(), strerror(errno) ); - return( -1 ); + Debug(2, "Sending HTTP message: %s", message.c_str()); + if ( mRtspSocket2.send(message.c_str(), message.size()) != (int)message.length() ) { + Error("Unable to send message '%s': %s", message.c_str(), strerror(errno)); + return -1; } - } + } // end if ( mMethod == RTP_RTSP_HTTP ) std::string localHost = ""; int localPorts[2] = { 0, 0 }; // Request supported RTSP commands by the server message = "OPTIONS "+mUrl+" RTSP/1.0\r\n"; - if ( !sendCommand( message ) ) + if ( !sendCommand(message) ) return -1; // A negative return here may indicate auth failure, but we will have setup the auth mechanisms so we need to retry. if ( !recvResponse(response) ) { if ( mNeedAuth ) { - Debug( 2, "Resending OPTIONS due to possible auth requirement" ); + Debug(2, "Resending OPTIONS due to possible auth requirement"); if ( !sendCommand(message) ) return -1; if ( !recvResponse(response) ) @@ -338,11 +338,11 @@ int RtspThread::run() { message = "DESCRIBE "+mUrl+" RTSP/1.0\r\n"; bool res; do { - if (mNeedAuth) + if ( mNeedAuth ) authTried = true; sendCommand(message); - // FIXME WHy sleep 1? - sleep(1); + // FIXME Why sleep 1? + usleep(10000); res = recvResponse(response); if ( !res && respCode==401 ) mNeedAuth = true; @@ -600,7 +600,8 @@ int RtspThread::run() { while( !mStop ) { now = time(NULL); // 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 ( !sendCommand( message ) ) return( -1 ); @@ -678,22 +679,21 @@ Debug(5, "sendkeepalive %d, timeout %d, now: %d last: %d since: %d", sendKeepali break; } if ( channel == remoteChannels[0] ) { - Debug( 4, "Got %d bytes on data channel %d, packet length is %d", buffer.size(), channel, len ); - Hexdump( 4, (char *)buffer, 16 ); - rtpDataThread.recvPacket( buffer+4, len ); - Debug( 4, "Received" ); + Debug(4, "Got %d bytes on data channel %d, packet length is %d", buffer.size(), channel, len); + Hexdump(4, (char *)buffer, 16); + rtpDataThread.recvPacket(buffer+4, len); } else if ( channel == remoteChannels[1] ) { // 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, packet length is %d", buffer.size(), channel, len ); - Hexdump( 4, (char *)buffer, 16 ); - rtpCtrlThread.recvPackets( buffer+4, len ); + Debug(4, "Got %d bytes on control channel %d, packet length is %d", buffer.size(), channel, len); + Hexdump(4, (char *)buffer, 16); + rtpCtrlThread.recvPackets(buffer+4, len); } else { - Error( "Unexpected channel selector %d in RTSP interleaved data", buffer[1] ); + Error("Unexpected channel selector %d in RTSP interleaved data", buffer[1]); buffer.clear(); break; } - buffer.consume( len+4 ); + buffer.consume(len+4); nBytes -= len+4; } else { if ( keepaliveResponse.compare( 0, keepaliveResponse.size(), (char *)buffer, keepaliveResponse.size() ) == 0 ) { diff --git a/src/zm_rtsp_auth.cpp b/src/zm_rtsp_auth.cpp index 2f8b2c3ce..5cd05063c 100644 --- a/src/zm_rtsp_auth.cpp +++ b/src/zm_rtsp_auth.cpp @@ -56,21 +56,20 @@ void Authenticator::reset() { fAuthMethod = AUTH_UNDEFINED; } -void Authenticator::authHandleHeader(std::string headerData) -{ +void Authenticator::authHandleHeader(std::string headerData) { const char* basic_match = "Basic "; const char* digest_match = "Digest "; size_t digest_match_len = strlen(digest_match); // Check if basic auth - if ( strncasecmp(headerData.c_str(),basic_match,strlen(basic_match)) == 0 ) { + if ( strncasecmp(headerData.c_str(), basic_match, strlen(basic_match)) == 0 ) { fAuthMethod = AUTH_BASIC; Debug(2, "Set authMethod to Basic"); } // Check if digest auth - else if (strncasecmp( headerData.c_str(),digest_match,digest_match_len ) == 0) { + else if ( strncasecmp(headerData.c_str(), digest_match, digest_match_len) == 0) { fAuthMethod = AUTH_DIGEST; - Debug( 2, "Set authMethod to Digest"); + Debug(2, "Set authMethod to Digest"); StringVector subparts = split(headerData.substr(digest_match_len, headerData.length() - digest_match_len), ","); // subparts are key="value" for ( size_t i = 0; i < subparts.size(); i++ ) { @@ -92,7 +91,7 @@ void Authenticator::authHandleHeader(std::string headerData) 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()); } -} +} // end void Authenticator::authHandleHeader(std::string headerData) std::string Authenticator::quote( const std::string &src ) { return replaceAll(replaceAll(src, "\\", "\\\\"), "\"", "\\\""); @@ -100,13 +99,13 @@ std::string Authenticator::quote( const std::string &src ) { std::string Authenticator::getAuthHeader(std::string method, std::string uri) { std::string result = "Authorization: "; - if (fAuthMethod == AUTH_BASIC) { - result += "Basic " + base64Encode( username() + ":" + password() ); - } else if (fAuthMethod == AUTH_DIGEST) { + if ( fAuthMethod == AUTH_BASIC ) { + result += "Basic " + base64Encode(username() + ":" + password()); + } else if ( fAuthMethod == AUTH_DIGEST ) { result += std::string("Digest ") + "username=\"" + quote(username()) + "\", realm=\"" + quote(realm()) + "\", " + "nonce=\"" + quote(nonce()) + "\", uri=\"" + quote(uri) + "\""; - if ( ! fQop.empty() ) { + if ( !fQop.empty() ) { result += ", qop=" + fQop; result += ", nc=" + stringtf("%08x",nc); result += ", cnonce=\"" + fCnonce + "\""; @@ -203,21 +202,21 @@ void Authenticator::checkAuthResponse(std::string &response) { for ( size_t i = 0; i < lines.size(); i++ ) { // stop at end of headers - if (lines[i].length()==0) + if ( lines[i].length() == 0 ) break; - 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]; - Debug( 2, "Found auth line at %d", i); - break; + Debug(2, "Found auth line at %d:", i); + //break; } } - if (!authLine.empty()) { - Debug( 2, "Analyze auth line %s", authLine.c_str()); - authHandleHeader( trimSpaces(authLine.substr(authenticate_match_len,authLine.length()-authenticate_match_len)) ); + if ( !authLine.empty() ) { + Debug(2, "Analyze auth line %s", authLine.c_str()); + authHandleHeader(trimSpaces(authLine.substr(authenticate_match_len, authLine.length()-authenticate_match_len))); } 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 diff --git a/src/zm_sdp.cpp b/src/zm_sdp.cpp index c7bf1b578..15f6ad5e3 100644 --- a/src/zm_sdp.cpp +++ b/src/zm_sdp.cpp @@ -376,6 +376,9 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const { #endif else 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) std::string codec_name; diff --git a/src/zm_thread.cpp b/src/zm_thread.cpp index 03d048bea..ac493a3fe 100644 --- a/src/zm_thread.cpp +++ b/src/zm_thread.cpp @@ -116,25 +116,32 @@ Condition::~Condition() { void Condition::wait() { // Locking done outside of this function - if ( pthread_cond_wait( &mCondition, mMutex.getMutex() ) < 0 ) - throw ThreadException( stringtf( "Unable to wait pthread condition: %s", strerror(errno) ) ); + if ( pthread_cond_wait(&mCondition, mMutex.getMutex()) < 0 ) + throw ThreadException(stringtf("Unable to wait pthread condition: %s", strerror(errno))); } -bool Condition::wait( int secs ) { +bool Condition::wait(int secs) { // Locking done outside of this function - Debug( 8, "Waiting for %d seconds", secs ); - struct timespec timeout = getTimeout( secs ); - if ( pthread_cond_timedwait( &mCondition, mMutex.getMutex(), &timeout ) < 0 && errno != ETIMEDOUT ) - throw ThreadException( stringtf( "Unable to timedwait pthread condition: %s", strerror(errno) ) ); - return( errno != ETIMEDOUT ); + Debug(8, "Waiting for %d seconds", secs); + struct timespec timeout = getTimeout(secs); + if ( + ( pthread_cond_timedwait(&mCondition, mMutex.getMutex(), &timeout) < 0 ) + && + ( errno != ETIMEDOUT ) + ) + throw ThreadException(stringtf("Unable to timedwait pthread condition: %s", strerror(errno))); + return errno != ETIMEDOUT; } bool Condition::wait( double secs ) { // Locking done outside of this function 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) ) ); - return( errno != ETIMEDOUT ); + return errno != ETIMEDOUT; } void Condition::signal() { @@ -177,11 +184,11 @@ template const T ThreadData::getUpdatedValue(double secs) const { mMutex.lock(); mChanged = false; //do { - mCondition.wait( secs ); + mCondition.wait(secs); //} while ( !mChanged ); const T valueCopy = mValue; mMutex.unlock(); - Debug(9, "Got value update, %p", this ); + Debug(9, "Got value update, %p", this); return valueCopy; } diff --git a/src/zm_thread.h b/src/zm_thread.h index 8cdfb892c..3f3e8c6b9 100644 --- a/src/zm_thread.h +++ b/src/zm_thread.h @@ -57,7 +57,9 @@ private: pthread_t pid() { return( pthread_self() ); } #endif 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,38 +171,36 @@ private: mutable Condition mCondition; public: - __attribute__((used)) ThreadData() : mValue(0), mCondition( mMutex ) { + __attribute__((used)) ThreadData() : + mValue(0), mCondition(mMutex) + { mChanged = false; } - explicit __attribute__((used)) ThreadData( T value ) : mValue( value ), mCondition( mMutex ) { + explicit __attribute__((used)) ThreadData(T value) : + mValue(value), mCondition(mMutex) { mChanged = false; } - //~ThreadData() {} - __attribute__((used)) operator T() const - { - return( getValue() ); + __attribute__((used)) operator T() const { + return getValue(); } - __attribute__((used)) const T operator=( const T value ) - { - return( setValue( value ) ); + __attribute__((used)) const T operator=( const T value ) { + return setValue(value); } - __attribute__((used)) const T getValueImmediate() const - { - return( mValue ); + __attribute__((used)) const T getValueImmediate() const { + return mValue; } - __attribute__((used)) T setValueImmediate( const T value ) - { - return( mValue = value ); + __attribute__((used)) T setValueImmediate( const T value ) { + return mValue = value; } __attribute__((used)) const T getValue() const; __attribute__((used)) T setValue( const T value ); __attribute__((used)) const T getUpdatedValue() const; - __attribute__((used)) const T getUpdatedValue( double secs ) const; - __attribute__((used)) const T getUpdatedValue( int secs ) const; - __attribute__((used)) void updateValueSignal( const T value ); - __attribute__((used)) void updateValueBroadcast( const T value ); + __attribute__((used)) const T getUpdatedValue(double secs) const; + __attribute__((used)) const T getUpdatedValue(int secs) const; + __attribute__((used)) void updateValueSignal(const T value); + __attribute__((used)) void updateValueBroadcast(const T value); }; class Thread { diff --git a/web/ajax/status.php b/web/ajax/status.php index d08948663..f90f24911 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -19,7 +19,7 @@ $statusData = array( 'limit' => 1, 'elements' => array( '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') ), 'Load' => array( 'func' => 'getLoad()' ), 'Disk' => array( 'func' => 'getDiskPercent()' ), @@ -211,17 +211,17 @@ function collectData() { $values = array(); $elements = &$entitySpec['elements']; - $lc_elements = array_change_key_case( $elements ); + $lc_elements = array_change_key_case($elements); $id = false; if ( isset($_REQUEST['id']) ) if ( !is_array($_REQUEST['id']) ) $id = array( validJsStr($_REQUEST['id']) ); else - $id = array_values( $_REQUEST['id'] ); + $id = array_values($_REQUEST['id']); if ( !isset($_REQUEST['element']) ) - $_REQUEST['element'] = array_keys( $elements ); + $_REQUEST['element'] = array_keys($elements); else if ( !is_array($_REQUEST['element']) ) $_REQUEST['element'] = array( validJsStr($_REQUEST['element']) ); @@ -235,18 +235,18 @@ function collectData() { foreach ( $_REQUEST['element'] as $element ) { if ( !($elementData = $lc_elements[strtolower($element)]) ) - ajaxError( 'Bad '.validJsStr($_REQUEST['entity']).' element '.$element ); + ajaxError('Bad '.validJsStr($_REQUEST['entity']).' element '.$element); if ( isset($elementData['func']) ) - $data[$element] = eval( 'return( '.$elementData['func'].' );' ); + $data[$element] = eval('return( '.$elementData['func'].' );'); else if ( isset($elementData['postFunc']) ) $postFuncs[$element] = $elementData['postFunc']; else if ( isset($elementData['zmu']) ) - $data[$element] = exec( escapeshellcmd( getZmuCommand( ' '.$elementData['zmu'] ) ) ); + $data[$element] = exec(escapeshellcmd(getZmuCommand(' '.$elementData['zmu']))); else { if ( isset($elementData['sql']) ) $fieldSql[] = $elementData['sql'].' as '.$element; else - $fieldSql[] = $element; + $fieldSql[] = '`'.$element.'`'; if ( isset($elementData['table']) && isset($elementData['join']) ) { $joinSql[] = 'left join '.$elementData['table'].' on '.$elementData['join']; } @@ -296,7 +296,7 @@ function collectData() { $sql .= ' '.strtoupper($matches[3]); } } 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 if has sort @@ -310,7 +310,7 @@ function collectData() { if ( !empty( $limit ) ) $sql .= ' limit '.$limit_offset.$limit; if ( isset($limit) && $limit == 1 ) { - if ( $sqlData = dbFetchOne( $sql, NULL, $values ) ) { + if ( $sqlData = dbFetchOne($sql, NULL, $values) ) { foreach ( $postFuncs as $element=>$func ) $sqlData[$element] = eval( 'return( '.$func.'( $sqlData ) );' ); $data = array_merge( $data, $sqlData ); diff --git a/web/skins/classic/views/control.php b/web/skins/classic/views/control.php index f2fe01f3f..9fad31c41 100644 --- a/web/skins/classic/views/control.php +++ b/web/skins/classic/views/control.php @@ -32,7 +32,7 @@ if ( !empty($_REQUEST['group']) ) { $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(); foreach ( dbFetchAll($sql, false, $params) as $row ) { if ( !visibleMonitor($row['Id']) ) { diff --git a/web/skins/classic/views/watch.php b/web/skins/classic/views/watch.php index e1f54e29d..70e5f410a 100644 --- a/web/skins/classic/views/watch.php +++ b/web/skins/classic/views/watch.php @@ -71,7 +71,7 @@ if ( canView('Control') && $monitor->Type() == 'Local' ) { -
:
+