1) Made shared memory 16 byte aligned and identical size and layout for all platforms.

2) Fixed a bug in zmwatch.pl: Not freeing shared memory handles between iterations.
3) Modified default monitor options to simplify new monitor creation.
pull/49/head
Kfir Itzhak 2011-05-10 13:50:54 +03:00
parent ea3a1a9072
commit b0bc227232
5 changed files with 115 additions and 78 deletions

View File

@ -134,30 +134,35 @@ our $mem_seq = 0;
our $mem_data =
{
"shared_data" => { "type"=>"SharedData", "seq"=>$mem_seq++, "contents"=> {
"size" => { "type"=>"int", "seq"=>$mem_seq++ },
"valid" => { "type"=>"bool1", "seq"=>$mem_seq++ },
"active" => { "type"=>"bool1", "seq"=>$mem_seq++ },
"signal" => { "type"=>"bool1", "seq"=>$mem_seq++ },
"state" => { "type"=>"enum", "seq"=>$mem_seq++},
"last_write_index" => { "type"=>"int", "seq"=>$mem_seq++ },
"last_read_index" => { "type"=>"int", "seq"=>$mem_seq++ },
"last_write_time" => { "type"=>"time_t", "seq"=>$mem_seq++ },
"last_read_time" => { "type"=>"time_t", "seq"=>$mem_seq++ },
"last_event" => { "type"=>"int", "seq"=>$mem_seq++ },
"action" => { "type"=>"enum", "seq"=>$mem_seq++ },
"brightness" => { "type"=>"int", "seq"=>$mem_seq++ },
"hue" => { "type"=>"int", "seq"=>$mem_seq++ },
"colour" => { "type"=>"int", "seq"=>$mem_seq++ },
"contrast" => { "type"=>"int", "seq"=>$mem_seq++ },
"alarm_x" => { "type"=>"int", "seq"=>$mem_seq++ },
"alarm_y" => { "type"=>"int", "seq"=>$mem_seq++ },
"size" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"last_write_index" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"last_read_index" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"state" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"last_event" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"action" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"brightness" => { "type"=>"int32", "seq"=>$mem_seq++ },
"hue" => { "type"=>"int32", "seq"=>$mem_seq++ },
"colour" => { "type"=>"int32", "seq"=>$mem_seq++ },
"contrast" => { "type"=>"int32", "seq"=>$mem_seq++ },
"alarm_x" => { "type"=>"int32", "seq"=>$mem_seq++ },
"alarm_y" => { "type"=>"int32", "seq"=>$mem_seq++ },
"valid" => { "type"=>"uchar", "seq"=>$mem_seq++ },
"active" => { "type"=>"uchar", "seq"=>$mem_seq++ },
"signal" => { "type"=>"uchar", "seq"=>$mem_seq++ },
"bpadding" => { "type"=>"uchar", "seq"=>$mem_seq++ },
"epadding1" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"epadding2" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"epadding3" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"last_write_time" => { "type"=>"time_t64", "seq"=>$mem_seq++ },
"last_read_time" => { "type"=>"time_t64", "seq"=>$mem_seq++ },
"control_state" => { "type"=>"uchar[256]", "seq"=>$mem_seq++ },
}
},
"trigger_data" => { "type"=>"TriggerData", "seq"=>$mem_seq++, "contents"=> {
"size" => { "type"=>"int", "seq"=>$mem_seq++ },
"trigger_state" => { "type"=>"enum", "seq"=>$mem_seq++ },
"trigger_score" => { "type"=>"int", "seq"=>$mem_seq++ },
"size" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"trigger_state" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"trigger_score" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"padding" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"trigger_cause" => { "type"=>"char[32]", "seq"=>$mem_seq++ },
"trigger_text" => { "type"=>"char[256]", "seq"=>$mem_seq++ },
"trigger_showtext" => { "type"=>"char[256]", "seq"=>$mem_seq++ },
@ -176,7 +181,7 @@ sub zmMemInit
foreach my $section_data ( sort { $a->{seq} <=> $b->{seq} } values( %$mem_data ) )
{
$section_data->{offset} = $offset;
$section_data->{align} = 4;
$section_data->{align} = 0;
if ( $section_data->{align} > 1 )
{
@ -188,11 +193,15 @@ sub zmMemInit
}
foreach my $member_data ( sort { $a->{seq} <=> $b->{seq} } values( %{$section_data->{contents}} ) )
{
if ( $member_data->{type} eq "long" || $member_data->{type} eq "time_t" || $member_data->{type} eq "size_t" || $member_data->{type} eq "bool8" )
if ( $member_data->{type} eq "long" || $member_data->{type} eq "ulong" || $member_data->{type} eq "size_t")
{
$member_data->{size} = $member_data->{align} = $native;
}
elsif ( $member_data->{type} eq "int" || $member_data->{type} eq "enum" || $member_data->{type} eq "bool4" )
elsif( $member_data->{type} eq "int64" || $member_data->{type} eq "uint64" || $member_data->{type} eq "time_t64")
{
$member_data->{size} = $member_data->{align} = 8;
}
elsif ( $member_data->{type} eq "int32" || $member_data->{type} eq "uint32" || $member_data->{type} eq "bool4" )
{
$member_data->{size} = $member_data->{align} = 4;
}
@ -200,7 +209,7 @@ sub zmMemInit
{
$member_data->{size} = $member_data->{align} = 2;
}
elsif ( $member_data->{type} =~ "/^u?char$/" || $member_data->{type} eq "bool1" )
elsif ( $member_data->{type} eq "char" || $member_data->{type} eq "uchar" || $member_data->{type} eq "bool1" )
{
$member_data->{size} = $member_data->{align} = 1;
}
@ -304,11 +313,16 @@ sub zmMemRead( $$;$ )
return( undef );
}
my $value;
if ( $type eq "long" || $type eq "time_t" || $type eq "size_t" || $type eq "bool8" )
if ( $type eq "long" || $type eq "ulong" || $type eq "size_t")
{
( $value ) = unpack( "l!", $data );
}
elsif ( $type eq "int" || $type eq "enum" || $type eq "bool4" )
elsif ( $type eq "int64" || $type eq "uint64" || $type eq "time_t64" )
{
# The "q" type is only available on 64bit platforms.
( $value ) = unpack( "l!", $data );
}
elsif ( $type eq "int32" || $type eq "uint32" || $type eq "bool4" )
{
( $value ) = unpack( "l", $data );
}
@ -382,11 +396,16 @@ sub zmMemWrite( $$;$ )
my $size = $mem_data->{$section}->{contents}->{$element}->{size};
my $data;
if ( $type eq "long" || $type eq "time_t" || $type eq "size_t" || $type eq "bool8" )
if ( $type eq "long" || $type eq "ulong" || $type eq "size_t")
{
$data = pack( "l!", $value );
}
elsif ( $type eq "int" || $type eq "enum" || $type eq "bool4" )
elsif ( $type eq "int64" || $type eq "uint64" || $type eq "time_t64" )
{
# The "q" type is only available on 64bit platforms.
$data = pack( "l!", $value );
}
elsif ( $type eq "int32" || $type eq "uint32" || $type eq "bool4" )
{
$data = pack( "l", $value );
}

View File

@ -87,6 +87,7 @@ while( 1 )
{
# Check we have got an image recently
my $image_time = zmGetLastWriteTime( $monitor );
zmMemInvalidate( $monitor );
next if ( !defined($image_time) ); # Can't read from shared data
next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died.
@ -95,9 +96,9 @@ while( 1 )
Debug( "Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay\n" );
if ( $image_delay > $max_image_delay )
{
Info( "Restarting capture daemon for ".$monitor->{Name}.", time since last capture $image_delay seconds ($now-$image_time)\n" );
$restart = 1;
}
Info( "Restarting capture daemon for ".$monitor->{Name}.", time since last capture $image_delay seconds ($now-$image_time)\n" );
$restart = 1;
}
}
else
{
@ -124,6 +125,7 @@ while( 1 )
{
# Check we have got an image recently
my $image_time = zmGetLastReadTime( $monitor );
zmMemInvalidate( $monitor );
next if ( !defined($image_time) ); # Can't read from shared data
next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died.

View File

@ -394,8 +394,10 @@ Monitor::Monitor(
struct timeval *shared_timestamps = (struct timeval *)((char *)trigger_data + sizeof(TriggerData));
unsigned char *shared_images = (unsigned char *)((char *)shared_timestamps + (image_buffer_count*sizeof(struct timeval)));
/* This shouldn't be needed if the shared memory start address is multiple of 16, but just in case */
if(((unsigned long)shared_images % 16) != 0) {
/* Align images buffer to nearest 16 byte boundary */
Debug(3,"Aligning shared memory images to the next 16 byte boundary");
shared_images = (uint8_t*)((unsigned long)shared_images + (16 - ((unsigned long)shared_images % 16)));
}
@ -585,7 +587,7 @@ void Monitor::AddZones( int p_n_zones, Zone *p_zones[] )
Monitor::State Monitor::GetState() const
{
return( shared_data->state );
return( (State)shared_data->state );
}
int Monitor::GetImage( int index, int scale ) const

View File

@ -29,6 +29,7 @@
#include "zm_camera.h"
#include <sys/time.h>
#include <stdint.h>
#define SIGNAL_CAUSE "Signal"
#define MOTION_CAUSE "Motion"
@ -86,43 +87,64 @@ protected:
typedef enum { CLOSE_TIME, CLOSE_IDLE, CLOSE_ALARM } EventCloseMode;
/* sizeof(SharedData) expected to be 336 bytes on 32bit and 64bit */
typedef struct
{
int size;
bool valid;
bool active;
bool signal;
State state;
int last_write_index;
int last_read_index;
time_t last_write_time;
time_t last_read_time;
int last_event;
unsigned int action;
int brightness;
int hue;
int colour;
int contrast;
int alarm_x;
int alarm_y;
char control_state[256];
uint32_t size; /* +0 */
uint32_t last_write_index; /* +4 */
uint32_t last_read_index; /* +8 */
uint32_t state; /* +12 */
uint32_t last_event; /* +16 */
uint32_t action; /* +20 */
int32_t brightness; /* +24 */
int32_t hue; /* +28 */
int32_t colour; /* +32 */
int32_t contrast; /* +36 */
int32_t alarm_x; /* +40 */
int32_t alarm_y; /* +44 */
uint8_t valid; /* +48 */
uint8_t active; /* +49 */
uint8_t signal; /* +50 */
uint8_t bpadding; /* +51 */
uint32_t epadding1; /* +52 */
uint32_t epadding2; /* +56 */
uint32_t epadding3; /* +60 */
/*
** This keeps 32bit time_t and 64bit time_t identical and compatible as long as time is before 2038.
** Shared memory layout should be identical for both 32bit and 64bit and is multiples of 16.
*/
union { /* +64 */
time_t last_write_time;
uint64_t extrapad1;
};
union { /* +72 */
time_t last_read_time;
uint64_t extrapad2;
};
uint8_t control_state[256]; /* +80 */
} SharedData;
typedef enum { TRIGGER_CANCEL, TRIGGER_ON, TRIGGER_OFF } TriggerState;
/* sizeof(TriggerData) expected to be 560 on 32bit & and 64bit */
typedef struct
{
int size;
TriggerState trigger_state;
int trigger_score;
uint32_t size;
uint32_t trigger_state;
uint32_t trigger_score;
uint32_t padding;
char trigger_cause[32];
char trigger_text[256];
char trigger_showtext[256];
} TriggerData;
/* sizeof(Snapshot) expected to be 16 bytes on 32bit and 32 bytes on 64bit */
struct Snapshot
{
struct timeval *timestamp;
Image *image;
void* padding;
};
class MonitorLink
@ -317,7 +339,7 @@ public:
void ForceAlarmOn( int force_score, const char *force_case, const char *force_text="" );
void ForceAlarmOff();
void CancelForced();
TriggerState GetTriggerState() const { return( trigger_data?trigger_data->trigger_state:TRIGGER_CANCEL ); }
TriggerState GetTriggerState() const { return( (TriggerState)(trigger_data?trigger_data->trigger_state:TRIGGER_CANCEL )); }
void actionReload();
void actionEnable();

View File

@ -56,26 +56,26 @@ else
'Enabled' => true,
'LinkedMonitors' => "",
'Type' => "",
'Device' => "/dev/video",
'Device' => "/dev/video0",
'Channel' => "0",
'Format' => "",
'Format' => 0x000000ff,
'Protocol' => "",
'Method' => "",
'Host' => "",
'Path' => "",
'Port' => "80",
'Colours' => "",
'Palette' => "",
'Width' => "",
'Height' => "",
'Colours' => 4,
'Palette' => fourcc('B','G','R','4'),
'Width' => "320",
'Height' => "240",
'Orientation' => "0",
'LabelFormat' => '%N - %y/%m/%d %H:%M:%S',
'LabelFormat' => '%N - %d/%m/%y %H:%M:%S',
'LabelX' => 0,
'LabelY' => 0,
'ImageBufferCount' => 40,
'ImageBufferCount' => 60,
'WarmupCount' => 25,
'PreEventCount' => 10,
'PostEventCount' => 10,
'PreEventCount' => 25,
'PostEventCount' => 25,
'StreamReplayBuffer' => 1000,
'AlarmFrameCount' => 1,
'Controllable' => 0,
@ -91,14 +91,14 @@ else
'SectionLength' => 600,
'FrameSkip' => 0,
'EventPrefix' => 'Event-',
'MaxFPS' => "",
'AlarmMaxFPS' => "",
'MaxFPS' => "5",
'AlarmMaxFPS' => "5",
'FPSReportInterval' => 1000,
'RefBlendPerc' => 7,
'DefaultView' => 'Events',
'DefaultRate' => '100',
'DefaultScale' => '100',
'SignalCheckColour' => '#0100BE',
'SignalCheckColour' => '#0000C0',
'WebColour' => 'red',
'Triggers' => "",
);
@ -328,8 +328,8 @@ if ( ZM_HAS_V4L2 )
//"SBGGR16" => fourcc('B','Y','R','2'), /* 16 BGBG.. GRGR.. */
/* compressed formats */
//"MJPEG" => fourcc('M','J','P','G'), /* Motion-JPEG */
"JPEG" => fourcc('J','P','E','G'), /* JFIF JPEG */
"*JPEG" => fourcc('J','P','E','G'), /* JFIF JPEG */
"*MJPEG" => fourcc('M','J','P','G'), /* Motion-JPEG */
//"DV" => fourcc('d','v','s','d'), /* 1394 */
//"MPEG" => fourcc('M','P','E','G'), /* MPEG-1/2/4 */
@ -608,14 +608,6 @@ switch ( $tab )
}
case 'source' :
{
// Set up initial palette value
if ( $newMonitor['Palette'] == '' )
{
if ( ZM_HAS_V4L && $newMonitor['Type'] == 'Local' )
$newMonitor['Palette'] = 4;
else
$newMonitor['Palette'] = 3;
}
if ( ZM_HAS_V4L && $newMonitor['Type'] == "Local" )
{
?>
@ -630,7 +622,7 @@ switch ( $tab )
<tr><td><?= $SLANG['CapturePalette'] ?></td><td><select name="newMonitor[Palette]"><?php foreach ( $v4l1LocalPalettes as $name => $value ) { ?><option value="<?= $value ?>"<?php if ( $value == $newMonitor['Palette'] ) { ?> selected="selected"<?php } ?>><?= $name ?></option><?php } ?></select></td></tr>
<?php
}
else if ( ZM_HAS_V4L2 && $newMonitor['Method'] == 'v4l2' )
else
{
?>
<tr><td><?= $SLANG['DeviceChannel'] ?></td><td><select name="newMonitor[Channel]"><?php foreach ( $v4l2DeviceChannels as $name => $value ) { ?><option value="<?= $value ?>"<?php if ( $value == $newMonitor['Channel'] ) { ?> selected="selected"<?php } ?>><?= $name ?></option><?php } ?></select></td></tr>