Bug 264 - Added support for zipped raw images.

git-svn-id: http://svn.zoneminder.com/svn/zm/trunk@1847 e3e1d417-86f3-4887-817a-d78f3d33393f
pull/27/merge
stan 2006-01-20 15:27:48 +00:00
parent a6fca601a2
commit d4e16016ba
9 changed files with 191 additions and 6 deletions

View File

@ -293,7 +293,7 @@ bool Image::WriteJpeg( const char *filename, int quality_override ) const
return( true ); return( true );
} }
bool Image::DecodeJpeg( JOCTET *inbuffer, int inbuffer_size ) bool Image::DecodeJpeg( const JOCTET *inbuffer, int inbuffer_size )
{ {
struct jpeg_decompress_struct *cinfo = jpg_dcinfo; struct jpeg_decompress_struct *cinfo = jpg_dcinfo;
@ -397,6 +397,34 @@ bool Image::EncodeJpeg( JOCTET *outbuffer, int *outbuffer_size, int quality_over
return( true ); return( true );
} }
bool Image::Unzip( const Bytef *inbuffer, unsigned long inbuffer_size )
{
unsigned long zip_size = size;
int result = uncompress( buffer, &zip_size, inbuffer, inbuffer_size );
if ( result != Z_OK )
{
Error(( "Unzip failed, result = %d", result ));
return( false );
}
if ( zip_size != size )
{
Error(( "Unzip failed, size mismatch, expected %d bytes, got %d", size, zip_size ));
return( false );
}
return( true );
}
bool Image::Zip( Bytef *outbuffer, unsigned long *outbuffer_size, int compression_level ) const
{
int result = compress2( outbuffer, outbuffer_size, buffer, size, compression_level );
if ( result != Z_OK )
{
Error(( "Zip failed, result = %d", result ));
return( false );
}
return( true );
}
bool Image::Crop( int lo_x, int lo_y, int hi_x, int hi_y ) bool Image::Crop( int lo_x, int lo_y, int hi_x, int hi_y )
{ {
int new_width = (hi_x-lo_x)+1;; int new_width = (hi_x-lo_x)+1;;

View File

@ -27,6 +27,7 @@
#include <assert.h> #include <assert.h>
#include <time.h> #include <time.h>
#include <math.h> #include <math.h>
#include <zlib.h>
extern "C" extern "C"
{ {
@ -239,9 +240,12 @@ public:
bool ReadJpeg( const char *filename ); bool ReadJpeg( const char *filename );
bool WriteJpeg( const char *filename, int quality_override=0 ) const; bool WriteJpeg( const char *filename, int quality_override=0 ) const;
bool DecodeJpeg( JOCTET *inbuffer, int inbuffer_size ); bool DecodeJpeg( const JOCTET *inbuffer, int inbuffer_size );
bool EncodeJpeg( JOCTET *outbuffer, int *outbuffer_size, int quality_override=0 ) const; bool EncodeJpeg( JOCTET *outbuffer, int *outbuffer_size, int quality_override=0 ) const;
bool Unzip( const Bytef *inbuffer, unsigned long inbuffer_size );
bool Zip( Bytef *outbuffer, unsigned long *outbuffer_size, int compression_level=Z_BEST_SPEED ) const;
bool Crop( int lo_x, int lo_y, int hi_y, int hi_y ); bool Crop( int lo_x, int lo_y, int hi_y, int hi_y );
void Overlay( const Image &image ); void Overlay( const Image &image );

View File

@ -348,7 +348,7 @@ static void term_source (j_decompress_ptr cinfo)
* for closing it after finishing decompression. * for closing it after finishing decompression.
*/ */
void jpeg_mem_src( j_decompress_ptr cinfo, JOCTET *inbuffer, int inbuffer_size ) void jpeg_mem_src( j_decompress_ptr cinfo, const JOCTET *inbuffer, int inbuffer_size )
{ {
mem_src_ptr src; mem_src_ptr src;

View File

@ -36,5 +36,5 @@ void zm_jpeg_error_exit( j_common_ptr cinfo );
void zm_jpeg_emit_message( j_common_ptr cinfo, int msg_level ); void zm_jpeg_emit_message( j_common_ptr cinfo, int msg_level );
// Prototypes for memory compress/decompression object */ // Prototypes for memory compress/decompression object */
void jpeg_mem_src(j_decompress_ptr cinfo, JOCTET *inbuffer, int inbuffer_size ); void jpeg_mem_src(j_decompress_ptr cinfo, const JOCTET *inbuffer, int inbuffer_size );
void jpeg_mem_dest(j_compress_ptr cinfo, JOCTET *outbuffer, int *outbuffer_size ); void jpeg_mem_dest(j_compress_ptr cinfo, JOCTET *outbuffer, int *outbuffer_size );

View File

@ -1748,6 +1748,92 @@ void Monitor::StreamImagesRaw( int scale, int maxfps, time_t ttl )
} }
} }
void Monitor::StreamImagesZip( int scale, int maxfps, time_t ttl )
{
fprintf( stdout, "Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame\r\n\r\n" );
int fps = int(GetFPS());
if ( !fps )
fps = 5;
int min_fps = 1;
int max_fps = maxfps;
int base_fps = int(GetFPS());
int effective_fps = base_fps;
int frame_mod = 1;
// Min frame repeat?
while( effective_fps > max_fps )
{
effective_fps /= 2;
frame_mod *= 2;
}
Debug( 1, ( "BFPS:%d, EFPS:%d, FM:%d", base_fps, effective_fps, frame_mod ));
int last_read_index = image_buffer_count;
time_t stream_start_time;
time( &stream_start_time );
int frame_count = 0;
struct timeval base_time;
struct DeltaTimeval delta_time;
unsigned long img_buffer_size = 0;
static Bytef img_buffer[ZM_MAX_IMAGE_SIZE];
Image scaled_image;
while ( true )
{
if ( feof( stdout ) || ferror( stdout ) )
{
break;
}
if ( last_read_index != shared_data->last_write_index )
{
last_read_index = shared_data->last_write_index;
if ( (frame_mod == 1) || ((frame_count%frame_mod) == 0) )
{
// Send the next frame
int index = shared_data->last_write_index%image_buffer_count;
//Info(( "%d: %x - %x", index, image_buffer[index].image, image_buffer[index].image->buffer ));
Snapshot *snap = &image_buffer[index];
Image *snap_image = snap->image;
if ( scale != 100 )
{
scaled_image.Assign( *snap_image );
scaled_image.Scale( scale );
snap_image = &scaled_image;
}
if ( !config.timestamp_on_capture )
{
TimestampImage( snap_image, snap->timestamp->tv_sec );
}
snap_image->Zip( img_buffer, &img_buffer_size );
fprintf( stdout, "--ZoneMinderFrame\r\n" );
fprintf( stdout, "Content-Length: %d\r\n", img_buffer_size );
fprintf( stdout, "Content-Type: image/x-rgbz\r\n\r\n" );
fwrite( img_buffer, img_buffer_size, 1, stdout );
fprintf( stdout, "\r\n\r\n" );
if ( ttl )
{
time_t now = time ( 0 );
if ( (now - stream_start_time) > ttl )
{
break;
}
}
}
frame_count++;
}
usleep( ZM_SAMPLE_RATE );
}
}
void Monitor::SingleImage( int scale) void Monitor::SingleImage( int scale)
{ {
int last_read_index = shared_data->last_write_index; int last_read_index = shared_data->last_write_index;
@ -1799,6 +1885,33 @@ void Monitor::SingleImageRaw( int scale)
fwrite( snap_image->Buffer(), snap_image->Size(), 1, stdout ); fwrite( snap_image->Buffer(), snap_image->Size(), 1, stdout );
} }
void Monitor::SingleImageZip( int scale)
{
int last_read_index = shared_data->last_write_index;
unsigned long img_buffer_size = 0;
static Bytef img_buffer[ZM_MAX_IMAGE_SIZE];
Image scaled_image;
int index = shared_data->last_write_index%image_buffer_count;
Snapshot *snap = &image_buffer[index];
Image *snap_image = snap->image;
if ( scale != 100 )
{
scaled_image.Assign( *snap_image );
scaled_image.Scale( scale );
snap_image = &scaled_image;
}
if ( !config.timestamp_on_capture )
{
TimestampImage( snap_image, snap->timestamp->tv_sec );
}
snap_image->Zip( img_buffer, &img_buffer_size );
fprintf( stdout, "Content-Length: %d\r\n", img_buffer_size );
fprintf( stdout, "Content-Type: image/x-rgbz\r\n\r\n" );
fwrite( img_buffer, img_buffer_size, 1, stdout );
}
#if HAVE_LIBAVCODEC #if HAVE_LIBAVCODEC
void Monitor::StreamMpeg( const char *format, int scale, int maxfps, int bitrate ) void Monitor::StreamMpeg( const char *format, int scale, int maxfps, int bitrate )

View File

@ -266,8 +266,10 @@ public:
static Monitor *Load( int id, bool load_zones=false, Purpose purpose=QUERY ); static Monitor *Load( int id, bool load_zones=false, Purpose purpose=QUERY );
void StreamImages( int scale=100, int maxfps=10, time_t ttl=0 ); void StreamImages( int scale=100, int maxfps=10, time_t ttl=0 );
void StreamImagesRaw( int scale=100, int maxfps=10, time_t ttl=0 ); void StreamImagesRaw( int scale=100, int maxfps=10, time_t ttl=0 );
void StreamImagesZip( int scale=100, int maxfps=10, time_t ttl=0 );
void SingleImage( int scale=100 ); void SingleImage( int scale=100 );
void SingleImageRaw( int scale=100 ); void SingleImageRaw( int scale=100 );
void SingleImageZip( int scale=100 );
#if HAVE_LIBAVCODEC #if HAVE_LIBAVCODEC
void StreamMpeg( const char *format, int scale=100, int maxfps=10, int bitrate=100000 ); void StreamMpeg( const char *format, int scale=100, int maxfps=10, int bitrate=100000 );
#endif // HAVE_LIBAVCODEC #endif // HAVE_LIBAVCODEC

View File

@ -358,6 +358,13 @@ int RemoteCamera::GetResponse()
format = X_RGB; format = X_RGB;
state = CONTENT; state = CONTENT;
} }
else if ( !strcasecmp( content_type, "image/x-rgbz" ) )
{
// Single image
mode = SINGLE_IMAGE;
format = X_RGBZ;
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
@ -445,6 +452,10 @@ int RemoteCamera::GetResponse()
{ {
format = X_RGB; format = X_RGB;
} }
else if ( !strcasecmp( content_type, "image/x-rgbz" ) )
{
format = X_RGBZ;
}
else else
{ {
Error(( "Found unsupported content type '%s'", content_type )); Error(( "Found unsupported content type '%s'", content_type ));
@ -771,6 +782,13 @@ int RemoteCamera::GetResponse()
format = X_RGB; format = X_RGB;
state = CONTENT; state = CONTENT;
} }
else if ( !strcasecmp( content_type, "image/x-rgbz" ) )
{
// Single image
mode = SINGLE_IMAGE;
format = X_RGBZ;
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
@ -924,6 +942,10 @@ int RemoteCamera::GetResponse()
{ {
format = X_RGB; format = X_RGB;
} }
else if ( !strcasecmp( content_type, "image/x-rgbz" ) )
{
format = X_RGBZ;
}
else else
{ {
Error(( "Found unsupported content type '%s'", content_type )); Error(( "Found unsupported content type '%s'", content_type ));
@ -1062,6 +1084,7 @@ int RemoteCamera::PostCapture( Image &image )
{ {
if ( !image.DecodeJpeg( buffer.Extract( content_length ), content_length ) ) if ( !image.DecodeJpeg( buffer.Extract( content_length ), content_length ) )
{ {
Disconnect();
return( -1 ); return( -1 );
} }
break; break;
@ -1077,6 +1100,16 @@ int RemoteCamera::PostCapture( Image &image )
image.Assign( width, height, colours, buffer ); image.Assign( width, height, colours, buffer );
break; break;
} }
case X_RGBZ :
{
if ( !image.Unzip( buffer.Extract( content_length ), content_length ) )
{
Disconnect();
return( -1 );
}
image.Assign( width, height, colours, buffer );
break;
}
default : default :
{ {
Error(( "Unexpected image format encountered" )); Error(( "Unexpected image format encountered" ));

View File

@ -47,7 +47,7 @@ protected:
int sd; int sd;
Buffer buffer; Buffer buffer;
enum { SINGLE_IMAGE, MULTI_IMAGE } mode; enum { SINGLE_IMAGE, MULTI_IMAGE } mode;
enum { UNDEF, JPEG, X_RGB } format; enum { UNDEF, JPEG, X_RGB, X_RGBZ } format;
enum { HEADER, HEADERCONT, SUBHEADER, SUBHEADERCONT, CONTENT } state; enum { HEADER, HEADERCONT, SUBHEADER, SUBHEADERCONT, CONTENT } state;
protected: protected:

View File

@ -48,7 +48,7 @@ bool ValidateAccess( User *user, int mon_id )
int main( int argc, const char *argv[] ) int main( int argc, const char *argv[] )
{ {
enum { ZMS_JPEG, ZMS_MPEG, ZMS_RAW, ZMS_SINGLE } mode = ZMS_JPEG; enum { ZMS_JPEG, ZMS_MPEG, ZMS_RAW, ZMS_ZIP, ZMS_SINGLE } mode = ZMS_JPEG;
char format[32] = ""; char format[32] = "";
int id = 0; int id = 0;
int event = 0; int event = 0;
@ -98,6 +98,7 @@ int main( int argc, const char *argv[] )
{ {
mode = !strcmp( value, "jpeg" )?ZMS_JPEG:ZMS_MPEG; mode = !strcmp( value, "jpeg" )?ZMS_JPEG:ZMS_MPEG;
mode = !strcmp( value, "raw" )?ZMS_RAW:mode; mode = !strcmp( value, "raw" )?ZMS_RAW:mode;
mode = !strcmp( value, "zip" )?ZMS_ZIP:mode;
mode = !strcmp( value, "single" )?ZMS_SINGLE:mode; mode = !strcmp( value, "single" )?ZMS_SINGLE:mode;
} }
else if ( !strcmp( name, "monitor" ) ) else if ( !strcmp( name, "monitor" ) )
@ -224,6 +225,10 @@ int main( int argc, const char *argv[] )
{ {
monitor->StreamImagesRaw( scale, maxfps, ttl ); monitor->StreamImagesRaw( scale, maxfps, ttl );
} }
else if ( mode == ZMS_ZIP )
{
monitor->StreamImagesZip( scale, maxfps, ttl );
}
else if ( mode == ZMS_SINGLE ) else if ( mode == ZMS_SINGLE )
{ {
monitor->SingleImage( scale ); monitor->SingleImage( scale );