This commit is contained in:
Isaac Connor 2019-02-25 10:21:43 -05:00
parent 279e0d8bcf
commit 448294f593
11 changed files with 193 additions and 135 deletions

View File

@ -241,7 +241,7 @@ int FfmpegCamera::OpenFfmpeg() {
} }
if ( ret < 0 ) { if ( ret < 0 ) {
Warning("Could not set rtsp_transport method '%s'\n", method.c_str()); Warning("Could not set rtsp_transport method '%s'", method.c_str());
} }
Debug(1, "Calling avformat_open_input for %s", mPath.c_str()); Debug(1, "Calling avformat_open_input for %s", mPath.c_str());

View File

@ -2082,6 +2082,10 @@ int LocalCamera::Capture( ZMPacket &zm_packet ) {
} /* prime capture */ } /* prime capture */
if ( ! zm_packet.image ) {
zm_packet.image = new Image(width, height, colours, subpixelorder);
}
if ( conversion_type != 0 ) { if ( conversion_type != 0 ) {
Debug(3, "Performing format conversion"); Debug(3, "Performing format conversion");

View File

@ -1630,6 +1630,7 @@ bool Monitor::Analyse() {
ZMPacket *snap; ZMPacket *snap;
// Is it possible for snap->score to be ! -1? // Is it possible for snap->score to be ! -1?
// get_analysis_packet will lock the packet
while ( ( snap = packetqueue->get_analysis_packet() ) && ( snap->score == -1 ) ) { while ( ( snap = packetqueue->get_analysis_packet() ) && ( snap->score == -1 ) ) {
unsigned int index = snap->image_index; unsigned int index = snap->image_index;
Debug(2, "Analysis index (%d), last_Write(%d)", index, shared_data->last_write_index); Debug(2, "Analysis index (%d), last_Write(%d)", index, shared_data->last_write_index);
@ -1638,7 +1639,6 @@ bool Monitor::Analyse() {
return 0; return 0;
} }
snap->lock();
packets_processed += 1; packets_processed += 1;
if ( snap->image_index == -1 ) { if ( snap->image_index == -1 ) {
@ -2069,7 +2069,6 @@ void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) {
db_mutex.lock(); db_mutex.lock();
static char sql[ZM_SQL_SML_BUFSIZ]; static char sql[ZM_SQL_SML_BUFSIZ];
db_mutex.lock();
snprintf(sql, sizeof(sql), "SELECT Id, Name FROM Monitors WHERE Id = %d AND Function != 'None' AND Function != 'Monitor' AND Enabled = 1", link_ids[i] ); snprintf(sql, sizeof(sql), "SELECT Id, Name FROM Monitors WHERE Id = %d AND Function != 'None' AND Function != 'Monitor' AND Enabled = 1", link_ids[i] );
if ( mysql_query(&dbconn, sql) ) { if ( mysql_query(&dbconn, sql) ) {
db_mutex.unlock(); db_mutex.unlock();
@ -2177,25 +2176,27 @@ int Monitor::LoadFfmpegMonitors(const char *file, Monitor **&monitors, Purpose p
int Monitor::Capture() { int Monitor::Capture() {
static int FirstCapture = 1; // Used in de-interlacing to indicate whether this is the even or odd image static int FirstCapture = 1; // Used in de-interlacing to indicate whether this is the even or odd image
unsigned int index = image_count % image_buffer_count; unsigned int index = 0;
//image_count % image_buffer_count;
if ( (index == shared_data->last_read_index) && (function > MONITOR) ) { if ( (index == shared_data->last_read_index) && (function > MONITOR) ) {
Warning( "Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", index, image_count ); Warning("Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", index, image_count);
time_t now = time(0); time_t now = time(0);
double approxFps = double(image_buffer_count)/double(now-image_buffer[index].timestamp->tv_sec); double approxFps = double(image_buffer_count)/double(now-image_buffer[index].timestamp->tv_sec);
time_t last_read_delta = now - shared_data->last_read_time; time_t last_read_delta = now - shared_data->last_read_time;
if ( last_read_delta > (image_buffer_count/approxFps) ) { if ( last_read_delta > (image_buffer_count/approxFps) ) {
Warning( "Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta ) Warning("Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta)
shared_data->last_read_index = image_buffer_count; shared_data->last_read_index = image_buffer_count;
} }
} else { } else {
Debug(2,"Capture: Current write index %d, last read index %d, current (%d)", shared_data->last_write_index, shared_data->last_read_index, index ); Debug(2,"Capture: Last write(capture) index %d, last read(analysis) index %d, current (%d)",
shared_data->last_write_index, shared_data->last_read_index, index );
} }
ZMPacket *packet = &image_buffer[index]; ZMPacket *packet = new ZMPacket();
Debug(2,"before lock"); //&image_buffer[index];
Debug(2,"before packet lock");
packet->lock(); packet->lock();
Debug(2,"before reset");
packet->reset(); packet->reset();
Image* capture_image = packet->image; Image* capture_image = packet->image;
int captureResult = 0; int captureResult = 0;
@ -2243,23 +2244,23 @@ int Monitor::Capture() {
if ( packet->packet.stream_index != video_stream_id ) { if ( packet->packet.stream_index != video_stream_id ) {
Debug(2, "Have audio packet (%d) != videostream_id:(%d) q.vpktcount(%d) event?(%d) ", Debug(2, "Have audio packet (%d) != videostream_id:(%d) q.vpktcount(%d) event?(%d) ",
packet->packet.stream_index, video_stream_id, packetqueue->video_packet_count, ( event ? 1 : 0 ) ); packet->packet.stream_index, video_stream_id, packetqueue->video_packet_count, ( event ? 1 : 0 ) );
// Only queue if we have some video packets in there. // Only queue if we have some video packets in there. Should push this logic into packetqueue
mutex.lock(); //mutex.lock();
if ( packetqueue->video_packet_count || event ) { if ( packetqueue->video_packet_count || event ) {
// Need to copy it into another ZMPacket. // Need to copy it into another ZMPacket.
ZMPacket *audio_packet = new ZMPacket(*packet); //ZMPacket *audio_packet = new ZMPacket(*packet);
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
audio_packet->codec_type = camera->get_AudioStream()->codecpar->codec_type; packet->codec_type = camera->get_AudioStream()->codecpar->codec_type;
#else #else
audio_packet->codec_type = camera->get_AudioStream()->codec->codec_type; packet->codec_type = camera->get_AudioStream()->codec->codec_type;
#endif #endif
Debug(2, "Queueing packet"); Debug(2, "Queueing packet");
packetqueue->queuePacket(audio_packet); packetqueue->queuePacket(packet);
} }
// Don't update last_write_index because that is used for live streaming // Don't update last_write_index because that is used for live streaming
//shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; //shared_data->last_write_time = image_buffer[index].timestamp->tv_sec;
mutex.unlock(); //mutex.unlock();
packet->unlock(); packet->unlock();
return 1; return 1;
} }
@ -2274,20 +2275,21 @@ int Monitor::Capture() {
//Debug(2,"About to decode"); //Debug(2,"About to decode");
if ( packet->decode(camera->get_VideoCodecContext()) ) { if ( packet->decode(camera->get_VideoCodecContext()) ) {
//Debug(2,"Getimage"); //Debug(2,"Getimage");
packet->get_image(); packet->get_image( image_buffer[index].image );
} }
// Have an av_packet, // Have an av_packet,
} }
Debug(2,"Before mutex lock"); //Debug(2,"Before mutex lock");
mutex.lock(); // FIXME this mutex is useless, packetqueue has it's own
//mutex.lock();
if ( packetqueue->video_packet_count || packet->keyframe || event ) { if ( packetqueue->video_packet_count || packet->keyframe || event ) {
Debug(2, "Have video packet for index (%d)", index); Debug(2, "Have video packet for index (%d)", index);
packetqueue->queuePacket(packet); packetqueue->queuePacket(packet);
} else { } else {
Debug(2, "Not queuing video packet for index (%d)", index); Debug(2, "Not queuing video packet for index (%d)", index);
} }
mutex.unlock(); //mutex.unlock();
/* Deinterlacing */ /* Deinterlacing */
if ( deinterlacing_value ) { if ( deinterlacing_value ) {
@ -2355,7 +2357,7 @@ int Monitor::Capture() {
// assume that we are connected // assume that we are connected
snprintf(sql, sizeof(sql), snprintf(sql, sizeof(sql),
"INSERT INTO Monitor_Status (MonitorId,CaptureFPS,CaptureBandwidth,Status) " "INSERT INTO Monitor_Status (MonitorId,CaptureFPS,CaptureBandwidth,Status) "
"VALUES (%d, %.2lf,%u) ON DUPLICATE KEY UPDATE " "VALUES (%d, %.2lf, %u, 'Connected') ON DUPLICATE KEY UPDATE "
"CaptureFPS = %.2lf, CaptureBandwidth=%u, Status='Connected'", "CaptureFPS = %.2lf, CaptureBandwidth=%u, Status='Connected'",
id, capture_fps, new_capture_bandwidth, capture_fps, new_capture_bandwidth); id, capture_fps, new_capture_bandwidth, capture_fps, new_capture_bandwidth);
if ( mysql_query(&dbconn, sql) ) { if ( mysql_query(&dbconn, sql) ) {
@ -2701,24 +2703,18 @@ Monitor::Orientation Monitor::getOrientation() const { return orientation; }
// 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. // 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() { void Monitor::get_ref_image() {
while ( ZMPacket * snap;
( shared_data->last_write_index == (unsigned int)image_buffer_count ) while ( ((!( snap = packetqueue->get_analysis_packet())) || ( snap->image_index == -1 )) && !zm_terminate) {
&& Debug(1, "Waiting for capture daemon lastwriteindex(%d) lastwritetime(%d)",
( shared_data->last_write_time == 0 )
&& ! zm_terminate
) {
Info("Waiting for capture daemon lastwriteindex(%d) lastwritetime(%d)",
shared_data->last_write_index, shared_data->last_write_time); shared_data->last_write_index, shared_data->last_write_time);
usleep(10000); //usleep(10000);
} }
if ( zm_terminate ) if ( zm_terminate )
return; return;
int last_write_index = shared_data->last_write_index ;
Debug(2,"Waiting for capture daemon unlock"); ref_image.Assign(width, height, camera->Colours(), camera->SubpixelOrder(), snap->image->Buffer(), camera->ImageSize());
image_buffer[last_write_index].mutex.lock(); Debug(2,"Have image about to unlock");
ref_image.Assign(width, height, camera->Colours(), camera->SubpixelOrder(), image_buffer[last_write_index].image->Buffer(), camera->ImageSize()); snap->unlock();
image_buffer[last_write_index].mutex.unlock();
} }
std::vector<Group *> Monitor::Groups() { std::vector<Group *> Monitor::Groups() {

View File

@ -74,9 +74,9 @@ bool MonitorStream::checkSwapPath(const char *path, bool create_path) {
} // end bool MonitorStream::checkSwapPath( const char *path, bool create_path ) } // end bool MonitorStream::checkSwapPath( const char *path, bool create_path )
void MonitorStream::processCommand(const CmdMsg *msg) { void MonitorStream::processCommand(const CmdMsg *msg) {
Debug( 2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0] ); Debug(2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0]);
// Check for incoming command // Check for incoming command
switch( (MsgCommand)msg->msg_data[0] ) { switch ( (MsgCommand)msg->msg_data[0] ) {
case CMD_PAUSE : case CMD_PAUSE :
Debug(1, "Got PAUSE command"); Debug(1, "Got PAUSE command");
paused = true; paused = true;
@ -414,19 +414,19 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) {
return false; return false;
} }
fputs("\r\n\r\n",stdout); fputs("\r\n\r\n",stdout);
fflush( stdout ); fflush(stdout);
struct timeval frameEndTime; struct timeval frameEndTime;
gettimeofday( &frameEndTime, NULL ); gettimeofday(&frameEndTime, NULL);
int frameSendTime = tvDiffMsec( frameStartTime, frameEndTime ); int frameSendTime = tvDiffMsec(frameStartTime, frameEndTime);
if ( frameSendTime > 1000/maxfps ) { if ( frameSendTime > 1000/maxfps ) {
maxfps /= 1.5; maxfps /= 1.5;
Error( "Frame send time %d msec too slow, throttling maxfps to %.2f", frameSendTime, maxfps ); Error("Frame send time %d msec too slow, throttling maxfps to %.2f", frameSendTime, maxfps);
} }
} }
last_frame_sent = TV_2_FLOAT( now ); last_frame_sent = TV_2_FLOAT(now);
return( true ); return true;
} // end bool MonitorStream::sendFrame( Image *image, struct timeval *timestamp ) } // end bool MonitorStream::sendFrame( Image *image, struct timeval *timestamp )
void MonitorStream::runStream() { void MonitorStream::runStream() {
@ -483,7 +483,7 @@ void MonitorStream::runStream() {
} else { } else {
swap_path = staticConfig.PATH_SWAP; swap_path = staticConfig.PATH_SWAP;
Debug( 3, "Checking swap path folder: %s", swap_path.c_str() ); Debug(3, "Checking swap path folder: %s", swap_path.c_str());
if ( checkSwapPath(swap_path.c_str(), true) ) { if ( checkSwapPath(swap_path.c_str(), true) ) {
swap_path += stringtf("/zmswap-m%d", monitor->Id()); swap_path += stringtf("/zmswap-m%d", monitor->Id());
@ -503,8 +503,8 @@ void MonitorStream::runStream() {
} else { } else {
Debug(2, "Assigning temporary buffer"); Debug(2, "Assigning temporary buffer");
temp_image_buffer = new SwapImage[temp_image_buffer_count]; temp_image_buffer = new SwapImage[temp_image_buffer_count];
memset( temp_image_buffer, 0, sizeof(*temp_image_buffer)*temp_image_buffer_count ); memset(temp_image_buffer, 0, sizeof(*temp_image_buffer)*temp_image_buffer_count);
Debug( 2, "Assigned temporary buffer" ); Debug(2, "Assigned temporary buffer");
} }
} }
} else { } else {

View File

@ -31,7 +31,7 @@ ZMPacket::ZMPacket( ) {
out_frame = NULL; out_frame = NULL;
image = NULL; image = NULL;
buffer = NULL; buffer = NULL;
av_init_packet( &packet ); av_init_packet(&packet);
packet.size = 0; // So we can detect whether it has been filled. packet.size = 0; // So we can detect whether it has been filled.
timestamp = NULL; timestamp = NULL;
analysis_image = NULL; analysis_image = NULL;
@ -47,8 +47,8 @@ ZMPacket::ZMPacket( ZMPacket &p ) {
out_frame = NULL; out_frame = NULL;
image = NULL; image = NULL;
buffer = NULL; buffer = NULL;
av_init_packet( &packet ); av_init_packet(&packet);
if ( zm_av_packet_ref( &packet, &p.packet ) < 0 ) { if ( zm_av_packet_ref(&packet, &p.packet) < 0 ) {
Error("error refing packet"); Error("error refing packet");
} }
timestamp = new struct timeval; timestamp = new struct timeval;
@ -59,17 +59,17 @@ ZMPacket::ZMPacket( ZMPacket &p ) {
} }
ZMPacket::~ZMPacket() { ZMPacket::~ZMPacket() {
zm_av_packet_unref( &packet ); zm_av_packet_unref(&packet);
if ( in_frame ) { if ( in_frame ) {
//av_free(frame->data); //av_free(frame->data);
av_frame_free( &in_frame ); av_frame_free(&in_frame);
} }
if ( out_frame ) { if ( out_frame ) {
//av_free(frame->data); //av_free(frame->data);
av_frame_free( &out_frame ); av_frame_free(&out_frame);
} }
if ( buffer ) { if ( buffer ) {
av_freep( &buffer ); av_freep(&buffer);
} }
if ( analysis_image ) { if ( analysis_image ) {
delete analysis_image; delete analysis_image;
@ -82,19 +82,19 @@ ZMPacket::~ZMPacket() {
void ZMPacket::reset() { void ZMPacket::reset() {
//Debug(2,"reset"); //Debug(2,"reset");
zm_av_packet_unref( &packet ); zm_av_packet_unref(&packet);
packet.size = 0; packet.size = 0;
if ( in_frame ) { if ( in_frame ) {
//Debug(4,"reset frame"); //Debug(4,"reset frame");
av_frame_free( &in_frame ); av_frame_free(&in_frame);
} }
if ( out_frame ) { if ( out_frame ) {
//Debug(4,"reset frame"); //Debug(4,"reset frame");
av_frame_free( &out_frame ); av_frame_free(&out_frame);
} }
if ( buffer ) { if ( buffer ) {
//Debug(4,"freeing buffer"); //Debug(4,"freeing buffer");
av_freep( &buffer ); av_freep(&buffer);
} }
if ( analysis_image ) { if ( analysis_image ) {
delete analysis_image; delete analysis_image;
@ -111,42 +111,44 @@ void ZMPacket::reset() {
} }
int ZMPacket::decode( AVCodecContext *ctx ) { int ZMPacket::decode( AVCodecContext *ctx ) {
Debug(4, "about to decode video, image_index is (%d)", image_index ); Debug(4, "about to decode video, image_index is (%d)", image_index);
if ( in_frame ) { if ( in_frame ) {
Error("Already have a frame?"); Error("Already have a frame?");
} else { } else {
in_frame = zm_av_frame_alloc(); in_frame = zm_av_frame_alloc();
} }
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
int ret = avcodec_send_packet( ctx, &packet ); Debug(4,"send_packet");
int ret = avcodec_send_packet(ctx, &packet);
if ( ret < 0 ) { if ( ret < 0 ) {
Error( "Unable to send packet: %s", av_make_error_string(ret).c_str() ); Error("Unable to send packet: %s", av_make_error_string(ret).c_str());
av_frame_free( &in_frame ); av_frame_free(&in_frame);
return 0; return 0;
} }
#if HAVE_AVUTIL_HWCONTEXT_H #if HAVE_AVUTIL_HWCONTEXT_H
if ( hwaccel ) { if ( hwaccel ) {
ret = avcodec_receive_frame( ctx, hwFrame ); ret = avcodec_receive_frame(ctx, hwFrame);
if ( ret < 0 ) { if ( ret < 0 ) {
Error( "Unable to receive frame: %s", av_make_error_string(ret).c_str() ); Error("Unable to receive frame: %s", av_make_error_string(ret).c_str());
av_frame_free( &in_frame ); av_frame_free(&in_frame);
return 0; return 0;
} }
ret = av_hwframe_transfer_data(frame, hwFrame, 0); ret = av_hwframe_transfer_data(frame, hwFrame, 0);
if ( ret < 0 ) { if ( ret < 0 ) {
Error( "Unable to transfer frame: %s", av_make_error_string(ret).c_str() ); Error("Unable to transfer frame: %s", av_make_error_string(ret).c_str());
av_frame_free( &in_frame ); av_frame_free(&in_frame);
return 0; return 0;
} }
} else { } else {
#endif #endif
ret = avcodec_receive_frame( ctx, in_frame ); Debug(4,"receive_frame");
ret = avcodec_receive_frame(ctx, in_frame);
if ( ret < 0 ) { if ( ret < 0 ) {
Error( "Unable to receive frame: %s", av_make_error_string(ret).c_str() ); Error("Unable to receive frame: %s", av_make_error_string(ret).c_str());
av_frame_free( &in_frame ); av_frame_free(&in_frame);
return 0; return 0;
} }
@ -156,38 +158,38 @@ int ZMPacket::decode( AVCodecContext *ctx ) {
# else # else
int frameComplete = 0; int frameComplete = 0;
int ret = zm_avcodec_decode_video( ctx, in_frame, &frameComplete, &packet ); int ret = zm_avcodec_decode_video(ctx, in_frame, &frameComplete, &packet);
if ( ret < 0 ) { if ( ret < 0 ) {
Error( "Unable to decode frame at frame %s", av_make_error_string(ret).c_str() ); Error("Unable to decode frame at frame %s", av_make_error_string(ret).c_str());
av_frame_free( &in_frame ); av_frame_free(&in_frame);
return 0; return 0;
} }
if ( ! frameComplete ) { if ( !frameComplete ) {
Debug(1, "incomplete frame?"); Debug(1, "incomplete frame?");
av_frame_free( &in_frame ); av_frame_free(&in_frame);
return 0; return 0;
} }
#endif #endif
return 1; return 1;
} // end ZMPacket::decode } // end ZMPacket::decode
Image * ZMPacket::get_image( Image *i ) { Image *ZMPacket::get_image(Image *i) {
if ( ! in_frame ) { if ( !in_frame ) {
Error("Can't get image without frame.. maybe need to decode first"); Error("Can't get image without frame.. maybe need to decode first");
return NULL; return NULL;
} }
if ( ! image ) { if ( !image ) {
if ( ! i ) { if ( !i ) {
Error("Need a pre-allocated image buffer"); Error("Need a pre-allocated image buffer");
return NULL; return NULL;
} }
image = i; image = i;
} }
image->Assign( in_frame ); image->Assign(in_frame);
return image; return image;
} }
Image *ZMPacket::set_image( Image *i ) { Image *ZMPacket::set_image(Image *i) {
image = i; image = i;
return image; return image;
} }

View File

@ -62,8 +62,12 @@ class ZMPacket {
explicit ZMPacket( ZMPacket &packet ); explicit ZMPacket( ZMPacket &packet );
ZMPacket(); ZMPacket();
~ZMPacket(); ~ZMPacket();
void lock() { mutex.lock(); }; void lock() {
void unlock() { mutex.unlock(); }; Debug(2,"Locking packet %d", this->image_index);
mutex.lock();
Debug(2,"packet %d locked", this->image_index);
};
void unlock() { Debug(2,"packet %d unlocked", this->image_index);mutex.unlock(); };
AVFrame *get_out_frame( const AVCodecContext *ctx ); AVFrame *get_out_frame( const AVCodecContext *ctx );
int get_codec_imgsize() { return codec_imgsize; }; int get_codec_imgsize() { return codec_imgsize; };
}; };

View File

@ -33,12 +33,15 @@ zm_packetqueue::zm_packetqueue( int video_image_count, int p_video_stream_id, in
packet_counts = new int[max_stream_id+1]; packet_counts = new int[max_stream_id+1];
for ( int i=0; i <= max_stream_id; ++i ) for ( int i=0; i <= max_stream_id; ++i )
packet_counts[i] = 0; packet_counts[i] = 0;
condition = new Condition(mutex);
} }
zm_packetqueue::~zm_packetqueue() { zm_packetqueue::~zm_packetqueue() {
clearQueue(); clearQueue();
delete[] packet_counts; delete[] packet_counts;
packet_counts = NULL; packet_counts = NULL;
delete condition;
condition = NULL;
} }
/* Enqueues the given packet. Will maintain the analysis_it pointer and image packet counts. /* Enqueues the given packet. Will maintain the analysis_it pointer and image packet counts.
@ -48,6 +51,7 @@ zm_packetqueue::~zm_packetqueue() {
bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) { bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) {
Debug(4, "packetqueue queuepacket, first_video_packet_index is %d", first_video_packet_index); Debug(4, "packetqueue queuepacket, first_video_packet_index is %d", first_video_packet_index);
mutex.lock();
if ( zm_packet->image_index != -1 ) { if ( zm_packet->image_index != -1 ) {
// It's a video packet // It's a video packet
@ -55,51 +59,33 @@ bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) {
// If we can never queue the same packet, then they can never go past // If we can never queue the same packet, then they can never go past
if ( zm_packet->image_index == first_video_packet_index ) { if ( zm_packet->image_index == first_video_packet_index ) {
Debug(2, "queuing packet that is already on the queue(%d)", zm_packet->image_index); Debug(2, "queuing packet that is already on the queue(%d)", zm_packet->image_index);
ZMPacket *p = NULL;; while ( pktQueue.size() ) {
while ( pktQueue.size() && (p = pktQueue.front()) && ( p->image_index != zm_packet->image_index ) ) { mutex.unlock();
if ( ( analysis_it != pktQueue.end() ) && ( *analysis_it == p ) ) { ZMPacket *p = popPacket();
Debug(2, "Increasing analysis_it, meaning analysis is not keeping up"); Debug(2,"Front packet index: %d", p->image_index);
++analysis_it; mutex.lock();
}
pktQueue.pop_front(); if ( p->codec_type != AVMEDIA_TYPE_VIDEO ) {
if ( p->codec_type == AVMEDIA_TYPE_VIDEO ) { Debug(2, "Deleting audio frame(%d)", p->image_index);
Debug(2, "Decreasing video_packet_count (%d), popped (%d)",
video_packet_count, p->image_index);
video_packet_count -= 1;
first_video_packet_index += 1;
first_video_packet_index %= max_video_packet_count;
} else {
Debug(2, "Deleteing audio frame(%d)", p->image_index);
delete p; delete p;
p = NULL; p = NULL;
} }
Debug(2,"pktQueue.size(%d)", pktQueue.size() ); Debug(2,"pktQueue.size(%d)", pktQueue.size());
if ( p->image_index == zm_packet->image_index )
break;
} // end while there are packets at the head of the queue that are not this one } // end while there are packets at the head of the queue that are not this one
if ( p && ( p->image_index == zm_packet->image_index ) ) {
// it should
video_packet_count -= 1;
pktQueue.pop_front();
first_video_packet_index += 1;
first_video_packet_index %= max_video_packet_count;
} else {
Error("SHould have found the packet! front packet index was %d, new packet index is %d ",
p->image_index, zm_packet->image_index
);
}
if ( analysis_it == pktQueue.end() ) { if ( analysis_it == pktQueue.end() ) {
// Analsys_it should only point to end when queue is empty // Analsys_it should only point to end when queue is empty
Debug(2,"pointing analysis_it to begining"); Debug(2,"pointing analysis_it to begining");
analysis_it = pktQueue.begin(); analysis_it = pktQueue.begin();
} }
} else if ( first_video_packet_index == -1 ) { }
if ( first_video_packet_index == -1 ) {
// Initialize the first_video_packet indicator // Initialize the first_video_packet indicator
first_video_packet_index = zm_packet->image_index; first_video_packet_index = zm_packet->image_index;
video_packet_count += 1;
} // end if } // end if
video_packet_count += 1;
} // end if queuing a video packet } // end if queuing a video packet
pktQueue.push_back(zm_packet); pktQueue.push_back(zm_packet);
@ -114,6 +100,10 @@ bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) {
} }
#endif #endif
// We signal on every packet because someday we may analyze sound
Debug(2,"Signalling");
condition->signal();
mutex.unlock();
return true; return true;
} // end bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) } // end bool zm_packetqueue::queuePacket(ZMPacket* zm_packet)
@ -122,6 +112,9 @@ ZMPacket* zm_packetqueue::popPacket( ) {
if ( pktQueue.empty() ) { if ( pktQueue.empty() ) {
return NULL; return NULL;
} }
Debug(2,"Mutex locking");
mutex.lock();
Debug(2,"Have Mutex lock");
ZMPacket *packet = pktQueue.front(); ZMPacket *packet = pktQueue.front();
if ( *analysis_it == packet ) if ( *analysis_it == packet )
@ -140,7 +133,9 @@ ZMPacket* zm_packetqueue::popPacket( ) {
} }
} }
packet_counts[packet->packet.stream_index] -= 1; packet_counts[packet->packet.stream_index] -= 1;
mutex.unlock();
// Should we lock the packet?
return packet; return packet;
} }
@ -155,6 +150,7 @@ unsigned int zm_packetqueue::clearQueue(unsigned int frames_to_keep, int stream_
if ( pktQueue.size() <= frames_to_keep ) { if ( pktQueue.size() <= frames_to_keep ) {
return 0; return 0;
} }
mutex.lock();
int packets_to_delete = pktQueue.size(); int packets_to_delete = pktQueue.size();
std::list<ZMPacket *>::reverse_iterator it; std::list<ZMPacket *>::reverse_iterator it;
@ -241,6 +237,7 @@ unsigned int zm_packetqueue::clearQueue(unsigned int frames_to_keep, int stream_
#endif #endif
Debug(3, "Deleted packets, resulting size is %d", pktQueue.size()); Debug(3, "Deleted packets, resulting size is %d", pktQueue.size());
mutex.unlock();
return delete_count; return delete_count;
} // end unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream_id ) } // end unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream_id )
@ -278,15 +275,22 @@ int zm_packetqueue::packet_count( int stream_id ) {
// Returns a packet to analyse or NULL // Returns a packet to analyse or NULL
ZMPacket *zm_packetqueue::get_analysis_packet() { ZMPacket *zm_packetqueue::get_analysis_packet() {
if ( ! pktQueue.size() ) mutex.lock();
return NULL; while ( (! pktQueue.size()) || ( analysis_it == pktQueue.end() ) ) {
if ( analysis_it == pktQueue.end() ) Debug(2,"waiting. Queue size %d analysis_it == end? %d", pktQueue.size(), ( analysis_it == pktQueue.end() ) );
return NULL;
condition->wait();
}
//Debug(2, "Distance from head: (%d)", std::distance( pktQueue.begin(), analysis_it ) ); //Debug(2, "Distance from head: (%d)", std::distance( pktQueue.begin(), analysis_it ) );
//Debug(2, "Distance from end: (%d)", std::distance( analysis_it, pktQueue.end() ) ); //Debug(2, "Distance from end: (%d)", std::distance( analysis_it, pktQueue.end() ) );
ZMPacket *p = *analysis_it;
Debug(2,"analysis_packet image_index: %d, about to lock packet", p->image_index);
p->lock();
Debug(2, "Locked packet, unlocking mutex");
mutex.unlock();
return *analysis_it; return p;
} // end ZMPacket *zm_packetqueue::get_analysis_packet() } // end ZMPacket *zm_packetqueue::get_analysis_packet()
// The idea is that analsys_it will only be == end() if the queue is empty // The idea is that analsys_it will only be == end() if the queue is empty
@ -301,3 +305,44 @@ bool zm_packetqueue::increment_analysis_it( ) {
analysis_it = next_it; analysis_it = next_it;
return true; return true;
} // end bool zm_packetqueue::increment_analysis_it( ) } // end bool zm_packetqueue::increment_analysis_it( )
// Locks the packet, but also removes it from the queue including analysis_it
void zm_packetqueue::lock_packet( ZMPacket &packet ) {
mutex.lock();
if ( packet.image_index != -1 ) {
// It's a video packet
// If we can never queue the same packet, then they can never go past
if ( packet.image_index == first_video_packet_index ) {
Debug(2, "queuing packet that is already on the queue(%d)", packet.image_index);
while ( pktQueue.size() ) {
mutex.unlock();
ZMPacket *p = popPacket();
Debug(2,"Front packet index: %d", p->image_index);
mutex.lock();
if ( p->codec_type != AVMEDIA_TYPE_VIDEO ) {
Debug(2, "Deleting audio frame(%d)", p->image_index);
delete p;
p = NULL;
}
Debug(2,"pktQueue.size(%d)", pktQueue.size());
if ( p->image_index == packet.image_index )
break;
} // end while there are packets at the head of the queue that are not this one
if ( analysis_it == pktQueue.end() ) {
// Analsys_it should only point to end when queue is empty
Debug(2,"pointing analysis_it to begining");
analysis_it = pktQueue.begin();
}
}
if ( first_video_packet_index == -1 ) {
// Initialize the first_video_packet indicator
first_video_packet_index = packet.image_index;
} // end if
video_packet_count += 1;
} // end if queuing a video packet
packet.lock();
mutex.unlock();
}

View File

@ -42,7 +42,8 @@ class zm_packetqueue {
int max_stream_id; int max_stream_id;
int *packet_counts; /* packet count for each stream_id, to keep track of how many video vs audio packets are in the queue */ int *packet_counts; /* packet count for each stream_id, to keep track of how many video vs audio packets are in the queue */
Mutex mutex; RecursiveMutex mutex;
Condition *condition;
public: public:
zm_packetqueue(int p_max_video_packet_count, int p_video_stream_id, int p_audio_stream_id); zm_packetqueue(int p_max_video_packet_count, int p_video_stream_id, int p_audio_stream_id);
@ -60,6 +61,7 @@ class zm_packetqueue {
// Functions to manage the analysis frame logic // Functions to manage the analysis frame logic
bool increment_analysis_it(); bool increment_analysis_it();
ZMPacket *get_analysis_packet(); ZMPacket *get_analysis_packet();
void lock_packet( ZMPacket &packet );
}; };
#endif /* ZM_PACKETQUEUE_H */ #endif /* ZM_PACKETQUEUE_H */

View File

@ -215,8 +215,9 @@ if ( $action ) {
# If I put this here, it protects all views and popups, but it has to go after actions.php because actions.php does the actual logging in. # If I put this here, it protects all views and popups, but it has to go after actions.php because actions.php does the actual logging in.
if ( ZM_OPT_USE_AUTH and !isset($user) and ($view != 'login') ) { if ( ZM_OPT_USE_AUTH and !isset($user) and ($view != 'login') ) {
Logger::Debug('Redirecting to login'); Logger::Debug('Redirecting to login');
$view = 'none'; # We adjust the view instead of redirecting so that we can store the original url and just to it after logging in
$redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=login'; $view = 'login';
#$redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=login';
$request = null; $request = null;
} else if ( ZM_SHOW_PRIVACY && ($view != 'privacy') && ($view != 'options') && (!$request) && canEdit('System') ) { } else if ( ZM_SHOW_PRIVACY && ($view != 'privacy') && ($view != 'options') && (!$request) && canEdit('System') ) {
$view = 'none'; $view = 'none';

View File

@ -36,7 +36,7 @@ if ( $user['MonitorIds'] ) {
} }
$Monitor = $Event->Monitor(); $Monitor = $Event->Monitor();
if (isset($_REQUEST['rate'])) { if ( isset($_REQUEST['rate']) ) {
$rate = validInt($_REQUEST['rate']); $rate = validInt($_REQUEST['rate']);
} else if ( isset($_COOKIE['zmEventRate']) ) { } else if ( isset($_COOKIE['zmEventRate']) ) {
$rate = $_COOKIE['zmEventRate']; $rate = $_COOKIE['zmEventRate'];
@ -44,7 +44,7 @@ if (isset($_REQUEST['rate'])) {
$rate = reScale(RATE_BASE, $Monitor->DefaultRate(), ZM_WEB_DEFAULT_RATE); $rate = reScale(RATE_BASE, $Monitor->DefaultRate(), ZM_WEB_DEFAULT_RATE);
} }
if (isset($_REQUEST['scale'])) { if ( isset($_REQUEST['scale']) ) {
$scale = validInt($_REQUEST['scale']); $scale = validInt($_REQUEST['scale']);
} else if ( isset( $_COOKIE['zmEventScaleAuto'] ) ) { } else if ( isset( $_COOKIE['zmEventScaleAuto'] ) ) {
// If we're using scale to fit use it on all monitors // If we're using scale to fit use it on all monitors
@ -56,12 +56,12 @@ if (isset($_REQUEST['scale'])) {
} }
$codec = 'auto'; $codec = 'auto';
if (isset($_REQUEST['codec'])) { if ( isset($_REQUEST['codec']) ) {
$codec = $_REQUEST['codec']; $codec = $_REQUEST['codec'];
session_start(); session_start();
$_SESSION['zmEventCodec'.$Event->MonitorId()] = $codec; $_SESSION['zmEventCodec'.$Event->MonitorId()] = $codec;
session_write_close(); session_write_close();
} else if ( isset( $_SESSION['zmEventCodec'.$Event->MonitorId()] ) ) { } else if ( isset($_SESSION['zmEventCodec'.$Event->MonitorId()]) ) {
$codec = $_SESSION['zmEventCodec'.$Event->MonitorId()]; $codec = $_SESSION['zmEventCodec'.$Event->MonitorId()];
} else { } else {
$codec = $Monitor->DefaultCodec(); $codec = $Monitor->DefaultCodec();
@ -91,7 +91,7 @@ if ( isset( $_REQUEST['replayMode'] ) )
if ( isset( $_COOKIE['replayMode']) && preg_match('#^[a-z]+$#', $_COOKIE['replayMode']) ) if ( isset( $_COOKIE['replayMode']) && preg_match('#^[a-z]+$#', $_COOKIE['replayMode']) )
$replayMode = validHtmlStr($_COOKIE['replayMode']); $replayMode = validHtmlStr($_COOKIE['replayMode']);
if ( ( ! $replayMode ) or ( ! $replayModes[$replayMode] ) ) { if ( ( !$replayMode ) or ( !$replayModes[$replayMode] ) ) {
$replayMode = 'none'; $replayMode = 'none';
} }
@ -145,7 +145,7 @@ if ( ! $Event->Id() ) {
<div id="nameControl"> <div id="nameControl">
<input type="text" id="eventName" name="eventName" value="<?php echo validHtmlStr($Event->Name()) ?>" /> <input type="text" id="eventName" name="eventName" value="<?php echo validHtmlStr($Event->Name()) ?>" />
<button value="Rename" type="button" data-on-click="renameEvent"<?php if ( !canEdit('Events') ) { ?> disabled="disabled"<?php } ?>> <button value="Rename" type="button" data-on-click="renameEvent"<?php if ( !canEdit('Events') ) { ?> disabled="disabled"<?php } ?>>
<?php echo translate('Rename') ?></button> <?php echo translate('Rename') ?></button>
</div> </div>
<?php <?php
if ( canEdit('Events') ) { if ( canEdit('Events') ) {
@ -172,8 +172,8 @@ if ( canEdit('Events') ) {
} // end if Event->DefaultVideo } // end if Event->DefaultVideo
?> ?>
<div id="exportEvent"><button type="button" data-on-click="exportEvent"><?php echo translate('Export') ?></button></div> <div id="exportEvent"><button type="button" data-on-click="exportEvent"><?php echo translate('Export') ?></button></div>
<div id="replayControl"><label for="replayMode"><?php echo translate('Replay') ?></label><?php echo buildSelect( "replayMode", $replayModes, "changeReplayMode();" ); ?></div> <div id="replayControl"><label for="replayMode"><?php echo translate('Replay') ?></label><?php echo buildSelect('replayMode', $replayModes, 'changeReplayMode();'); ?></div>
<div id="scaleControl"><label for="scale"><?php echo translate('Scale') ?></label><?php echo buildSelect( "scale", $scales, "changeScale();" ); ?></div> <div id="scaleControl"><label for="scale"><?php echo translate('Scale') ?></label><?php echo buildSelect('scale', $scales, 'changeScale();'); ?></div>
<div id="codecControl"><label for="codec"><?php echo translate('Codec') ?></label><?php echo htmlSelect('codec', $codecs, $codec, array('onchange'=>'changeCodec(this);') ); ?></div> <div id="codecControl"><label for="codec"><?php echo translate('Codec') ?></label><?php echo htmlSelect('codec', $codecs, $codec, array('onchange'=>'changeCodec(this);') ); ?></div>
</div> </div>
</div> </div>
@ -192,7 +192,6 @@ if ( $video_tag ) {
<?php <?php
} else { } else {
?> ?>
<?php if ( !$video_tag ) { ?>
<div id="imageFeed"> <div id="imageFeed">
<?php <?php
if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) { if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
@ -212,7 +211,9 @@ if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
<div class="progressBox" id="progressBox" title="" style="width: 0%;"></div> <div class="progressBox" id="progressBox" title="" style="width: 0%;"></div>
</div><!--progressBar--> </div><!--progressBar-->
</div><!--imageFeed--> </div><!--imageFeed-->
<?php } /*end if !DefaultVideo*/ ?> <?php
} /*end if !DefaultVideo*/
?>
<p id="dvrControls"> <p id="dvrControls">
<input type="button" value="&lt;+" id="prevBtn" title="<?php echo translate('Prev') ?>" class="inactive" data-on-click-true="streamPrev"/> <input type="button" value="&lt;+" id="prevBtn" title="<?php echo translate('Prev') ?>" class="inactive" data-on-click-true="streamPrev"/>
<input type="button" value="&lt;&lt;" id="fastRevBtn" title="<?php echo translate('Rewind') ?>" class="inactive" data-on-click-true="streamFastRev"/> <input type="button" value="&lt;&lt;" id="fastRevBtn" title="<?php echo translate('Rewind') ?>" class="inactive" data-on-click-true="streamFastRev"/>

View File

@ -18,8 +18,11 @@
} }
?>"; ?>";
//var newUrl = thisUrl + querySuffix; if ( querySuffix == '?view=login' ) {
var newUrl = '<?php echo $_SERVER['PHP_SELF'] ?>' + querySuffix; querySuffix = '?view=console';
}
var newUrl = querySuffix;
console.log("Redirecting to" + newUrl + ' ' + thisUrl);
window.location.replace(newUrl); window.location.replace(newUrl);
} }
).delay( 500 ); ).delay( 500 );