@@ -441,6 +441,191 @@ TEST_P(SingleStreamDecoderTest, GetAudioMetadata) {
441441 EXPECT_NEAR (*audioStream.durationSecondsFromHeader , 13.25 , 1e-1 );
442442}
443443
444+ TEST_P (SingleStreamDecoderTest, FloatingPointPrecisionExactTimestampsWork) {
445+ std::string path = getResourcePath (" nasa_13013.mp4" );
446+
447+ std::unique_ptr<SingleStreamDecoder> ourDecoder =
448+ std::make_unique<SingleStreamDecoder>(
449+ path, SingleStreamDecoder::SeekMode::exact);
450+ ourDecoder->scanFileAndUpdateMetadataAndIndex ();
451+ std::vector<Transform*> transforms;
452+ ourDecoder->addVideoStream (-1 , transforms);
453+
454+ ContainerMetadata metadata = ourDecoder->getContainerMetadata ();
455+ const auto & videoStream = metadata.allStreamMetadata [3 ];
456+
457+ EXPECT_TRUE (videoStream.beginStreamPtsSecondsFromContent .has_value ());
458+ double minSeconds = videoStream.beginStreamPtsSecondsFromContent .value ();
459+
460+ EXPECT_NO_THROW ({
461+ auto timestamps = torch::tensor ({minSeconds}, torch::dtype (torch::kDouble ));
462+ auto output = ourDecoder->getFramesPlayedAt (timestamps);
463+ EXPECT_EQ (output.data .size (0 ), 1 );
464+ });
465+ }
466+
467+ TEST_P (SingleStreamDecoderTest, FloatingPointPrecisionSmallEpsilonErrorsWork) {
468+ std::string path = getResourcePath (" nasa_13013.mp4" );
469+
470+ std::unique_ptr<SingleStreamDecoder> ourDecoder =
471+ std::make_unique<SingleStreamDecoder>(
472+ path, SingleStreamDecoder::SeekMode::exact);
473+ ourDecoder->scanFileAndUpdateMetadataAndIndex ();
474+ std::vector<Transform*> transforms;
475+ ourDecoder->addVideoStream (-1 , transforms);
476+
477+ ContainerMetadata metadata = ourDecoder->getContainerMetadata ();
478+ const auto & videoStream = metadata.allStreamMetadata [3 ];
479+
480+ EXPECT_TRUE (videoStream.beginStreamPtsSecondsFromContent .has_value ());
481+ double minSeconds = videoStream.beginStreamPtsSecondsFromContent .value ();
482+
483+ // Simulate small floating-point precision errors from video processing
484+ constexpr double eps = std::numeric_limits<double >::epsilon ();
485+ double almostMinSeconds = minSeconds - eps * 100 ;
486+
487+ EXPECT_NO_THROW ({
488+ auto timestamps =
489+ torch::tensor ({almostMinSeconds}, torch::dtype (torch::kDouble ));
490+ auto output = ourDecoder->getFramesPlayedAt (timestamps);
491+ EXPECT_EQ (output.data .size (0 ), 1 );
492+ });
493+ }
494+
495+ TEST_P (SingleStreamDecoderTest, FloatingPointPrecisionLargerEpsilonErrorsWork) {
496+ std::string path = getResourcePath (" nasa_13013.mp4" );
497+
498+ std::unique_ptr<SingleStreamDecoder> ourDecoder =
499+ std::make_unique<SingleStreamDecoder>(
500+ path, SingleStreamDecoder::SeekMode::exact);
501+ ourDecoder->scanFileAndUpdateMetadataAndIndex ();
502+ std::vector<Transform*> transforms;
503+ ourDecoder->addVideoStream (-1 , transforms);
504+
505+ ContainerMetadata metadata = ourDecoder->getContainerMetadata ();
506+ const auto & videoStream = metadata.allStreamMetadata [3 ];
507+
508+ EXPECT_TRUE (videoStream.beginStreamPtsSecondsFromContent .has_value ());
509+ double minSeconds = videoStream.beginStreamPtsSecondsFromContent .value ();
510+
511+ constexpr double eps = std::numeric_limits<double >::epsilon ();
512+ double precisionErrorSeconds = minSeconds - eps * 500 ;
513+
514+ EXPECT_NO_THROW ({
515+ auto timestamps =
516+ torch::tensor ({precisionErrorSeconds}, torch::dtype (torch::kDouble ));
517+ auto output = ourDecoder->getFramesPlayedAt (timestamps);
518+ EXPECT_EQ (output.data .size (0 ), 1 );
519+ });
520+ }
521+
522+ TEST_P (
523+ SingleStreamDecoderTest,
524+ FloatingPointPrecisionInvalidTimestampsStillFail) {
525+ std::string path = getResourcePath (" nasa_13013.mp4" );
526+
527+ std::unique_ptr<SingleStreamDecoder> ourDecoder =
528+ std::make_unique<SingleStreamDecoder>(
529+ path, SingleStreamDecoder::SeekMode::exact);
530+ ourDecoder->scanFileAndUpdateMetadataAndIndex ();
531+ std::vector<Transform*> transforms;
532+ ourDecoder->addVideoStream (-1 , transforms);
533+
534+ ContainerMetadata metadata = ourDecoder->getContainerMetadata ();
535+ const auto & videoStream = metadata.allStreamMetadata [3 ];
536+
537+ EXPECT_TRUE (videoStream.beginStreamPtsSecondsFromContent .has_value ());
538+ double minSeconds = videoStream.beginStreamPtsSecondsFromContent .value ();
539+
540+ // Ensure genuinely invalid timestamps still fail appropriately
541+ double definitelyInvalidTimestamp = minSeconds - 0.1 ;
542+
543+ EXPECT_THROW (
544+ {
545+ auto timestamps = torch::tensor (
546+ {definitelyInvalidTimestamp}, torch::dtype (torch::kDouble ));
547+ ourDecoder->getFramesPlayedAt (timestamps);
548+ },
549+ c10::Error);
550+ }
551+
552+ TEST_P (
553+ SingleStreamDecoderTest,
554+ FloatingPointPrecisionBatchTimestampsWithEpsilonErrorsWork) {
555+ std::string path = getResourcePath (" nasa_13013.mp4" );
556+
557+ std::unique_ptr<SingleStreamDecoder> ourDecoder =
558+ std::make_unique<SingleStreamDecoder>(
559+ path, SingleStreamDecoder::SeekMode::exact);
560+ ourDecoder->scanFileAndUpdateMetadataAndIndex ();
561+ std::vector<Transform*> transforms;
562+ ourDecoder->addVideoStream (-1 , transforms);
563+
564+ ContainerMetadata metadata = ourDecoder->getContainerMetadata ();
565+ const auto & videoStream = metadata.allStreamMetadata [3 ];
566+
567+ EXPECT_TRUE (videoStream.beginStreamPtsSecondsFromContent .has_value ());
568+ double minSeconds = videoStream.beginStreamPtsSecondsFromContent .value ();
569+
570+ constexpr double eps = std::numeric_limits<double >::epsilon ();
571+ auto mixedTimestamps = torch::tensor (
572+ {minSeconds, minSeconds - eps * 10 , minSeconds + eps * 50 },
573+ torch::dtype (torch::kDouble ));
574+
575+ EXPECT_NO_THROW ({
576+ auto output = ourDecoder->getFramesPlayedAt (mixedTimestamps);
577+ EXPECT_EQ (output.data .size (0 ), 3 );
578+ });
579+ }
580+
581+ TEST_P (SingleStreamDecoderTest, HandleFloatingPointPrecisionInRangeValidation) {
582+ std::string path = getResourcePath (" nasa_13013.mp4" );
583+
584+ // Set exact seek mode to enable precise timestamp validation
585+ std::unique_ptr<SingleStreamDecoder> ourDecoder =
586+ std::make_unique<SingleStreamDecoder>(
587+ path, SingleStreamDecoder::SeekMode::exact);
588+ ourDecoder->scanFileAndUpdateMetadataAndIndex ();
589+ std::vector<Transform*> transforms;
590+ ourDecoder->addVideoStream (-1 , transforms);
591+
592+ // Get the metadata to understand the valid timestamp range
593+ ContainerMetadata metadata = ourDecoder->getContainerMetadata ();
594+ const auto & videoStream = metadata.allStreamMetadata [3 ]; // Video stream index
595+
596+ EXPECT_TRUE (videoStream.beginStreamPtsSecondsFromContent .has_value ());
597+ double minSeconds = videoStream.beginStreamPtsSecondsFromContent .value ();
598+
599+ // Test case 1: Range starting exactly at minSeconds - should work
600+ EXPECT_NO_THROW ({
601+ auto output =
602+ ourDecoder->getFramesPlayedInRange (minSeconds, minSeconds + 1.0 );
603+ EXPECT_GT (output.data .size (0 ), 0 );
604+ });
605+
606+ // Test case 2: Range with floating-point precision error at start
607+ constexpr double eps = std::numeric_limits<double >::epsilon ();
608+ double startWithPrecisionError = minSeconds - eps * 100 ;
609+
610+ // This should NOT throw an error with our fix
611+ EXPECT_NO_THROW ({
612+ auto output = ourDecoder->getFramesPlayedInRange (
613+ startWithPrecisionError, minSeconds + 1.0 );
614+ EXPECT_GT (output.data .size (0 ), 0 );
615+ });
616+
617+ // Test case 3: Test that genuinely invalid range still fails appropriately
618+ double definitelyInvalidStart = minSeconds - 0.1 ;
619+
620+ // This should still throw an error (not a precision issue)
621+ EXPECT_THROW (
622+ {
623+ ourDecoder->getFramesPlayedInRange (
624+ definitelyInvalidStart, minSeconds + 1.0 );
625+ },
626+ c10::Error);
627+ }
628+
444629INSTANTIATE_TEST_SUITE_P (
445630 FromFileAndMemory,
446631 SingleStreamDecoderTest,
0 commit comments