diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index 059f88b39..5d82bf8f0 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -19,7 +19,7 @@ #ifndef ZM_FFMPEG_H #define ZM_FFMPEG_H - +#include #if HAVE_LIBAVCODEC #ifdef __cplusplus @@ -27,17 +27,35 @@ extern "C" { #endif #if HAVE_LIBAVUTIL_AVUTIL_H #include +#include +#elif HAVE_FFMPEG_AVUTIL_H +#include +#include +#else +#error "No location for avutils.h found" #endif #if HAVE_LIBAVCODEC_AVCODEC_H #include +#elif HAVE_FFMPEG_AVCODEC_H +#include +#else +#error "No location for avcodec.h found" #endif #if HAVE_LIBAVFORMAT_AVFORMAT_H #include +#elif HAVE_FFMPEG_AVFORMAT_H +#include +#else +#error "No location for avformat.h found" #endif #if HAVE_LIBSWSCALE #if HAVE_LIBSWSCALE_SWSCALE_H #include -#include // this is a fix for error: ‘av_rescale_q’ was not declared in this scope +#include // this is a fix for error: тАШav_rescale_qтАЩ was not declared in this scope +#elif HAVE_FFMPEG_SWSCALE_H +#include +#else +#error "No location for swscale.h found" #endif #endif // HAVE_LIBSWSCALE #ifdef __cplusplus @@ -72,3 +90,4 @@ extern "C" { #endif // HAVE_LIBAVCODEC #endif // ZM_FFMPEG_H + diff --git a/src/zm_remote_camera_rtsp.cpp b/src/zm_remote_camera_rtsp.cpp index e352589f6..cffb91cce 100644 --- a/src/zm_remote_camera_rtsp.cpp +++ b/src/zm_remote_camera_rtsp.cpp @@ -203,7 +203,7 @@ int RemoteCameraRtsp::PrimeCapture() if( (unsigned int)pSize != imagesize) { Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize); } - +/* #if HAVE_LIBSWSCALE if(!sws_isSupportedInput(mCodecContext->pix_fmt)) { Fatal("swscale does not support the codec format: %c%c%c%c",(mCodecContext->pix_fmt)&0xff,((mCodecContext->pix_fmt>>8)&0xff),((mCodecContext->pix_fmt>>16)&0xff),((mCodecContext->pix_fmt>>24)&0xff)); @@ -216,7 +216,7 @@ int RemoteCameraRtsp::PrimeCapture() #else // HAVE_LIBSWSCALE Fatal( "You must compile ffmpeg with the --enable-swscale option to use RTSP cameras" ); #endif // HAVE_LIBSWSCALE - +*/ return( 0 ); } diff --git a/src/zm_rtp_source.cpp b/src/zm_rtp_source.cpp index 4f53327df..92c4f3d34 100644 --- a/src/zm_rtp_source.cpp +++ b/src/zm_rtp_source.cpp @@ -253,15 +253,57 @@ bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen ) { const RtpDataHeader *rtpHeader; rtpHeader = (RtpDataHeader *)packet; + bool fragmentEnd = false; + + // Each RTP packet delivers only one NAL. It can be either the Single NAL + // ( in that case it must be in one packet ) or the Fragmentation NALs + // that delivers large single NAL... if ( updateSeq( ntohs(rtpHeader->seqN) ) ) { Hexdump( 4, packet+sizeof(RtpDataHeader), 16 ); + if ( ((packet[sizeof(RtpDataHeader)] & 0x1f) == 28 && + (packet[sizeof(RtpDataHeader)+1] & 0x80)) || + ((packet[sizeof(RtpDataHeader)] & 0x1f) != 28 && + prevM && rtpHeader->m) ) + mFrameGood = true; // This means that if packet is in sequence + // and is single NAL with mark set (and prev packet + // was NAL with mark set or it is Fragmentation NAL with + // Start bit set then we assume that sequence + // was restored and we can handle packet if ( mFrameGood ) + { + // check if there fragmentation NAL + if ( (packet[sizeof(RtpDataHeader)] & 0x1f) == 28 ) + { + // is this NAL the first NAL in fragmentation sequence + if ( packet[sizeof(RtpDataHeader)+1] & 0x80 ) + { + // if there is any data in frame then we must + // discard it because that frame was incomplete + if ( mFrame.size() ) + mFrame.clear(); + // Now we will form new header of frame + mFrame.append("\x0\x0\x1\x0",4); + *(mFrame+3) = (packet[sizeof(RtpDataHeader)+1] & 0x1f) | + (packet[sizeof(RtpDataHeader)] & 0x60); + } + else + if ( packet[sizeof(RtpDataHeader)+1] & 0x40 ) + fragmentEnd = true; + mFrame.append(packet+sizeof(RtpDataHeader)+2, packetLen-sizeof(RtpDataHeader)-2); + } + else + { +// mframe.clear(); + if ( !mFrame.size() ) + mFrame.append("\x0\x0\x1",3); mFrame.append( packet+sizeof(RtpDataHeader), packetLen-sizeof(RtpDataHeader) ); + } + } Hexdump( 4, mFrame.head(), 16 ); - if ( rtpHeader->m ) + if ( rtpHeader->m || fragmentEnd ) { if ( mFrameGood ) { @@ -297,10 +339,13 @@ bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen ) mFrameGood = false; mFrame.clear(); } - if ( rtpHeader->m ) + if ( rtpHeader->m || fragmentEnd ) { mFrameGood = true; + prevM = true; } + else + prevM = false; updateJitter( rtpHeader ); diff --git a/src/zm_rtp_source.h b/src/zm_rtp_source.h index 7d4143697..4ffd6e101 100644 --- a/src/zm_rtp_source.h +++ b/src/zm_rtp_source.h @@ -84,6 +84,7 @@ private: Buffer mFrame; int mFrameCount; bool mFrameGood; + bool prevM; ThreadData mFrameReady; ThreadData mFrameProcessed; diff --git a/src/zm_rtsp.cpp b/src/zm_rtsp.cpp index a86c8bbb0..3d82e7f35 100644 --- a/src/zm_rtsp.cpp +++ b/src/zm_rtsp.cpp @@ -576,13 +576,15 @@ int RtspThread::run() { if ( buffer[0] == '$' ) { + if ( buffer.size() < 4 ) + break; unsigned char channel = buffer[1]; unsigned short len = ntohs( *((unsigned short *)(buffer+2)) ); Debug( 4, "Got %d bytes left, expecting %d byte packet on channel %d", buffer.size(), len, channel ); if ( (unsigned short)buffer.size() < (len+4) ) { - Debug( 4, "Missing %zd bytes, rereading", (len+4)-nBytes ); + Debug( 4, "Missing %d bytes, rereading", (len+4)-buffer.size() ); break; } if ( channel == remoteChannels[0] ) @@ -594,8 +596,10 @@ int RtspThread::run() } else if ( channel == remoteChannels[1] ) { - len = ntohs( *((unsigned short *)(buffer+2)) ); - Debug( 4, "Got %zd bytes on control channel %d", nBytes, channel ); +// 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 ); } else diff --git a/src/zm_sdp.cpp b/src/zm_sdp.cpp index aa33206c5..50e29d7eb 100644 --- a/src/zm_sdp.cpp +++ b/src/zm_sdp.cpp @@ -144,6 +144,7 @@ SessionDescriptor::MediaDescriptor::MediaDescriptor( const std::string &type, in mClock( 0 ), mWidth( 0 ), mHeight( 0 ), + mSprops( "" ), mConnInfo( 0 ) { } @@ -273,6 +274,13 @@ SessionDescriptor::SessionDescriptor( const std::string &url, const std::string else if ( attr3Tokens[0] == "config" ) { } + else if ( attr3Tokens[0] == "sprop-parameter-sets" ) + { + size_t t = attr2Tokens[i].find("="); + char *c = (char *)attr2Tokens[i].c_str() + t + 1; + Debug(4, "sprop-parameter-sets value %s", c); + currMedia->setSprops(std::string(c)); + } else { Debug( 3, "Ignoring SDP fmtp attribute '%s' for media '%s'", attr3Tokens[0].c_str(), currMedia->getType().c_str() ) @@ -330,6 +338,11 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const strncpy( formatContext->filename, mUrl.c_str(), sizeof(formatContext->filename) ); + if ( mName.length() ) + strncpy( formatContext->title, mName.c_str(), sizeof(formatContext->title) ); + if ( mInfo.length() ) + strncpy( formatContext->comment, mInfo.c_str(), sizeof(formatContext->comment) ); + //formatContext->nb_streams = mMediaList.size(); for ( unsigned int i = 0; i < mMediaList.size(); i++ ) { @@ -395,6 +408,58 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const stream->codec->width = mediaDesc->getWidth(); if ( mediaDesc->getHeight() ) stream->codec->height = mediaDesc->getHeight(); + if ( stream->codec->codec_id == CODEC_ID_H264 && mediaDesc->getSprops().size()) + { + uint8_t start_sequence[]= { 0, 0, 1 }; + stream->codec->extradata_size= 0; + stream->codec->extradata= NULL; + char pvalue[1024], *value = pvalue; + + strcpy(pvalue, mediaDesc->getSprops().c_str()); + + while (*value) { + char base64packet[1024]; + uint8_t decoded_packet[1024]; + uint32_t packet_size; + char *dst = base64packet; + + while (*value && *value != ',' + && (dst - base64packet) < sizeof(base64packet) - 1) { + *dst++ = *value++; + } + *dst++ = '\0'; + + if (*value == ',') + value++; + + packet_size= av_base64_decode(decoded_packet, (const char *)base64packet, (int)sizeof(decoded_packet)); + Hexdump(4, (char *)decoded_packet, packet_size); + if (packet_size) { + uint8_t *dest = + (uint8_t *)av_malloc(packet_size + sizeof(start_sequence) + + stream->codec->extradata_size + + FF_INPUT_BUFFER_PADDING_SIZE); + if(dest) { + if(stream->codec->extradata_size) { + // av_realloc? + memcpy(dest, stream->codec->extradata, stream->codec->extradata_size); + av_free(stream->codec->extradata); + } + + memcpy(dest+stream->codec->extradata_size, start_sequence, sizeof(start_sequence)); + memcpy(dest+stream->codec->extradata_size+sizeof(start_sequence), decoded_packet, packet_size); + memset(dest+stream->codec->extradata_size+sizeof(start_sequence)+ + packet_size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + + stream->codec->extradata= dest; + stream->codec->extradata_size+= sizeof(start_sequence)+packet_size; +// } else { +// av_log(codec, AV_LOG_ERROR, "Unable to allocate memory for extradata!"); +// return AVERROR(ENOMEM); + } + } + } + } } return( formatContext ); diff --git a/src/zm_sdp.h b/src/zm_sdp.h index ba4652aea..bfaa52ad7 100644 --- a/src/zm_sdp.h +++ b/src/zm_sdp.h @@ -103,6 +103,7 @@ public: int mClock; int mWidth; int mHeight; + std::string mSprops; ConnInfo *mConnInfo; @@ -171,6 +172,14 @@ public: return( mHeight ); } + void setSprops(const std::string props) + { + mSprops = props; + } + const std::string getSprops() const + { + return ( mSprops ); + } const double getFrameRate() const { return( mFrameRate ); diff --git a/src/zm_stream.cpp b/src/zm_stream.cpp index 2cea2f10b..41e75768f 100644 --- a/src/zm_stream.cpp +++ b/src/zm_stream.cpp @@ -27,6 +27,13 @@ StreamBase::~StreamBase() { +#if HAVE_LIBAVCODEC + if ( vid_stream ) + { + delete vid_stream; + vid_stream = NULL; + } +#endif closeComms(); } diff --git a/src/zm_stream.h b/src/zm_stream.h index 22f8b153d..ef442ab8e 100644 --- a/src/zm_stream.h +++ b/src/zm_stream.h @@ -57,7 +57,7 @@ protected: } DataMsg; typedef enum { MSG_CMD=1, MSG_DATA_WATCH, MSG_DATA_EVENT } MsgType; - typedef enum { CMD_NONE=0, CMD_PAUSE, CMD_PLAY, CMD_STOP, CMD_FASTFWD, CMD_SLOWFWD, CMD_SLOWREV, CMD_FASTREV, CMD_ZOOMIN, CMD_ZOOMOUT, CMD_PAN, CMD_SCALE, CMD_PREV, CMD_NEXT, CMD_SEEK, CMD_VARPLAY, CMD_QUERY=99 } MsgCommand; + typedef enum { CMD_NONE=0, CMD_PAUSE, CMD_PLAY, CMD_STOP, CMD_FASTFWD, CMD_SLOWFWD, CMD_SLOWREV, CMD_FASTREV, CMD_ZOOMIN, CMD_ZOOMOUT, CMD_PAN, CMD_SCALE, CMD_PREV, CMD_NEXT, CMD_SEEK, CMD_VARPLAY, CMD_GET_IMAGE, CMD_QUERY=99 } MsgCommand; protected: Monitor *monitor;