@@ -845,27 +845,29 @@ bool EventStream::sendFrame(Microseconds delta_us) {
845845 curr_frame_id = std::clamp (curr_frame_id, 1 , (int )event_data->frames .size ());
846846 }
847847
848- std::string filepath;
848+ // Reusable string member avoids per-frame heap allocations.
849+ // After the first frame, the string's buffer is reused (unless path exceeds capacity).
850+ reuse_filepath_.clear ();
849851 struct stat filestat = {};
850852
851853 // This needs to be abstracted. If we are saving jpgs, then load the capture file.
852854 // If we are only saving analysis frames, then send that.
853855 if ((frame_type == FRAME_ANALYSIS) && (event_data->SaveJPEGs & 2 )) {
854- filepath = stringtf (staticConfig.analyse_file_format .c_str (), event_data->path .c_str (), curr_frame_id);
855- if (stat (filepath .c_str (), &filestat) < 0 ) {
856- Debug (1 , " analyze file %s not found will try to stream from other" , filepath .c_str ());
857- filepath = stringtf (staticConfig.capture_file_format .c_str (), event_data->path .c_str (), curr_frame_id);
858- if (stat (filepath .c_str (), &filestat) < 0 ) {
859- Debug (1 , " capture file %s not found either" , filepath .c_str ());
860- filepath = " " ;
856+ reuse_filepath_ = stringtf (staticConfig.analyse_file_format .c_str (), event_data->path .c_str (), curr_frame_id);
857+ if (stat (reuse_filepath_ .c_str (), &filestat) < 0 ) {
858+ Debug (1 , " analyze file %s not found will try to stream from other" , reuse_filepath_ .c_str ());
859+ reuse_filepath_ = stringtf (staticConfig.capture_file_format .c_str (), event_data->path .c_str (), curr_frame_id);
860+ if (stat (reuse_filepath_ .c_str (), &filestat) < 0 ) {
861+ Debug (1 , " capture file %s not found either" , reuse_filepath_ .c_str ());
862+ reuse_filepath_. clear () ;
861863 }
862864 }
863865 } else if (event_data->SaveJPEGs & 1 ) {
864- filepath = stringtf (staticConfig.capture_file_format .c_str (), event_data->path .c_str (), curr_frame_id);
865- if (stat (filepath .c_str (), &filestat) < 0 ) {
866+ reuse_filepath_ = stringtf (staticConfig.capture_file_format .c_str (), event_data->path .c_str (), curr_frame_id);
867+ if (stat (reuse_filepath .c_str (), &filestat) < 0 ) {
866868 Debug (1 , " Capture file %s not found (bulk/interpolated frame %d), trying ffmpeg_input" ,
867- filepath .c_str (), curr_frame_id);
868- filepath = " " ;
869+ reuse_filepath .c_str (), curr_frame_id);
870+ reuse_filepathi. clear () ;
869871 // Fall through — ffmpeg_input will be tried below if available
870872 }
871873 } else if (!ffmpeg_input) {
@@ -874,7 +876,7 @@ bool EventStream::sendFrame(Microseconds delta_us) {
874876 }
875877
876878 if ( type == STREAM_MPEG ) {
877- Image image (filepath .c_str ());
879+ Image image (reuse_filepath_ .c_str ());
878880
879881 Image *send_image = prepareImage (&image);
880882
@@ -889,19 +891,19 @@ bool EventStream::sendFrame(Microseconds delta_us) {
889891 config.mpeg_timed_frames ,
890892 delta_us.count () * 1000 );
891893 } else {
892- bool send_raw = (type == STREAM_JPEG) && ((scale >= ZM_SCALE_BASE) && (zoom == ZM_SCALE_BASE)) && !filepath .empty ();
894+ bool send_raw = (type == STREAM_JPEG) && ((scale >= ZM_SCALE_BASE) && (zoom == ZM_SCALE_BASE)) && !reuse_filepath_ .empty ();
893895
894896 if (send_raw) {
895897 fprintf (stdout, " --" BOUNDARY " \r\n " );
896- if (!send_file (filepath )) {
897- Error (" Can't send %s: %s" , filepath .c_str (), strerror (errno));
898+ if (!send_file (reuse_filepath_ )) {
899+ Error (" Can't send %s: %s" , reuse_filepath_ .c_str (), strerror (errno));
898900 return false ;
899901 }
900902 } else {
901903 Image *image = nullptr ;
902904
903- if (!filepath .empty ()) {
904- image = new Image (filepath .c_str ());
905+ if (!reuse_filepath_ .empty ()) {
906+ image = new Image (reuse_filepath_ .c_str ());
905907 } else if (ffmpeg_input) {
906908 // Get the frame from the mp4 input
907909 const FrameData *frame_data = &event_data->frames [curr_frame_id-1 ];
0 commit comments