Merge ../ZoneMinder.connortechnology

This commit is contained in:
Isaac Connor 2017-05-20 09:03:57 -04:00
commit a5ee8307d0
9 changed files with 1227 additions and 1432 deletions

View File

@ -129,7 +129,7 @@ BEGIN {
} # end BEGIN } # end BEGIN
sub loadConfigFromDB { sub loadConfigFromDB {
print( "Loading config from DB\n" ); print( "Loading config from DB" );
my $dbh = ZoneMinder::Database::zmDbConnect(); my $dbh = ZoneMinder::Database::zmDbConnect();
if ( !$dbh ) { if ( !$dbh ) {
print( "Error: unable to load options from database: $DBI::errstr\n" ); print( "Error: unable to load options from database: $DBI::errstr\n" );
@ -160,11 +160,12 @@ sub loadConfigFromDB {
$option_count++;; $option_count++;;
} }
$sth->finish(); $sth->finish();
print( " $option_count entries\n" );
return( $option_count ); return( $option_count );
} # end sub loadConfigFromDB } # end sub loadConfigFromDB
sub saveConfigToDB { sub saveConfigToDB {
print( "Saving config to DB\n" ); print( "Saving config to DB " . @options . " entries\n" );
my $dbh = ZoneMinder::Database::zmDbConnect(); my $dbh = ZoneMinder::Database::zmDbConnect();
if ( !$dbh ) { if ( !$dbh ) {
print( "Error: unable to save options to database: $DBI::errstr\n" ); print( "Error: unable to save options to database: $DBI::errstr\n" );

View File

@ -82,7 +82,7 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
struct tm *stime = localtime( &start_time.tv_sec ); struct tm *stime = localtime( &start_time.tv_sec );
snprintf( sql, sizeof(sql), "insert into Events ( MonitorId, Name, StartTime, Width, Height, Cause, Notes, Videoed ) values ( %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', '%d' )", monitor->Id(), start_time.tv_sec, monitor->Width(), monitor->Height(), cause.c_str(), notes.c_str(), videoEvent ); snprintf( sql, sizeof(sql), "insert into Events ( MonitorId, Name, StartTime, Width, Height, Cause, Notes, Videoed ) values ( %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', '%d' )", monitor->Id(), start_time.tv_sec, monitor->Width(), monitor->Height(), cause.c_str(), notes.c_str(), videoEvent );
if ( mysql_query( &dbconn, sql ) ) { if ( mysql_query( &dbconn, sql ) ) {
Error( "Can't insert event: %s", mysql_error( &dbconn ) ); Error( "Can't insert event: %s. sql was (%s)", mysql_error( &dbconn ), sql );
exit( mysql_errno( &dbconn ) ); exit( mysql_errno( &dbconn ) );
} }
id = mysql_insert_id( &dbconn ); id = mysql_insert_id( &dbconn );
@ -163,11 +163,9 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
if ( monitor->GetOptVideoWriter() != 0 ) { if ( monitor->GetOptVideoWriter() != 0 ) {
snprintf( video_name, sizeof(video_name), "%d-%s", id, "video.mp4" ); snprintf( video_name, sizeof(video_name), "%d-%s", id, "video.mp4" );
snprintf( video_file, sizeof(video_file), video_file_format, path, video_name ); snprintf( video_file, sizeof(video_file), video_file_format, path, video_name );
snprintf( timecodes_name, sizeof(timecodes_name), "%d-%s", id, "video.timecodes" );
snprintf( timecodes_file, sizeof(timecodes_file), video_file_format, path, timecodes_name );
/* X264 MP4 video writer */ /* X264 MP4 video writer */
if(monitor->GetOptVideoWriter() == 1) { if ( monitor->GetOptVideoWriter() == X264ENCODE ) {
#if ZM_HAVE_VIDEOWRITER_X264MP4 #if ZM_HAVE_VIDEOWRITER_X264MP4
videowriter = new X264MP4Writer(video_file, monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder(), monitor->GetOptEncoderParams()); videowriter = new X264MP4Writer(video_file, monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder(), monitor->GetOptEncoderParams());
#else #else
@ -184,6 +182,9 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
videowriter = NULL; videowriter = NULL;
} }
snprintf( timecodes_name, sizeof(timecodes_name), "%d-%s", id, "video.timecodes" );
snprintf( timecodes_file, sizeof(timecodes_file), video_file_format, path, timecodes_name );
/* Create timecodes file */ /* Create timecodes file */
timecodes_fd = fopen(timecodes_file, "wb"); timecodes_fd = fopen(timecodes_file, "wb");
if ( timecodes_fd == NULL ) { if ( timecodes_fd == NULL ) {
@ -330,12 +331,12 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap ) {
noteSet.insert( newNote ); noteSet.insert( newNote );
update = true; update = true;
} }
} } // end for
} } // end if ( noteSetMap.size() == 0
} } // end if newNoteSetupMap.size() > 0
} } // end foreach newNoteSetMap
} } // end if have old notes
} } // end if have new notes
if ( update ) { if ( update ) {
std::string notes; std::string notes;

View File

@ -181,8 +181,9 @@ void Logger::initialise( const std::string &id, const Options &options ) {
} }
} }
} }
} } // end foreach target
} } // end if config.log_debug
logFile( tempLogFile ); logFile( tempLogFile );
@ -196,7 +197,6 @@ void Logger::initialise( const std::string &id, const Options &options ) {
mFlush = (envPtr = getenv( "LOG_FLUSH")) ? atoi( envPtr ) : false; mFlush = (envPtr = getenv( "LOG_FLUSH")) ? atoi( envPtr ) : false;
//mRuntime = (envPtr = getenv( "LOG_RUNTIME")) ? atoi( envPtr ) : false; //mRuntime = (envPtr = getenv( "LOG_RUNTIME")) ? atoi( envPtr ) : false;
{ {
struct sigaction action; struct sigaction action;
memset( &action, 0, sizeof(action) ); memset( &action, 0, sizeof(action) );
@ -465,16 +465,13 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co
gettimeofday( &timeVal, NULL ); gettimeofday( &timeVal, NULL );
#if 0 #if 0
if ( logRuntime ) if ( logRuntime ) {
{
static struct timeval logStart; static struct timeval logStart;
subtractTime( &timeVal, &logStart ); subtractTime( &timeVal, &logStart );
snprintf( timeString, sizeof(timeString), "%ld.%03ld", timeVal.tv_sec, timeVal.tv_usec/1000 ); snprintf( timeString, sizeof(timeString), "%ld.%03ld", timeVal.tv_sec, timeVal.tv_usec/1000 );
} } else {
else
{
#endif #endif
char *timePtr = timeString; char *timePtr = timeString;
timePtr += strftime( timePtr, sizeof(timeString), "%x %H:%M:%S", localtime(&timeVal.tv_sec) ); timePtr += strftime( timePtr, sizeof(timeString), "%x %H:%M:%S", localtime(&timeVal.tv_sec) );

View File

@ -25,8 +25,7 @@
#include "zm_mpeg.h" #include "zm_mpeg.h"
#if HAVE_LIBAVCODEC #if HAVE_LIBAVCODEC
extern "C" extern "C" {
{
#include <libavutil/mathematics.h> #include <libavutil/mathematics.h>
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
} }
@ -40,8 +39,7 @@ VideoStream::MimeData VideoStream::mime_data[] = {
{ "mov", "video/quicktime" } { "mov", "video/quicktime" }
}; };
void VideoStream::Initialise( ) void VideoStream::Initialise( ) {
{
if ( logDebugging() ) { if ( logDebugging() ) {
av_log_set_level( AV_LOG_DEBUG ); av_log_set_level( AV_LOG_DEBUG );
} else { } else {
@ -55,16 +53,14 @@ void VideoStream::Initialise( )
initialised = true; initialised = true;
} }
void VideoStream::SetupFormat( ) void VideoStream::SetupFormat( ) {
{
/* allocate the output media context */ /* allocate the output media context */
ofc = NULL; ofc = NULL;
#if (LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 2, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100)) #if (LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 2, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100))
avformat_alloc_output_context2( &ofc, NULL, format, filename ); avformat_alloc_output_context2( &ofc, NULL, format, filename );
#else #else
AVFormatContext *s= avformat_alloc_context(); AVFormatContext *s= avformat_alloc_context();
if(!s) if(!s) {
{
Fatal( "avformat_alloc_context failed %d \"%s\"", (size_t)ofc, av_err2str((size_t)ofc) ); Fatal( "avformat_alloc_context failed %d \"%s\"", (size_t)ofc, av_err2str((size_t)ofc) );
} }
@ -92,8 +88,7 @@ void VideoStream::SetupFormat( )
if (s->oformat->priv_data_size > 0) { if (s->oformat->priv_data_size > 0) {
s->priv_data = av_mallocz(s->oformat->priv_data_size); 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." ); Fatal( "Could not allocate private data for output format." );
} }
#if LIBAVFORMAT_VERSION_CHECK(52, 92, 0, 92, 0) #if LIBAVFORMAT_VERSION_CHECK(52, 92, 0, 92, 0)
@ -102,21 +97,17 @@ void VideoStream::SetupFormat( )
av_opt_set_defaults(s->priv_data); av_opt_set_defaults(s->priv_data);
} }
#endif #endif
} } else {
else
{
s->priv_data = NULL; s->priv_data = NULL;
} }
if(filename) if ( filename ) {
{
snprintf( s->filename, sizeof(s->filename), "%s", filename ); snprintf( s->filename, sizeof(s->filename), "%s", filename );
} }
ofc = s; ofc = s;
#endif #endif
if ( !ofc ) if ( !ofc ) {
{
Fatal( "avformat_alloc_..._context failed: %d", ofc ); Fatal( "avformat_alloc_..._context failed: %d", ofc );
} }
@ -124,8 +115,7 @@ void VideoStream::SetupFormat( )
Debug( 1, "Using output format: %s (%s)", of->name, of->long_name ); Debug( 1, "Using output format: %s (%s)", of->name, of->long_name );
} }
void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int height, int bitrate, double frame_rate ) void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int height, int bitrate, double frame_rate ) {
{
/* ffmpeg format matching */ /* ffmpeg format matching */
switch(colours) { switch(colours) {
case ZM_COLOUR_RGB24: case ZM_COLOUR_RGB24:
@ -164,29 +154,23 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
break; break;
} }
if ( strcmp( "rtp", of->name ) == 0 ) if ( strcmp( "rtp", of->name ) == 0 ) {
{
// RTP must have a packet_size. // RTP must have a packet_size.
// Not sure what this value should be really... // Not sure what this value should be really...
ofc->packet_size = width*height; ofc->packet_size = width*height;
if ( of->video_codec == AV_CODEC_ID_NONE) if ( of->video_codec == AV_CODEC_ID_NONE ) {
{
// RTP does not have a default codec in ffmpeg <= 0.8. // RTP does not have a default codec in ffmpeg <= 0.8.
of->video_codec = AV_CODEC_ID_MPEG4; of->video_codec = AV_CODEC_ID_MPEG4;
} }
} }
_AVCODECID codec_id = of->video_codec; _AVCODECID codec_id = of->video_codec;
if ( codec_name ) if ( codec_name ) {
{
AVCodec *a = avcodec_find_encoder_by_name(codec_name); AVCodec *a = avcodec_find_encoder_by_name(codec_name);
if ( a ) if ( a ) {
{
codec_id = a->id; codec_id = a->id;
} } else {
else
{
#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100)) #if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100))
Debug( 1, "Could not find codec \"%s\". Using default \"%s\"", codec_name, avcodec_get_name( codec_id ) ); Debug( 1, "Could not find codec \"%s\". Using default \"%s\"", codec_name, avcodec_get_name( codec_id ) );
#else #else
@ -198,11 +182,9 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
/* add the video streams using the default format codecs /* add the video streams using the default format codecs
and initialize the codecs */ and initialize the codecs */
ost = NULL; ost = NULL;
if ( codec_id != AV_CODEC_ID_NONE ) if ( codec_id != AV_CODEC_ID_NONE ) {
{
codec = avcodec_find_encoder( codec_id ); codec = avcodec_find_encoder( codec_id );
if ( !codec ) if ( !codec ) {
{
#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100)) #if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100))
Fatal( "Could not find encoder for '%s'", avcodec_get_name( codec_id ) ); Fatal( "Could not find encoder for '%s'", avcodec_get_name( codec_id ) );
#else #else
@ -222,8 +204,7 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
ost = av_new_stream( ofc, 0 ); ost = av_new_stream( ofc, 0 );
#endif #endif
if ( !ost ) if ( !ost ) {
{
Fatal( "Could not alloc stream" ); Fatal( "Could not alloc stream" );
} }
ost->id = ofc->nb_streams - 1; ost->id = ofc->nb_streams - 1;
@ -236,15 +217,12 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
c->codec_type = codec->type; c->codec_type = codec->type;
c->pix_fmt = strcmp( "mjpeg", ofc->oformat->name ) == 0 ? AV_PIX_FMT_YUVJ422P : AV_PIX_FMT_YUV420P; c->pix_fmt = strcmp( "mjpeg", ofc->oformat->name ) == 0 ? AV_PIX_FMT_YUVJ422P : AV_PIX_FMT_YUV420P;
if ( bitrate <= 100 ) if ( bitrate <= 100 ) {
{
// Quality based bitrate control (VBR). Scale is 1..31 where 1 is best. // Quality based bitrate control (VBR). Scale is 1..31 where 1 is best.
// This gets rid of artifacts in the beginning of the movie; and well, even quality. // This gets rid of artifacts in the beginning of the movie; and well, even quality.
c->flags |= CODEC_FLAG_QSCALE; c->flags |= CODEC_FLAG_QSCALE;
c->global_quality = FF_QP2LAMBDA * (31 - (31 * (bitrate / 100.0))); c->global_quality = FF_QP2LAMBDA * (31 - (31 * (bitrate / 100.0)));
} } else {
else
{
c->bit_rate = bitrate; c->bit_rate = bitrate;
} }
@ -266,30 +244,23 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
// some formats want stream headers to be separate // some formats want stream headers to be separate
if ( of->flags & AVFMT_GLOBALHEADER ) if ( of->flags & AVFMT_GLOBALHEADER )
c->flags |= CODEC_FLAG_GLOBAL_HEADER; c->flags |= CODEC_FLAG_GLOBAL_HEADER;
} } else {
else
{
Fatal( "of->video_codec == AV_CODEC_ID_NONE" ); Fatal( "of->video_codec == AV_CODEC_ID_NONE" );
} }
} }
void VideoStream::SetParameters( ) void VideoStream::SetParameters( ) {
{
} }
const char *VideoStream::MimeType( ) const const char *VideoStream::MimeType( ) const {
{ for ( unsigned int i = 0; i < sizeof (mime_data) / sizeof (*mime_data); i++ ) {
for ( unsigned int i = 0; i < sizeof (mime_data) / sizeof (*mime_data); i++ ) if ( strcmp( format, mime_data[i].format ) == 0 ) {
{
if ( strcmp( format, mime_data[i].format ) == 0 )
{
Debug( 1, "MimeType is \"%s\"", mime_data[i].mime_type ); Debug( 1, "MimeType is \"%s\"", mime_data[i].mime_type );
return ( mime_data[i].mime_type); return ( mime_data[i].mime_type);
} }
} }
const char *mime_type = of->mime_type; const char *mime_type = of->mime_type;
if ( !mime_type ) if ( !mime_type ) {
{
std::string mime = "video/"; std::string mime = "video/";
mime = mime.append( format ); mime = mime.append( format );
mime_type = mime.c_str( ); mime_type = mime.c_str( );
@ -301,14 +272,12 @@ const char *VideoStream::MimeType( ) const
return ( mime_type); return ( mime_type);
} }
void VideoStream::OpenStream( ) void VideoStream::OpenStream( ) {
{
int avRet; int avRet;
/* now that all the parameters are set, we can open the /* now that all the parameters are set, we can open the
video codecs and allocate the necessary encode buffers */ video codecs and allocate the necessary encode buffers */
if ( ost ) if ( ost ) {
{
AVCodecContext *c = ost->codec; AVCodecContext *c = ost->codec;
/* open the codec */ /* open the codec */
@ -329,26 +298,19 @@ void VideoStream::OpenStream( )
#else #else
opicture = avcodec_alloc_frame( ); opicture = avcodec_alloc_frame( );
#endif #endif
if ( !opicture ) if ( !opicture ) {
{
Panic( "Could not allocate opicture" ); Panic( "Could not allocate opicture" );
} }
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
int size = av_image_get_buffer_size( c->pix_fmt, c->width, int size = av_image_get_buffer_size( c->pix_fmt, c->width, c->height, 1 );
c->height, 1 );
#else #else
int size = avpicture_get_size( c->pix_fmt, c->width, c->height ); int size = avpicture_get_size( c->pix_fmt, c->width, c->height );
#endif #endif
uint8_t *opicture_buf = (uint8_t *)av_malloc( size ); uint8_t *opicture_buf = (uint8_t *)av_malloc( size );
if ( !opicture_buf ) if ( !opicture_buf ) {
{
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
av_frame_free( &opicture ); av_frame_free( &opicture );
#else
av_freep( &opicture );
#endif
Panic( "Could not allocate opicture_buf" ); Panic( "Could not allocate opicture_buf" );
} }
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
@ -363,31 +325,23 @@ void VideoStream::OpenStream( )
picture is needed too. It is then converted to the required picture is needed too. It is then converted to the required
output format */ output format */
tmp_opicture = NULL; tmp_opicture = NULL;
if ( c->pix_fmt != pf ) if ( c->pix_fmt != pf ) {
{
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) #if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
tmp_opicture = av_frame_alloc( ); tmp_opicture = av_frame_alloc( );
#else #else
tmp_opicture = avcodec_alloc_frame( ); tmp_opicture = avcodec_alloc_frame( );
#endif #endif
if ( !tmp_opicture ) if ( !tmp_opicture ) {
{
Panic( "Could not allocate tmp_opicture" ); Panic( "Could not allocate tmp_opicture" );
} }
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
int size = av_image_get_buffer_size( pf, c->width, int size = av_image_get_buffer_size( pf, c->width, c->height,1 );
c->height,1 );
#else #else
int size = avpicture_get_size( pf, c->width, c->height ); int size = avpicture_get_size( pf, c->width, c->height );
#endif #endif
uint8_t *tmp_opicture_buf = (uint8_t *)av_malloc( size ); uint8_t *tmp_opicture_buf = (uint8_t *)av_malloc( size );
if ( !tmp_opicture_buf ) if ( !tmp_opicture_buf ) {
{
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
av_frame_free( &tmp_opicture ); av_frame_free( &tmp_opicture );
#else
av_freep( &tmp_opicture );
#endif
Panic( "Could not allocate tmp_opicture_buf" ); Panic( "Could not allocate tmp_opicture_buf" );
} }
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
@ -402,8 +356,7 @@ void VideoStream::OpenStream( )
} }
/* open the output file, if needed */ /* open the output file, if needed */
if ( !(of->flags & AVFMT_NOFILE) ) if ( !(of->flags & AVFMT_NOFILE) ) {
{
int ret; int ret;
#if LIBAVFORMAT_VERSION_CHECK(53, 15, 0, 21, 0) #if LIBAVFORMAT_VERSION_CHECK(53, 15, 0, 21, 0)
ret = avio_open2( &ofc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL ); ret = avio_open2( &ofc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL );
@ -412,21 +365,17 @@ void VideoStream::OpenStream( )
#else #else
ret = url_fopen( &ofc->pb, filename, AVIO_FLAG_WRITE ); ret = url_fopen( &ofc->pb, filename, AVIO_FLAG_WRITE );
#endif #endif
if ( ret < 0 ) if ( ret < 0 ) {
{
Fatal( "Could not open '%s'", filename ); Fatal( "Could not open '%s'", filename );
} }
Debug( 1, "Opened output \"%s\"", filename ); Debug( 1, "Opened output \"%s\"", filename );
} } else {
else
{
Fatal( "of->flags & AVFMT_NOFILE" ); Fatal( "of->flags & AVFMT_NOFILE" );
} }
video_outbuf = NULL; video_outbuf = NULL;
if ( !(of->flags & AVFMT_RAWPICTURE) ) if ( !(of->flags & AVFMT_RAWPICTURE) ) {
{
/* allocate output buffer */ /* allocate output buffer */
/* XXX: API change will be done */ /* XXX: API change will be done */
// TODO: Make buffer dynamic. // TODO: Make buffer dynamic.
@ -449,8 +398,7 @@ void VideoStream::OpenStream( )
int ret = avformat_write_header( ofc, NULL ); int ret = avformat_write_header( ofc, NULL );
#endif #endif
if ( ret < 0 ) if ( ret < 0 ) {
{
Fatal( "?_write_header failed with error %d \"%s\"", ret, av_err2str( ret ) ); Fatal( "?_write_header failed with error %d \"%s\"", ret, av_err2str( ret ) );
} }
} }
@ -467,21 +415,18 @@ VideoStream::VideoStream( const char *in_filename, const char *in_format, int bi
buffer_copy_used(0), buffer_copy_used(0),
packet_index(0) packet_index(0)
{ {
if ( !initialised ) if ( !initialised ) {
{
Initialise( ); Initialise( );
} }
if ( format ) if ( format ) {
{
int length = strlen(format); int length = strlen(format);
codec_and_format = new char[length+1];; codec_and_format = new char[length+1];;
strcpy( codec_and_format, format ); strcpy( codec_and_format, format );
format = codec_and_format; format = codec_and_format;
codec_name = NULL; codec_name = NULL;
char *f = strchr(codec_and_format, '/'); char *f = strchr(codec_and_format, '/');
if (f != NULL) if (f != NULL) {
{
*f = 0; *f = 0;
codec_name = f+1; codec_name = f+1;
} }
@ -498,19 +443,16 @@ VideoStream::VideoStream( const char *in_filename, const char *in_format, int bi
packet_index = 0; packet_index = 0;
// Initialize mutex used by streaming thread. // Initialize mutex used by streaming thread.
if ( pthread_mutex_init( buffer_copy_lock, NULL ) != 0 ) if ( pthread_mutex_init( buffer_copy_lock, NULL ) != 0 ) {
{
Fatal("pthread_mutex_init failed"); Fatal("pthread_mutex_init failed");
} }
} }
VideoStream::~VideoStream( ) VideoStream::~VideoStream( ) {
{
Debug( 1, "VideoStream destructor." ); Debug( 1, "VideoStream destructor." );
// Stop streaming thread. // Stop streaming thread.
if ( streaming_thread ) if ( streaming_thread ) {
{
do_streaming = false; do_streaming = false;
void* thread_exit_code; void* thread_exit_code;
@ -520,15 +462,12 @@ VideoStream::~VideoStream( )
pthread_join(streaming_thread, &thread_exit_code); pthread_join(streaming_thread, &thread_exit_code);
} }
if ( buffer_copy != NULL ) if ( buffer_copy != NULL ) {
{
av_free( buffer_copy ); av_free( buffer_copy );
} }
if ( buffer_copy_lock ) if ( buffer_copy_lock ) {
{ if ( pthread_mutex_destroy( buffer_copy_lock ) != 0 ) {
if ( pthread_mutex_destroy( buffer_copy_lock ) != 0 )
{
Error( "pthread_mutex_destroy failed" ); Error( "pthread_mutex_destroy failed" );
} }
delete buffer_copy_lock; delete buffer_copy_lock;
@ -541,23 +480,13 @@ VideoStream::~VideoStream( )
} }
/* close each codec */ /* close each codec */
if ( ost ) if ( ost ) {
{
avcodec_close( ost->codec ); avcodec_close( ost->codec );
av_free( opicture->data[0] ); av_free( opicture->data[0] );
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
av_frame_free( &opicture ); av_frame_free( &opicture );
#else if ( tmp_opicture ) {
av_freep( &opicture );
#endif
if ( tmp_opicture )
{
av_free( tmp_opicture->data[0] ); av_free( tmp_opicture->data[0] );
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
av_frame_free( &tmp_opicture ); av_frame_free( &tmp_opicture );
#else
av_freep( &tmp_opicture );
#endif
} }
av_free( video_outbuf ); av_free( video_outbuf );
} }
@ -566,13 +495,11 @@ VideoStream::~VideoStream( )
av_write_trailer( ofc ); av_write_trailer( ofc );
/* free the streams */ /* free the streams */
for ( unsigned int i = 0; i < ofc->nb_streams; i++ ) for ( unsigned int i = 0; i < ofc->nb_streams; i++ ) {
{
av_freep( &ofc->streams[i] ); av_freep( &ofc->streams[i] );
} }
if ( !(of->flags & AVFMT_NOFILE) ) if ( !(of->flags & AVFMT_NOFILE) ) {
{
/* close the output file */ /* close the output file */
#if LIBAVFORMAT_VERSION_CHECK(52, 105, 0, 105, 0) #if LIBAVFORMAT_VERSION_CHECK(52, 105, 0, 105, 0)
avio_close( ofc->pb ); avio_close( ofc->pb );
@ -585,30 +512,24 @@ VideoStream::~VideoStream( )
av_free( ofc ); av_free( ofc );
/* free format and codec_name data. */ /* free format and codec_name data. */
if ( codec_and_format ) if ( codec_and_format ) {
{
delete codec_and_format; delete codec_and_format;
} }
} }
double VideoStream::EncodeFrame( const uint8_t *buffer, int buffer_size, bool _add_timestamp, unsigned int _timestamp ) double VideoStream::EncodeFrame( const uint8_t *buffer, int buffer_size, bool _add_timestamp, unsigned int _timestamp ) {
{ if ( pthread_mutex_lock( buffer_copy_lock ) != 0 ) {
if ( pthread_mutex_lock( buffer_copy_lock ) != 0 )
{
Fatal( "EncodeFrame: pthread_mutex_lock failed." ); Fatal( "EncodeFrame: pthread_mutex_lock failed." );
} }
if (buffer_copy_size < buffer_size) if (buffer_copy_size < buffer_size) {
{ if ( buffer_copy ) {
if ( buffer_copy )
{
av_free( buffer_copy ); av_free( buffer_copy );
} }
// Allocate a buffer to store source images for the streaming thread to encode. // Allocate a buffer to store source images for the streaming thread to encode.
buffer_copy = (uint8_t *)av_malloc( buffer_size ); buffer_copy = (uint8_t *)av_malloc( buffer_size );
if ( !buffer_copy ) if ( !buffer_copy ) {
{
Panic( "Could not allocate buffer_copy" ); Panic( "Could not allocate buffer_copy" );
} }
buffer_copy_size = buffer_size; buffer_copy_size = buffer_size;
@ -619,13 +540,11 @@ double VideoStream::EncodeFrame( const uint8_t *buffer, int buffer_size, bool _a
buffer_copy_used = buffer_size; buffer_copy_used = buffer_size;
memcpy(buffer_copy, buffer, buffer_size); memcpy(buffer_copy, buffer, buffer_size);
if ( pthread_mutex_unlock( buffer_copy_lock ) != 0 ) if ( pthread_mutex_unlock( buffer_copy_lock ) != 0 ) {
{
Fatal( "EncodeFrame: pthread_mutex_unlock failed." ); Fatal( "EncodeFrame: pthread_mutex_unlock failed." );
} }
if ( streaming_thread == 0 ) if ( streaming_thread == 0 ) {
{
Debug( 1, "Starting streaming thread" ); Debug( 1, "Starting streaming thread" );
// Start a thread for streaming encoded video. // Start a thread for streaming encoded video.
@ -640,20 +559,17 @@ double VideoStream::EncodeFrame( const uint8_t *buffer, int buffer_size, bool _a
return _timestamp; return _timestamp;
} }
double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, bool add_timestamp, unsigned int timestamp ) double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, bool add_timestamp, unsigned int timestamp ) {
{
#ifdef HAVE_LIBSWSCALE #ifdef HAVE_LIBSWSCALE
static struct SwsContext *img_convert_ctx = 0; static struct SwsContext *img_convert_ctx = 0;
#endif // HAVE_LIBSWSCALE #endif // HAVE_LIBSWSCALE
AVCodecContext *c = ost->codec; AVCodecContext *c = ost->codec;
if ( c->pix_fmt != pf ) if ( c->pix_fmt != pf ) {
{
memcpy( tmp_opicture->data[0], buffer, buffer_size ); memcpy( tmp_opicture->data[0], buffer, buffer_size );
#ifdef HAVE_LIBSWSCALE #ifdef HAVE_LIBSWSCALE
if ( !img_convert_ctx ) if ( !img_convert_ctx ) {
{
img_convert_ctx = sws_getCachedContext( NULL, c->width, c->height, pf, c->width, c->height, c->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL ); img_convert_ctx = sws_getCachedContext( NULL, c->width, c->height, pf, c->width, c->height, c->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL );
if ( !img_convert_ctx ) if ( !img_convert_ctx )
Panic( "Unable to initialise image scaling context" ); Panic( "Unable to initialise image scaling context" );
@ -662,9 +578,7 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size,
#else // HAVE_LIBSWSCALE #else // HAVE_LIBSWSCALE
Fatal( "swscale is required for MPEG mode" ); Fatal( "swscale is required for MPEG mode" );
#endif // HAVE_LIBSWSCALE #endif // HAVE_LIBSWSCALE
} } else {
else
{
memcpy( opicture->data[0], buffer, buffer_size ); memcpy( opicture->data[0], buffer, buffer_size );
} }
AVFrame *opicture_ptr = opicture; AVFrame *opicture_ptr = opicture;
@ -672,8 +586,7 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size,
AVPacket *pkt = packet_buffers[packet_index]; AVPacket *pkt = packet_buffers[packet_index];
av_init_packet( pkt ); av_init_packet( pkt );
int got_packet = 0; int got_packet = 0;
if ( of->flags & AVFMT_RAWPICTURE ) if ( of->flags & AVFMT_RAWPICTURE ) {
{
#if LIBAVCODEC_VERSION_CHECK(52, 30, 2, 30, 2) #if LIBAVCODEC_VERSION_CHECK(52, 30, 2, 30, 2)
pkt->flags |= AV_PKT_FLAG_KEY; pkt->flags |= AV_PKT_FLAG_KEY;
#else #else
@ -683,16 +596,13 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size,
pkt->data = (uint8_t *)opicture_ptr; pkt->data = (uint8_t *)opicture_ptr;
pkt->size = sizeof (AVPicture); pkt->size = sizeof (AVPicture);
got_packet = 1; got_packet = 1;
} } else {
else
{
opicture_ptr->pts = c->frame_number; opicture_ptr->pts = c->frame_number;
opicture_ptr->quality = c->global_quality; opicture_ptr->quality = c->global_quality;
#if LIBAVFORMAT_VERSION_CHECK(54, 1, 0, 2, 100) #if LIBAVFORMAT_VERSION_CHECK(54, 1, 0, 2, 100)
int ret = avcodec_encode_video2( c, pkt, opicture_ptr, &got_packet ); int ret = avcodec_encode_video2( c, pkt, opicture_ptr, &got_packet );
if ( ret != 0 ) if ( ret != 0 ) {
{
Fatal( "avcodec_encode_video2 failed with errorcode %d \"%s\"", ret, av_err2str( ret ) ); Fatal( "avcodec_encode_video2 failed with errorcode %d \"%s\"", ret, av_err2str( ret ) );
} }
#else #else
@ -701,8 +611,7 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size,
pkt->data = got_packet ? video_outbuf : NULL; pkt->data = got_packet ? video_outbuf : NULL;
pkt->size = got_packet ? out_size : 0; pkt->size = got_packet ? out_size : 0;
#endif #endif
if ( got_packet ) if ( got_packet ) {
{
// if ( c->coded_frame->key_frame ) // if ( c->coded_frame->key_frame )
// { // {
//#if LIBAVCODEC_VERSION_CHECK(52, 30, 2, 30, 2) //#if LIBAVCODEC_VERSION_CHECK(52, 30, 2, 30, 2)
@ -712,12 +621,10 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size,
//#endif //#endif
// } // }
if ( pkt->pts != (int64_t)AV_NOPTS_VALUE ) if ( pkt->pts != (int64_t)AV_NOPTS_VALUE ) {
{
pkt->pts = av_rescale_q( pkt->pts, c->time_base, ost->time_base ); pkt->pts = av_rescale_q( pkt->pts, c->time_base, ost->time_base );
} }
if ( pkt->dts != (int64_t)AV_NOPTS_VALUE ) if ( pkt->dts != (int64_t)AV_NOPTS_VALUE ) {
{
pkt->dts = av_rescale_q( pkt->dts, c->time_base, ost->time_base ); pkt->dts = av_rescale_q( pkt->dts, c->time_base, ost->time_base );
} }
pkt->duration = av_rescale_q( pkt->duration, c->time_base, ost->time_base ); pkt->duration = av_rescale_q( pkt->duration, c->time_base, ost->time_base );
@ -731,8 +638,7 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size,
int VideoStream::SendPacket(AVPacket *packet) { int VideoStream::SendPacket(AVPacket *packet) {
int ret = av_write_frame( ofc, packet ); int ret = av_write_frame( ofc, packet );
if ( ret != 0 ) if ( ret != 0 ) {
{
Fatal( "Error %d while writing video frame: %s", ret, av_err2str( errno ) ); Fatal( "Error %d while writing video frame: %s", ret, av_err2str( errno ) );
} }
#if LIBAVCODEC_VERSION_CHECK(57, 8, 0, 12, 100) #if LIBAVCODEC_VERSION_CHECK(57, 8, 0, 12, 100)
@ -758,15 +664,13 @@ void *VideoStream::StreamingThreadCallback(void *ctx){
timespec start_time; timespec start_time;
clock_gettime(CLOCK_MONOTONIC, &start_time); clock_gettime(CLOCK_MONOTONIC, &start_time);
uint64_t start_time_ns = (start_time.tv_sec*nanosecond_multiplier) + start_time.tv_nsec; uint64_t start_time_ns = (start_time.tv_sec*nanosecond_multiplier) + start_time.tv_nsec;
while(videoStream->do_streaming) while(videoStream->do_streaming) {
{
timespec current_time; timespec current_time;
clock_gettime(CLOCK_MONOTONIC, &current_time); clock_gettime(CLOCK_MONOTONIC, &current_time);
uint64_t current_time_ns = (current_time.tv_sec*nanosecond_multiplier) + current_time.tv_nsec; uint64_t current_time_ns = (current_time.tv_sec*nanosecond_multiplier) + current_time.tv_nsec;
uint64_t target_ns = start_time_ns + (target_interval_ns * frame_count); uint64_t target_ns = start_time_ns + (target_interval_ns * frame_count);
if ( current_time_ns < target_ns ) if ( current_time_ns < target_ns ) {
{
// It's not time to render a frame yet. // It's not time to render a frame yet.
usleep( (target_ns - current_time_ns) * 0.001 ); usleep( (target_ns - current_time_ns) * 0.001 );
} }
@ -789,19 +693,16 @@ void *VideoStream::StreamingThreadCallback(void *ctx){
// Lock buffer and render next frame. // Lock buffer and render next frame.
if ( pthread_mutex_lock( videoStream->buffer_copy_lock ) != 0 ) if ( pthread_mutex_lock( videoStream->buffer_copy_lock ) != 0 ) {
{
Fatal( "StreamingThreadCallback: pthread_mutex_lock failed." ); Fatal( "StreamingThreadCallback: pthread_mutex_lock failed." );
} }
if ( videoStream->buffer_copy ) if ( videoStream->buffer_copy ) {
{
// Encode next frame. // Encode next frame.
videoStream->ActuallyEncodeFrame( videoStream->buffer_copy, videoStream->buffer_copy_used, videoStream->add_timestamp, videoStream->timestamp ); videoStream->ActuallyEncodeFrame( videoStream->buffer_copy, videoStream->buffer_copy_used, videoStream->add_timestamp, videoStream->timestamp );
} }
if ( pthread_mutex_unlock( videoStream->buffer_copy_lock ) != 0 ) if ( pthread_mutex_unlock( videoStream->buffer_copy_lock ) != 0 ) {
{
Fatal( "StreamingThreadCallback: pthread_mutex_unlock failed." ); Fatal( "StreamingThreadCallback: pthread_mutex_unlock failed." );
} }

View File

@ -189,8 +189,7 @@ int RemoteCameraHttp::SendRequest()
* > 0 is the # of bytes read. * > 0 is the # of bytes read.
*/ */
int RemoteCameraHttp::ReadData( Buffer &buffer, unsigned int bytes_expected ) int RemoteCameraHttp::ReadData( Buffer &buffer, unsigned int bytes_expected ) {
{
fd_set rfds; fd_set rfds;
FD_ZERO(&rfds); FD_ZERO(&rfds);
FD_SET(sd, &rfds); FD_SET(sd, &rfds);
@ -198,35 +197,49 @@ int RemoteCameraHttp::ReadData( Buffer &buffer, unsigned int bytes_expected )
struct timeval temp_timeout = timeout; struct timeval temp_timeout = timeout;
int n_found = select( sd+1, &rfds, NULL, NULL, &temp_timeout ); int n_found = select( sd+1, &rfds, NULL, NULL, &temp_timeout );
if( n_found == 0 ) if( n_found == 0 ) {
{
Debug( 4, "Select timed out timeout was %d secs %d usecs", temp_timeout.tv_sec, temp_timeout.tv_usec ); Debug( 4, "Select timed out timeout was %d secs %d usecs", temp_timeout.tv_sec, temp_timeout.tv_usec );
int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (sd, SOL_SOCKET, SO_ERROR, &error, &len);
if(retval != 0 ) {
Debug( 1, "error getting socket error code %s", strerror(retval) );
}
if (error != 0) {
return -1;
}
// Why are we disconnecting? It's just a timeout, meaning that data wasn't available. // Why are we disconnecting? It's just a timeout, meaning that data wasn't available.
//Disconnect(); //Disconnect();
return( 0 ); return( 0 );
} } else if ( n_found < 0) {
else if ( n_found < 0)
{
Error( "Select error: %s", strerror(errno) ); Error( "Select error: %s", strerror(errno) );
return( -1 ); return( -1 );
} }
int total_bytes_to_read = 0; unsigned int total_bytes_to_read = 0;
if ( bytes_expected ) if ( bytes_expected ) {
{
total_bytes_to_read = bytes_expected; total_bytes_to_read = bytes_expected;
} } else {
else if ( ioctl( sd, FIONREAD, &total_bytes_to_read ) < 0 ) {
{
if ( ioctl( sd, FIONREAD, &total_bytes_to_read ) < 0 )
{
Error( "Can't ioctl(): %s", strerror(errno) ); Error( "Can't ioctl(): %s", strerror(errno) );
return( -1 ); return( -1 );
} }
if ( total_bytes_to_read == 0 ) if ( total_bytes_to_read == 0 ) {
{ if ( mode == SINGLE_IMAGE ) {
int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt( sd, SOL_SOCKET, SO_ERROR, &error, &len );
if(retval != 0 ) {
Debug( 1, "error getting socket error code %s", strerror(retval) );
}
if (error != 0) {
return -1;
}
// Case where we are grabbing a single jpg, but no content-length was given, so the expectation is that we read until close.
return( 0 );
}
// If socket is closed locally, then select will fail, but if it is closed remotely // If socket is closed locally, then select will fail, but if it is closed remotely
// then we have an exception on our socket.. but no data. // then we have an exception on our socket.. but no data.
Debug( 3, "Socket closed remotely" ); Debug( 3, "Socket closed remotely" );
@ -241,34 +254,27 @@ int RemoteCameraHttp::ReadData( Buffer &buffer, unsigned int bytes_expected )
} else { } else {
Debug(3, "Just getting %d", total_bytes_to_read ); Debug(3, "Just getting %d", total_bytes_to_read );
} }
} } // end if bytes_expected or not
Debug( 3, "Expecting %d bytes", total_bytes_to_read ); Debug( 3, "Expecting %d bytes", total_bytes_to_read );
int total_bytes_read = 0; int total_bytes_read = 0;
do do {
{
int bytes_read = buffer.read_into( sd, total_bytes_to_read ); int bytes_read = buffer.read_into( sd, total_bytes_to_read );
if ( bytes_read < 0) if ( bytes_read < 0 ) {
{
Error( "Read error: %s", strerror(errno) ); Error( "Read error: %s", strerror(errno) );
return( -1 ); return( -1 );
} } else if ( bytes_read == 0 ) {
else if ( bytes_read == 0)
{
Debug( 2, "Socket closed" ); Debug( 2, "Socket closed" );
//Disconnect(); // Disconnect is done outside of ReadData now. //Disconnect(); // Disconnect is done outside of ReadData now.
return( -1 ); return( -1 );
} } else if ( (unsigned int)bytes_read < total_bytes_to_read ) {
else if ( bytes_read < total_bytes_to_read )
{
Error( "Incomplete read, expected %d, got %d", total_bytes_to_read, bytes_read ); Error( "Incomplete read, expected %d, got %d", total_bytes_to_read, bytes_read );
return( -1 ); return( -1 );
} }
Debug( 3, "Read %d bytes", bytes_read ); Debug( 3, "Read %d bytes", bytes_read );
total_bytes_read += bytes_read; total_bytes_read += bytes_read;
total_bytes_to_read -= bytes_read; total_bytes_to_read -= bytes_read;
} } while ( total_bytes_to_read );
while ( total_bytes_to_read );
Debug( 4, buffer ); Debug( 4, buffer );
@ -308,6 +314,7 @@ int RemoteCameraHttp::GetResponse()
static RegExpr *content_type_expr = 0; static RegExpr *content_type_expr = 0;
while ( ! ( buffer_len = ReadData( buffer ) ) ) { while ( ! ( buffer_len = ReadData( buffer ) ) ) {
Debug(4, "Timeout waiting for REGEXP HEADER");
} }
if ( buffer_len < 0 ) { if ( buffer_len < 0 ) {
Error( "Unable to read header data" ); Error( "Unable to read header data" );
@ -481,6 +488,7 @@ int RemoteCameraHttp::GetResponse()
{ {
Debug( 3, "Unable to extract subheader from stream, retrying" ); Debug( 3, "Unable to extract subheader from stream, retrying" );
while ( ! ( buffer_len = ReadData( buffer ) ) ) { while ( ! ( buffer_len = ReadData( buffer ) ) ) {
Debug(4, "Timeout waiting to extract subheader");
} }
if ( buffer_len < 0 ) { if ( buffer_len < 0 ) {
Error( "Unable to extract subheader data" ); Error( "Unable to extract subheader data" );
@ -533,6 +541,7 @@ Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_
while ( !content_length ) while ( !content_length )
{ {
while ( ! ( buffer_len = ReadData( buffer ) ) ) { while ( ! ( buffer_len = ReadData( buffer ) ) ) {
Debug(4, "Timeout waiting for content");
} }
if ( buffer_len < 0 ) { if ( buffer_len < 0 ) {
Error( "Unable to read content" ); Error( "Unable to read content" );
@ -633,10 +642,8 @@ Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_
static char content_boundary[64]; static char content_boundary[64];
static int content_boundary_len; static int content_boundary_len;
while ( true ) while ( true ) {
{ switch( state ) {
switch( state )
{
case HEADER : case HEADER :
{ {
n_headers = 0; n_headers = 0;
@ -658,6 +665,7 @@ Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_
case HEADERCONT : case HEADERCONT :
{ {
while ( ! ( buffer_len = ReadData( buffer ) ) ) { while ( ! ( buffer_len = ReadData( buffer ) ) ) {
Debug(4, "Timeout waiting for HEADERCONT");
} }
if ( buffer_len < 0 ) { if ( buffer_len < 0 ) {
Error( "Unable to read header" ); Error( "Unable to read header" );
@ -669,13 +677,10 @@ Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_
int header_len = buffer.size(); int header_len = buffer.size();
bool all_headers = false; bool all_headers = false;
while( true ) while( true ) {
{
int crlf_len = memspn( header_ptr, "\r\n", header_len ); int crlf_len = memspn( header_ptr, "\r\n", header_len );
if ( n_headers ) if ( n_headers ) {
{ if ( (crlf_len == 2 && !strncmp( header_ptr, "\n\n", crlf_len )) || (crlf_len == 4 && !strncmp( header_ptr, "\r\n\r\n", crlf_len )) ) {
if ( (crlf_len == 2 && !strncmp( header_ptr, "\n\n", crlf_len )) || (crlf_len == 4 && !strncmp( header_ptr, "\r\n\r\n", crlf_len )) )
{
*header_ptr = '\0'; *header_ptr = '\0';
header_ptr += crlf_len; header_ptr += crlf_len;
header_len -= buffer.consume( header_ptr-(char *)buffer ); header_len -= buffer.consume( header_ptr-(char *)buffer );
@ -683,14 +688,10 @@ Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_
break; break;
} }
} }
if ( crlf_len ) if ( crlf_len ) {
{ if ( header_len == crlf_len ) {
if ( header_len == crlf_len )
{
break; break;
} } else {
else
{
*header_ptr = '\0'; *header_ptr = '\0';
header_ptr += crlf_len; header_ptr += crlf_len;
header_len -= buffer.consume( header_ptr-(char *)buffer ); header_len -= buffer.consume( header_ptr-(char *)buffer );
@ -698,57 +699,40 @@ Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_
} }
Debug( 6, "%s", header_ptr ); Debug( 6, "%s", header_ptr );
if ( (crlf = mempbrk( header_ptr, "\r\n", header_len )) ) if ( (crlf = mempbrk( header_ptr, "\r\n", header_len )) ) {
{
//headers[n_headers++] = header_ptr; //headers[n_headers++] = header_ptr;
n_headers++; n_headers++;
if ( !http_header && (strncasecmp( header_ptr, http_match, http_match_len ) == 0) ) if ( !http_header && (strncasecmp( header_ptr, http_match, http_match_len ) == 0) ) {
{
http_header = header_ptr+http_match_len; http_header = header_ptr+http_match_len;
Debug( 6, "Got http header '%s'", header_ptr ); Debug( 6, "Got http header '%s'", header_ptr );
} } else if ( !connection_header && (strncasecmp( header_ptr, connection_match, connection_match_len) == 0) ) {
else if ( !connection_header && (strncasecmp( header_ptr, connection_match, connection_match_len) == 0) )
{
connection_header = header_ptr+connection_match_len; connection_header = header_ptr+connection_match_len;
Debug( 6, "Got connection header '%s'", header_ptr ); Debug( 6, "Got connection header '%s'", header_ptr );
} } else if ( !content_length_header && (strncasecmp( header_ptr, content_length_match, content_length_match_len) == 0) ) {
else if ( !content_length_header && (strncasecmp( header_ptr, content_length_match, content_length_match_len) == 0) )
{
content_length_header = header_ptr+content_length_match_len; content_length_header = header_ptr+content_length_match_len;
Debug( 6, "Got content length header '%s'", header_ptr ); Debug( 6, "Got content length header '%s'", header_ptr );
} } else if ( !authenticate_header && (strncasecmp( header_ptr, authenticate_match, authenticate_match_len) == 0) ) {
else if ( !authenticate_header && (strncasecmp( header_ptr, authenticate_match, authenticate_match_len) == 0) )
{
authenticate_header = header_ptr; authenticate_header = header_ptr;
Debug( 6, "Got authenticate header '%s'", header_ptr ); Debug( 6, "Got authenticate header '%s'", header_ptr );
} } else if ( !content_type_header && (strncasecmp( header_ptr, content_type_match, content_type_match_len) == 0) ) {
else if ( !content_type_header && (strncasecmp( header_ptr, content_type_match, content_type_match_len) == 0) )
{
content_type_header = header_ptr+content_type_match_len; content_type_header = header_ptr+content_type_match_len;
Debug( 6, "Got content type header '%s'", header_ptr ); Debug( 6, "Got content type header '%s'", header_ptr );
} } else {
else
{
Debug( 6, "Got ignored header '%s'", header_ptr ); Debug( 6, "Got ignored header '%s'", header_ptr );
} }
header_ptr = crlf; header_ptr = crlf;
header_len -= buffer.consume( header_ptr-(char *)buffer ); header_len -= buffer.consume( header_ptr-(char *)buffer );
} } else {
else
{
// No end of line found // No end of line found
break; break;
} }
} } // end while search for headers
if ( all_headers ) if ( all_headers ) {
{
char *start_ptr, *end_ptr; char *start_ptr, *end_ptr;
if ( !http_header ) if ( !http_header ) {
{
Error( "Unable to extract HTTP status from header" ); Error( "Unable to extract HTTP status from header" );
return( -1 ); return( -1 );
} }
@ -756,6 +740,7 @@ Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_
start_ptr = http_header; start_ptr = http_header;
end_ptr = start_ptr+strspn( start_ptr, "10." ); end_ptr = start_ptr+strspn( start_ptr, "10." );
// FIXME WHy are we memsetting every time? Can we not do it once?
memset( http_version, 0, sizeof(http_version) ); memset( http_version, 0, sizeof(http_version) );
strncpy( http_version, start_ptr, end_ptr-start_ptr ); strncpy( http_version, start_ptr, end_ptr-start_ptr );
@ -800,82 +785,65 @@ Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_
} else { } else {
Debug( 2, "Need some other kind of Authentication" ); Debug( 2, "Need some other kind of Authentication" );
} }
} else if ( status < 200 || status > 299 ) } else if ( status < 200 || status > 299 ) {
{
Error( "Invalid response status %s: %s", status_code, status_mesg ); Error( "Invalid response status %s: %s", status_code, status_mesg );
return( -1 ); return( -1 );
} }
Debug( 3, "Got status '%d' (%s), http version %s", status, status_mesg, http_version ); Debug( 3, "Got status '%d' (%s), http version %s", status, status_mesg, http_version );
if ( connection_header ) if ( connection_header ) {
{
memset( connection_type, 0, sizeof(connection_type) ); memset( connection_type, 0, sizeof(connection_type) );
start_ptr = connection_header + strspn( connection_header, " " ); start_ptr = connection_header + strspn( connection_header, " " );
// FIXME Should we not use strncpy?
strcpy( connection_type, start_ptr ); strcpy( connection_type, start_ptr );
Debug( 3, "Got connection '%s'", connection_type ); Debug( 3, "Got connection '%s'", connection_type );
} }
if ( content_length_header ) if ( content_length_header ) {
{
start_ptr = content_length_header + strspn( content_length_header, " " ); start_ptr = content_length_header + strspn( content_length_header, " " );
content_length = atoi( start_ptr ); content_length = atoi( start_ptr );
Debug( 3, "Got content length '%d'", content_length ); Debug( 3, "Got content length '%d'", content_length );
} }
if ( content_type_header ) if ( content_type_header ) {
{
memset( content_type, 0, sizeof(content_type) ); memset( content_type, 0, sizeof(content_type) );
start_ptr = content_type_header + strspn( content_type_header, " " ); start_ptr = content_type_header + strspn( content_type_header, " " );
if ( (end_ptr = strchr( start_ptr, ';' )) ) if ( (end_ptr = strchr( start_ptr, ';' )) ) {
{
strncpy( content_type, start_ptr, end_ptr-start_ptr ); strncpy( content_type, start_ptr, end_ptr-start_ptr );
Debug( 3, "Got content type '%s'", content_type ); Debug( 3, "Got content type '%s'", content_type );
start_ptr = end_ptr + strspn( end_ptr, "; " ); start_ptr = end_ptr + strspn( end_ptr, "; " );
if ( strncasecmp( start_ptr, boundary_match, boundary_match_len ) == 0 ) if ( strncasecmp( start_ptr, boundary_match, boundary_match_len ) == 0 ) {
{
start_ptr += boundary_match_len; start_ptr += boundary_match_len;
start_ptr += strspn( start_ptr, "-" ); start_ptr += strspn( start_ptr, "-" );
content_boundary_len = sprintf( content_boundary, "--%s", start_ptr ); content_boundary_len = sprintf( content_boundary, "--%s", start_ptr );
Debug( 3, "Got content boundary '%s'", content_boundary ); Debug( 3, "Got content boundary '%s'", content_boundary );
} } else {
else
{
Error( "No content boundary found in header '%s'", content_type_header ); Error( "No content boundary found in header '%s'", content_type_header );
} }
} } else {
else
{
strcpy( content_type, start_ptr ); strcpy( content_type, start_ptr );
Debug( 3, "Got content type '%s'", content_type ); Debug( 3, "Got content type '%s'", content_type );
} }
} }
if ( !strcasecmp( content_type, "image/jpeg" ) || !strcasecmp( content_type, "image/jpg" ) ) if ( !strcasecmp( content_type, "image/jpeg" ) || !strcasecmp( content_type, "image/jpg" ) ) {
{
// Single image // Single image
mode = SINGLE_IMAGE; mode = SINGLE_IMAGE;
format = JPEG; format = JPEG;
state = CONTENT; state = CONTENT;
} } else if ( !strcasecmp( content_type, "image/x-rgb" ) ) {
else if ( !strcasecmp( content_type, "image/x-rgb" ) )
{
// Single image // Single image
mode = SINGLE_IMAGE; mode = SINGLE_IMAGE;
format = X_RGB; format = X_RGB;
state = CONTENT; state = CONTENT;
} } else if ( !strcasecmp( content_type, "image/x-rgbz" ) ) {
else if ( !strcasecmp( content_type, "image/x-rgbz" ) )
{
// Single image // Single image
mode = SINGLE_IMAGE; mode = SINGLE_IMAGE;
format = X_RGBZ; format = X_RGBZ;
state = CONTENT; state = CONTENT;
} } else if ( !strcasecmp( content_type, "multipart/x-mixed-replace" ) ) {
else if ( !strcasecmp( content_type, "multipart/x-mixed-replace" ) )
{
// Image stream, so start processing // Image stream, so start processing
if ( !content_boundary[0] ) if ( !content_boundary[0] ) {
{
Error( "No content boundary found in header '%s'", content_type_header ); Error( "No content boundary found in header '%s'", content_type_header );
return( -1 ); return( -1 );
} }
@ -886,14 +854,11 @@ Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_
//{ //{
//// MPEG stream, coming soon! //// MPEG stream, coming soon!
//} //}
else else {
{
Error( "Unrecognised content type '%s'", content_type ); Error( "Unrecognised content type '%s'", content_type );
return( -1 ); return( -1 );
} }
} } else {
else
{
Debug( 3, "Unable to extract entire header from stream, continuing" ); Debug( 3, "Unable to extract entire header from stream, continuing" );
state = HEADERCONT; state = HEADERCONT;
//return( -1 ); //return( -1 );
@ -916,13 +881,10 @@ Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_
int subheader_len = buffer.size(); int subheader_len = buffer.size();
bool all_headers = false; bool all_headers = false;
while( true ) while( true ) {
{
int crlf_len = memspn( subheader_ptr, "\r\n", subheader_len ); int crlf_len = memspn( subheader_ptr, "\r\n", subheader_len );
if ( n_subheaders ) if ( n_subheaders ) {
{ if ( (crlf_len == 2 && !strncmp( subheader_ptr, "\n\n", crlf_len )) || (crlf_len == 4 && !strncmp( subheader_ptr, "\r\n\r\n", crlf_len )) ) {
if ( (crlf_len == 2 && !strncmp( subheader_ptr, "\n\n", crlf_len )) || (crlf_len == 4 && !strncmp( subheader_ptr, "\r\n\r\n", crlf_len )) )
{
*subheader_ptr = '\0'; *subheader_ptr = '\0';
subheader_ptr += crlf_len; subheader_ptr += crlf_len;
subheader_len -= buffer.consume( subheader_ptr-(char *)buffer ); subheader_len -= buffer.consume( subheader_ptr-(char *)buffer );
@ -930,14 +892,10 @@ Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_
break; break;
} }
} }
if ( crlf_len ) if ( crlf_len ) {
{ if ( subheader_len == crlf_len ) {
if ( subheader_len == crlf_len )
{
break; break;
} } else {
else
{
*subheader_ptr = '\0'; *subheader_ptr = '\0';
subheader_ptr += crlf_len; subheader_ptr += crlf_len;
subheader_len -= buffer.consume( subheader_ptr-(char *)buffer ); subheader_len -= buffer.consume( subheader_ptr-(char *)buffer );
@ -946,67 +904,53 @@ Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_
Debug( 6, "%d: %s", subheader_len, subheader_ptr ); Debug( 6, "%d: %s", subheader_len, subheader_ptr );
if ( (crlf = mempbrk( subheader_ptr, "\r\n", subheader_len )) ) if ( (crlf = mempbrk( subheader_ptr, "\r\n", subheader_len )) ) {
{
//subheaders[n_subheaders++] = subheader_ptr; //subheaders[n_subheaders++] = subheader_ptr;
n_subheaders++; n_subheaders++;
if ( !boundary_header && (strncasecmp( subheader_ptr, content_boundary, content_boundary_len ) == 0) ) if ( !boundary_header && (strncasecmp( subheader_ptr, content_boundary, content_boundary_len ) == 0) ) {
{
boundary_header = subheader_ptr; boundary_header = subheader_ptr;
Debug( 4, "Got boundary subheader '%s'", subheader_ptr ); Debug( 4, "Got boundary subheader '%s'", subheader_ptr );
} } else if ( !subcontent_length_header[0] && (strncasecmp( subheader_ptr, content_length_match, content_length_match_len) == 0) ) {
else if ( !subcontent_length_header[0] && (strncasecmp( subheader_ptr, content_length_match, content_length_match_len) == 0) )
{
strncpy( subcontent_length_header, subheader_ptr+content_length_match_len, sizeof(subcontent_length_header) ); strncpy( subcontent_length_header, subheader_ptr+content_length_match_len, sizeof(subcontent_length_header) );
*(subcontent_length_header+strcspn( subcontent_length_header, "\r\n" )) = '\0'; *(subcontent_length_header+strcspn( subcontent_length_header, "\r\n" )) = '\0';
Debug( 4, "Got content length subheader '%s'", subcontent_length_header ); Debug( 4, "Got content length subheader '%s'", subcontent_length_header );
} } else if ( !subcontent_type_header[0] && (strncasecmp( subheader_ptr, content_type_match, content_type_match_len) == 0) ) {
else if ( !subcontent_type_header[0] && (strncasecmp( subheader_ptr, content_type_match, content_type_match_len) == 0) )
{
strncpy( subcontent_type_header, subheader_ptr+content_type_match_len, sizeof(subcontent_type_header) ); strncpy( subcontent_type_header, subheader_ptr+content_type_match_len, sizeof(subcontent_type_header) );
*(subcontent_type_header+strcspn( subcontent_type_header, "\r\n" )) = '\0'; *(subcontent_type_header+strcspn( subcontent_type_header, "\r\n" )) = '\0';
Debug( 4, "Got content type subheader '%s'", subcontent_type_header ); Debug( 4, "Got content type subheader '%s'", subcontent_type_header );
} } else {
else
{
Debug( 6, "Got ignored subheader '%s' found", subheader_ptr ); Debug( 6, "Got ignored subheader '%s' found", subheader_ptr );
} }
subheader_ptr = crlf; subheader_ptr = crlf;
subheader_len -= buffer.consume( subheader_ptr-(char *)buffer ); subheader_len -= buffer.consume( subheader_ptr-(char *)buffer );
} } else {
else
{
// No line end found // No line end found
break; break;
} }
} }
if ( all_headers && boundary_header ) if ( all_headers && boundary_header ) {
{
char *start_ptr/*, *end_ptr*/; char *start_ptr/*, *end_ptr*/;
Debug( 3, "Got boundary '%s'", boundary_header ); Debug( 3, "Got boundary '%s'", boundary_header );
if ( subcontent_length_header[0] ) if ( subcontent_length_header[0] ) {
{
start_ptr = subcontent_length_header + strspn( subcontent_length_header, " " ); start_ptr = subcontent_length_header + strspn( subcontent_length_header, " " );
content_length = atoi( start_ptr ); content_length = atoi( start_ptr );
Debug( 3, "Got subcontent length '%d'", content_length ); Debug( 3, "Got subcontent length '%d'", content_length );
} }
if ( subcontent_type_header[0] ) if ( subcontent_type_header[0] ) {
{
memset( content_type, 0, sizeof(content_type) ); memset( content_type, 0, sizeof(content_type) );
start_ptr = subcontent_type_header + strspn( subcontent_type_header, " " ); start_ptr = subcontent_type_header + strspn( subcontent_type_header, " " );
strcpy( content_type, start_ptr ); strcpy( content_type, start_ptr );
Debug( 3, "Got subcontent type '%s'", content_type ); Debug( 3, "Got subcontent type '%s'", content_type );
} }
state = CONTENT; state = CONTENT;
} } else {
else
{
Debug( 3, "Unable to extract subheader from stream, retrying" ); Debug( 3, "Unable to extract subheader from stream, retrying" );
while ( ! ( buffer_len = ReadData( buffer ) ) ) { while ( ! ( buffer_len = ReadData( buffer ) ) ) {
Debug(1, "Timeout waiting to extra subheader non regexp");
} }
if ( buffer_len < 0 ) { if ( buffer_len < 0 ) {
Error( "Unable to read subheader" ); Error( "Unable to read subheader" );
@ -1016,8 +960,7 @@ Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_
} }
break; break;
} }
case CONTENT : case CONTENT : {
{
// if content_type is something like image/jpeg;size=, this will strip the ;size= // if content_type is something like image/jpeg;size=, this will strip the ;size=
char * semicolon = strchr( content_type, ';' ); char * semicolon = strchr( content_type, ';' );
@ -1025,50 +968,39 @@ Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_
*semicolon = '\0'; *semicolon = '\0';
} }
if ( !strcasecmp( content_type, "image/jpeg" ) || !strcasecmp( content_type, "image/jpg" ) ) if ( !strcasecmp( content_type, "image/jpeg" ) || !strcasecmp( content_type, "image/jpg" ) ) {
{
format = JPEG; format = JPEG;
} } else if ( !strcasecmp( content_type, "image/x-rgb" ) ) {
else if ( !strcasecmp( content_type, "image/x-rgb" ) )
{
format = X_RGB; format = X_RGB;
} } else if ( !strcasecmp( content_type, "image/x-rgbz" ) ) {
else if ( !strcasecmp( content_type, "image/x-rgbz" ) )
{
format = X_RGBZ; format = X_RGBZ;
} } else {
else
{
Error( "Found unsupported content type '%s'", content_type ); Error( "Found unsupported content type '%s'", content_type );
return( -1 ); return( -1 );
} }
if ( format == JPEG && buffer.size() >= 2 ) // This is an early test for jpeg content, so we can bail early
{ if ( format == JPEG && buffer.size() >= 2 ) {
if ( buffer[0] != 0xff || buffer[1] != 0xd8 ) if ( buffer[0] != 0xff || buffer[1] != 0xd8 ) {
{
Error( "Found bogus jpeg header '%02x%02x'", buffer[0], buffer[1] ); Error( "Found bogus jpeg header '%02x%02x'", buffer[0], buffer[1] );
return( -1 ); return( -1 );
} }
} }
if ( content_length ) if ( content_length ) {
{ while ( (long)buffer.size() < content_length ) {
while ( (long)buffer.size() < content_length )
{
//int buffer_len = ReadData( buffer, content_length-buffer.size() ); //int buffer_len = ReadData( buffer, content_length-buffer.size() );
Debug(4, "getting more data");
if ( ReadData( buffer ) < 0 ) { if ( ReadData( buffer ) < 0 ) {
Error( "Unable to read content" ); Error( "Unable to read content" );
return( -1 ); return( -1 );
} }
} }
Debug( 3, "Got end of image by length, content-length = %d", content_length ); Debug( 3, "Got end of image by length, content-length = %d", content_length );
} } else {
else // Read until we find the end of image or the stream closes.
{ while ( !content_length ) {
int content_pos = 0; Debug(4, "!content_length, ReadData");
while ( !content_length )
{
buffer_len = ReadData( buffer ); buffer_len = ReadData( buffer );
if ( buffer_len < 0 ) if ( buffer_len < 0 )
{ {
@ -1076,54 +1008,47 @@ Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_
return( -1 ); return( -1 );
} }
int buffer_size = buffer.size(); int buffer_size = buffer.size();
if ( buffer_len ) if ( buffer_len ) {
{ // Got some data
if ( mode == MULTI_IMAGE )
{ if ( mode == MULTI_IMAGE ) {
while ( char *start_ptr = (char *)memstr( (char *)buffer+content_pos, "\r\n--", buffer_size-content_pos ) ) // Look for the boundary marker, determine content length using it's position
{ if ( char *start_ptr = (char *)memstr( (char *)buffer, "\r\n--", buffer_size ) ) {
content_length = start_ptr - (char *)buffer; content_length = start_ptr - (char *)buffer;
Debug( 3, "Got end of image by pattern (crlf--), content-length = %d", content_length ); Debug( 2, "Got end of image by pattern (crlf--), content-length = %d", content_length );
break; } else {
Debug( 2, "Did not find end of image by patten (crlf--) yet, content-length = %d", content_length );
} }
} } // end if MULTI_IMAGE
} } else {
else
{
content_length = buffer_size; content_length = buffer_size;
Debug( 3, "Got end of image by closure, content-length = %d", content_length ); Debug( 2, "Got end of image by closure, content-length = %d", content_length );
if ( mode == SINGLE_IMAGE ) if ( mode == SINGLE_IMAGE ) {
{
char *end_ptr = (char *)buffer+buffer_size; char *end_ptr = (char *)buffer+buffer_size;
while( *end_ptr == '\r' || *end_ptr == '\n' ) // strip off any last line feeds
{ while( *end_ptr == '\r' || *end_ptr == '\n' ) {
content_length--; content_length--;
end_ptr--; end_ptr--;
} }
if ( end_ptr != ((char *)buffer+buffer_size) ) if ( end_ptr != ((char *)buffer+buffer_size) ) {
{ Debug( 2, "Trimmed end of image, new content-length = %d", content_length );
Debug( 3, "Trimmed end of image, new content-length = %d", content_length );
} }
} } // end if SINGLE_IMAGE
} } // end if read some data
} } // end while ! content_length
} } // end if content_length
if ( mode == SINGLE_IMAGE )
{ if ( mode == SINGLE_IMAGE ) {
state = HEADER; state = HEADER;
Disconnect(); Disconnect();
} } else {
else
{
state = SUBHEADER; state = SUBHEADER;
} }
if ( format == JPEG && buffer.size() >= 2 ) if ( format == JPEG && buffer.size() >= 2 ) {
{ if ( buffer[0] != 0xff || buffer[1] != 0xd8 ) {
if ( buffer[0] != 0xff || buffer[1] != 0xd8 )
{
Error( "Found bogus jpeg header '%02x%02x'", buffer[0], buffer[1] ); Error( "Found bogus jpeg header '%02x%02x'", buffer[0], buffer[1] );
return( -1 ); return( -1 );
} }
@ -1131,8 +1056,8 @@ Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_
Debug( 3, "Returning %d bytes, buffer size: (%d) bytes of captured content", content_length, buffer.size() ); Debug( 3, "Returning %d bytes, buffer size: (%d) bytes of captured content", content_length, buffer.size() );
return( content_length ); return( content_length );
} } // end cast CONTENT
} } // end switch
} }
} }
return( 0 ); return( 0 );

View File

@ -120,7 +120,7 @@ bool RtpSource::updateSeq( uint16_t seq )
{ {
if ( uDelta == 1 ) if ( uDelta == 1 )
{ {
Debug( 3, "Packet in sequence, gap %d", uDelta ); Debug( 4, "Packet in sequence, gap %d", uDelta );
} }
else else
{ {
@ -312,7 +312,8 @@ bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen )
extraHeader = 2; extraHeader = 2;
break; break;
} }
default: { default:
{
Debug(3, "Unhandled nalType %d", nalType ); Debug(3, "Unhandled nalType %d", nalType );
} }
} }
@ -332,12 +333,15 @@ bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen )
{ {
if ( mFrameGood ) if ( mFrameGood )
{ {
Debug( 2, "Got new frame %d, %d bytes", mFrameCount, mFrame.size() ); Debug( 3, "Got new frame %d, %d bytes", mFrameCount, mFrame.size() );
mFrameProcessed.setValueImmediate( false ); mFrameProcessed.setValueImmediate( false );
mFrameReady.updateValueSignal( true ); mFrameReady.updateValueSignal( true );
if ( !mFrameProcessed.getValueImmediate() ) if ( !mFrameProcessed.getValueImmediate() )
{ {
// What is the point of this for loop? Is it just me, or will it call getUpdatedValue once or twice? Could it not be better written as
// if ( ! mFrameProcessed.getUpdatedValue( 1 ) && mFrameProcessed.getUpdatedValue( 1 ) ) return false;
for ( int count = 0; !mFrameProcessed.getUpdatedValue( 1 ); count++ ) for ( int count = 0; !mFrameProcessed.getUpdatedValue( 1 ); count++ )
if( count > 1 ) if( count > 1 )
return( false ); return( false );
@ -390,7 +394,7 @@ bool RtpSource::getFrame( Buffer &buffer )
buffer = mFrame; buffer = mFrame;
mFrameReady.setValueImmediate( false ); mFrameReady.setValueImmediate( false );
mFrameProcessed.updateValueSignal( true ); mFrameProcessed.updateValueSignal( true );
Debug( 3, "Copied %d bytes", buffer.size() ); Debug( 4, "Copied %d bytes", buffer.size() );
return( true ); return( true );
} }

View File

@ -70,7 +70,11 @@ X264MP4Writer::X264MP4Writer(const char* p_path, const unsigned int p_width, con
/* Calculate the image sizes. We will need this for parameter checking */ /* Calculate the image sizes. We will need this for parameter checking */
zm_imgsize = colours * width * height; zm_imgsize = colours * width * height;
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
codec_imgsize = av_image_get_buffer_size( codec_pf, width, height, 1 );
#else
codec_imgsize = avpicture_get_size( codec_pf, width, height); codec_imgsize = avpicture_get_size( codec_pf, width, height);
#endif
if(!codec_imgsize) { if(!codec_imgsize) {
Error("Failed calculating codec pixel format image size"); Error("Failed calculating codec pixel format image size");
} }

View File

@ -549,7 +549,7 @@ void VideoStore::dumpPacket( AVPacket *pkt ){
int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) { int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) {
av_init_packet(&opkt); av_init_packet(&opkt);
int duration; int duration = 0;
//Scale the PTS of the outgoing packet to be the correct time base //Scale the PTS of the outgoing packet to be the correct time base
if (ipkt->pts != AV_NOPTS_VALUE) { if (ipkt->pts != AV_NOPTS_VALUE) {

View File

@ -71,8 +71,7 @@ possible, this should run at more or less constant speed.
#include "zm_signal.h" #include "zm_signal.h"
#include "zm_monitor.h" #include "zm_monitor.h"
void Usage() void Usage() {
{
fprintf( stderr, "zmc -d <device_path> or -r <proto> -H <host> -P <port> -p <path> or -f <file_path> or -m <monitor_id>\n" ); fprintf( stderr, "zmc -d <device_path> or -r <proto> -H <host> -P <port> -p <path> or -f <file_path> or -m <monitor_id>\n" );
fprintf( stderr, "Options:\n" ); fprintf( stderr, "Options:\n" );
@ -88,8 +87,7 @@ void Usage()
exit( 0 ); exit( 0 );
} }
int main( int argc, char *argv[] ) int main( int argc, char *argv[] ) {
{
self = argv[0]; self = argv[0];
srand( getpid() * time( 0 ) ); srand( getpid() * time( 0 ) );
@ -115,13 +113,11 @@ int main( int argc, char *argv[] )
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
while (1) while (1) {
{
int option_index = 0; int option_index = 0;
int c = getopt_long (argc, argv, "d:H:P:p:f:m:h:v", long_options, &option_index); int c = getopt_long (argc, argv, "d:H:P:p:f:m:h:v", long_options, &option_index);
if (c == -1) if (c == -1) {
{
break; break;
} }
@ -158,8 +154,7 @@ int main( int argc, char *argv[] )
} }
} }
if (optind < argc) if (optind < argc) {
{
fprintf( stderr, "Extraneous options, " ); fprintf( stderr, "Extraneous options, " );
while (optind < argc) while (optind < argc)
printf ("%s ", argv[optind++]); printf ("%s ", argv[optind++]);
@ -168,37 +163,28 @@ int main( int argc, char *argv[] )
} }
int modes = ( device[0]?1:0 + host[0]?1:0 + file[0]?1:0 + (monitor_id>0?1:0) ); int modes = ( device[0]?1:0 + host[0]?1:0 + file[0]?1:0 + (monitor_id>0?1:0) );
if ( modes > 1 ) if ( modes > 1 ) {
{ fprintf( stderr, "Only one of device, host/port/path, file or monitor id allowed\n" );
fprintf( stderr, "Only one of device, file or monitor id allowed\n" );
Usage(); Usage();
exit( 0 ); exit( 0 );
} }
if ( modes < 1 ) if ( modes < 1 ) {
{ fprintf( stderr, "One of device, host/port/path, file or monitor id must be specified\n" );
fprintf( stderr, "One of device, file or monitor id must be specified\n" );
Usage(); Usage();
exit( 0 ); exit( 0 );
} }
char log_id_string[32] = ""; char log_id_string[32] = "";
if ( device[0] ) if ( device[0] ) {
{
const char *slash_ptr = strrchr( device, '/' ); const char *slash_ptr = strrchr( device, '/' );
snprintf( log_id_string, sizeof(log_id_string), "zmc_d%s", slash_ptr?slash_ptr+1:device ); snprintf( log_id_string, sizeof(log_id_string), "zmc_d%s", slash_ptr?slash_ptr+1:device );
} } else if ( host[0] ) {
else if ( host[0] )
{
snprintf( log_id_string, sizeof(log_id_string), "zmc_h%s", host ); snprintf( log_id_string, sizeof(log_id_string), "zmc_h%s", host );
} } else if ( file[0] ) {
else if ( file[0] )
{
const char *slash_ptr = strrchr( file, '/' ); const char *slash_ptr = strrchr( file, '/' );
snprintf( log_id_string, sizeof(log_id_string), "zmc_f%s", slash_ptr?slash_ptr+1:file ); snprintf( log_id_string, sizeof(log_id_string), "zmc_f%s", slash_ptr?slash_ptr+1:file );
} } else {
else
{
snprintf( log_id_string, sizeof(log_id_string), "zmc_m%d", monitor_id ); snprintf( log_id_string, sizeof(log_id_string), "zmc_m%d", monitor_id );
} }
@ -211,35 +197,26 @@ int main( int argc, char *argv[] )
Monitor **monitors = 0; Monitor **monitors = 0;
int n_monitors = 0; int n_monitors = 0;
#if ZM_HAS_V4L #if ZM_HAS_V4L
if ( device[0] ) if ( device[0] ) {
{
n_monitors = Monitor::LoadLocalMonitors( device, monitors, Monitor::CAPTURE ); n_monitors = Monitor::LoadLocalMonitors( device, monitors, Monitor::CAPTURE );
} } else
else
#endif // ZM_HAS_V4L #endif // ZM_HAS_V4L
if ( host[0] ) if ( host[0] ) {
{
if ( !port ) if ( !port )
port = "80"; port = "80";
n_monitors = Monitor::LoadRemoteMonitors( protocol, host, port, path, monitors, Monitor::CAPTURE ); n_monitors = Monitor::LoadRemoteMonitors( protocol, host, port, path, monitors, Monitor::CAPTURE );
} } else if ( file[0] ) {
else if ( file[0] )
{
n_monitors = Monitor::LoadFileMonitors( file, monitors, Monitor::CAPTURE ); n_monitors = Monitor::LoadFileMonitors( file, monitors, Monitor::CAPTURE );
} } else {
else
{
Monitor *monitor = Monitor::Load( monitor_id, true, Monitor::CAPTURE ); Monitor *monitor = Monitor::Load( monitor_id, true, Monitor::CAPTURE );
if ( monitor ) if ( monitor ) {
{
monitors = new Monitor *[1]; monitors = new Monitor *[1];
monitors[0] = monitor; monitors[0] = monitor;
n_monitors = 1; n_monitors = 1;
} }
} }
if ( !n_monitors ) if ( !n_monitors ) {
{
Error( "No monitors found" ); Error( "No monitors found" );
exit ( -1 ); exit ( -1 );
} }
@ -255,8 +232,7 @@ int main( int argc, char *argv[] )
sigaddset( &block_set, SIGUSR1 ); sigaddset( &block_set, SIGUSR1 );
sigaddset( &block_set, SIGUSR2 ); sigaddset( &block_set, SIGUSR2 );
if ( monitors[0]->PrimeCapture() < 0 ) if ( monitors[0]->PrimeCapture() < 0 ) {
{
Error( "Failed to prime capture of initial monitor" ); Error( "Failed to prime capture of initial monitor" );
exit( -1 ); exit( -1 );
} }
@ -265,8 +241,7 @@ int main( int argc, char *argv[] )
long *alarm_capture_delays = new long[n_monitors]; long *alarm_capture_delays = new long[n_monitors];
long *next_delays = new long[n_monitors]; long *next_delays = new long[n_monitors];
struct timeval * last_capture_times = new struct timeval[n_monitors]; struct timeval * last_capture_times = new struct timeval[n_monitors];
for ( int i = 0; i < n_monitors; i++ ) for ( int i = 0; i < n_monitors; i++ ) {
{
last_capture_times[i].tv_sec = last_capture_times[i].tv_usec = 0; last_capture_times[i].tv_sec = last_capture_times[i].tv_usec = 0;
capture_delays[i] = monitors[i]->GetCaptureDelay(); capture_delays[i] = monitors[i]->GetCaptureDelay();
alarm_capture_delays[i] = monitors[i]->GetAlarmCaptureDelay(); alarm_capture_delays[i] = monitors[i]->GetAlarmCaptureDelay();
@ -275,18 +250,14 @@ int main( int argc, char *argv[] )
int result = 0; int result = 0;
struct timeval now; struct timeval now;
struct DeltaTimeval delta_time; struct DeltaTimeval delta_time;
while( !zm_terminate ) while( !zm_terminate ) {
{
sigprocmask( SIG_BLOCK, &block_set, 0 ); sigprocmask( SIG_BLOCK, &block_set, 0 );
for ( int i = 0; i < n_monitors; i++ ) for ( int i = 0; i < n_monitors; i++ ) {
{
long min_delay = MAXINT; long min_delay = MAXINT;
gettimeofday( &now, NULL ); gettimeofday( &now, NULL );
for ( int j = 0; j < n_monitors; j++ ) for ( int j = 0; j < n_monitors; j++ ) {
{ if ( last_capture_times[j].tv_sec ) {
if ( last_capture_times[j].tv_sec )
{
DELTA_TIMEVAL( delta_time, now, last_capture_times[j], DT_PREC_3 ); DELTA_TIMEVAL( delta_time, now, last_capture_times[j], DT_PREC_3 );
if ( monitors[i]->GetState() == Monitor::ALARM ) if ( monitors[i]->GetState() == Monitor::ALARM )
next_delays[j] = alarm_capture_delays[j]-delta_time.delta; next_delays[j] = alarm_capture_delays[j]-delta_time.delta;
@ -294,58 +265,49 @@ int main( int argc, char *argv[] )
next_delays[j] = capture_delays[j]-delta_time.delta; next_delays[j] = capture_delays[j]-delta_time.delta;
if ( next_delays[j] < 0 ) if ( next_delays[j] < 0 )
next_delays[j] = 0; next_delays[j] = 0;
} } else {
else
{
next_delays[j] = 0; next_delays[j] = 0;
} }
if ( next_delays[j] <= min_delay ) if ( next_delays[j] <= min_delay ) {
{
min_delay = next_delays[j]; min_delay = next_delays[j];
} }
} }
if ( next_delays[i] <= min_delay || next_delays[i] <= 0 ) if ( next_delays[i] <= min_delay || next_delays[i] <= 0 ) {
{ if ( monitors[i]->PreCapture() < 0 ) {
if ( monitors[i]->PreCapture() < 0 )
{
Error( "Failed to pre-capture monitor %d %d (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors ); Error( "Failed to pre-capture monitor %d %d (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors );
zm_terminate = true; zm_terminate = true;
result = -1; result = -1;
break; break;
} }
if ( monitors[i]->Capture() < 0 ) if ( monitors[i]->Capture() < 0 ) {
{
Error( "Failed to capture image from monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors ); Error( "Failed to capture image from monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors );
zm_terminate = true; zm_terminate = true;
result = -1; result = -1;
break; break;
} }
if ( monitors[i]->PostCapture() < 0 ) if ( monitors[i]->PostCapture() < 0 ) {
{
Error( "Failed to post-capture monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors ); Error( "Failed to post-capture monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors );
zm_terminate = true; zm_terminate = true;
result = -1; result = -1;
break; break;
} }
if ( next_delays[i] > 0 ) if ( next_delays[i] > 0 ) {
{
gettimeofday( &now, NULL ); gettimeofday( &now, NULL );
DELTA_TIMEVAL( delta_time, now, last_capture_times[i], DT_PREC_3 ); DELTA_TIMEVAL( delta_time, now, last_capture_times[i], DT_PREC_3 );
long sleep_time = next_delays[i]-delta_time.delta; long sleep_time = next_delays[i]-delta_time.delta;
if ( sleep_time > 0 ) if ( sleep_time > 0 ) {
{
usleep( sleep_time*(DT_MAXGRAN/DT_PREC_3) ); usleep( sleep_time*(DT_MAXGRAN/DT_PREC_3) );
} }
} }
gettimeofday( &(last_capture_times[i]), NULL ); gettimeofday( &(last_capture_times[i]), NULL );
} } // end if next_delay <= min_delay || next_delays[i] <= 0 )
}
} // end foreach n_monitors
sigprocmask( SIG_UNBLOCK, &block_set, 0 ); sigprocmask( SIG_UNBLOCK, &block_set, 0 );
} } // end while ! zm_terminate
for ( int i = 0; i < n_monitors; i++ ) for ( int i = 0; i < n_monitors; i++ ) {
{
delete monitors[i]; delete monitors[i];
} }
delete [] monitors; delete [] monitors;