diff --git a/src/zm_camera.cpp b/src/zm_camera.cpp index 6f2c5b023..55a58ffca 100644 --- a/src/zm_camera.cpp +++ b/src/zm_camera.cpp @@ -20,8 +20,8 @@ #include "zm.h" #include "zm_camera.h" -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 ) : - id( p_id ), +Camera::Camera( unsigned int p_monitor_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 ) : + monitor_id( p_monitor_id ), type( p_type ), width( p_width), height( p_height ), @@ -37,7 +37,7 @@ Camera::Camera( int p_id, SourceType p_type, int p_width, int p_height, int p_co pixels = width * height; imagesize = pixels * colours; - Debug(2,"New camera id: %d width: %d height: %d colours: %d subpixelorder: %d capture: %d",id,width,height,colours,subpixelorder,capture); + Debug(2,"New camera id: %d width: %d height: %d colours: %d subpixelorder: %d capture: %d",monitor_id,width,height,colours,subpixelorder,capture); /* Because many loops are unrolled and work on 16 colours/time or 4 pixels/time, we have to meet requirements */ if((colours == ZM_COLOUR_GRAY8 || colours == ZM_COLOUR_RGB32) && (imagesize % 16) != 0) { @@ -47,7 +47,11 @@ Camera::Camera( int p_id, SourceType p_type, int p_width, int p_height, int p_co } } -Camera::~Camera() -{ +Camera::~Camera() { } +Monitor *Camera::getMonitor() { + if ( ! monitor ) + monitor = Monitor::Load( monitor_id, false, Monitor::QUERY ); + return monitor; +} diff --git a/src/zm_camera.h b/src/zm_camera.h index 461789178..1a90f037c 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 @@ -34,7 +38,8 @@ class Camera protected: typedef enum { LOCAL_SRC, REMOTE_SRC, FILE_SRC, FFMPEG_SRC, LIBVLC_SRC, CURL_SRC } SourceType; - int id; + unsigned int monitor_id; + Monitor * monitor; // Null on instantiation, set as soon as possible. SourceType type; unsigned int width; unsigned int height; @@ -50,10 +55,11 @@ protected: 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 ); + Camera( unsigned int p_monitor_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 ); } + unsigned int getId() const { return( monitor_id ); } + Monitor *getMonitor(); SourceType Type() const { return( type ); } bool IsLocal() const { return( type == LOCAL_SRC ); } bool IsRemote() const { return( type == REMOTE_SRC ); } @@ -81,7 +87,7 @@ public: 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 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 deb8db571..d70ba394c 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -591,19 +591,25 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi Debug(3, "Record Audio on but no audio stream found"); videoStore = new VideoStore((const char *) event_file, "mp4", mFormatContext->streams[mVideoStreamId], - NULL, startTime); + NULL, + startTime, + this->getMonitor()->getOrientation()); + } else { Debug(3, "Video module initiated with audio stream"); videoStore = new VideoStore((const char *) event_file, "mp4", mFormatContext->streams[mVideoStreamId], mFormatContext->streams[mAudioStreamId], - startTime); + startTime, + this->getMonitor()->getOrientation()); } } else { Debug(3, "Record_audio is false so exclude audio stream"); videoStore = new VideoStore((const char *) event_file, "mp4", mFormatContext->streams[mVideoStreamId], - NULL, startTime); + NULL, + startTime, + this->getMonitor()->getOrientation()); } wasRecording = true; strcpy(oldDirectory, event_file); @@ -633,19 +639,23 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi Debug(3, "Record Audio on but no audio stream found"); videoStore = new VideoStore((const char *) event_file, "mp4", mFormatContext->streams[mVideoStreamId], - NULL, startTime); + NULL, + startTime, + this->getMonitor()->getOrientation()); } else { Debug(3, "Video module initiated with audio stream"); videoStore = new VideoStore((const char *) event_file, "mp4", mFormatContext->streams[mVideoStreamId], mFormatContext->streams[mAudioStreamId], - startTime); + startTime, + this->getMonitor()->getOrientation()); } } else { Debug(3, "Record_audio is false so exclude audio stream"); videoStore = new VideoStore((const char *) event_file, "mp4", mFormatContext->streams[mVideoStreamId], - NULL, startTime); + NULL, startTime, + this->getMonitor()->getOrientation()); } strcpy(oldDirectory, event_file); } diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 7cbac5d15..216f9f4b1 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -4446,3 +4446,16 @@ 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 cf27e1b0a..392bdea57 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_utils.h" @@ -327,6 +328,7 @@ 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( @@ -419,15 +421,16 @@ public: { 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 Width() const { return width; } + unsigned int Height() const { return height; } + unsigned int Colours() const; + unsigned int SubpixelOrder() const; int GetOptSaveJPEGs() const { return( savejpegspref ); } int GetOptVideoWriter() const { return( videowriterpref ); } - const std::vector* GetOptEncoderParams() const { return( &encoderparamsvec ); } + const std::vector* GetOptEncoderParams() const { return( &encoderparamsvec ); } State GetState() const; int GetImage( int index=-1, int scale=100 ); @@ -457,19 +460,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.cpp b/src/zm_remote_camera.cpp index 1ffe5f568..be177c2c6 100644 --- a/src/zm_remote_camera.cpp +++ b/src/zm_remote_camera.cpp @@ -22,7 +22,7 @@ #include "zm_utils.h" RemoteCamera::RemoteCamera( - int p_id, + unsigned int p_monitor_id, const std::string &p_protocol, const std::string &p_host, const std::string &p_port, @@ -37,7 +37,7 @@ RemoteCamera::RemoteCamera( bool p_capture, bool p_record_audio ) : - Camera( p_id, REMOTE_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ), + Camera( p_monitor_id, REMOTE_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ), protocol( p_protocol ), host( p_host ), port( p_port ), diff --git a/src/zm_remote_camera.h b/src/zm_remote_camera.h index 6add0398a..b24d6a68f 100644 --- a/src/zm_remote_camera.h +++ b/src/zm_remote_camera.h @@ -27,6 +27,7 @@ #include #include #include +#include // // Class representing 'remote' cameras, i.e. those which are @@ -56,7 +57,7 @@ protected: public: RemoteCamera( - int p_id, + unsigned int p_monitor_id, const std::string &p_proto, const std::string &p_host, const std::string &p_port, diff --git a/src/zm_remote_camera_http.cpp b/src/zm_remote_camera_http.cpp index 02641632d..17f3969a4 100644 --- a/src/zm_remote_camera_http.cpp +++ b/src/zm_remote_camera_http.cpp @@ -30,9 +30,12 @@ #ifdef SOLARIS #include // FIONREAD and friends #endif +#ifdef __FreeBSD__ +#include +#endif RemoteCameraHttp::RemoteCameraHttp( - int p_id, + unsigned int p_monitor_id, const std::string &p_method, const std::string &p_host, const std::string &p_port, @@ -46,7 +49,7 @@ RemoteCameraHttp::RemoteCameraHttp( bool p_capture, bool p_record_audio ) : RemoteCamera( - p_id, + p_monitor_id, "http", p_host, p_port, @@ -71,7 +74,7 @@ RemoteCameraHttp::RemoteCameraHttp( else if ( p_method == "regexp" ) method = REGEXP; else - Fatal( "Unrecognised method '%s' when creating HTTP camera %d", p_method.c_str(), id ); + Fatal( "Unrecognised method '%s' when creating HTTP camera %d", p_method.c_str(), monitor_id ); if ( capture ) { Initialise(); @@ -135,7 +138,12 @@ int RemoteCameraHttp::Connect() { close(sd); sd = -1; - Warning("Can't connect to remote camera: %s", strerror(errno) ); + char buf[sizeof(struct in6_addr)]; + struct sockaddr_in *addr; + addr = (struct sockaddr_in *)p->ai_addr; + inet_ntop( AF_INET, &(addr->sin_addr), buf, INET6_ADDRSTRLEN ); + + Warning("Can't connect to remote camera mid: %d at %s: %s", monitor_id, buf, strerror(errno) ); continue; } diff --git a/src/zm_remote_camera_http.h b/src/zm_remote_camera_http.h index f0b8a4415..079dd8482 100644 --- a/src/zm_remote_camera_http.h +++ b/src/zm_remote_camera_http.h @@ -45,7 +45,7 @@ protected: enum { SIMPLE, REGEXP } method; public: - RemoteCameraHttp(int p_id, const std::string &method, const std::string &host, const std::string &port, const std::string &path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ); + RemoteCameraHttp( unsigned int p_monitor_id, const std::string &method, const std::string &host, const std::string &port, const std::string &path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ); ~RemoteCameraHttp(); void Initialise(); diff --git a/src/zm_remote_camera_rtsp.cpp b/src/zm_remote_camera_rtsp.cpp index 85f7af340..2e5e4b710 100644 --- a/src/zm_remote_camera_rtsp.cpp +++ b/src/zm_remote_camera_rtsp.cpp @@ -28,8 +28,8 @@ #include #include -RemoteCameraRtsp::RemoteCameraRtsp( int p_id, const std::string &p_method, const std::string &p_host, const std::string &p_port, const std::string &p_path, int p_width, int p_height, bool p_rtsp_describe, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : - RemoteCamera( p_id, "rtsp", p_host, p_port, p_path, p_width, p_height, p_colours, p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ), +RemoteCameraRtsp::RemoteCameraRtsp( unsigned int p_monitor_id, const std::string &p_method, const std::string &p_host, const std::string &p_port, const std::string &p_path, int p_width, int p_height, bool p_rtsp_describe, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : + RemoteCamera( p_monitor_id, "rtsp", p_host, p_port, p_path, p_width, p_height, p_colours, p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ), rtsp_describe( p_rtsp_describe ), rtspThread( 0 ) @@ -43,7 +43,7 @@ RemoteCameraRtsp::RemoteCameraRtsp( int p_id, const std::string &p_method, const else if ( p_method == "rtpRtspHttp" ) method = RtspThread::RTP_RTSP_HTTP; else - Fatal( "Unrecognised method '%s' when creating RTSP camera %d", p_method.c_str(), id ); + Fatal( "Unrecognised method '%s' when creating RTSP camera %d", p_method.c_str(), monitor_id ); if ( capture ) { @@ -137,7 +137,7 @@ void RemoteCameraRtsp::Terminate() int RemoteCameraRtsp::Connect() { - rtspThread = new RtspThread( id, method, protocol, host, port, path, auth, rtsp_describe ); + rtspThread = new RtspThread( monitor_id, method, protocol, host, port, path, auth, rtsp_describe ); rtspThread->start(); @@ -467,7 +467,11 @@ 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); @@ -487,7 +491,11 @@ 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 ); } @@ -537,7 +545,7 @@ int RemoteCameraRtsp::CaptureAndRecord( Image &image, bool recording, char* even } // end if video or audio packet #if LIBAVCODEC_VERSION_CHECK(57, 8, 0, 12, 100) - av_packet_unref( &packet); + av_packet_unref( &packet ); #else av_free_packet( &packet ); #endif diff --git a/src/zm_remote_camera_rtsp.h b/src/zm_remote_camera_rtsp.h index 1a1da6999..3af753fea 100644 --- a/src/zm_remote_camera_rtsp.h +++ b/src/zm_remote_camera_rtsp.h @@ -73,7 +73,7 @@ protected: #endif public: - RemoteCameraRtsp( int p_id, const std::string &method, const std::string &host, const std::string &port, const std::string &path, int p_width, int p_height, bool p_rtsp_describe, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ); + RemoteCameraRtsp( unsigned int p_monitor_id, const std::string &method, const std::string &host, const std::string &port, const std::string &path, int p_width, int p_height, bool p_rtsp_describe, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ); ~RemoteCameraRtsp(); void Initialise(); diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 47c1be13d..45cd1d280 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -35,7 +35,8 @@ 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 orientation ) { AVDictionary *pmetadata = NULL; @@ -91,18 +92,55 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, "%s\n", av_make_error_string(ret).c_str()); } + if ( video_st->sample_aspect_ratio.den != video_st->codec->sample_aspect_ratio.den ) { + Warning("Fixingample_aspect_ratio.den"); + video_st->sample_aspect_ratio.den = video_st->codec->sample_aspect_ratio.den; + } + if ( video_st->sample_aspect_ratio.num != input_st->codec->sample_aspect_ratio.num ) { + Warning("Fixingample_aspect_ratio.num"); + video_st->sample_aspect_ratio.num = input_st->codec->sample_aspect_ratio.num; + } + if ( video_st->codec->codec_id != input_st->codec->codec_id ) { + Warning("Fixing video_st->codec->codec_id"); + video_st->codec->codec_id = input_st->codec->codec_id; + } + if ( ! video_st->codec->time_base.num ) { + Warning("video_st->codec->time_base.num is not set%d/%d. Fixing by setting it to 1", video_st->codec->time_base.num, video_st->codec->time_base.den); + Warning("video_st->codec->time_base.num is not set%d/%d. Fixing by setting it to 1", video_st->time_base.num, video_st->time_base.den); + video_st->codec->time_base.num = video_st->time_base.num; + video_st->codec->time_base.den = video_st->time_base.den; + } + video_st->codec->codec_tag = 0; if (oc->oformat->flags & AVFMT_GLOBALHEADER) { video_st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; } + if ( orientation ) { + if ( orientation == Monitor::ROTATE_0 ) { + + } else if ( orientation == Monitor::ROTATE_90 ) { + dsr = av_dict_set( &video_st->metadata, "rotate", "90", 0); + if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); + } else if ( orientation == Monitor::ROTATE_180 ) { + dsr = av_dict_set( &video_st->metadata, "rotate", "180", 0); + if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); + } else if ( orientation == Monitor::ROTATE_270 ) { + dsr = av_dict_set( &video_st->metadata, "rotate", "270", 0); + if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); + } else { + Warning( "Unsupported Orientation(%d)", orientation ); + } + } + + if (inpaud_st) { audio_st = avformat_new_stream(oc, inpaud_st->codec->codec); if (!audio_st) { Error("Unable to create audio out stream\n"); audio_st = NULL; } else { - ret=avcodec_copy_context(audio_st->codec, inpaud_st->codec); + ret = avcodec_copy_context(audio_st->codec, inpaud_st->codec); if (ret < 0) { Fatal("Unable to copy audio context %s\n", av_make_error_string(ret).c_str()); } diff --git a/src/zm_videostore.h b/src/zm_videostore.h index 0d72f42b6..a11973b4a 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: @@ -26,7 +28,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);