@@ -57,7 +57,7 @@ def __init__(self, settings):
5757 self ._fast_start : bool = bool (self .ns .get ("fast_start" , False ))
5858 self ._retrieve_timeout_ms : int = 100 # default; may be overridden by trigger settings
5959 self ._timestamp_tick_frequency_hz : float | None = None
60- self ._last_frame_timestamp_metadata : FrameTimestampMetadata | None = None
60+ self ._timestamp_tick_frequency_source : str | None = None
6161
6262 # ---- Trigger settings ----
6363 raw_trigger = self .ns .get ("trigger" , self ._props .get ("trigger" ))
@@ -157,10 +157,6 @@ def actual_output_format(self) -> str | None:
157157 return None
158158 return "Mono8" if self ._should_output_mono () else "BGR8"
159159
160- @property
161- def last_frame_timestamp_metadata (self ) -> FrameTimestampMetadata | None :
162- return self ._last_frame_timestamp_metadata
163-
164160 @property
165161 def recommended_preserve_mono (self ) -> bool | None :
166162 if not self ._camera_pixel_format :
@@ -184,7 +180,7 @@ def static_capabilities(cls) -> dict[str, SupportLevel]:
184180 "stable_identity" : SupportLevel .SUPPORTED ,
185181 "hardware_trigger" : SupportLevel .BEST_EFFORT ,
186182 "preserve_mono" : SupportLevel .SUPPORTED ,
187- "hardware_frame_timestamps" : SupportLevel .SUPPORTED ,
183+ "hardware_frame_timestamps" : SupportLevel .BEST_EFFORT ,
188184 }
189185 )
190186 return caps
@@ -667,10 +663,22 @@ def open(self) -> None:
667663 node = getattr (self ._camera , "GevTimestampTickFrequency" , None )
668664 if node is not None and node .IsReadable ():
669665 self ._timestamp_tick_frequency_hz = float (node .GetValue ())
670- LOG .info ("[Basler] timestamp tick frequency: %.3f Hz" , self ._timestamp_tick_frequency_hz )
666+ self ._timestamp_tick_frequency_source = "GevTimestampTickFrequency"
667+ LOG .info (
668+ "[Basler] timestamp tick frequency: %.3f Hz from GevTimestampTickFrequency" ,
669+ self ._timestamp_tick_frequency_hz ,
670+ )
671671 except Exception :
672672 LOG .debug ("[Basler] Could not read GevTimestampTickFrequency" , exc_info = True )
673673
674+ if not self ._timestamp_tick_frequency_hz or self ._timestamp_tick_frequency_hz <= 0 :
675+ self ._timestamp_tick_frequency_hz = 1_000_000_000.0
676+ self ._timestamp_tick_frequency_source = "assumed_default_1ghz"
677+ LOG .info (
678+ "[Basler] timestamp tick frequency unavailable; assuming %.3f Hz" ,
679+ self ._timestamp_tick_frequency_hz ,
680+ )
681+
674682 # Persist stable identity into namespace
675683 try :
676684 serial = device .GetSerialNumber ()
@@ -690,6 +698,10 @@ def _make_timestamp_metadata(self, grab_result) -> FrameTimestampMetadata | None
690698 except Exception :
691699 return None
692700
701+ if ticks == 0 :
702+ # Basler returns 0 if the timestamp is not available (e.g. for some GigE cameras)
703+ return None
704+
693705 freq = getattr (self , "_timestamp_tick_frequency_hz" , None )
694706 seconds = ticks / freq if freq and freq > 0 else None
695707
@@ -704,6 +716,9 @@ def _make_timestamp_metadata(self, grab_result) -> FrameTimestampMetadata | None
704716 tick_frequency_hz = freq ,
705717 timebase = "Basler camera timestamp counter" ,
706718 kind = "camera_clock" ,
719+ extra = {
720+ "tick_frequency_source" : self ._timestamp_tick_frequency_source ,
721+ },
707722 )
708723
709724 def read (self ) -> CapturedFrame :
@@ -738,7 +753,6 @@ def read(self) -> CapturedFrame:
738753 with self ._timing .measure ("Basler.timestamp" ):
739754 software_timestamp = time .time ()
740755 timestamp_metadata = self ._make_timestamp_metadata (grab_result )
741- self ._last_frame_timestamp_metadata = timestamp_metadata
742756
743757 if not self ._logged_first_frame :
744758 self ._logged_first_frame = True
0 commit comments