2008-07-16 16:35:59 +08:00
|
|
|
//
|
2008-07-25 17:08:15 +08:00
|
|
|
// ZoneMinder RTP Source Class Implementation, $Date$, $Revision$
|
2008-07-25 17:33:23 +08:00
|
|
|
// Copyright (C) 2001-2008 Philip Coombes
|
2008-07-16 16:35:59 +08:00
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License
|
|
|
|
// as published by the Free Software Foundation; either version 2
|
|
|
|
// of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
2016-12-26 23:23:16 +08:00
|
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2008-07-16 16:35:59 +08:00
|
|
|
//
|
|
|
|
|
|
|
|
#include "zm_rtp_source.h"
|
|
|
|
|
|
|
|
#include "zm_time.h"
|
|
|
|
#include "zm_rtp_data.h"
|
|
|
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
2014-01-02 00:19:42 +08:00
|
|
|
#if HAVE_LIBAVCODEC
|
|
|
|
|
2019-04-29 00:05:32 +08:00
|
|
|
RtpSource::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 ) :
|
2020-05-08 01:41:29 +08:00
|
|
|
mId(id),
|
|
|
|
mSsrc(ssrc),
|
|
|
|
mLocalHost(localHost),
|
|
|
|
mRemoteHost(remoteHost),
|
|
|
|
mRtpClock(rtpClock),
|
|
|
|
mCodecId(codecId),
|
|
|
|
mFrame(65536),
|
|
|
|
mFrameCount(0),
|
|
|
|
mFrameGood(true),
|
|
|
|
mFrameReady(false),
|
|
|
|
mFrameProcessed(false)
|
2008-07-16 16:35:59 +08:00
|
|
|
{
|
2016-06-22 00:26:08 +08:00
|
|
|
char hostname[256] = "";
|
2020-05-08 01:41:29 +08:00
|
|
|
gethostname(hostname, sizeof(hostname));
|
2008-07-16 16:35:59 +08:00
|
|
|
|
2020-05-08 01:41:29 +08:00
|
|
|
mCname = stringtf("zm-%d@%s", mId, hostname);
|
|
|
|
Debug(3, "RTP CName = %s", mCname.c_str());
|
2008-07-16 16:35:59 +08:00
|
|
|
|
2020-05-08 01:41:29 +08:00
|
|
|
init(seq);
|
2016-06-22 00:26:08 +08:00
|
|
|
mMaxSeq = seq - 1;
|
|
|
|
mProbation = MIN_SEQUENTIAL;
|
2008-07-16 16:35:59 +08:00
|
|
|
|
2016-06-22 00:26:08 +08:00
|
|
|
mLocalPortChans[0] = localPortBase;
|
|
|
|
mLocalPortChans[1] = localPortBase+1;
|
2008-07-16 16:35:59 +08:00
|
|
|
|
2016-06-22 00:26:08 +08:00
|
|
|
mRemotePortChans[0] = remotePortBase;
|
|
|
|
mRemotePortChans[1] = remotePortBase+1;
|
2008-07-16 16:35:59 +08:00
|
|
|
|
2016-06-22 00:26:08 +08:00
|
|
|
mRtpFactor = mRtpClock;
|
2008-07-16 16:35:59 +08:00
|
|
|
|
2016-06-22 00:26:08 +08:00
|
|
|
mBaseTimeReal = tvNow();
|
|
|
|
mBaseTimeNtp = tvZero();
|
|
|
|
mBaseTimeRtp = rtpTime;
|
|
|
|
|
|
|
|
mLastSrTimeReal = tvZero();
|
|
|
|
mLastSrTimeNtp = tvZero();
|
|
|
|
mLastSrTimeRtp = 0;
|
2008-07-16 16:35:59 +08:00
|
|
|
|
2019-04-29 00:05:32 +08:00
|
|
|
if ( mCodecId != AV_CODEC_ID_H264 && mCodecId != AV_CODEC_ID_MPEG4 )
|
|
|
|
Warning("The device is using a codec (%d) that may not be supported. Do not be surprised if things don't work.", mCodecId);
|
2008-07-16 16:35:59 +08:00
|
|
|
}
|
|
|
|
|
2020-05-08 01:41:29 +08:00
|
|
|
void RtpSource::init(uint16_t seq) {
|
2019-04-29 00:05:32 +08:00
|
|
|
Debug(3, "Initialising sequence");
|
2016-06-22 00:26:08 +08:00
|
|
|
mBaseSeq = seq;
|
|
|
|
mMaxSeq = seq;
|
|
|
|
mBadSeq = RTP_SEQ_MOD + 1; // so seq == mBadSeq is false
|
|
|
|
mCycles = 0;
|
|
|
|
mReceivedPackets = 0;
|
|
|
|
mReceivedPrior = 0;
|
|
|
|
mExpectedPrior = 0;
|
|
|
|
// other initialization
|
|
|
|
mJitter = 0;
|
|
|
|
mTransit = 0;
|
2008-07-16 16:35:59 +08:00
|
|
|
}
|
|
|
|
|
2020-05-08 01:41:29 +08:00
|
|
|
bool RtpSource::updateSeq(uint16_t seq) {
|
2016-06-22 00:26:08 +08:00
|
|
|
uint16_t uDelta = seq - mMaxSeq;
|
2008-07-16 16:35:59 +08:00
|
|
|
|
2016-06-22 00:26:08 +08:00
|
|
|
// Source is not valid until MIN_SEQUENTIAL packets with
|
|
|
|
// sequential sequence numbers have been received.
|
2020-05-08 01:41:29 +08:00
|
|
|
Debug(5, "Seq: %d", seq);
|
2008-07-16 16:35:59 +08:00
|
|
|
|
2019-04-29 00:05:32 +08:00
|
|
|
if ( mProbation) {
|
2016-06-22 00:26:08 +08:00
|
|
|
// packet is in sequence
|
2020-05-08 01:41:29 +08:00
|
|
|
if ( seq == mMaxSeq + 1 ) {
|
|
|
|
Debug(3, "Sequence in probation %d, in sequence", mProbation);
|
2016-06-22 00:26:08 +08:00
|
|
|
mProbation--;
|
|
|
|
mMaxSeq = seq;
|
2019-04-29 00:05:32 +08:00
|
|
|
if ( mProbation == 0 ) {
|
2020-05-08 01:41:29 +08:00
|
|
|
init(seq);
|
2016-06-22 00:26:08 +08:00
|
|
|
mReceivedPackets++;
|
2020-05-08 01:41:29 +08:00
|
|
|
return true;
|
2016-06-22 00:26:08 +08:00
|
|
|
}
|
2019-04-29 00:05:32 +08:00
|
|
|
} else {
|
2020-05-08 01:41:29 +08:00
|
|
|
Warning("Sequence in probation %d, out of sequence", mProbation);
|
2016-06-22 00:26:08 +08:00
|
|
|
mProbation = MIN_SEQUENTIAL - 1;
|
|
|
|
mMaxSeq = seq;
|
2020-05-08 01:41:29 +08:00
|
|
|
return false;
|
2016-06-22 00:26:08 +08:00
|
|
|
}
|
2020-05-08 01:41:29 +08:00
|
|
|
return true;
|
2019-04-29 00:05:32 +08:00
|
|
|
} else if ( uDelta < MAX_DROPOUT ) {
|
|
|
|
if ( uDelta == 1 ) {
|
2020-05-08 01:41:29 +08:00
|
|
|
Debug(4, "Packet in sequence, gap %d", uDelta);
|
2019-04-29 00:05:32 +08:00
|
|
|
} else {
|
2020-05-08 01:41:29 +08:00
|
|
|
Warning("Packet in sequence, gap %d", uDelta);
|
2016-06-22 00:26:08 +08:00
|
|
|
}
|
2008-07-16 16:35:59 +08:00
|
|
|
|
2016-06-22 00:26:08 +08:00
|
|
|
// in order, with permissible gap
|
2019-04-29 00:05:32 +08:00
|
|
|
if ( seq < mMaxSeq ) {
|
2016-06-22 00:26:08 +08:00
|
|
|
// Sequence number wrapped - count another 64K cycle.
|
|
|
|
mCycles += RTP_SEQ_MOD;
|
2008-07-16 16:35:59 +08:00
|
|
|
}
|
2016-06-22 00:26:08 +08:00
|
|
|
mMaxSeq = seq;
|
2019-04-29 00:05:32 +08:00
|
|
|
} else if ( uDelta <= RTP_SEQ_MOD - MAX_MISORDER ) {
|
2020-05-08 01:41:29 +08:00
|
|
|
Warning("Packet out of sequence, gap %d", uDelta);
|
2016-06-22 00:26:08 +08:00
|
|
|
// the sequence number made a very large jump
|
2019-04-29 00:05:32 +08:00
|
|
|
if ( seq == mBadSeq ) {
|
2020-05-08 01:41:29 +08:00
|
|
|
Debug(3, "Restarting sequence");
|
2016-06-22 00:26:08 +08:00
|
|
|
// Two sequential packets -- assume that the other side
|
|
|
|
// restarted without telling us so just re-sync
|
|
|
|
// (i.e., pretend this was the first packet).
|
2020-05-08 01:41:29 +08:00
|
|
|
init(seq);
|
2019-04-29 00:05:32 +08:00
|
|
|
} else {
|
2016-06-22 00:26:08 +08:00
|
|
|
mBadSeq = (seq + 1) & (RTP_SEQ_MOD-1);
|
2020-05-08 01:41:29 +08:00
|
|
|
return false;
|
2008-07-16 16:35:59 +08:00
|
|
|
}
|
2019-04-29 00:05:32 +08:00
|
|
|
} else {
|
2020-05-08 01:41:29 +08:00
|
|
|
Warning("Packet duplicate or reordered, gap %d", uDelta);
|
2016-06-22 00:26:08 +08:00
|
|
|
// duplicate or reordered packet
|
2020-05-08 01:41:29 +08:00
|
|
|
return false;
|
2016-06-22 00:26:08 +08:00
|
|
|
}
|
|
|
|
mReceivedPackets++;
|
|
|
|
return( uDelta==1?true:false );
|
2008-07-16 16:35:59 +08:00
|
|
|
}
|
|
|
|
|
2019-04-29 00:05:32 +08:00
|
|
|
void RtpSource::updateJitter( const RtpDataHeader *header ) {
|
|
|
|
if ( mRtpFactor > 0 ) {
|
2020-05-08 01:41:29 +08:00
|
|
|
uint32_t localTimeRtp = mBaseTimeRtp + uint32_t(tvDiffSec(mBaseTimeReal) * mRtpFactor);
|
2016-06-22 00:26:08 +08:00
|
|
|
uint32_t packetTransit = localTimeRtp - ntohl(header->timestampN);
|
2020-05-08 01:41:29 +08:00
|
|
|
|
|
|
|
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);
|
2016-06-22 00:26:08 +08:00
|
|
|
|
2019-04-29 00:05:32 +08:00
|
|
|
if ( mTransit > 0 ) {
|
2016-06-22 00:26:08 +08:00
|
|
|
// Jitter
|
|
|
|
int d = packetTransit - mTransit;
|
2020-05-08 01:41:29 +08:00
|
|
|
Debug(5, "Jitter D = %d", d);
|
2016-06-22 00:26:08 +08:00
|
|
|
if ( d < 0 )
|
|
|
|
d = -d;
|
|
|
|
//mJitter += (1./16.) * ((double)d - mJitter);
|
|
|
|
mJitter += d - ((mJitter + 8) >> 4);
|
2008-07-16 16:35:59 +08:00
|
|
|
}
|
2016-06-22 00:26:08 +08:00
|
|
|
mTransit = packetTransit;
|
2019-04-29 00:05:32 +08:00
|
|
|
} else {
|
2016-06-22 00:26:08 +08:00
|
|
|
mJitter = 0;
|
|
|
|
}
|
2020-05-08 01:41:29 +08:00
|
|
|
Debug(5, "RTP Jitter: %d", mJitter);
|
2008-07-16 16:35:59 +08:00
|
|
|
}
|
|
|
|
|
2020-05-08 01:41:29 +08:00
|
|
|
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)));
|
2008-07-16 16:35:59 +08:00
|
|
|
|
2020-05-08 01:41:29 +08:00
|
|
|
Debug(5, "ntpTime: %ld.%06ld, rtpTime: %x", ntpTime.tv_sec, ntpTime.tv_usec, rtpTime);
|
2016-06-22 00:26:08 +08:00
|
|
|
|
2019-04-29 00:05:32 +08:00
|
|
|
if ( mBaseTimeNtp.tv_sec == 0 ) {
|
2016-06-22 00:26:08 +08:00
|
|
|
mBaseTimeReal = tvNow();
|
|
|
|
mBaseTimeNtp = ntpTime;
|
|
|
|
mBaseTimeRtp = rtpTime;
|
2019-04-29 00:05:32 +08:00
|
|
|
} else if ( !mRtpClock ) {
|
2020-05-08 01:41:29 +08:00
|
|
|
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);
|
2008-07-16 16:35:59 +08:00
|
|
|
|
2016-06-22 00:26:08 +08:00
|
|
|
double diffNtpTime = tvDiffSec( mBaseTimeNtp, ntpTime );
|
|
|
|
uint32_t diffRtpTime = rtpTime - mBaseTimeRtp;
|
|
|
|
mRtpFactor = (uint32_t)(diffRtpTime / diffNtpTime);
|
2008-07-16 16:35:59 +08:00
|
|
|
|
2020-05-08 01:41:29 +08:00
|
|
|
Debug( 5, "NTP-diff: %.6f RTP-diff: %d RTPfactor: %d",
|
|
|
|
diffNtpTime, diffRtpTime, mRtpFactor);
|
2016-06-22 00:26:08 +08:00
|
|
|
}
|
|
|
|
mLastSrTimeNtpSecs = ntpTimeSecs;
|
|
|
|
mLastSrTimeNtpFrac = ntpTimeFrac;
|
|
|
|
mLastSrTimeNtp = ntpTime;
|
|
|
|
mLastSrTimeRtp = rtpTime;
|
2008-07-16 16:35:59 +08:00
|
|
|
}
|
|
|
|
|
2019-04-29 00:05:32 +08:00
|
|
|
void RtpSource::updateRtcpStats() {
|
2016-06-22 00:26:08 +08:00
|
|
|
uint32_t extendedMax = mCycles + mMaxSeq;
|
|
|
|
mExpectedPackets = extendedMax - mBaseSeq + 1;
|
|
|
|
// The number of packets lost is defined to be the number of packets
|
|
|
|
// expected less the number of packets actually received:
|
|
|
|
mLostPackets = mExpectedPackets - mReceivedPackets;
|
|
|
|
uint32_t expectedInterval = mExpectedPackets - mExpectedPrior;
|
|
|
|
mExpectedPrior = mExpectedPackets;
|
|
|
|
uint32_t receivedInterval = mReceivedPackets - mReceivedPrior;
|
|
|
|
mReceivedPrior = mReceivedPackets;
|
|
|
|
uint32_t lostInterval = expectedInterval - receivedInterval;
|
|
|
|
|
|
|
|
if ( expectedInterval == 0 || lostInterval <= 0 )
|
|
|
|
mLostFraction = 0;
|
|
|
|
else
|
|
|
|
mLostFraction = (lostInterval << 8) / expectedInterval;
|
2020-05-08 01:41:29 +08:00
|
|
|
|
|
|
|
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);
|
2008-07-16 16:35:59 +08:00
|
|
|
}
|
|
|
|
|
2020-05-08 01:41:29 +08:00
|
|
|
bool RtpSource::handlePacket(const unsigned char *packet, size_t packetLen) {
|
2016-06-22 00:26:08 +08:00
|
|
|
const RtpDataHeader *rtpHeader;
|
|
|
|
rtpHeader = (RtpDataHeader *)packet;
|
|
|
|
int rtpHeaderSize = 12 + rtpHeader->cc * 4;
|
|
|
|
// No need to check for nal type as non fragmented packets already have 001 start sequence appended
|
|
|
|
bool h264FragmentEnd = (mCodecId == AV_CODEC_ID_H264) && (packet[rtpHeaderSize+1] & 0x40);
|
|
|
|
// M stands for Marker, it is the 8th bit
|
|
|
|
// The interpretation of the marker is defined by a profile. It is intended
|
|
|
|
// to allow significant events such as frame boundaries to be marked in the
|
|
|
|
// packet stream. A profile may define additional marker bits or specify
|
|
|
|
// that there is no marker bit by changing the number of bits in the payload type field.
|
|
|
|
bool thisM = rtpHeader->m || h264FragmentEnd;
|
|
|
|
|
2020-05-08 01:41:29 +08:00
|
|
|
if ( updateSeq(ntohs(rtpHeader->seqN)) ) {
|
|
|
|
Hexdump(4, packet+rtpHeaderSize, 16);
|
2016-06-22 00:26:08 +08:00
|
|
|
|
2019-04-29 00:05:32 +08:00
|
|
|
if ( mFrameGood ) {
|
2016-06-22 00:26:08 +08:00
|
|
|
int extraHeader = 0;
|
|
|
|
|
2019-04-29 00:05:32 +08:00
|
|
|
if ( mCodecId == AV_CODEC_ID_H264 ) {
|
2016-06-22 00:26:08 +08:00
|
|
|
int nalType = (packet[rtpHeaderSize] & 0x1f);
|
2020-05-08 01:41:29 +08:00
|
|
|
Debug(3, "Have H264 frame: nal type is %d", nalType);
|
2013-12-01 06:00:52 +08:00
|
|
|
|
2019-04-29 00:05:32 +08:00
|
|
|
switch (nalType) {
|
2016-06-22 00:26:08 +08:00
|
|
|
case 24: // STAP-A
|
|
|
|
extraHeader = 2;
|
|
|
|
break;
|
|
|
|
case 25: // STAP-B
|
|
|
|
case 26: // MTAP-16
|
|
|
|
case 27: // MTAP-24
|
|
|
|
extraHeader = 3;
|
|
|
|
break;
|
|
|
|
// FU-A and FU-B
|
|
|
|
case 28: case 29:
|
|
|
|
// Is this NAL the first NAL in fragmentation sequence
|
2019-04-29 00:05:32 +08:00
|
|
|
if ( packet[rtpHeaderSize+1] & 0x80 ) {
|
2016-06-22 00:26:08 +08:00
|
|
|
// Now we will form new header of frame
|
|
|
|
mFrame.append( "\x0\x0\x1\x0", 4 );
|
|
|
|
// Reconstruct NAL header from FU headers
|
|
|
|
*(mFrame+3) = (packet[rtpHeaderSize+1] & 0x1f) |
|
|
|
|
(packet[rtpHeaderSize] & 0xe0);
|
|
|
|
}
|
|
|
|
|
|
|
|
extraHeader = 2;
|
|
|
|
break;
|
2017-04-19 02:17:48 +08:00
|
|
|
default:
|
2020-05-08 01:41:29 +08:00
|
|
|
Debug(3, "Unhandled nalType %d", nalType);
|
2008-07-16 16:35:59 +08:00
|
|
|
}
|
2016-06-22 00:26:08 +08:00
|
|
|
|
|
|
|
// Append NAL frame start code
|
|
|
|
if ( !mFrame.size() )
|
2020-05-08 01:41:29 +08:00
|
|
|
mFrame.append("\x0\x0\x1", 3);
|
2019-04-29 00:05:32 +08:00
|
|
|
} // end if H264
|
2020-05-08 01:41:29 +08:00
|
|
|
mFrame.append(packet+rtpHeaderSize+extraHeader,
|
|
|
|
packetLen-rtpHeaderSize-extraHeader);
|
2016-06-22 00:26:08 +08:00
|
|
|
} else {
|
2020-05-08 01:41:29 +08:00
|
|
|
Debug(3, "NOT H264 frame: type is %d", mCodecId);
|
2008-07-16 16:35:59 +08:00
|
|
|
}
|
2016-06-22 00:26:08 +08:00
|
|
|
|
2020-05-08 01:41:29 +08:00
|
|
|
Hexdump(4, mFrame.head(), 16);
|
2016-06-22 00:26:08 +08:00
|
|
|
|
2019-04-29 00:05:32 +08:00
|
|
|
if ( thisM ) {
|
|
|
|
if ( mFrameGood ) {
|
2020-05-08 01:41:29 +08:00
|
|
|
Debug(3, "Got new frame %d, %d bytes", mFrameCount, mFrame.size());
|
2016-06-22 00:26:08 +08:00
|
|
|
|
2020-05-08 01:41:29 +08:00
|
|
|
mFrameProcessed.setValueImmediate(false);
|
|
|
|
mFrameReady.updateValueSignal(true);
|
2019-04-29 00:05:32 +08:00
|
|
|
if ( !mFrameProcessed.getValueImmediate() ) {
|
2016-06-22 00:26:08 +08:00
|
|
|
// 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;
|
|
|
|
|
2020-12-28 01:03:44 +08:00
|
|
|
for ( int count = 0; !mFrameProcessed.getUpdatedValue(1); count++ )
|
2020-05-08 01:41:29 +08:00
|
|
|
if ( count > 1 )
|
|
|
|
return false;
|
2008-07-16 16:35:59 +08:00
|
|
|
}
|
2016-06-22 00:26:08 +08:00
|
|
|
mFrameCount++;
|
2019-04-29 00:05:32 +08:00
|
|
|
} else {
|
2020-05-08 01:41:29 +08:00
|
|
|
Warning("Discarding incomplete frame %d, %d bytes", mFrameCount, mFrame.size());
|
2016-06-22 00:26:08 +08:00
|
|
|
}
|
|
|
|
mFrame.clear();
|
2008-07-16 16:35:59 +08:00
|
|
|
}
|
2019-04-29 00:05:32 +08:00
|
|
|
} else {
|
|
|
|
if ( mFrame.size() ) {
|
2020-05-08 01:41:29 +08:00
|
|
|
Warning("Discarding partial frame %d, %d bytes", mFrameCount, mFrame.size());
|
2019-04-29 00:05:32 +08:00
|
|
|
} else {
|
2020-05-08 01:41:29 +08:00
|
|
|
Warning("Discarding frame %d", mFrameCount);
|
2016-06-22 00:26:08 +08:00
|
|
|
}
|
|
|
|
mFrameGood = false;
|
|
|
|
mFrame.clear();
|
|
|
|
}
|
2019-04-29 00:05:32 +08:00
|
|
|
if ( thisM ) {
|
2016-06-22 00:26:08 +08:00
|
|
|
mFrameGood = true;
|
|
|
|
prevM = true;
|
2019-04-29 00:05:32 +08:00
|
|
|
} else
|
2016-06-22 00:26:08 +08:00
|
|
|
prevM = false;
|
|
|
|
|
2019-09-23 22:53:21 +08:00
|
|
|
updateJitter(rtpHeader);
|
2016-06-22 00:26:08 +08:00
|
|
|
|
2019-04-29 00:05:32 +08:00
|
|
|
return true;
|
2008-07-16 16:35:59 +08:00
|
|
|
}
|
|
|
|
|
2020-05-08 01:41:29 +08:00
|
|
|
bool RtpSource::getFrame(Buffer &buffer) {
|
2019-04-29 00:05:32 +08:00
|
|
|
if ( !mFrameReady.getValueImmediate() ) {
|
2019-09-23 22:53:21 +08:00
|
|
|
Debug(3, "Getting frame but not ready");
|
2016-06-22 00:26:08 +08:00
|
|
|
// Allow for a couple of spurious returns
|
2020-12-28 01:03:44 +08:00
|
|
|
for ( int count = 0; !mFrameReady.getUpdatedValue(1); count++ ) {
|
2016-06-22 00:26:08 +08:00
|
|
|
if ( count > 1 )
|
2019-09-23 22:53:21 +08:00
|
|
|
return false;
|
2020-12-28 01:03:44 +08:00
|
|
|
}
|
2016-06-22 00:26:08 +08:00
|
|
|
}
|
|
|
|
buffer = mFrame;
|
2019-09-23 22:53:21 +08:00
|
|
|
mFrameReady.setValueImmediate(false);
|
|
|
|
mFrameProcessed.updateValueSignal(true);
|
|
|
|
Debug(4, "Copied %d bytes", buffer.size());
|
2019-04-29 00:05:32 +08:00
|
|
|
return true;
|
2008-07-16 16:35:59 +08:00
|
|
|
}
|
2013-11-29 05:32:06 +08:00
|
|
|
|
2014-01-02 00:19:42 +08:00
|
|
|
#endif // HAVE_LIBAVCODEC
|