@@ -58,7 +58,7 @@ def __init__(self, settings):
5858 self ._fast_start : bool = bool (self .ns .get ("fast_start" , False ))
5959 self ._retrieve_timeout_ms : int = 100 # default; may be overridden by trigger settings
6060 self ._timestamp_tick_frequency_hz : float | None = None
61- self ._last_frame_timestamp_metadata : FrameTimestampMetadata | None = None
61+ self ._timestamp_tick_frequency_source : str | None = None
6262
6363 # ---- Trigger settings ----
6464 raw_trigger = self .ns .get ("trigger" , self ._props .get ("trigger" ))
@@ -158,10 +158,6 @@ def actual_output_format(self) -> str | None:
158158 return None
159159 return "Mono8" if self ._should_output_mono () else "BGR8"
160160
161- @property
162- def last_frame_timestamp_metadata (self ) -> FrameTimestampMetadata | None :
163- return self ._last_frame_timestamp_metadata
164-
165161 @property
166162 def recommended_preserve_mono (self ) -> bool | None :
167163 if not self ._camera_pixel_format :
@@ -185,7 +181,7 @@ def static_capabilities(cls) -> dict[str, SupportLevel]:
185181 "stable_identity" : SupportLevel .SUPPORTED ,
186182 "hardware_trigger" : SupportLevel .BEST_EFFORT ,
187183 "preserve_mono" : SupportLevel .SUPPORTED ,
188- "hardware_frame_timestamps" : SupportLevel .SUPPORTED ,
184+ "hardware_frame_timestamps" : SupportLevel .BEST_EFFORT ,
189185 }
190186 )
191187 return caps
@@ -678,10 +674,22 @@ def open(self) -> None:
678674 node = getattr (self ._camera , "GevTimestampTickFrequency" , None )
679675 if node is not None and node .IsReadable ():
680676 self ._timestamp_tick_frequency_hz = float (node .GetValue ())
681- LOG .info ("[Basler] timestamp tick frequency: %.3f Hz" , self ._timestamp_tick_frequency_hz )
677+ self ._timestamp_tick_frequency_source = "GevTimestampTickFrequency"
678+ LOG .info (
679+ "[Basler] timestamp tick frequency: %.3f Hz from GevTimestampTickFrequency" ,
680+ self ._timestamp_tick_frequency_hz ,
681+ )
682682 except Exception :
683683 LOG .debug ("[Basler] Could not read GevTimestampTickFrequency" , exc_info = True )
684684
685+ if not self ._timestamp_tick_frequency_hz or self ._timestamp_tick_frequency_hz <= 0 :
686+ self ._timestamp_tick_frequency_hz = 1_000_000_000.0
687+ self ._timestamp_tick_frequency_source = "assumed_default_1ghz"
688+ LOG .info (
689+ "[Basler] timestamp tick frequency unavailable; assuming %.3f Hz" ,
690+ self ._timestamp_tick_frequency_hz ,
691+ )
692+
685693 # Persist stable identity into namespace
686694 try :
687695 serial = device .GetSerialNumber ()
@@ -701,6 +709,10 @@ def _make_timestamp_metadata(self, grab_result) -> FrameTimestampMetadata | None
701709 except Exception :
702710 return None
703711
712+ if ticks == 0 :
713+ # Basler returns 0 if the timestamp is not available (e.g. for some GigE cameras)
714+ return None
715+
704716 freq = getattr (self , "_timestamp_tick_frequency_hz" , None )
705717 seconds = ticks / freq if freq and freq > 0 else None
706718
@@ -715,6 +727,9 @@ def _make_timestamp_metadata(self, grab_result) -> FrameTimestampMetadata | None
715727 tick_frequency_hz = freq ,
716728 timebase = "Basler camera timestamp counter" ,
717729 kind = "camera_clock" ,
730+ extra = {
731+ "tick_frequency_source" : self ._timestamp_tick_frequency_source ,
732+ },
718733 )
719734
720735 def read (self ) -> CapturedFrame :
@@ -749,7 +764,6 @@ def read(self) -> CapturedFrame:
749764 with self ._timing .measure ("Basler.timestamp" ):
750765 software_timestamp = time .time ()
751766 timestamp_metadata = self ._make_timestamp_metadata (grab_result )
752- self ._last_frame_timestamp_metadata = timestamp_metadata
753767
754768 if not self ._logged_first_frame :
755769 self ._logged_first_frame = True
0 commit comments