diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 4a4c841fb..40b25d19a 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -168,35 +168,19 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string snprintf( video_name, sizeof(video_name), "%d-%s", id, "video.mp4" ); snprintf( video_file, sizeof(video_file), staticConfig.video_file_format, path, video_name ); Debug(1,"Writing video file to %s", video_file ); -#if 0 - /* X264 MP4 video writer */ - if ( monitor->GetOptVideoWriter() == Monitor::X264ENCODE ) { -#if ZM_HAVE_VIDEOWRITER_X264MP4 - videowriter = new X264MP4Writer(video_file, monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder(), monitor->GetOptEncoderParams()); -#else - Error("ZoneMinder was not compiled with the X264 MP4 video writer, check dependencies (x264 and mp4v2)"); -#endif - } + Camera * camera = monitor->getCamera(); + videoStore = new VideoStore( + video_file, + "mp4", + camera->get_VideoStream(), + ( monitor->RecordAudio() ? camera->get_AudioStream() : NULL ), + monitor ); - if ( videowriter != NULL ) { - /* Open the video stream */ - int nRet = videowriter->Open(); - if(nRet != 0) { - Error("Failed opening video stream"); - delete videowriter; - videowriter = NULL; - } + if ( ! videoStore->open() ) { + delete videoStore; + videoStore = NULL; + } - snprintf( timecodes_name, sizeof(timecodes_name), "%d-%s", id, "video.timecodes" ); - snprintf( timecodes_file, sizeof(timecodes_file), staticConfig.video_file_format, path, timecodes_name ); - - /* Create timecodes file */ - timecodes_fd = fopen(timecodes_file, "wb"); - if ( timecodes_fd == NULL ) { - Error("Failed creating timecodes file"); - } - } -#endif } else { /* No video object */ videowriter = NULL; @@ -210,7 +194,6 @@ Event::~Event() { DELTA_TIMEVAL( delta_time, end_time, start_time, DT_PREC_2 ); if ( frames > last_db_frame ) { - Debug( 1, "Adding closing frame %d to DB", frames ); snprintf( sql, sizeof(sql), "insert into Frames ( EventId, FrameId, TimeStamp, Delta ) values ( %d, %d, from_unixtime( %ld ), %s%ld.%02ld )", id, frames, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec ); if ( mysql_query( &dbconn, sql ) ) { @@ -220,17 +203,9 @@ Event::~Event() { } /* Close the video file */ - if ( videowriter != NULL ) { - int nRet = videowriter->Close(); - if ( nRet != 0 ) { - Error("Failed closing video stream"); - } - delete videowriter; - videowriter = NULL; - - /* Close the timecodes file */ - fclose(timecodes_fd); - timecodes_fd = NULL; + if ( videoStore ) { + delete videoStore; + videoStore = NULL; } snprintf( sql, sizeof(sql), "update Events set Name='%s%d', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' where Id = %d", monitor->EventPrefix(), id, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, video_name, id ); @@ -273,7 +248,7 @@ Debug(3, "Writing image to %s", event_file ); } return rc; -} +} // end Event::WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame ) bool Event::WriteFrameVideo( const Image *image, const struct timeval timestamp, VideoWriter* videow ) { const Image* frameimg = image; @@ -308,6 +283,11 @@ bool Event::WriteFrameVideo( const Image *image, const struct timeval timestamp, return( true ); } +bool Event::WritePacket( ZMPacket &packet ) { + + videoStore->writePacket( &packet ); +} + void Event::updateNotes( const StringSetMap &newNoteSetMap ) { bool update = false; diff --git a/src/zm_event.h b/src/zm_event.h index 38ae4186c..8a7cfbb3c 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -38,7 +38,9 @@ #include "zm_image.h" #include "zm_stream.h" #include "zm_video.h" +#include "zm_packet.h" +class VideoStore; class Zone; class Monitor; class EventStream; @@ -85,6 +87,7 @@ class Event { unsigned int max_score; char path[PATH_MAX]; VideoWriter* videowriter; + VideoStore *videoStore; FILE* timecodes_fd; char video_name[PATH_MAX]; char video_file[PATH_MAX]; @@ -119,6 +122,7 @@ class Event { void AddFrames( int n_frames, Image **images, struct timeval **timestamps ); void AddFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL ); + bool WritePacket( ZMPacket &p ); private: void AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps ); diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 22675f040..34affb0fd 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2893,87 +2893,6 @@ int Monitor::Capture() { return -1; } - int video_stream_id = camera->get_VideoStreamId(); - - //Video recording - if ( video_store_data->recording.tv_sec ) { - if ( shared_data->last_event_id != this->GetVideoWriterEventId() ) { - Debug(2, "Have change of event. last_event(%d), our current (%d)", - shared_data->last_event_id, - this->GetVideoWriterEventId() - ); - if ( videoStore ) { - Debug(2, "Have videostore already?"); - // I don't know if this is important or not... but I figure we might as well write this last packet out to the store before closing it. - // Also don't know how much it matters for audio. - int ret = videoStore->writePacket( &packet ); - if ( ret < 0 ) { //Less than zero and we skipped a frame - Warning("Error writing last packet to videostore."); - } - - delete videoStore; - videoStore = NULL; - this->SetVideoWriterEventId( 0 ); - } // end if videoStore - } // end if end of recording - - if ( shared_data->last_event_id and ! videoStore ) { - Debug(2,"New videostore"); - videoStore = new VideoStore( - (const char *) video_store_data->event_file, - "mp4", - camera->get_VideoStream(), - ( record_audio ? camera->get_AudioStream() : NULL ), - video_store_data->recording.tv_sec, - this ); - - if ( ! videoStore->open() ) { - delete videoStore; - videoStore = NULL; - } else { - this->SetVideoWriterEventId(shared_data->last_event_id); - - Debug(2, "Clearing packets"); - // Clear all packets that predate the moment when the recording began - packetqueue.clear_unwanted_packets(&video_store_data->recording, video_stream_id); - videoStore->write_packets(packetqueue); - } // success opening - } // end if ! was recording - } else { // Not recording - if ( videoStore ) { - Info("Deleting videoStore instance"); - delete videoStore; - videoStore = NULL; - this->SetVideoWriterEventId( 0 ); - } - - // Buffer video packets, since we are not recording. - // All audio packets are keyframes, so only if it's a video keyframe - if ( ( packet.packet.stream_index == video_stream_id ) && ( packet.keyframe ) ) { - packetqueue.clearQueue( this->GetPreEventCount(), video_stream_id ); - } - // The following lines should ensure that the queue always begins with a video keyframe - if ( packet.packet.stream_index == camera->get_AudioStreamId() ) { - //Debug(2, "Have audio packet, reocrd_audio is (%d) and packetqueue.size is (%d)", record_audio, packetqueue.size() ); - if ( record_audio && packetqueue.size() ) { - // if it's audio, and we are doing audio, and there is already something in the queue - packetqueue.queuePacket( &packet ); - } - } else if ( packet.packet.stream_index == video_stream_id ) { - if ( packet.keyframe || packetqueue.size() ) // it's a keyframe or we already have something in the queue - packetqueue.queuePacket( &packet ); - } // end if audio or video - } // end if recording or not - - if ( videoStore ) { - //Write the packet to our video store, it will be smart enough to know what to do - int ret = videoStore->writePacket( &packet ); - if ( ret < 0 ) { //Less than zero and we skipped a frame - Warning("problem writing packet"); - } - } - } // end if deinterlacing - /* Deinterlacing */ if ( deinterlacing_value ) { if ( deinterlacing_value == 1 ) { @@ -3006,11 +2925,6 @@ int Monitor::Capture() { } } - if ( capture_image->Size() > camera->ImageSize() ) { - Error( "Captured image %d does not match expected size %d check width, height and colour depth",capture_image->Size(),camera->ImageSize() ); - return( -1 ); - } - 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 ); time_t now = time(0); @@ -3025,10 +2939,40 @@ int Monitor::Capture() { if ( privacy_bitmask ) capture_image->MaskPrivacy( privacy_bitmask ); - gettimeofday( image_buffer[index].timestamp, NULL ); + //gettimeofday( image_buffer[index].timestamp, NULL ); if ( config.timestamp_on_capture ) { - TimestampImage( capture_image, image_buffer[index].timestamp ); + TimestampImage( capture_image, &packet.timestamp ); } + + int video_stream_id = camera->get_VideoStreamId(); + + //packetqueue.clear_unwanted_packets(&video_store_data->recording, video_stream_id); + //videoStore->write_packets(packetqueue); + if ( ! event ) { + // Buffer video packets, since we are not recording. + // All audio packets are keyframes, so only if it's a video keyframe + if ( ( packet.packet.stream_index == video_stream_id ) && ( packet.keyframe ) ) { + packetqueue.clearQueue( this->GetPreEventCount(), video_stream_id ); + } + // The following lines should ensure that the queue always begins with a video keyframe + if ( packet.packet.stream_index == camera->get_AudioStreamId() ) { + //Debug(2, "Have audio packet, reocrd_audio is (%d) and packetqueue.size is (%d)", record_audio, packetqueue.size() ); + if ( record_audio && packetqueue.size() ) { + // if it's audio, and we are doing audio, and there is already something in the queue + packetqueue.queuePacket( &packet ); + } + } else if ( packet.packet.stream_index == video_stream_id ) { + if ( packet.keyframe || packetqueue.size() ) // it's a keyframe or we already have something in the queue + packetqueue.queuePacket( &packet ); + } // end if audio or video + } else { + //Write the packet to our video store, it will be smart enough to know what to do + if ( ! event->WritePacket( packet ) ) { + Warning("problem writing packet"); + } + } // end if recording or not + } // end if deinterlacing + shared_data->signal = CheckSignal(capture_image); shared_data->last_write_index = index; shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 23d665f50..8ee2e3723 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -404,6 +404,9 @@ public: inline Function GetFunction() const { return( function ); } + inline Camera *getCamera() { + return camera; + } inline bool Enabled() { if ( function <= MONITOR ) return( false ); @@ -425,6 +428,9 @@ public: inline bool Exif() { return( embed_exif ); } + inline bool RecordAudio() { + return record_audio; + } Orientation getOrientation() const; unsigned int Width() const { return width; } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 1c5fab370..3ed87fc3d 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -36,7 +36,6 @@ VideoStore::VideoStore( const char *format_in, AVStream *p_video_in_stream, AVStream *p_audio_in_stream, - int64_t nStartTime, Monitor *monitor ) { video_in_stream = p_video_in_stream; diff --git a/src/zm_videostore.h b/src/zm_videostore.h index c3536fb3e..ec9b44bdd 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -88,7 +88,6 @@ public: const char *format_in, AVStream *video_in_stream, AVStream *audio_in_stream, - int64_t starttime, Monitor * p_monitor ); ~VideoStore();