From ed3e975e5a854088e05c90547db6a430dae06b0d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 12 May 2016 11:55:48 -0400 Subject: [PATCH 1/5] take fid and eid as alternate parameters --- web/views/image.php | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/web/views/image.php b/web/views/image.php index cbaf2f731..9bc242244 100644 --- a/web/views/image.php +++ b/web/views/image.php @@ -37,6 +37,8 @@ if ( !canView( 'Events' ) ) $view = "error"; return; } +require_once('includes/Event.php'); +require_once('includes/Frame.php'); header( 'Content-type: image/jpeg' ); @@ -58,11 +60,27 @@ if (!function_exists('imagescale')) $errorText = false; if ( empty($_REQUEST['path']) ) { + if ( ! empty($_REQUEST['fid']) ) { + if ( ! empty($_REQUEST['eid'] ) ) { + $Event = new Event( $_REQUEST['eid'] ); + $Frame = Frame::find_one( array( 'EventId' => $_REQUEST['eid'], 'FrameId' => $_REQUEST['fid'] ) ); + if ( ! $Frame ) { + Fatal("No Frame found for event(".$_REQUEST['eid'].") and frame id(".$_REQUEST['fid'].")"); + } + $path = $Event->Path().'/'.sprintf("%'.0".ZM_EVENT_IMAGE_DIGITS.'d',$_REQUEST['fid']).'-capture.jpg'; + } else { +# If we are only specifying fid, then the fid must be the primary key into the frames table. But when the event is specified, then it is the frame # + $Frame = new Frame( $_REQUEST['fid'] ); + $Event = new Event( $Frame->EventId() ); + $path = $Event->Path().'/'.sprintf("%'.0".ZM_EVENT_IMAGE_DIGITS.'d',$Frame->FrameId()).'-capture.jpg'; + } + } else { $errorText = "No image path"; + } } else { - $path = $_REQUEST['path']; + $path = ZM_DIR_EVENTS . '/' . $_REQUEST['path']; if ( !empty($user['MonitorIds']) ) { $imageOk = false; @@ -111,10 +129,10 @@ if ( $errorText ) Error( $errorText ); else if( ($scale==0 || $scale==100) && $width==0 && $height==0 ) - readfile( ZM_DIR_EVENTS.'/'.$path ); + readfile( $path ); else { - $i = imagecreatefromjpeg ( ZM_DIR_EVENTS.'/'.$path ); + $i = imagecreatefromjpeg ( $path ); $oldWidth=imagesx($i); $oldHeight=imagesy($i); if($width==0 && $height==0) // scale has to be set to get here with both zero From 71e9553648b92a34ae2484bed40f7546c81830e7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 May 2016 14:51:26 -0400 Subject: [PATCH 2/5] add rotation to video --- src/zm_camera.cpp | 5 ++ src/zm_camera.h | 90 +++++++++++++++++++---------------- src/zm_ffmpeg_camera.cpp | 4 +- src/zm_monitor.cpp | 12 +++++ src/zm_monitor.h | 20 ++++---- src/zm_remote_camera_rtsp.cpp | 4 +- src/zm_videostore.cpp | 9 +++- src/zm_videostore.h | 6 ++- 8 files changed, 91 insertions(+), 59 deletions(-) diff --git a/src/zm_camera.cpp b/src/zm_camera.cpp index f8c9fd6af..4759ddc1b 100644 --- a/src/zm_camera.cpp +++ b/src/zm_camera.cpp @@ -51,3 +51,8 @@ Camera::~Camera() { } +Monitor *Camera::getMonitor() { + if ( ! monitor ) + monitor = Monitor::Load( id, false, Monitor::QUERY ); + return monitor; +} diff --git a/src/zm_camera.h b/src/zm_camera.h index eb161b9f0..4d58d4ff1 100644 --- a/src/zm_camera.h +++ b/src/zm_camera.h @@ -25,6 +25,10 @@ #include "zm_image.h" +class Camera; + +#include "zm_monitor.h" + // // Abstract base class for cameras. This is intended just to express // common attributes @@ -32,56 +36,58 @@ class Camera { protected: - typedef enum { LOCAL_SRC, REMOTE_SRC, FILE_SRC, FFMPEG_SRC, LIBVLC_SRC, CURL_SRC } SourceType; + typedef enum { LOCAL_SRC, REMOTE_SRC, FILE_SRC, FFMPEG_SRC, LIBVLC_SRC, CURL_SRC } SourceType; - int id; - SourceType type; - unsigned int width; - unsigned int height; - unsigned int colours; - unsigned int subpixelorder; - unsigned int pixels; - unsigned int imagesize; - int brightness; - int hue; - int colour; - int contrast; - bool capture; - bool record_audio; + int id; // This is actually monitor id + Monitor * monitor; // Null on instantiation, set as soon as possible. + SourceType type; + unsigned int width; + unsigned int height; + unsigned int colours; + unsigned int subpixelorder; + unsigned int pixels; + unsigned int imagesize; + int brightness; + int hue; + int colour; + int contrast; + bool capture; + bool record_audio; public: - Camera( int p_id, SourceType p_type, int p_width, int p_height, int p_colours, int p_subpixelorder, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ); - virtual ~Camera(); + Camera( int p_id, SourceType p_type, int p_width, int p_height, int p_colours, int p_subpixelorder, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ); + virtual ~Camera(); - int getId() const { return( id ); } - SourceType Type() const { return( type ); } - bool IsLocal() const { return( type == LOCAL_SRC ); } - bool IsRemote() const { return( type == REMOTE_SRC ); } - bool IsFile() const { return( type == FILE_SRC ); } - bool IsFfmpeg() const { return( type == FFMPEG_SRC ); } - bool IsLibvlc() const { return( type == LIBVLC_SRC ); } - bool IscURL() const { return( type == CURL_SRC ); } - unsigned int Width() const { return( width ); } - unsigned int Height() const { return( height ); } - unsigned int Colours() const { return( colours ); } - unsigned int SubpixelOrder() const { return( subpixelorder ); } - unsigned int Pixels() const { return( pixels ); } - unsigned int ImageSize() const { return( imagesize ); } + int getId() const { return( id ); } + Monitor *getMonitor(); + SourceType Type() const { return( type ); } + bool IsLocal() const { return( type == LOCAL_SRC ); } + bool IsRemote() const { return( type == REMOTE_SRC ); } + bool IsFile() const { return( type == FILE_SRC ); } + bool IsFfmpeg() const { return( type == FFMPEG_SRC ); } + bool IsLibvlc() const { return( type == LIBVLC_SRC ); } + bool IscURL() const { return( type == CURL_SRC ); } + unsigned int Width() const { return( width ); } + unsigned int Height() const { return( height ); } + unsigned int Colours() const { return( colours ); } + unsigned int SubpixelOrder() const { return( subpixelorder ); } + unsigned int Pixels() const { return( pixels ); } + unsigned int ImageSize() const { return( imagesize ); } - virtual int Brightness( int/*p_brightness*/=-1 ) { return( -1 ); } - virtual int Hue( int/*p_hue*/=-1 ) { return( -1 ); } - virtual int Colour( int/*p_colour*/=-1 ) { return( -1 ); } - virtual int Contrast( int/*p_contrast*/=-1 ) { return( -1 ); } + virtual int Brightness( int/*p_brightness*/=-1 ) { return( -1 ); } + virtual int Hue( int/*p_hue*/=-1 ) { return( -1 ); } + virtual int Colour( int/*p_colour*/=-1 ) { return( -1 ); } + virtual int Contrast( int/*p_contrast*/=-1 ) { return( -1 ); } - bool CanCapture() const { return( capture ); } + bool CanCapture() const { return( capture ); } - bool SupportsNativeVideo() const { return( (type == FFMPEG_SRC )||(type == REMOTE_SRC)); } + bool SupportsNativeVideo() const { return( (type == FFMPEG_SRC )||(type == REMOTE_SRC)); } - virtual int PrimeCapture() { return( 0 ); } - virtual int PreCapture()=0; - virtual int Capture( Image &image )=0; - virtual int PostCapture()=0; - virtual int CaptureAndRecord( Image &image, bool recording, char* event_directory)=0; + virtual int PrimeCapture() { return( 0 ); } + virtual int PreCapture()=0; + virtual int Capture( Image &image )=0; + virtual int PostCapture()=0; + virtual int CaptureAndRecord( Image &image, bool recording, char* event_directory)=0; }; #endif // ZM_CAMERA_H diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index a6ca38e67..bef231c01 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -604,7 +604,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi //Instantiate the video storage module Debug(3, "recording and ! wasRecording %s", event_file); - videoStore = new VideoStore((const char *)event_file, "mp4", mFormatContext->streams[mVideoStreamId],mAudioStreamId==-1?NULL:mFormatContext->streams[mAudioStreamId],startTime); + videoStore = new VideoStore((const char *)event_file, "mp4", mFormatContext->streams[mVideoStreamId],mAudioStreamId==-1?NULL:mFormatContext->streams[mAudioStreamId],startTime, this->getMonitor()->getOrientation() ); wasRecording = true; strcpy(oldDirectory, event_file); @@ -629,7 +629,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi videoStore = NULL; } - videoStore = new VideoStore((const char *)event_file, "mp4", mFormatContext->streams[mVideoStreamId],mAudioStreamId==-1?NULL:mFormatContext->streams[mAudioStreamId],startTime); + videoStore = new VideoStore((const char *)event_file, "mp4", mFormatContext->streams[mVideoStreamId],mAudioStreamId==-1?NULL:mFormatContext->streams[mAudioStreamId],startTime, this->getMonitor()->getOrientation()); strcpy(oldDirectory, event_file); } diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index f5f7b3c84..8448d2dee 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -4399,3 +4399,15 @@ void Monitor::SingleImageZip( int scale) fprintf( stdout, "Content-Type: image/x-rgbz\r\n\r\n" ); fwrite( img_buffer, img_buffer_size, 1, stdout ); } +unsigned int Monitor::Colours() const { return( camera->Colours() ); } + unsigned int Monitor::SubpixelOrder() const { return( camera->SubpixelOrder() ); } + int Monitor::PrimeCapture() { + return( camera->PrimeCapture() ); + } + int Monitor::PreCapture() { + return( camera->PreCapture() ); + } + int Monitor::PostCapture() { + return( camera->PostCapture() ); + } + Monitor::Orientation Monitor::getOrientation()const { return orientation; } diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 70f77ca4c..39f3dfa17 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -29,6 +29,7 @@ #include "zm_rgb.h" #include "zm_zone.h" #include "zm_event.h" +class Monitor; #include "zm_camera.h" #include "zm_storage.h" #include "zm_utils.h" @@ -326,6 +327,8 @@ protected: MonitorLink **linked_monitors; public: + Monitor( int p_id ); + // OurCheckAlarms seems to be unused. Check it on zm_monitor.cpp for more info. //bool OurCheckAlarms( Zone *zone, const Image *pImage ); Monitor( @@ -416,11 +419,12 @@ public: inline bool Exif() { return( embed_exif ); } + Orientation getOrientation()const; unsigned int Width() const { return width; } unsigned int Height() const { return height; } - unsigned int Colours() const { return( camera->Colours() ); } - unsigned int SubpixelOrder() const { return( camera->SubpixelOrder() ); } + unsigned int Colours() const; + unsigned int SubpixelOrder() const; int GetOptSaveJPEGs() const { return( savejpegspref ); } int GetOptVideoWriter() const { return( videowriterpref ); } @@ -454,16 +458,10 @@ public: int actionColour( int p_colour=-1 ); int actionContrast( int p_contrast=-1 ); - inline int PrimeCapture() { - return( camera->PrimeCapture() ); - } - inline int PreCapture() { - return( camera->PreCapture() ); - } + int PrimeCapture(); + int PreCapture(); int Capture(); - int PostCapture() { - return( camera->PostCapture() ); - } + int PostCapture(); unsigned int DetectMotion( const Image &comp_image, Event::StringSet &zoneSet ); // DetectBlack seems to be unused. Check it on zm_monitor.cpp for more info. diff --git a/src/zm_remote_camera_rtsp.cpp b/src/zm_remote_camera_rtsp.cpp index 5256b1de2..83cb341fe 100644 --- a/src/zm_remote_camera_rtsp.cpp +++ b/src/zm_remote_camera_rtsp.cpp @@ -499,7 +499,7 @@ int RemoteCameraRtsp::CaptureAndRecord( Image &image, bool recording, char* even if ( recording && !wasRecording ) { //Instantiate the video storage module - videoStore = new VideoStore((const char *)event_file, "mp4", mFormatContext->streams[mVideoStreamId],mAudioStreamId==-1?NULL:mFormatContext->streams[mAudioStreamId],startTime); + videoStore = new VideoStore((const char *)event_file, "mp4", mFormatContext->streams[mVideoStreamId],mAudioStreamId==-1?NULL:mFormatContext->streams[mAudioStreamId],startTime, this->getMonitor()->getOrientation() ); wasRecording = true; strcpy(oldDirectory, event_file); @@ -519,7 +519,7 @@ int RemoteCameraRtsp::CaptureAndRecord( Image &image, bool recording, char* even videoStore = NULL; } - videoStore = new VideoStore((const char *)event_file, "mp4", mFormatContext->streams[mVideoStreamId],mAudioStreamId==-1?NULL:mFormatContext->streams[mAudioStreamId],startTime); + videoStore = new VideoStore((const char *)event_file, "mp4", mFormatContext->streams[mVideoStreamId],mAudioStreamId==-1?NULL:mFormatContext->streams[mAudioStreamId],startTime, this->getMonitor()->getOrientation() ); strcpy( oldDirectory, event_file ); } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 8357ba5f7..64d8cb303 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -35,7 +35,9 @@ extern "C"{ VideoStore::VideoStore(const char *filename_in, const char *format_in, AVStream *input_st, AVStream *inpaud_st, - int64_t nStartTime) { + int64_t nStartTime, + Monitor::Orientation p_orientation +) { AVDictionary *pmetadata = NULL; int dsr; @@ -75,6 +77,11 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, dsr = av_dict_set(&pmetadata, "title", "Zoneminder Security Recording", 0); if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); + if ( p_orientation == Monitor::ROTATE_90 ) { + dsr = av_dict_set(&pmetadata, "rotate", "90", 0); + if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); + } + oc->metadata = pmetadata; fmt = oc->oformat; diff --git a/src/zm_videostore.h b/src/zm_videostore.h index 0d72f42b6..6b2d3d8cc 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -5,6 +5,8 @@ #if HAVE_LIBAVCODEC +#include "zm_monitor.h" + class VideoStore { private: @@ -15,6 +17,8 @@ private: const char *filename; const char *format; + + Monitor::Orientation orientation; bool keyframeMessage; int keyframeSkipNumber; @@ -26,7 +30,7 @@ private: int64_t filter_in_rescale_delta_last; public: - VideoStore(const char *filename_in, const char *format_in, AVStream *input_st, AVStream *inpaud_st, int64_t nStartTime); + VideoStore(const char *filename_in, const char *format_in, AVStream *input_st, AVStream *inpaud_st, int64_t nStartTime, Monitor::Orientation p_orientation ); ~VideoStore(); int writeVideoFramePacket(AVPacket *pkt, AVStream *input_st);//, AVPacket *lastKeyframePkt); From c11a92efdd10130d9d5b8a5f922e0266329f0022 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 May 2016 15:11:17 -0400 Subject: [PATCH 3/5] implement 180,270 rorations and cleanup --- src/zm_videostore.cpp | 18 ++++++++++++++---- src/zm_videostore.h | 22 ++++++++++------------ 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 2f2102327..cd698c295 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -36,7 +36,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, AVStream *input_st, AVStream *inpaud_st, int64_t nStartTime, - Monitor::Orientation p_orientation + Monitor::Orientation orientation ) { AVDictionary *pmetadata = NULL; @@ -76,9 +76,19 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, dsr = av_dict_set(&pmetadata, "title", "Zoneminder Security Recording", 0); if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); - if ( p_orientation == Monitor::ROTATE_90 ) { - dsr = av_dict_set(&pmetadata, "rotate", "90", 0); - if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); + if ( orientation ) { + if ( orientation == Monitor::ROTATE_90 ) { + dsr = av_dict_set(&pmetadata, "rotate", "90", 0); + if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); + } else if ( orientation == Monitor::ROTATE_180 ) { + dsr = av_dict_set(&pmetadata, "rotate", "180", 0); + if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); + } else if ( orientation == Monitor::ROTATE_270 ) { + dsr = av_dict_set(&pmetadata, "rotate", "270", 0); + if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); + } else { + Warning( "Unsupported Orientation(%d)", orientation ); + } } oc->metadata = pmetadata; diff --git a/src/zm_videostore.h b/src/zm_videostore.h index 6b2d3d8cc..1d962342c 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -17,25 +17,23 @@ private: const char *filename; const char *format; - - Monitor::Orientation orientation; - bool keyframeMessage; - int keyframeSkipNumber; + bool keyframeMessage; + int keyframeSkipNumber; - int64_t startTime; - int64_t startPts; - int64_t startDts; - int64_t prevDts; - int64_t filter_in_rescale_delta_last; + int64_t startTime; + int64_t startPts; + int64_t startDts; + int64_t prevDts; + int64_t filter_in_rescale_delta_last; public: VideoStore(const char *filename_in, const char *format_in, AVStream *input_st, AVStream *inpaud_st, int64_t nStartTime, Monitor::Orientation p_orientation ); ~VideoStore(); - int writeVideoFramePacket(AVPacket *pkt, AVStream *input_st);//, AVPacket *lastKeyframePkt); - int writeAudioFramePacket(AVPacket *pkt, AVStream *input_st); - void dumpPacket( AVPacket *pkt ); + int writeVideoFramePacket(AVPacket *pkt, AVStream *input_st);//, AVPacket *lastKeyframePkt); + int writeAudioFramePacket(AVPacket *pkt, AVStream *input_st); + void dumpPacket( AVPacket *pkt ); }; /* From 235095ed5f12bb2f5f1047a328b6456a39b1a645 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 16 May 2016 10:32:43 -0400 Subject: [PATCH 4/5] fix URL to image view --- web/includes/Frame.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/Frame.php b/web/includes/Frame.php index 5973cd1bf..707569157 100644 --- a/web/includes/Frame.php +++ b/web/includes/Frame.php @@ -70,7 +70,7 @@ class Frame { } public function getImageSrc( ) { - return ZM_BASE_URL.'/index.php?view=image&fid='.$this->{'Id'}; + return $_SERVER['PHP_SELF'].'?view=image&fid='.$this->{'Id'}; } // end function getImageSrc public static function find( $parameters = array(), $limit = NULL ) { From df8964c1f9179c77127d5ed7f059fd1fd494cf55 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 16 May 2016 10:33:21 -0400 Subject: [PATCH 5/5] use eid= & fid= instead of path to frame image. The use of view=image also provides more security. --- web/skins/classic/views/frame.php | 35 ++++++++++++++++++------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/web/skins/classic/views/frame.php b/web/skins/classic/views/frame.php index 9edaa0371..29ddcc1d6 100644 --- a/web/skins/classic/views/frame.php +++ b/web/skins/classic/views/frame.php @@ -24,6 +24,8 @@ if ( !canView( 'Events' ) ) return; } +require_once('includes/Frame.php'); + $eid = validInt($_REQUEST['eid']); if ( !empty($_REQUEST['fid']) ) $fid = validInt($_REQUEST['fid']); @@ -38,52 +40,57 @@ if ( !empty($fid) ) { } else { $frame = dbFetchOne( 'SELECT * FROM Frames WHERE EventId = ? AND Score = ?', NULL, array( $eid, $event['MaxScore'] ) ); } +$frame = new Frame( $frame ); $maxFid = $event['Frames']; $firstFid = 1; -$prevFid = $frame['FrameId']-1; -$nextFid = $frame['FrameId']+1; +$prevFid = $frame->FrameId()-1; +$nextFid = $frame->FrameId()+1; $lastFid = $maxFid; -$alarmFrame = $frame['Type']=='Alarm'; +$alarmFrame = $frame->Type()=='Alarm'; if ( isset( $_REQUEST['scale'] ) ) $scale = validInt($_REQUEST['scale']); else $scale = max( reScale( SCALE_BASE, $event['DefaultScale'], ZM_WEB_DEFAULT_SCALE ), SCALE_BASE ); -$imageData = getImageSrc( $event, $frame, $scale, (isset($_REQUEST['show']) && $_REQUEST['show']=="capt") ); +$imageData = getImageSrc( $event, $frame->FrameId(), $scale, (isset($_REQUEST['show']) && $_REQUEST['show']=="capt") ); $imagePath = $imageData['thumbPath']; $eventPath = $imageData['eventPath']; -$dImagePath = sprintf( "%s/%0".ZM_EVENT_IMAGE_DIGITS."d-diag-d.jpg", $eventPath, $frame['FrameId'] ); -$rImagePath = sprintf( "%s/%0".ZM_EVENT_IMAGE_DIGITS."d-diag-r.jpg", $eventPath, $frame['FrameId'] ); +$dImagePath = sprintf( "%s/%0".ZM_EVENT_IMAGE_DIGITS."d-diag-d.jpg", $eventPath, $frame->FrameId() ); +$rImagePath = sprintf( "%s/%0".ZM_EVENT_IMAGE_DIGITS."d-diag-r.jpg", $eventPath, $frame->FrameId() ); $focusWindow = true; -xhtmlHeaders(__FILE__, translate('Frame')." - ".$event['Id']." - ".$frame['FrameId'] ); +xhtmlHeaders(__FILE__, translate('Frame')." - ".$event['Id']." - ".$frame->FrameId() ); ?>
-

"><?php echo $frame['EventId']." class=""/>

+

+"> +<?php echo $frame->EventId().FrameId() ?>" class=""/> + +

- 1 ) { ?> +FrameId() > 1 ) { ?> - 1 ) { ?> +FrameId() > 1 ) { ?> - +FrameId() < $maxFid ) { ?> - +FrameId() < $maxFid ) { ?>