mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-05-18 03:25:02 -04:00
some fixes
This commit is contained in:
@@ -45,6 +45,7 @@ Camera::Camera( unsigned int p_monitor_id, SourceType p_type, unsigned int p_wid
|
||||
} else if(colours == ZM_COLOUR_RGB24 && ((imagesize % 64) != 0 || (imagesize % 12) != 0)) {
|
||||
Fatal("Image size is not multiples of 12 and 64");
|
||||
}
|
||||
monitor = NULL;
|
||||
}
|
||||
|
||||
Camera::~Camera() {
|
||||
|
||||
@@ -761,10 +761,10 @@ void Select::clearTimeout()
|
||||
void Select::calcMaxFd()
|
||||
{
|
||||
mMaxFd = -1;
|
||||
for ( CommsSet::iterator iter = mReaders.begin(); iter != mReaders.end(); iter++ )
|
||||
for ( CommsSet::iterator iter = mReaders.begin(); iter != mReaders.end(); ++iter )
|
||||
if ( (*iter)->getMaxDesc() > mMaxFd )
|
||||
mMaxFd = (*iter)->getMaxDesc();
|
||||
for ( CommsSet::iterator iter = mWriters.begin(); iter != mWriters.end(); iter++ )
|
||||
for ( CommsSet::iterator iter = mWriters.begin(); iter != mWriters.end(); ++iter )
|
||||
if ( (*iter)->getMaxDesc() > mMaxFd )
|
||||
mMaxFd = (*iter)->getMaxDesc();
|
||||
}
|
||||
@@ -839,12 +839,12 @@ int Select::wait()
|
||||
|
||||
mReadable.clear();
|
||||
FD_ZERO(&rfds);
|
||||
for ( CommsSet::iterator iter = mReaders.begin(); iter != mReaders.end(); iter++ )
|
||||
for ( CommsSet::iterator iter = mReaders.begin(); iter != mReaders.end(); ++iter )
|
||||
FD_SET((*iter)->getReadDesc(),&rfds);
|
||||
|
||||
mWriteable.clear();
|
||||
FD_ZERO(&wfds);
|
||||
for ( CommsSet::iterator iter = mWriters.begin(); iter != mWriters.end(); iter++ )
|
||||
for ( CommsSet::iterator iter = mWriters.begin(); iter != mWriters.end(); ++iter )
|
||||
FD_SET((*iter)->getWriteDesc(),&wfds);
|
||||
|
||||
int nFound = select( mMaxFd+1, &rfds, &wfds, NULL, selectTimeout );
|
||||
@@ -858,10 +858,10 @@ int Select::wait()
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( CommsSet::iterator iter = mReaders.begin(); iter != mReaders.end(); iter++ )
|
||||
for ( CommsSet::iterator iter = mReaders.begin(); iter != mReaders.end(); ++iter )
|
||||
if ( FD_ISSET((*iter)->getReadDesc(),&rfds) )
|
||||
mReadable.push_back( *iter );
|
||||
for ( CommsSet::iterator iter = mWriters.begin(); iter != mWriters.end(); iter++ )
|
||||
for ( CommsSet::iterator iter = mWriters.begin(); iter != mWriters.end(); ++iter )
|
||||
if ( FD_ISSET((*iter)->getWriteDesc(),&rfds) )
|
||||
mWriteable.push_back( *iter );
|
||||
}
|
||||
|
||||
@@ -478,32 +478,24 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
virtual int sendto( const void *msg, int len, const SockAddr *addr=0 ) const
|
||||
{
|
||||
virtual int sendto( const void *msg, int len, const SockAddr *addr=0 ) const {
|
||||
ssize_t nBytes = ::sendto( mSd, msg, len, 0, addr?addr->getAddr():NULL, addr?addr->getAddrSize():0 );
|
||||
if ( nBytes < 0 )
|
||||
Debug( 1, "Sendto of %d bytes on sd %d failed: %s", len, mSd, strerror(errno) );
|
||||
return( nBytes );
|
||||
}
|
||||
virtual int recvfrom( void *msg, int len, SockAddr *addr=0 ) const
|
||||
{
|
||||
virtual int recvfrom( void *msg, int len, SockAddr *addr=0 ) const {
|
||||
ssize_t nBytes = 0;
|
||||
if ( addr )
|
||||
{
|
||||
if ( addr ) {
|
||||
struct sockaddr sockAddr;
|
||||
socklen_t sockLen;
|
||||
nBytes = ::recvfrom( mSd, msg, len, 0, &sockAddr, &sockLen );
|
||||
if ( nBytes < 0 )
|
||||
{
|
||||
if ( nBytes < 0 ) {
|
||||
Debug( 1, "Recvfrom of %d bytes max on sd %d (with address) failed: %s", len, mSd, strerror(errno) );
|
||||
}
|
||||
else if ( sockLen )
|
||||
{
|
||||
} else if ( sockLen ) {
|
||||
addr = SockAddr::newSockAddr( sockAddr, sockLen );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
nBytes = ::recvfrom( mSd, msg, len, 0, NULL, 0 );
|
||||
if ( nBytes < 0 )
|
||||
Debug( 1, "Recvfrom of %d bytes max on sd %d (no address) failed: %s", len, mSd, strerror(errno) );
|
||||
|
||||
@@ -520,19 +520,19 @@ int cURLCamera::progress_callback(void *userdata, double dltotal, double dlnow,
|
||||
|
||||
/* These functions call the functions in the class for the correct object */
|
||||
size_t data_callback_dispatcher(void *buffer, size_t size, size_t nmemb, void *userdata) {
|
||||
return ((cURLCamera*)userdata)->data_callback(buffer,size,nmemb,userdata);
|
||||
return reinterpret_cast<cURLCamera*>(userdata)->data_callback(buffer,size,nmemb,userdata);
|
||||
}
|
||||
|
||||
size_t header_callback_dispatcher(void *buffer, size_t size, size_t nmemb, void *userdata) {
|
||||
return ((cURLCamera*)userdata)->header_callback(buffer,size,nmemb,userdata);
|
||||
return reinterpret_cast<cURLCamera*>(userdata)->header_callback(buffer,size,nmemb,userdata);
|
||||
}
|
||||
|
||||
int progress_callback_dispatcher(void *userdata, double dltotal, double dlnow, double ultotal, double ulnow) {
|
||||
return ((cURLCamera*)userdata)->progress_callback(userdata,dltotal,dlnow,ultotal,ulnow);
|
||||
return reinterpret_cast<cURLCamera*>(userdata)->progress_callback(userdata,dltotal,dlnow,ultotal,ulnow);
|
||||
}
|
||||
|
||||
void* thread_func_dispatcher(void* object) {
|
||||
return ((cURLCamera*)object)->thread_func();
|
||||
return reinterpret_cast<cURLCamera*>(object)->thread_func();
|
||||
}
|
||||
|
||||
#endif // HAVE_LIBCURL
|
||||
|
||||
@@ -228,11 +228,11 @@ Event::~Event() {
|
||||
|
||||
void Event::createNotes( std::string ¬es ) {
|
||||
notes.clear();
|
||||
for ( StringSetMap::const_iterator mapIter = noteSetMap.begin(); mapIter != noteSetMap.end(); mapIter++ ) {
|
||||
for ( StringSetMap::const_iterator mapIter = noteSetMap.begin(); mapIter != noteSetMap.end(); ++mapIter ) {
|
||||
notes += mapIter->first;
|
||||
notes += ": ";
|
||||
const StringSet &stringSet = mapIter->second;
|
||||
for ( StringSet::const_iterator setIter = stringSet.begin(); setIter != stringSet.end(); setIter++ ) {
|
||||
for ( StringSet::const_iterator setIter = stringSet.begin(); setIter != stringSet.end(); ++setIter ) {
|
||||
if ( setIter != stringSet.begin() )
|
||||
notes += ", ";
|
||||
notes += *setIter;
|
||||
@@ -310,7 +310,7 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap ) {
|
||||
noteSetMap = newNoteSetMap;
|
||||
update = true;
|
||||
} else {
|
||||
for ( StringSetMap::const_iterator newNoteSetMapIter = newNoteSetMap.begin(); newNoteSetMapIter != newNoteSetMap.end(); newNoteSetMapIter++ ) {
|
||||
for ( StringSetMap::const_iterator newNoteSetMapIter = newNoteSetMap.begin(); newNoteSetMapIter != newNoteSetMap.end(); ++newNoteSetMapIter ) {
|
||||
const std::string &newNoteGroup = newNoteSetMapIter->first;
|
||||
const StringSet &newNoteSet = newNoteSetMapIter->second;
|
||||
//Info( "Got %d new strings", newNoteSet.size() );
|
||||
@@ -323,7 +323,7 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap ) {
|
||||
} else {
|
||||
StringSet ¬eSet = noteSetMapIter->second;
|
||||
//Info( "Found note group %s, got %d strings", newNoteGroup.c_str(), newNoteSet.size() );
|
||||
for ( StringSet::const_iterator newNoteSetIter = newNoteSet.begin(); newNoteSetIter != newNoteSet.end(); newNoteSetIter++ ) {
|
||||
for ( StringSet::const_iterator newNoteSetIter = newNoteSet.begin(); newNoteSetIter != newNoteSet.end(); ++newNoteSetIter ) {
|
||||
const std::string &newNote = *newNoteSetIter;
|
||||
StringSet::iterator noteSetIter = noteSet.find( newNote );
|
||||
if ( noteSetIter == noteSet.end() ) {
|
||||
@@ -384,7 +384,6 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap ) {
|
||||
}
|
||||
|
||||
strncpy( notesStr, notes.c_str(), sizeof(notesStr) );
|
||||
notesLen = notes.length();
|
||||
|
||||
if ( mysql_stmt_execute( stmt ) ) {
|
||||
Fatal( "Unable to execute sql '%s': %s", sql, mysql_stmt_error(stmt) );
|
||||
|
||||
@@ -176,13 +176,13 @@ bool EventStream::loadEventData( int event_id ) {
|
||||
event_data->n_frames = mysql_num_rows( result );
|
||||
|
||||
event_data->frames = new FrameData[event_data->frame_count];
|
||||
int id, last_id = 0;
|
||||
int last_id = 0;
|
||||
time_t timestamp, last_timestamp = event_data->start_time;
|
||||
double delta, last_delta = 0.0;
|
||||
double last_delta = 0.0;
|
||||
while ( ( dbrow = mysql_fetch_row( result ) ) ) {
|
||||
id = atoi(dbrow[0]);
|
||||
int id = atoi(dbrow[0]);
|
||||
timestamp = atoi(dbrow[1]);
|
||||
delta = atof(dbrow[2]);
|
||||
double delta = atof(dbrow[2]);
|
||||
int id_diff = id - last_id;
|
||||
double frame_delta = (delta-last_delta)/id_diff;
|
||||
if ( id_diff > 1 ) {
|
||||
@@ -414,7 +414,6 @@ void EventStream::processCommand( const CmdMsg *msg ) {
|
||||
}
|
||||
send_frame = true;
|
||||
break;
|
||||
send_frame = true;
|
||||
}
|
||||
case CMD_PAN :
|
||||
{
|
||||
|
||||
@@ -75,7 +75,7 @@ class EventStream : public StreamBase {
|
||||
|
||||
int curr_frame_id;
|
||||
double curr_stream_time;
|
||||
bool send_frame;
|
||||
bool send_frame;
|
||||
|
||||
EventData *event_data;
|
||||
FFmpeg_Input *ffmpeg_input;
|
||||
@@ -97,6 +97,7 @@ class EventStream : public StreamBase {
|
||||
|
||||
curr_frame_id = 0;
|
||||
curr_stream_time = 0.0;
|
||||
send_frame = false;
|
||||
|
||||
event_data = 0;
|
||||
|
||||
|
||||
@@ -109,8 +109,6 @@ int av_dict_parse_string(AVDictionary **pm, const char *str,
|
||||
const char *key_val_sep, const char *pairs_sep,
|
||||
int flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
@@ -118,7 +116,7 @@ int av_dict_parse_string(AVDictionary **pm, const char *str,
|
||||
flags &= ~(AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
|
||||
|
||||
while (*str) {
|
||||
if ((ret = parse_key_value_pair(pm, &str, key_val_sep, pairs_sep, flags)) < 0)
|
||||
if ((int ret = parse_key_value_pair(pm, &str, key_val_sep, pairs_sep, flags)) < 0)
|
||||
return ret;
|
||||
|
||||
if (*str)
|
||||
|
||||
@@ -107,7 +107,6 @@ FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::stri
|
||||
mRawFrame = NULL;
|
||||
mFrame = NULL;
|
||||
frameCount = 0;
|
||||
startTime = 0;
|
||||
mIsOpening = false;
|
||||
mCanCapture = false;
|
||||
mOpenStart = 0;
|
||||
@@ -275,8 +274,8 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
AVDictionaryEntry *e;
|
||||
if ( (e = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
AVDictionaryEntry *e = NULL;
|
||||
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
Warning( "Option %s not recognized by ffmpeg", e->key);
|
||||
}
|
||||
|
||||
@@ -294,7 +293,6 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
#endif
|
||||
Fatal( "Unable to find stream info from %s due to: %s", mPath.c_str(), strerror(errno) );
|
||||
|
||||
startTime = av_gettime();//FIXME here or after find_Stream_info
|
||||
Debug ( 1, "Got stream info" );
|
||||
|
||||
// Find first video stream present
|
||||
@@ -416,21 +414,20 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
if ( avcodec_open(mVideoCodecContext, mVideoCodec) < 0 ){
|
||||
#else
|
||||
Debug ( 1, "Calling avcodec_open2" );
|
||||
if ( avcodec_open2(mVideoCodecContext, mVideoCodec, &opts) < 0 ) {
|
||||
if ( avcodec_open2(mVideoCodecContext, mVideoCodec, &opts) < 0 ) {
|
||||
#endif
|
||||
AVDictionaryEntry *e;
|
||||
if ( (e = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
Warning( "Option %s not recognized by ffmpeg", e->key);
|
||||
AVDictionaryEntry *e = NULL;
|
||||
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
Warning( "Option %s not recognized by ffmpeg", e->key);
|
||||
}
|
||||
Fatal( "Unable to open codec for video stream from %s", mPath.c_str() );
|
||||
} else {
|
||||
AVDictionaryEntry *e = NULL;
|
||||
if ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
Warning( "Option %s not recognized by ffmpeg", e->key);
|
||||
}
|
||||
}
|
||||
Fatal( "Unable to open codec for video stream from %s", mPath.c_str() );
|
||||
} else {
|
||||
|
||||
AVDictionaryEntry *e;
|
||||
if ( (e = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
Warning( "Option %s not recognized by ffmpeg", e->key);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end if success opening codec
|
||||
|
||||
if (mVideoCodecContext->hwaccel != NULL) {
|
||||
Debug(1, "HWACCEL in use");
|
||||
@@ -451,17 +448,18 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
zm_dump_stream_format(mFormatContext, mAudioStreamId, 0, 0);
|
||||
// Open the codec
|
||||
#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0)
|
||||
Debug ( 1, "Calling avcodec_open" );
|
||||
if ( avcodec_open(mAudioCodecContext, mAudioCodec) < 0 )
|
||||
Debug ( 1, "Calling avcodec_open" );
|
||||
if ( avcodec_open(mAudioCodecContext, mAudioCodec) < 0 )
|
||||
#else
|
||||
Debug ( 1, "Calling avcodec_open2" );
|
||||
if ( avcodec_open2(mAudioCodecContext, mAudioCodec, 0) < 0 )
|
||||
Debug ( 1, "Calling avcodec_open2" );
|
||||
if ( avcodec_open2(mAudioCodecContext, mAudioCodec, 0) < 0 )
|
||||
#endif
|
||||
Fatal( "Unable to open codec for video stream from %s", mPath.c_str() );
|
||||
Fatal( "Unable to open codec for video stream from %s", mPath.c_str() );
|
||||
}
|
||||
}
|
||||
} // end if have audio stream
|
||||
|
||||
Debug ( 1, "Opened codec" );
|
||||
# if 0
|
||||
|
||||
// Allocate space for the native video frame
|
||||
mRawFrame = zm_av_frame_alloc();
|
||||
@@ -508,6 +506,7 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
Fatal( "You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras" );
|
||||
#endif // HAVE_LIBSWSCALE
|
||||
|
||||
#endif
|
||||
if ( (unsigned int)mVideoCodecContext->width != width || (unsigned int)mVideoCodecContext->height != height ) {
|
||||
Warning( "Monitor dimensions are %dx%d but camera is sending %dx%d", width, height, mVideoCodecContext->width, mVideoCodecContext->height );
|
||||
}
|
||||
|
||||
@@ -46,8 +46,6 @@ class FfmpegCamera : public Camera {
|
||||
|
||||
#if HAVE_LIBAVFORMAT
|
||||
AVFormatContext *mFormatContext;
|
||||
int mVideoStreamId;
|
||||
int mAudioStreamId;
|
||||
AVCodec *mVideoCodec;
|
||||
AVCodec *mAudioCodec;
|
||||
AVFrame *mRawFrame;
|
||||
@@ -82,7 +80,6 @@ class FfmpegCamera : public Camera {
|
||||
pthread_t mReopenThread;
|
||||
#endif // HAVE_LIBAVFORMAT
|
||||
|
||||
|
||||
#if HAVE_LIBSWSCALE
|
||||
struct SwsContext *mConvertContext;
|
||||
#endif
|
||||
|
||||
115
src/zm_image.cpp
115
src/zm_image.cpp
@@ -146,7 +146,7 @@ Image::Image( const AVFrame *frame ) {
|
||||
void Image::Assign( const AVFrame *frame ) {
|
||||
/* Assume the dimensions etc are correct. FIXME */
|
||||
|
||||
AVPixelFormat format = (AVPixelFormat)AVPixFormat();
|
||||
AVPixelFormat format = (AVPixelFormat)AVPixFormat();
|
||||
|
||||
AVFrame *dest_frame = zm_av_frame_alloc();
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
@@ -174,6 +174,8 @@ AVPixelFormat format = (AVPixelFormat)AVPixFormat();
|
||||
Fatal("You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras");
|
||||
#endif // HAVE_LIBSWSCALE
|
||||
av_frame_free( &dest_frame );
|
||||
sws_freeContext(mConvertContext);
|
||||
mConvertContext = NULL;
|
||||
} // end Image::Image( const AVFrame *frame )
|
||||
|
||||
Image::Image( const Image &p_image ) {
|
||||
@@ -464,7 +466,6 @@ void Image::Initialise() {
|
||||
|
||||
/* Requests a writeable buffer to the image. This is safer than buffer() because this way we can guarantee that a buffer of required size exists */
|
||||
uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder) {
|
||||
unsigned int newsize;
|
||||
|
||||
if ( p_colours != ZM_COLOUR_GRAY8 && p_colours != ZM_COLOUR_RGB24 && p_colours != ZM_COLOUR_RGB32 ) {
|
||||
Error("WriteBuffer called with unexpected colours: %d",p_colours);
|
||||
@@ -477,7 +478,7 @@ uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_hei
|
||||
}
|
||||
|
||||
if ( p_width != width || p_height != height || p_colours != colours || p_subpixelorder != subpixelorder ) {
|
||||
newsize = (p_width * p_height) * p_colours;
|
||||
unsigned int newsize = (p_width * p_height) * p_colours;
|
||||
|
||||
if ( buffer == NULL ) {
|
||||
AllocImgBuffer(newsize);
|
||||
@@ -2109,8 +2110,8 @@ void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int
|
||||
void Image::Timestamp( const char *label, const time_t when, const Coord &coord, const int size ) {
|
||||
char time_text[64];
|
||||
strftime( time_text, sizeof(time_text), "%y/%m/%d %H:%M:%S", localtime( &when ) );
|
||||
char text[64];
|
||||
if ( label ) {
|
||||
char text[64];
|
||||
snprintf( text, sizeof(text), "%s - %s", label, time_text );
|
||||
Annotate( text, coord, size );
|
||||
} else {
|
||||
@@ -2632,8 +2633,7 @@ void Image::Rotate( int angle )
|
||||
unsigned int new_width = width;
|
||||
uint8_t* rotate_buffer = AllocBuffer(size);
|
||||
|
||||
switch( angle )
|
||||
{
|
||||
switch( angle ) {
|
||||
case 90 :
|
||||
{
|
||||
new_height = width;
|
||||
@@ -2642,41 +2642,27 @@ void Image::Rotate( int angle )
|
||||
unsigned int line_bytes = new_width*colours;
|
||||
unsigned char *s_ptr = buffer;
|
||||
|
||||
if ( colours == ZM_COLOUR_GRAY8 )
|
||||
{
|
||||
unsigned char *d_ptr;
|
||||
for ( unsigned int i = new_width; i > 0; i-- )
|
||||
{
|
||||
d_ptr = rotate_buffer+(i-1);
|
||||
for ( unsigned int j = new_height; j > 0; j-- )
|
||||
{
|
||||
if ( colours == ZM_COLOUR_GRAY8 ) {
|
||||
for ( unsigned int i = new_width; i > 0; i-- ) {
|
||||
unsigned char *d_ptr = rotate_buffer+(i-1);
|
||||
for ( unsigned int j = new_height; j > 0; j-- ) {
|
||||
*d_ptr = *s_ptr++;
|
||||
d_ptr += line_bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( colours == ZM_COLOUR_RGB32 )
|
||||
{
|
||||
} else if ( colours == ZM_COLOUR_RGB32 ) {
|
||||
Rgb* s_rptr = (Rgb*)s_ptr;
|
||||
Rgb* d_rptr;
|
||||
for ( unsigned int i = new_width; i > 0; i-- )
|
||||
{
|
||||
d_rptr = (Rgb*)(rotate_buffer+((i-1)<<2));
|
||||
for ( unsigned int j = new_height; j > 0; j-- )
|
||||
{
|
||||
for ( unsigned int i = new_width; i > 0; i-- ) {
|
||||
Rgb* d_rptr = (Rgb*)(rotate_buffer+((i-1)<<2));
|
||||
for ( unsigned int j = new_height; j > 0; j-- ) {
|
||||
*d_rptr = *s_rptr++;
|
||||
d_rptr += new_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* Assume RGB24 */
|
||||
{
|
||||
unsigned char *d_ptr;
|
||||
for ( unsigned int i = new_width; i > 0; i-- )
|
||||
{
|
||||
d_ptr = rotate_buffer+((i-1)*3);
|
||||
for ( unsigned int j = new_height; j > 0; j-- )
|
||||
{
|
||||
} else /* Assume RGB24 */ {
|
||||
for ( unsigned int i = new_width; i > 0; i-- ) {
|
||||
unsigned char *d_ptr = rotate_buffer+((i-1)*3);
|
||||
for ( unsigned int j = new_height; j > 0; j-- ) {
|
||||
*d_ptr = *s_ptr++;
|
||||
*(d_ptr+1) = *s_ptr++;
|
||||
*(d_ptr+2) = *s_ptr++;
|
||||
@@ -2691,28 +2677,20 @@ void Image::Rotate( int angle )
|
||||
unsigned char *s_ptr = buffer+size;
|
||||
unsigned char *d_ptr = rotate_buffer;
|
||||
|
||||
if ( colours == ZM_COLOUR_GRAY8 )
|
||||
{
|
||||
while( s_ptr > buffer )
|
||||
{
|
||||
if ( colours == ZM_COLOUR_GRAY8 ) {
|
||||
while( s_ptr > buffer ) {
|
||||
s_ptr--;
|
||||
*d_ptr++ = *s_ptr;
|
||||
}
|
||||
}
|
||||
else if ( colours == ZM_COLOUR_RGB32 )
|
||||
{
|
||||
} else if ( colours == ZM_COLOUR_RGB32 ) {
|
||||
Rgb* s_rptr = (Rgb*)s_ptr;
|
||||
Rgb* d_rptr = (Rgb*)d_ptr;
|
||||
while( s_rptr > (Rgb*)buffer )
|
||||
{
|
||||
while( s_rptr > (Rgb*)buffer ) {
|
||||
s_rptr--;
|
||||
*d_rptr++ = *s_rptr;
|
||||
}
|
||||
}
|
||||
else /* Assume RGB24 */
|
||||
{
|
||||
while( s_ptr > buffer )
|
||||
{
|
||||
} else /* Assume RGB24 */ {
|
||||
while( s_ptr > buffer ) {
|
||||
s_ptr -= 3;
|
||||
*d_ptr++ = *s_ptr;
|
||||
*d_ptr++ = *(s_ptr+1);
|
||||
@@ -2729,43 +2707,29 @@ void Image::Rotate( int angle )
|
||||
unsigned int line_bytes = new_width*colours;
|
||||
unsigned char *s_ptr = buffer+size;
|
||||
|
||||
if ( colours == ZM_COLOUR_GRAY8 )
|
||||
{
|
||||
unsigned char *d_ptr;
|
||||
for ( unsigned int i = new_width; i > 0; i-- )
|
||||
{
|
||||
d_ptr = rotate_buffer+(i-1);
|
||||
for ( unsigned int j = new_height; j > 0; j-- )
|
||||
{
|
||||
if ( colours == ZM_COLOUR_GRAY8 ) {
|
||||
for ( unsigned int i = new_width; i > 0; i-- ) {
|
||||
unsigned char *d_ptr = rotate_buffer+(i-1);
|
||||
for ( unsigned int j = new_height; j > 0; j-- ) {
|
||||
s_ptr--;
|
||||
*d_ptr = *s_ptr;
|
||||
d_ptr += line_bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( colours == ZM_COLOUR_RGB32 )
|
||||
{
|
||||
} else if ( colours == ZM_COLOUR_RGB32 ) {
|
||||
Rgb* s_rptr = (Rgb*)s_ptr;
|
||||
Rgb* d_rptr;
|
||||
for ( unsigned int i = new_width; i > 0; i-- )
|
||||
{
|
||||
d_rptr = (Rgb*)(rotate_buffer+((i-1)<<2));
|
||||
for ( unsigned int j = new_height; j > 0; j-- )
|
||||
{
|
||||
for ( unsigned int i = new_width; i > 0; i-- ) {
|
||||
Rgb* d_rptr = (Rgb*)(rotate_buffer+((i-1)<<2));
|
||||
for ( unsigned int j = new_height; j > 0; j-- ) {
|
||||
s_rptr--;
|
||||
*d_rptr = *s_rptr;
|
||||
d_rptr += new_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* Assume RGB24 */
|
||||
{
|
||||
unsigned char *d_ptr;
|
||||
for ( unsigned int i = new_width; i > 0; i-- )
|
||||
{
|
||||
d_ptr = rotate_buffer+((i-1)*3);
|
||||
for ( unsigned int j = new_height; j > 0; j-- )
|
||||
{
|
||||
} else /* Assume RGB24 */ {
|
||||
for ( unsigned int i = new_width; i > 0; i-- ) {
|
||||
unsigned char *d_ptr = rotate_buffer+((i-1)*3);
|
||||
for ( unsigned int j = new_height; j > 0; j-- ) {
|
||||
*(d_ptr+2) = *(--s_ptr);
|
||||
*(d_ptr+1) = *(--s_ptr);
|
||||
*d_ptr = *(--s_ptr);
|
||||
@@ -2778,18 +2742,15 @@ void Image::Rotate( int angle )
|
||||
}
|
||||
|
||||
AssignDirect( new_width, new_height, colours, subpixelorder, rotate_buffer, size, ZM_BUFTYPE_ZM);
|
||||
|
||||
}
|
||||
|
||||
/* RGB32 compatible: complete */
|
||||
void Image::Flip( bool leftright )
|
||||
{
|
||||
void Image::Flip( bool leftright ) {
|
||||
uint8_t* flip_buffer = AllocBuffer(size);
|
||||
|
||||
unsigned int line_bytes = width*colours;
|
||||
unsigned int line_bytes2 = 2*line_bytes;
|
||||
if ( leftright )
|
||||
{
|
||||
if ( leftright ) {
|
||||
// Horizontal flip, left to right
|
||||
unsigned char *s_ptr = buffer+line_bytes;
|
||||
unsigned char *d_ptr = flip_buffer;
|
||||
|
||||
@@ -276,8 +276,7 @@ static boolean fill_input_buffer (j_decompress_ptr cinfo)
|
||||
memcpy( src->buffer, src->inbuffer, (size_t) src->inbuffer_size );
|
||||
nbytes = src->inbuffer_size;
|
||||
|
||||
if ( nbytes <= 0 )
|
||||
{
|
||||
if ( nbytes == 0 ) {
|
||||
if ( src->start_of_data ) /* Treat empty input file as fatal error */
|
||||
ERREXIT(cinfo, JERR_INPUT_EMPTY);
|
||||
WARNMS(cinfo, JWRN_JPEG_EOF);
|
||||
|
||||
@@ -1501,20 +1501,20 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
|
||||
sprintf( output+strlen(output), "Video Capabilities\n" );
|
||||
sprintf( output+strlen(output), " Name: %s\n", vid_cap.name );
|
||||
sprintf( output+strlen(output), " Type: %d\n%s%s%s%s%s%s%s%s%s%s%s%s%s%s", vid_cap.type,
|
||||
vid_cap.type&VID_TYPE_CAPTURE?" Can capture\n":"",
|
||||
vid_cap.type&VID_TYPE_TUNER?" Can tune\n":"",
|
||||
vid_cap.type&VID_TYPE_TELETEXT?" Does teletext\n":"",
|
||||
vid_cap.type&VID_TYPE_OVERLAY?" Overlay onto frame buffer\n":"",
|
||||
vid_cap.type&VID_TYPE_CHROMAKEY?" Overlay by chromakey\n":"",
|
||||
vid_cap.type&VID_TYPE_CLIPPING?" Can clip\n":"",
|
||||
vid_cap.type&VID_TYPE_FRAMERAM?" Uses the frame buffer memory\n":"",
|
||||
vid_cap.type&VID_TYPE_SCALES?" Scalable\n":"",
|
||||
vid_cap.type&VID_TYPE_MONOCHROME?" Monochrome only\n":"",
|
||||
vid_cap.type&VID_TYPE_SUBCAPTURE?" Can capture subareas of the image\n":"",
|
||||
vid_cap.type&VID_TYPE_MPEG_DECODER?" Can decode MPEG streams\n":"",
|
||||
vid_cap.type&VID_TYPE_MPEG_ENCODER?" Can encode MPEG streams\n":"",
|
||||
vid_cap.type&VID_TYPE_MJPEG_DECODER?" Can decode MJPEG streams\n":"",
|
||||
vid_cap.type&VID_TYPE_MJPEG_ENCODER?" Can encode MJPEG streams\n":""
|
||||
(vid_cap.type&VID_TYPE_CAPTURE)?" Can capture\n":"",
|
||||
(vid_cap.type&VID_TYPE_TUNER)?" Can tune\n":"",
|
||||
(vid_cap.type&VID_TYPE_TELETEXT)?" Does teletext\n":"",
|
||||
(vid_cap.type&VID_TYPE_OVERLAY)?" Overlay onto frame buffer\n":"",
|
||||
(vid_cap.type&VID_TYPE_CHROMAKEY)?" Overlay by chromakey\n":"",
|
||||
(vid_cap.type&VID_TYPE_CLIPPING)?" Can clip\n":"",
|
||||
(vid_cap.type&VID_TYPE_FRAMERAM)?" Uses the frame buffer memory\n":"",
|
||||
(vid_cap.type&VID_TYPE_SCALES)?" Scalable\n":"",
|
||||
(vid_cap.type&VID_TYPE_MONOCHROME)?" Monochrome only\n":"",
|
||||
(vid_cap.type&VID_TYPE_SUBCAPTURE)?" Can capture subareas of the image\n":"",
|
||||
(vid_cap.type&VID_TYPE_MPEG_DECODER)?" Can decode MPEG streams\n":"",
|
||||
(vid_cap.type&VID_TYPE_MPEG_ENCODER)?" Can encode MPEG streams\n":"",
|
||||
(vid_cap.type&VID_TYPE_MJPEG_DECODER)?" Can decode MJPEG streams\n":"",
|
||||
(vid_cap.type&VID_TYPE_MJPEG_ENCODER)?" Can encode MJPEG streams\n":""
|
||||
);
|
||||
sprintf( output+strlen(output), " Video Channels: %d\n", vid_cap.channels );
|
||||
sprintf( output+strlen(output), " Audio Channels: %d\n", vid_cap.audios );
|
||||
|
||||
@@ -344,6 +344,7 @@ Monitor::Monitor(
|
||||
fps = 0.0;
|
||||
event_count = 0;
|
||||
image_count = 0;
|
||||
analysis_image_count = 0;
|
||||
ready_count = warmup_count;
|
||||
first_alarm_count = 0;
|
||||
last_alarm_count = 0;
|
||||
@@ -758,6 +759,7 @@ double Monitor::GetFPS() const {
|
||||
struct timeval time1 = snap1->timestamp;
|
||||
|
||||
int image_count = image_buffer_count;
|
||||
|
||||
int index2 = (index1+1)%image_buffer_count;
|
||||
if ( index2 == image_buffer_count ) {
|
||||
return 0.0;
|
||||
@@ -774,7 +776,9 @@ double Monitor::GetFPS() const {
|
||||
struct timeval time2 = snap2->timestamp;
|
||||
|
||||
double time_diff = tvDiffSec( time2, time1 );
|
||||
|
||||
if ( ! time_diff ) {
|
||||
return 0.0;
|
||||
}
|
||||
double curr_fps = image_count/time_diff;
|
||||
|
||||
if ( curr_fps < 0.0 ) {
|
||||
@@ -1193,6 +1197,15 @@ bool Monitor::Analyse() {
|
||||
}
|
||||
|
||||
ZMPacket *snap = &image_buffer[index];
|
||||
if ( snap->packet.stream_index != camera->get_VideoStreamId() ) {
|
||||
if ( event ) {
|
||||
//event->AddFrame( snap_image, *timestamp, score );
|
||||
event->AddPacket( snap, 0 );
|
||||
}
|
||||
mutex.unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
struct timeval *timestamp = &snap->timestamp;
|
||||
//Debug(2, "timestamp for index (%d) %s", index, timeval_to_string( *timestamp ) );
|
||||
Image *snap_image = snap->image;
|
||||
@@ -2852,6 +2865,7 @@ packet->reset();
|
||||
|
||||
if ( FirstCapture ) {
|
||||
FirstCapture = 0;
|
||||
mutex.unlock();
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
@@ -2865,12 +2879,23 @@ packet->reset();
|
||||
signalcolor = rgb_convert(signal_check_colour, ZM_SUBPIX_ORDER_BGR);
|
||||
capture_image->Fill(signalcolor);
|
||||
shared_data->signal = false;
|
||||
mutex.unlock();
|
||||
return -1;
|
||||
} else if ( captureResult > 0 ) {
|
||||
|
||||
if ( packet->packet.size && ! packet->frame ) {
|
||||
packet->decode( camera->get_VideoCodecContext() );
|
||||
packet->get_image();
|
||||
if ( packet->packet.stream_index == camera->get_VideoStreamId() ) {
|
||||
packet->decode( camera->get_VideoCodecContext() );
|
||||
packet->get_image();
|
||||
} else {
|
||||
packet->decode( camera->get_AudioCodecContext() );
|
||||
shared_data->last_write_index = index;
|
||||
shared_data->last_write_time = image_buffer[index].timestamp.tv_sec;
|
||||
mutex.unlock();
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
Debug(2,"Not decoding");
|
||||
}
|
||||
|
||||
/* Deinterlacing */
|
||||
@@ -3339,7 +3364,7 @@ ZMPacket *Monitor::getSnapshot() {
|
||||
|
||||
// Wait for camera to get an image, and then assign it as the base reference image. So this should be done as the first task in the analysis thread startup.
|
||||
void Monitor::get_ref_image() {
|
||||
while (
|
||||
while (
|
||||
( shared_data->last_write_index == (unsigned int)image_buffer_count )
|
||||
&&
|
||||
( shared_data->last_write_time == 0 )
|
||||
|
||||
@@ -330,7 +330,7 @@ protected:
|
||||
MonitorLink **linked_monitors;
|
||||
|
||||
public:
|
||||
Monitor( int p_id );
|
||||
explicit Monitor( int p_id );
|
||||
|
||||
// OurCheckAlarms seems to be unused. Check it on zm_monitor.cpp for more info.
|
||||
//bool OurCheckAlarms( Zone *zone, const Image *pImage );
|
||||
|
||||
@@ -658,7 +658,10 @@ Debug(2, "Have checking command Queue for connkey: %d", connkey );
|
||||
replay_rate = ZM_RATE_BASE;
|
||||
}
|
||||
}
|
||||
// Last read index is analysis... what do we care about analysis? I think we are using the same variable for two purposese
|
||||
if ( (unsigned int)last_read_index != monitor->shared_data->last_write_index ) {
|
||||
|
||||
// Is his % neccessary? is last_write_index not guaranteed to be < image_buffer_count?
|
||||
int index = monitor->shared_data->last_write_index%monitor->image_buffer_count;
|
||||
last_read_index = monitor->shared_data->last_write_index;
|
||||
//Debug( 1, "%d: %x - %x", index, image_buffer[index].image, image_buffer[index].image->buffer );
|
||||
|
||||
@@ -88,7 +88,7 @@ void VideoStream::SetupFormat( ) {
|
||||
|
||||
if (s->oformat->priv_data_size > 0) {
|
||||
s->priv_data = av_mallocz(s->oformat->priv_data_size);
|
||||
if (!s->priv_data) {
|
||||
if ( !(s->priv_data) ) {
|
||||
Fatal( "Could not allocate private data for output format." );
|
||||
}
|
||||
#if LIBAVFORMAT_VERSION_CHECK(52, 92, 0, 92, 0)
|
||||
@@ -286,19 +286,19 @@ const char *VideoStream::MimeType( ) const {
|
||||
}
|
||||
|
||||
void VideoStream::OpenStream( ) {
|
||||
int avRet;
|
||||
int ret;
|
||||
|
||||
/* now that all the parameters are set, we can open the
|
||||
video codecs and allocate the necessary encode buffers */
|
||||
if ( ost ) {
|
||||
/* open the codec */
|
||||
#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0)
|
||||
if ( (avRet = avcodec_open( codec_context, codec )) < 0 )
|
||||
if ( (ret = avcodec_open( codec_context, codec )) < 0 )
|
||||
#else
|
||||
if ( (avRet = avcodec_open2( codec_context, codec, 0 )) < 0 )
|
||||
if ( (ret = avcodec_open2( codec_context, codec, 0 )) < 0 )
|
||||
#endif
|
||||
{
|
||||
Fatal( "Could not open codec. Error code %d \"%s\"", avRet, av_err2str( avRet ) );
|
||||
Fatal( "Could not open codec. Error code %d \"%s\"", ret, av_err2str(ret) );
|
||||
}
|
||||
|
||||
Debug( 1, "Opened codec" );
|
||||
@@ -364,7 +364,6 @@ void VideoStream::OpenStream( ) {
|
||||
|
||||
/* open the output file, if needed */
|
||||
if ( !(of->flags & AVFMT_NOFILE) ) {
|
||||
int ret;
|
||||
#if LIBAVFORMAT_VERSION_CHECK(53, 15, 0, 21, 0)
|
||||
ret = avio_open2( &ofc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL );
|
||||
#elif LIBAVFORMAT_VERSION_CHECK(52, 102, 0, 102, 0)
|
||||
@@ -405,9 +404,9 @@ void VideoStream::OpenStream( ) {
|
||||
#endif
|
||||
|
||||
#if !LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 4, 0)
|
||||
int ret = av_write_header( ofc );
|
||||
ret = av_write_header( ofc );
|
||||
#else
|
||||
int ret = avformat_write_header( ofc, NULL );
|
||||
ret = avformat_write_header( ofc, NULL );
|
||||
#endif
|
||||
|
||||
if ( ret < 0 ) {
|
||||
|
||||
@@ -46,6 +46,8 @@ ZMPacket::ZMPacket( Image *i ) {
|
||||
}
|
||||
|
||||
ZMPacket::ZMPacket( AVPacket *p ) {
|
||||
frame = NULL;
|
||||
image = NULL;
|
||||
av_init_packet( &packet );
|
||||
set_packet( p );
|
||||
keyframe = p->flags & AV_PKT_FLAG_KEY;
|
||||
@@ -55,6 +57,8 @@ ZMPacket::ZMPacket( AVPacket *p ) {
|
||||
}
|
||||
|
||||
ZMPacket::ZMPacket( AVPacket *p, struct timeval *t ) {
|
||||
frame = NULL;
|
||||
image = NULL;
|
||||
av_init_packet( &packet );
|
||||
set_packet( p );
|
||||
timestamp = *t;
|
||||
@@ -91,19 +95,19 @@ ZMPacket::~ZMPacket() {
|
||||
}
|
||||
|
||||
void ZMPacket::reset() {
|
||||
Debug(2,"reset");
|
||||
//Debug(2,"reset");
|
||||
zm_av_packet_unref( &packet );
|
||||
packet.size = 0;
|
||||
if ( in_frame ) {
|
||||
Debug(4,"reset frame");
|
||||
//Debug(4,"reset frame");
|
||||
av_frame_free( &in_frame );
|
||||
}
|
||||
if ( frame ) {
|
||||
Debug(4,"reset frame");
|
||||
//Debug(4,"reset frame");
|
||||
av_frame_free( &frame );
|
||||
}
|
||||
if ( buffer ) {
|
||||
Debug(4,"freeing buffer");
|
||||
//Debug(4,"freeing buffer");
|
||||
av_freep( &buffer );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,9 +51,9 @@ class ZMPacket {
|
||||
int decode( AVCodecContext *ctx );
|
||||
void reset();
|
||||
ZMPacket( AVPacket *packet, struct timeval *timestamp );
|
||||
ZMPacket( AVPacket *packet );
|
||||
explicit ZMPacket( AVPacket *packet );
|
||||
ZMPacket( AVPacket *packet, AVFrame *frame, Image *image );
|
||||
ZMPacket( Image *image );
|
||||
explicit ZMPacket( Image *image );
|
||||
ZMPacket();
|
||||
~ZMPacket();
|
||||
|
||||
|
||||
@@ -42,7 +42,9 @@ RemoteCamera::RemoteCamera(
|
||||
host( p_host ),
|
||||
port( p_port ),
|
||||
path( p_path ),
|
||||
hp( 0 )
|
||||
hp( 0 ),
|
||||
mNeedAuth(false),
|
||||
mAuthenticator(NULL)
|
||||
{
|
||||
if ( path[0] != '/' )
|
||||
path = '/'+path;
|
||||
@@ -97,14 +99,13 @@ void RemoteCamera::Initialise() {
|
||||
|
||||
int RemoteCamera::Read( int fd, char *buf, int size ) {
|
||||
int ReceivedBytes = 0;
|
||||
int bytes;
|
||||
while ( ReceivedBytes < size ) {
|
||||
// recv blocks until we get data, but it may be of ARBITRARY LENGTH and INCOMPLETE
|
||||
int bytes_to_recv = size - ReceivedBytes;
|
||||
if ( SOCKET_BUF_SIZE < bytes_to_recv )
|
||||
bytes_to_recv = SOCKET_BUF_SIZE;
|
||||
//Debug(3, "Aiming to receive %d of %d bytes", bytes_to_recv, size );
|
||||
bytes = recv(fd, &buf[ReceivedBytes], bytes_to_recv, 0); //socket, buffer, len, flags
|
||||
int bytes = recv(fd, &buf[ReceivedBytes], bytes_to_recv, 0); //socket, buffer, len, flags
|
||||
if ( bytes <= 0 ) {
|
||||
Error("RemoteCamera::Read Recv error. Closing Socket\n");
|
||||
return -1;
|
||||
|
||||
@@ -531,9 +531,6 @@ int RemoteCameraHttp::GetResponse() {
|
||||
} else
|
||||
#endif // HAVE_LIBPCRE
|
||||
{
|
||||
if ( method == REGEXP ) {
|
||||
Warning( "Unable to use netcam regexps as not compiled with libpcre" );
|
||||
}
|
||||
static const char *http_match = "HTTP/";
|
||||
static const char *connection_match = "Connection:";
|
||||
static const char *content_length_match = "Content-length:";
|
||||
|
||||
@@ -332,7 +332,7 @@ int RtpCtrlThread::run()
|
||||
timeout = false;
|
||||
last_receive = time(NULL);
|
||||
}
|
||||
for ( Select::CommsList::iterator iter = readable.begin(); iter != readable.end(); iter++ )
|
||||
for ( Select::CommsList::iterator iter = readable.begin(); iter != readable.end(); ++iter )
|
||||
{
|
||||
if ( UdpInetSocket *socket = dynamic_cast<UdpInetSocket *>(*iter) )
|
||||
{
|
||||
|
||||
@@ -94,7 +94,7 @@ int RtpDataThread::run()
|
||||
mStop = true;
|
||||
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) )
|
||||
{
|
||||
|
||||
226
src/zm_rtsp.cpp
226
src/zm_rtsp.cpp
@@ -36,8 +36,7 @@ int RtspThread::smMinDataPort = 0;
|
||||
int RtspThread::smMaxDataPort = 0;
|
||||
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)
|
||||
@@ -46,20 +45,15 @@ bool RtspThread::sendCommand( std::string message )
|
||||
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 )
|
||||
{
|
||||
if ( mMethod == RTP_RTSP_HTTP ) {
|
||||
message = base64Encode( message );
|
||||
Debug( 2, "Sending encoded RTSP 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) );
|
||||
return( false );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mRtspSocket.send( message.c_str(), message.size() ) != (int)message.length() )
|
||||
{
|
||||
} else {
|
||||
if ( mRtspSocket.send( message.c_str(), message.size() ) != (int)message.length() ) {
|
||||
Error( "Unable to send message '%s': %s", message.c_str(), strerror(errno) );
|
||||
return( false );
|
||||
}
|
||||
@@ -67,77 +61,60 @@ bool RtspThread::sendCommand( std::string message )
|
||||
return( true );
|
||||
}
|
||||
|
||||
bool RtspThread::recvResponse( std::string &response )
|
||||
{
|
||||
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;
|
||||
respCode = -1;
|
||||
char respText[ZM_NETWORK_BUFSIZ];
|
||||
if ( sscanf( response.c_str(), "RTSP/%f %3d %[^\r\n]\r\n", &respVer, &respCode, respText ) != 3 )
|
||||
{
|
||||
if ( isalnum(response[0]) )
|
||||
{
|
||||
if ( sscanf( response.c_str(), "RTSP/%f %3d %[^\r\n]\r\n", &respVer, &respCode, respText ) != 3 ) {
|
||||
if ( isalnum(response[0]) ) {
|
||||
Error( "Response parse failure in '%s'", response.c_str() );
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Error( "Response parse failure, %zd bytes follow", response.size() );
|
||||
if ( response.size() )
|
||||
Hexdump( Logger::ERROR, response.data(), min(response.size(),16) );
|
||||
}
|
||||
return( false );
|
||||
}
|
||||
if ( respCode == 401)
|
||||
{
|
||||
if ( respCode == 401) {
|
||||
Debug( 2, "Got 401 access denied response code, check WWW-Authenticate header and retry");
|
||||
mAuthenticator->checkAuthResponse(response);
|
||||
mNeedAuth = true;
|
||||
return( false );
|
||||
}
|
||||
else if ( respCode != 200 )
|
||||
{
|
||||
} else if ( respCode != 200 ) {
|
||||
Error( "Unexpected response code %d, text is '%s'", respCode, respText );
|
||||
return( false );
|
||||
}
|
||||
return( true );
|
||||
}
|
||||
|
||||
int RtspThread::requestPorts()
|
||||
{
|
||||
if ( !smMinDataPort )
|
||||
{
|
||||
int RtspThread::requestPorts() {
|
||||
if ( !smMinDataPort ) {
|
||||
char sql[ZM_SQL_SML_BUFSIZ];
|
||||
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 ) );
|
||||
exit( mysql_errno( &dbconn ) );
|
||||
}
|
||||
|
||||
MYSQL_RES *result = mysql_store_result( &dbconn );
|
||||
if ( !result )
|
||||
{
|
||||
if ( !result ) {
|
||||
Error( "Can't use query result: %s", mysql_error( &dbconn ) );
|
||||
exit( mysql_errno( &dbconn ) );
|
||||
}
|
||||
int nMonitors = mysql_num_rows( result );
|
||||
int position = 0;
|
||||
if ( nMonitors )
|
||||
{
|
||||
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ )
|
||||
{
|
||||
if ( nMonitors ) {
|
||||
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) {
|
||||
int id = atoi(dbrow[0]);
|
||||
if ( mId == id )
|
||||
{
|
||||
if ( mId == id ) {
|
||||
position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Minor hack for testing when not strictly enabled
|
||||
nMonitors = 1;
|
||||
position = 0;
|
||||
@@ -148,11 +125,9 @@ int RtspThread::requestPorts()
|
||||
smMaxDataPort = smMinDataPort + portRange - 1;
|
||||
Debug( 2, "Assigned RTP port range is %d-%d", smMinDataPort, smMaxDataPort );
|
||||
}
|
||||
for ( int i = smMinDataPort; i <= smMaxDataPort; i++ )
|
||||
{
|
||||
for ( int i = smMinDataPort; i <= smMaxDataPort; i++ ) {
|
||||
PortSet::const_iterator iter = smAssignedPorts.find( i );
|
||||
if ( iter == smAssignedPorts.end() )
|
||||
{
|
||||
if ( iter == smAssignedPorts.end() ) {
|
||||
smAssignedPorts.insert( i );
|
||||
return( i );
|
||||
}
|
||||
@@ -161,8 +136,7 @@ int RtspThread::requestPorts()
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
void RtspThread::releasePorts( int port )
|
||||
{
|
||||
void RtspThread::releasePorts( int port ) {
|
||||
if ( port > 0 )
|
||||
smAssignedPorts.erase( port );
|
||||
}
|
||||
@@ -185,8 +159,7 @@ RtspThread::RtspThread( int id, RtspMethod method, const std::string &protocol,
|
||||
mStop( false )
|
||||
{
|
||||
mUrl = mProtocol+"://"+mHost+":"+mPort;
|
||||
if ( !mPath.empty() )
|
||||
{
|
||||
if ( !mPath.empty() ) {
|
||||
if ( mPath[0] == '/' )
|
||||
mUrl += mPath;
|
||||
else
|
||||
@@ -208,10 +181,8 @@ RtspThread::RtspThread( int id, RtspMethod method, const std::string &protocol,
|
||||
mAuthenticator = new zm::Authenticator(parts[0], "");
|
||||
}
|
||||
|
||||
RtspThread::~RtspThread()
|
||||
{
|
||||
if ( mFormatContext )
|
||||
{
|
||||
RtspThread::~RtspThread() {
|
||||
if ( mFormatContext ) {
|
||||
#if LIBAVFORMAT_VERSION_CHECK(52, 96, 0, 96, 0)
|
||||
avformat_free_context( mFormatContext );
|
||||
#else
|
||||
@@ -219,16 +190,14 @@ RtspThread::~RtspThread()
|
||||
#endif
|
||||
mFormatContext = NULL;
|
||||
}
|
||||
if ( mSessDesc )
|
||||
{
|
||||
if ( mSessDesc ) {
|
||||
delete mSessDesc;
|
||||
mSessDesc = NULL;
|
||||
}
|
||||
delete mAuthenticator;
|
||||
}
|
||||
|
||||
int RtspThread::run()
|
||||
{
|
||||
int RtspThread::run() {
|
||||
std::string message;
|
||||
std::string response;
|
||||
|
||||
@@ -246,8 +215,7 @@ int RtspThread::run()
|
||||
|
||||
|
||||
bool authTried = false;
|
||||
if ( mMethod == RTP_RTSP_HTTP )
|
||||
{
|
||||
if ( mMethod == RTP_RTSP_HTTP ) {
|
||||
if ( !mRtspSocket2.connect( mHost.c_str(), mPort.c_str() ) )
|
||||
Fatal( "Unable to connect auxiliary RTSP/HTTP socket" );
|
||||
//Select select( 0.25 );
|
||||
@@ -271,13 +239,11 @@ int RtspThread::run()
|
||||
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() )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
@@ -285,14 +251,10 @@ 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 ( isalnum(response[0]) )
|
||||
{
|
||||
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() );
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Error( "Response parse failure, %zd bytes follow", response.size() );
|
||||
if ( response.size() )
|
||||
Hexdump( Logger::ERROR, response.data(), min(response.size(),16) );
|
||||
@@ -313,8 +275,7 @@ int RtspThread::run()
|
||||
|
||||
} while (respCode == 401 && !authTried);
|
||||
|
||||
if ( respCode != 200 )
|
||||
{
|
||||
if ( respCode != 200 ) {
|
||||
Error( "Unexpected response code %d, text is '%s'", respCode, respText );
|
||||
return( -1 );
|
||||
}
|
||||
@@ -327,8 +288,7 @@ int RtspThread::run()
|
||||
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() )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
@@ -383,17 +343,14 @@ int RtspThread::run()
|
||||
if( sdpStart == std::string::npos )
|
||||
return( -1 );
|
||||
|
||||
if ( mRtspDescribe )
|
||||
{
|
||||
if ( mRtspDescribe ) {
|
||||
std::string DescHeader = response.substr( 0,sdpStart );
|
||||
Debug( 1, "Processing DESCRIBE response header '%s'", DescHeader.c_str() );
|
||||
|
||||
lines = split( DescHeader, "\r\n" );
|
||||
for ( size_t i = 0; i < lines.size(); i++ )
|
||||
{
|
||||
for ( size_t i = 0; i < lines.size(); i++ ) {
|
||||
// If the device sends us a url value for Content-Base in the response header, we should use that instead
|
||||
if ( ( lines[i].size() > 13 ) && ( lines[i].substr( 0, 13 ) == "Content-Base:" ) )
|
||||
{
|
||||
if ( ( lines[i].size() > 13 ) && ( lines[i].substr( 0, 13 ) == "Content-Base:" ) ) {
|
||||
mUrl = trimSpaces( lines[i].substr( 13 ) );
|
||||
Info("Received new Content-Base in DESCRIBE response header. Updated device Url to: '%s'", mUrl.c_str() );
|
||||
break;
|
||||
@@ -406,13 +363,10 @@ int RtspThread::run()
|
||||
std::string sdp = response.substr( sdpStart );
|
||||
Debug( 1, "Processing SDP '%s'", sdp.c_str() );
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
mSessDesc = new SessionDescriptor( mUrl, sdp );
|
||||
mFormatContext = mSessDesc->generateFormatContext();
|
||||
}
|
||||
catch( const Exception &e )
|
||||
{
|
||||
} catch( const Exception &e ) {
|
||||
Error( e.getMessage().c_str() );
|
||||
return( -1 );
|
||||
}
|
||||
@@ -436,10 +390,8 @@ int RtspThread::run()
|
||||
|
||||
_AVCODECID codecId;
|
||||
|
||||
if ( mFormatContext->nb_streams >= 1 )
|
||||
{
|
||||
for ( unsigned int i = 0; i < mFormatContext->nb_streams; i++ )
|
||||
{
|
||||
if ( mFormatContext->nb_streams >= 1 ) {
|
||||
for ( unsigned int i = 0; i < mFormatContext->nb_streams; i++ ) {
|
||||
SessionDescriptor::MediaDescriptor *mediaDesc = mSessDesc->getStream( i );
|
||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO )
|
||||
@@ -449,12 +401,9 @@ int RtspThread::run()
|
||||
{
|
||||
// Check if control Url is absolute or relative
|
||||
controlUrl = mediaDesc->getControlUrl();
|
||||
if (std::equal(trackUrl.begin(), trackUrl.end(), controlUrl.begin()))
|
||||
{
|
||||
if (std::equal(trackUrl.begin(), trackUrl.end(), controlUrl.begin())) {
|
||||
trackUrl = controlUrl;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
if ( *trackUrl.rbegin() != '/') {
|
||||
trackUrl += "/" + controlUrl;
|
||||
} else {
|
||||
@@ -470,8 +419,7 @@ int RtspThread::run()
|
||||
}
|
||||
}
|
||||
|
||||
switch( mMethod )
|
||||
{
|
||||
switch( mMethod ) {
|
||||
case RTP_UNICAST :
|
||||
{
|
||||
localPorts[0] = requestPorts();
|
||||
@@ -508,10 +456,8 @@ int RtspThread::run()
|
||||
int timeout = 0;
|
||||
char transport[256] = "";
|
||||
|
||||
for ( size_t i = 0; i < lines.size(); i++ )
|
||||
{
|
||||
if ( ( lines[i].size() > 8 ) && ( lines[i].substr( 0, 8 ) == "Session:" ) )
|
||||
{
|
||||
for ( size_t i = 0; i < lines.size(); i++ ) {
|
||||
if ( ( lines[i].size() > 8 ) && ( lines[i].substr( 0, 8 ) == "Session:" ) ) {
|
||||
StringVector sessionLine = split( lines[i].substr(9), ";" );
|
||||
session = trimSpaces( sessionLine[0] );
|
||||
if ( sessionLine.size() == 2 )
|
||||
@@ -536,41 +482,31 @@ int RtspThread::run()
|
||||
std::string distribution = "";
|
||||
unsigned long ssrc = 0;
|
||||
StringVector parts = split( transport, ";" );
|
||||
for ( size_t i = 0; i < parts.size(); i++ )
|
||||
{
|
||||
for ( size_t i = 0; i < parts.size(); i++ ) {
|
||||
if ( parts[i] == "unicast" || parts[i] == "multicast" )
|
||||
distribution = parts[i];
|
||||
else if ( startsWith( parts[i], "server_port=" ) )
|
||||
{
|
||||
else if ( startsWith( parts[i], "server_port=" ) ) {
|
||||
method = "RTP/UNICAST";
|
||||
StringVector subparts = split( parts[i], "=" );
|
||||
StringVector ports = split( subparts[1], "-" );
|
||||
remotePorts[0] = strtol( ports[0].c_str(), NULL, 10 );
|
||||
remotePorts[1] = strtol( ports[1].c_str(), NULL, 10 );
|
||||
}
|
||||
else if ( startsWith( parts[i], "interleaved=" ) )
|
||||
{
|
||||
} else if ( startsWith( parts[i], "interleaved=" ) ) {
|
||||
method = "RTP/RTSP";
|
||||
StringVector subparts = split( parts[i], "=" );
|
||||
StringVector channels = split( subparts[1], "-" );
|
||||
remoteChannels[0] = strtol( channels[0].c_str(), NULL, 10 );
|
||||
remoteChannels[1] = strtol( channels[1].c_str(), NULL, 10 );
|
||||
}
|
||||
else if ( startsWith( parts[i], "port=" ) )
|
||||
{
|
||||
} else if ( startsWith( parts[i], "port=" ) ) {
|
||||
method = "RTP/MULTICAST";
|
||||
StringVector subparts = split( parts[i], "=" );
|
||||
StringVector ports = split( subparts[1], "-" );
|
||||
localPorts[0] = strtol( ports[0].c_str(), NULL, 10 );
|
||||
localPorts[1] = strtol( ports[1].c_str(), NULL, 10 );
|
||||
}
|
||||
else if ( startsWith( parts[i], "destination=" ) )
|
||||
{
|
||||
} else if ( startsWith( parts[i], "destination=" ) ) {
|
||||
StringVector subparts = split( parts[i], "=" );
|
||||
localHost = subparts[1];
|
||||
}
|
||||
else if ( startsWith( parts[i], "ssrc=" ) )
|
||||
{
|
||||
} else if ( startsWith( parts[i], "ssrc=" ) ) {
|
||||
StringVector subparts = split( parts[i], "=" );
|
||||
ssrc = strtoll( subparts[1].c_str(), NULL, 16 );
|
||||
}
|
||||
@@ -592,13 +528,11 @@ int RtspThread::run()
|
||||
|
||||
lines = split( response, "\r\n" );
|
||||
std::string rtpInfo;
|
||||
for ( size_t i = 0; i < lines.size(); i++ )
|
||||
{
|
||||
for ( size_t i = 0; i < lines.size(); i++ ) {
|
||||
if ( ( lines[i].size() > 9 ) && ( lines[i].substr( 0, 9 ) == "RTP-Info:" ) )
|
||||
rtpInfo = trimSpaces( lines[i].substr( 9 ) );
|
||||
// Check for a timeout again. Some rtsp devices don't send a timeout until after the PLAY command is sent
|
||||
if ( ( lines[i].size() > 8 ) && ( lines[i].substr( 0, 8 ) == "Session:" ) && ( timeout == 0 ) )
|
||||
{
|
||||
if ( ( lines[i].size() > 8 ) && ( lines[i].substr( 0, 8 ) == "Session:" ) && ( timeout == 0 ) ) {
|
||||
StringVector sessionLine = split( lines[i].substr(9), ";" );
|
||||
if ( sessionLine.size() == 2 )
|
||||
sscanf( trimSpaces( sessionLine[1] ).c_str(), "timeout=%d", &timeout );
|
||||
@@ -610,31 +544,22 @@ int RtspThread::run()
|
||||
int seq = 0;
|
||||
unsigned long rtpTime = 0;
|
||||
StringVector streams;
|
||||
if ( rtpInfo.empty() )
|
||||
{
|
||||
if ( rtpInfo.empty() ) {
|
||||
Debug( 1, "RTP Info Empty. Starting values for Sequence and Rtptime shall be zero.");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Debug( 2, "Got RTP Info %s", rtpInfo.c_str() );
|
||||
// More than one stream can be included in the RTP Info
|
||||
streams = split( rtpInfo.c_str(), "," );
|
||||
for ( size_t i = 0; i < streams.size(); i++ )
|
||||
{
|
||||
for ( size_t i = 0; i < streams.size(); i++ ) {
|
||||
// We want the stream that matches the trackUrl we are using
|
||||
if ( streams[i].find(controlUrl.c_str()) != std::string::npos )
|
||||
{
|
||||
if ( streams[i].find(controlUrl.c_str()) != std::string::npos ) {
|
||||
// Parse the sequence and rtptime values
|
||||
parts = split( streams[i].c_str(), ";" );
|
||||
for ( size_t j = 0; j < parts.size(); j++ )
|
||||
{
|
||||
if ( startsWith( parts[j], "seq=" ) )
|
||||
{
|
||||
for ( size_t j = 0; j < parts.size(); j++ ) {
|
||||
if ( startsWith( parts[j], "seq=" ) ) {
|
||||
StringVector subparts = split( parts[j], "=" );
|
||||
seq = strtol( subparts[1].c_str(), NULL, 10 );
|
||||
}
|
||||
else if ( startsWith( parts[j], "rtptime=" ) )
|
||||
{
|
||||
} else if ( startsWith( parts[j], "rtptime=" ) ) {
|
||||
StringVector subparts = split( parts[j], "=" );
|
||||
rtpTime = strtol( subparts[1].c_str(), NULL, 10 );
|
||||
}
|
||||
@@ -651,8 +576,7 @@ int RtspThread::run()
|
||||
time_t now;
|
||||
message = "GET_PARAMETER "+mUrl+" RTSP/1.0\r\nSession: "+session+"\r\n";
|
||||
|
||||
switch( mMethod )
|
||||
{
|
||||
switch( mMethod ) {
|
||||
case RTP_UNICAST :
|
||||
{
|
||||
RtpSource *source = new RtpSource( mId, "", localPorts[0], mHost, remotePorts[0], ssrc, seq, rtpClock, rtpTime, codecId );
|
||||
@@ -663,13 +587,11 @@ int RtspThread::run()
|
||||
rtpDataThread.start();
|
||||
rtpCtrlThread.start();
|
||||
|
||||
while( !mStop )
|
||||
{
|
||||
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) );
|
||||
if ( sendKeepalive && (timeout > 0) && ((now-lastKeepalive) > (timeout-5)) )
|
||||
{
|
||||
if ( sendKeepalive && (timeout > 0) && ((now-lastKeepalive) > (timeout-5)) ) {
|
||||
if ( !sendCommand( message ) )
|
||||
return( -1 );
|
||||
lastKeepalive = now;
|
||||
@@ -721,11 +643,9 @@ Debug(5, "sendkeepalive %d, timeout %d, now: %d last: %d since: %d", sendKeepali
|
||||
Buffer buffer( ZM_NETWORK_BUFSIZ );
|
||||
std::string keepaliveMessage = "OPTIONS "+mUrl+" RTSP/1.0\r\n";
|
||||
std::string keepaliveResponse = "RTSP/1.0 200 OK\r\n";
|
||||
while ( !mStop && select.wait() >= 0 )
|
||||
{
|
||||
while ( !mStop && select.wait() >= 0 ) {
|
||||
Select::CommsList readable = select.getReadable();
|
||||
if ( readable.size() == 0 )
|
||||
{
|
||||
if ( readable.size() == 0 ) {
|
||||
Error( "RTSP timed out" );
|
||||
break;
|
||||
}
|
||||
@@ -735,23 +655,19 @@ Debug(5, "sendkeepalive %d, timeout %d, now: %d last: %d since: %d", sendKeepali
|
||||
buffer.append( tempBuffer, nBytes );
|
||||
Debug( 4, "Read %zd bytes on sd %d, %d total", nBytes, mRtspSocket.getReadDesc(), buffer.size() );
|
||||
|
||||
while( buffer.size() > 0 )
|
||||
{
|
||||
if ( buffer[0] == '$' )
|
||||
{
|
||||
while( buffer.size() > 0 ) {
|
||||
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) )
|
||||
{
|
||||
if ( (unsigned short)buffer.size() < (len+4) ) {
|
||||
Debug( 4, "Missing %d bytes, rereading", (len+4)-buffer.size() );
|
||||
break;
|
||||
}
|
||||
if ( channel == remoteChannels[0] )
|
||||
{
|
||||
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 );
|
||||
|
||||
@@ -31,8 +31,7 @@
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
class RtspThread : public Thread
|
||||
{
|
||||
class RtspThread : public Thread {
|
||||
public:
|
||||
typedef enum { RTP_UNICAST, RTP_MULTICAST, RTP_RTSP, RTP_RTSP_HTTP } RtspMethod;
|
||||
typedef enum { UNDEFINED, UNICAST, MULTICAST } RtspDist;
|
||||
|
||||
@@ -26,7 +26,11 @@
|
||||
|
||||
namespace zm {
|
||||
|
||||
Authenticator::Authenticator(std::string &username, std::string password) {
|
||||
Authenticator::Authenticator( const std::string &username, const std::string &password) :
|
||||
fCnonce( "0a4f113b" ),
|
||||
fUsername(username),
|
||||
fPassword(password)
|
||||
{
|
||||
#ifdef HAVE_GCRYPT_H
|
||||
// Special initialisation for libgcrypt
|
||||
if ( !gcry_check_version( GCRYPT_VERSION ) )
|
||||
@@ -38,10 +42,7 @@ Authenticator::Authenticator(std::string &username, std::string password) {
|
||||
#endif // HAVE_GCRYPT_H
|
||||
|
||||
fAuthMethod = AUTH_UNDEFINED;
|
||||
fUsername = username;
|
||||
fPassword = password;
|
||||
nc = 1;
|
||||
fCnonce = "0a4f113b";
|
||||
}
|
||||
|
||||
Authenticator::~Authenticator() {
|
||||
@@ -96,13 +97,11 @@ void Authenticator::authHandleHeader(std::string headerData)
|
||||
}
|
||||
}
|
||||
|
||||
std::string Authenticator::quote(std::string src)
|
||||
{
|
||||
std::string Authenticator::quote( const std::string &src ) {
|
||||
return replaceAll(replaceAll(src, "\\", "\\\\"), "\"", "\\\"");
|
||||
}
|
||||
|
||||
std::string Authenticator::getAuthHeader(std::string method, std::string uri)
|
||||
{
|
||||
std::string Authenticator::getAuthHeader(std::string method, std::string uri) {
|
||||
std::string result = "Authorization: ";
|
||||
if (fAuthMethod == AUTH_BASIC)
|
||||
{
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace zm {
|
||||
enum AuthMethod { AUTH_UNDEFINED = 0, AUTH_BASIC = 1, AUTH_DIGEST = 2 };
|
||||
class Authenticator {
|
||||
public:
|
||||
Authenticator(std::string &username, std::string password);
|
||||
Authenticator(const std::string &username, const std::string &password);
|
||||
virtual ~Authenticator();
|
||||
void reset();
|
||||
|
||||
@@ -60,7 +60,7 @@ private:
|
||||
std::string fQop;
|
||||
std::string fUsername;
|
||||
std::string fPassword;
|
||||
std::string quote( std::string src );
|
||||
std::string quote( const std::string &src );
|
||||
int nc;
|
||||
};
|
||||
|
||||
|
||||
34
src/zm_sdp.h
34
src/zm_sdp.h
@@ -71,7 +71,7 @@ public:
|
||||
int mNoAddresses;
|
||||
|
||||
public:
|
||||
ConnInfo( const std::string &connInfo );
|
||||
explicit ConnInfo( const std::string &connInfo );
|
||||
};
|
||||
|
||||
class BandInfo {
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
int mValue;
|
||||
|
||||
public:
|
||||
BandInfo( const std::string &bandInfo );
|
||||
explicit BandInfo( const std::string &bandInfo );
|
||||
};
|
||||
|
||||
class MediaDescriptor {
|
||||
@@ -138,48 +138,38 @@ public:
|
||||
{
|
||||
return( mControlUrl );
|
||||
}
|
||||
void setControlUrl( const std::string &controlUrl )
|
||||
{
|
||||
void setControlUrl( const std::string &controlUrl ) {
|
||||
mControlUrl = controlUrl;
|
||||
}
|
||||
|
||||
const int getClock() const
|
||||
{
|
||||
const int getClock() const {
|
||||
return( mClock );
|
||||
}
|
||||
void setClock( int clock )
|
||||
{
|
||||
void setClock( int clock ) {
|
||||
mClock = clock;
|
||||
}
|
||||
|
||||
void setFrameSize( int width, int height )
|
||||
{
|
||||
void setFrameSize( int width, int height ) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
}
|
||||
int getWidth() const
|
||||
{
|
||||
int getWidth() const {
|
||||
return( mWidth );
|
||||
}
|
||||
int getHeight() const
|
||||
{
|
||||
int getHeight() const {
|
||||
return( mHeight );
|
||||
}
|
||||
|
||||
void setSprops(const std::string props)
|
||||
{
|
||||
void setSprops(const std::string &props) {
|
||||
mSprops = props;
|
||||
}
|
||||
const std::string getSprops() const
|
||||
{
|
||||
const std::string getSprops() const {
|
||||
return ( mSprops );
|
||||
}
|
||||
const double getFrameRate() const
|
||||
{
|
||||
const double getFrameRate() const {
|
||||
return( mFrameRate );
|
||||
}
|
||||
void setFrameRate( double frameRate )
|
||||
{
|
||||
void setFrameRate( double frameRate ) {
|
||||
mFrameRate = frameRate;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -32,8 +32,8 @@ protected:
|
||||
|
||||
public:
|
||||
Storage();
|
||||
Storage( MYSQL_ROW &dbrow );
|
||||
Storage( unsigned int p_id );
|
||||
explicit Storage( MYSQL_ROW &dbrow );
|
||||
explicit Storage( unsigned int p_id );
|
||||
~Storage();
|
||||
|
||||
unsigned int Id() const { return( id ); }
|
||||
|
||||
@@ -82,9 +82,29 @@ int SWScale::Convert(
|
||||
AVFrame *in_frame,
|
||||
AVFrame *out_frame
|
||||
) {
|
||||
|
||||
// THe J formats are deprecated, so we need to convert
|
||||
AVPixelFormat format;
|
||||
switch ( in_frame->format ) {
|
||||
case AV_PIX_FMT_YUVJ420P :
|
||||
format = AV_PIX_FMT_YUV420P;
|
||||
break;
|
||||
case AV_PIX_FMT_YUVJ422P :
|
||||
format = AV_PIX_FMT_YUV422P;
|
||||
break;
|
||||
case AV_PIX_FMT_YUVJ444P :
|
||||
format = AV_PIX_FMT_YUV444P;
|
||||
break;
|
||||
case AV_PIX_FMT_YUVJ440P :
|
||||
format = AV_PIX_FMT_YUV440P;
|
||||
break;
|
||||
default:
|
||||
format = (AVPixelFormat)in_frame->format;
|
||||
break;
|
||||
}
|
||||
/* Get the context */
|
||||
swscale_ctx = sws_getCachedContext( swscale_ctx,
|
||||
in_frame->width, in_frame->height, (AVPixelFormat)in_frame->format,
|
||||
in_frame->width, in_frame->height, format,
|
||||
out_frame->width, out_frame->height, (AVPixelFormat)out_frame->format,
|
||||
SWS_FAST_BILINEAR, NULL, NULL, NULL );
|
||||
if ( swscale_ctx == NULL ) {
|
||||
@@ -124,6 +144,24 @@ int SWScale::Convert(
|
||||
return -3;
|
||||
}
|
||||
|
||||
// THe J formats are deprecated, so we need to convert
|
||||
switch ( in_pf ) {
|
||||
case AV_PIX_FMT_YUVJ420P :
|
||||
in_pf = AV_PIX_FMT_YUV420P;
|
||||
break;
|
||||
case AV_PIX_FMT_YUVJ422P :
|
||||
in_pf = AV_PIX_FMT_YUV422P;
|
||||
break;
|
||||
case AV_PIX_FMT_YUVJ444P :
|
||||
in_pf = AV_PIX_FMT_YUV444P;
|
||||
break;
|
||||
case AV_PIX_FMT_YUVJ440P :
|
||||
in_pf = AV_PIX_FMT_YUV440P;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#if LIBSWSCALE_VERSION_CHECK(0, 8, 0, 8, 0)
|
||||
/* Warn if the input or output pixelformat is not supported */
|
||||
if(!sws_isSupportedInput(in_pf)) {
|
||||
|
||||
@@ -80,7 +80,7 @@ const std::string stringtf( const char *format, ... )
|
||||
return( tempString );
|
||||
}
|
||||
|
||||
const std::string stringtf( const std::string format, ... )
|
||||
const std::string stringtf( const std::string &format, ... )
|
||||
{
|
||||
va_list ap;
|
||||
char tempBuffer[8192];
|
||||
|
||||
@@ -33,7 +33,7 @@ std::string trimSet(std::string str, std::string trimset);
|
||||
std::string replaceAll(std::string str, std::string from, std::string to);
|
||||
|
||||
const std::string stringtf( const char *format, ... );
|
||||
const std::string stringtf( const std::string format, ... );
|
||||
const std::string stringtf( const std::string &format, ... );
|
||||
|
||||
bool startsWith( const std::string &haystack, const std::string &needle );
|
||||
StringVector split( const std::string &string, const std::string &chars, int limit=0 );
|
||||
|
||||
@@ -118,6 +118,7 @@ Debug(2,"Copied video context from input stream");
|
||||
#else
|
||||
avcodec_copy_context( video_out_ctx, video_in_ctx );
|
||||
#endif
|
||||
video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate
|
||||
// Same codec, just copy the packets, otherwise we have to decode/encode
|
||||
video_out_codec = (AVCodec *)video_in_ctx->codec;
|
||||
// Only set orientation if doing passthrough, otherwise the frame image will be rotated
|
||||
@@ -281,10 +282,9 @@ Error("Codec not set");
|
||||
);
|
||||
} // end if copying or trasncoding
|
||||
|
||||
|
||||
video_out_stream = avformat_new_stream(oc, video_out_codec);
|
||||
if ( !video_out_stream ) {
|
||||
Fatal("Unable to create video out stream\n");
|
||||
if ( ! video_out_stream ) {
|
||||
Fatal("Unable to create video out stream");
|
||||
} else {
|
||||
Debug(2, "Success creating video out stream");
|
||||
}
|
||||
@@ -303,7 +303,7 @@ Debug(2, "%dx%d", video_out_stream->codec->width, video_out_stream->codec->heigh
|
||||
zm_dump_codec(video_out_ctx);
|
||||
zm_dump_codec(video_out_stream->codec);
|
||||
#endif
|
||||
#if 0
|
||||
#if 1
|
||||
video_out_stream->time_base.num = video_out_ctx->time_base.num;
|
||||
video_out_stream->time_base.den = video_out_ctx->time_base.den;
|
||||
#endif
|
||||
@@ -964,6 +964,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) {
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
av_init_packet(&opkt);
|
||||
int data_present;
|
||||
if ( (ret = avcodec_encode_video2(
|
||||
video_out_ctx, &opkt, zm_packet->frame, &data_present)) < 0) {
|
||||
@@ -983,9 +984,16 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) {
|
||||
AVPacket *ipkt = &zm_packet->packet;
|
||||
Debug(3, "Doing passthrough, just copy packet");
|
||||
// Just copy it because the codec is the same
|
||||
av_init_packet(&opkt);
|
||||
opkt.data = ipkt->data;
|
||||
opkt.size = ipkt->size;
|
||||
opkt.flags = ipkt->flags;
|
||||
if ( ! video_last_pts ) {
|
||||
video_last_pts = zm_packet->timestamp.tv_sec*1000000 + zm_packet->timestamp.tv_usec;
|
||||
opkt.dts = opkt.pts = 0;
|
||||
} else {
|
||||
opkt.dts = opkt.pts = ( zm_packet->timestamp.tv_sec*1000000 + zm_packet->timestamp.tv_usec ) - video_last_pts;
|
||||
}
|
||||
}
|
||||
|
||||
int keyframe = opkt.flags & AV_PKT_FLAG_KEY;
|
||||
@@ -1014,7 +1022,7 @@ void VideoStore::write_video_packet( AVPacket &opkt ) {
|
||||
|
||||
//AVPacket safepkt;
|
||||
//memcpy(&safepkt, &opkt, sizeof(AVPacket));
|
||||
av_packet_rescale_ts( &opkt, video_out_ctx->time_base, video_out_stream->time_base );
|
||||
//av_packet_rescale_ts( &opkt, video_out_ctx->time_base, video_out_stream->time_base );
|
||||
|
||||
Debug(1,
|
||||
"writing video packet pts(%d) dts(%d) duration(%d) packet_count(%d)",
|
||||
@@ -1102,11 +1110,12 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) {
|
||||
}
|
||||
#endif
|
||||
int frame_size = out_frame->nb_samples;
|
||||
in_frame->pts = audio_next_pts;
|
||||
|
||||
// Resample the in into the audioSampleBuffer until we proceed the whole
|
||||
// decoded data
|
||||
if ((ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data,
|
||||
0, in_frame->nb_samples)) < 0) {
|
||||
0, frame_size)) < 0) {
|
||||
Error("Could not resample frame (error '%s')\n",
|
||||
av_make_error_string(ret).c_str());
|
||||
av_frame_unref(in_frame);
|
||||
@@ -1115,16 +1124,14 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) {
|
||||
av_frame_unref(in_frame);
|
||||
|
||||
int samples_available = avresample_available(resample_ctx);
|
||||
|
||||
if (samples_available < frame_size) {
|
||||
if ( samples_available < frame_size ) {
|
||||
Debug(1, "Not enough samples yet (%d)", samples_available);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Debug(3, "Output_frame samples (%d)", out_frame->nb_samples);
|
||||
// Read a frame audio data from the resample fifo
|
||||
if (avresample_read(resample_ctx, out_frame->data, frame_size) !=
|
||||
frame_size) {
|
||||
if ( avresample_read(resample_ctx, out_frame->data, frame_size) != frame_size) {
|
||||
Warning("Error reading resampled audio: ");
|
||||
return 0;
|
||||
}
|
||||
@@ -1146,8 +1153,8 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) {
|
||||
|
||||
// av_frame_unref( out_frame );
|
||||
|
||||
if ((ret = avcodec_receive_packet(audio_out_ctx, &opkt)) < 0) {
|
||||
if (AVERROR(EAGAIN) == ret) {
|
||||
if ( (ret = avcodec_receive_packet(audio_out_ctx, &opkt)) < 0 ) {
|
||||
if ( AVERROR(EAGAIN) == ret ) {
|
||||
// THe codec may need more samples than it has, perfectly valid
|
||||
Debug(3, "Could not recieve packet (error '%s')",
|
||||
av_make_error_string(ret).c_str());
|
||||
@@ -1155,20 +1162,20 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) {
|
||||
Error("Could not recieve packet (error %d = '%s')", ret,
|
||||
av_make_error_string(ret).c_str());
|
||||
}
|
||||
zm_av_packet_unref(&opkt);
|
||||
//zm_av_packet_unref(&opkt);
|
||||
av_frame_unref(in_frame);
|
||||
// av_frame_unref( out_frame );
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
if ((ret = avcodec_encode_audio2(audio_out_ctx, &opkt, out_frame,
|
||||
if ( (ret = avcodec_encode_audio2(audio_out_ctx, &opkt, out_frame,
|
||||
&data_present)) < 0) {
|
||||
Error("Could not encode frame (error '%s')",
|
||||
av_make_error_string(ret).c_str());
|
||||
zm_av_packet_unref(&opkt);
|
||||
return 0;
|
||||
}
|
||||
if (!data_present) {
|
||||
if ( !data_present ) {
|
||||
Debug(2, "Not ready to out a frame yet.");
|
||||
zm_av_packet_unref(&opkt);
|
||||
return 0;
|
||||
@@ -1176,11 +1183,13 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) {
|
||||
#endif
|
||||
|
||||
#endif
|
||||
opkt.duration = out_frame->nb_samples;
|
||||
} else {
|
||||
av_init_packet(&opkt);
|
||||
Debug(5, "after init packet");
|
||||
opkt.data = ipkt->data;
|
||||
opkt.size = ipkt->size;
|
||||
opkt.duration = ipkt->duration;
|
||||
}
|
||||
|
||||
// PTS is difficult, because of the buffering of the audio packets in the
|
||||
@@ -1245,7 +1254,7 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) {
|
||||
opkt.dts = opkt.pts;
|
||||
}
|
||||
|
||||
opkt.duration = out_frame ? out_frame->nb_samples : ipkt->duration;
|
||||
//opkt.duration = out_frame ? out_frame->nb_samples : ipkt->duration;
|
||||
// opkt.duration = av_rescale_q(ipkt->duration, audio_in_stream->time_base,
|
||||
// audio_out_stream->time_base);
|
||||
Debug(2, "opkt.pts (%d), opkt.dts(%d) opkt.duration = (%d)", opkt.pts,
|
||||
@@ -1260,7 +1269,7 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) {
|
||||
AVPacket safepkt;
|
||||
memcpy(&safepkt, &opkt, sizeof(AVPacket));
|
||||
ret = av_interleaved_write_frame(oc, &opkt);
|
||||
if (ret != 0) {
|
||||
if ( ret != 0 ) {
|
||||
Error("Error writing audio frame packet: %s\n",
|
||||
av_make_error_string(ret).c_str());
|
||||
dumpPacket(&safepkt);
|
||||
|
||||
Reference in New Issue
Block a user