diff --git a/test/generate_reference_resources.sh b/test/generate_reference_resources.sh
index fba098a7..7428edf8 100755
--- a/test/generate_reference_resources.sh
+++ b/test/generate_reference_resources.sh
@@ -77,3 +77,22 @@ do
   python3 "$TORCHCODEC_PATH/test/convert_image_to_tensor.py" "$bmp"
   rm -f "$bmp"
 done
+
+# This video was generated by running the following:
+# ffmpeg -f lavfi -i testsrc=duration=10:size=128x128:rate=30        -vf "setpts=PTS*if(gt(N\,30)\,1.5\,1)" -c:v libx264 -bf 0 var_fps_video.mp4
+VIDEO_PATH=$RESOURCES_DIR/var_fps_video.mp4
+STREAMS=(0)
+
+FRAMES=(0 1 2 3 4 5 10 15 20 25 30 35 40 45 50 55 60)
+for stream in "${STREAMS[@]}"; do
+  for frame in "${FRAMES[@]}"; do
+    frame_name=$(printf "%06d" "$frame")
+    ffmpeg -y -i "$VIDEO_PATH" -map 0:"$stream" -vf select="eq(n\,$frame)" -vsync vfr -q:v 2 "$VIDEO_PATH.stream$stream.frame$frame_name.bmp"
+  done
+done
+
+for bmp in "$RESOURCES_DIR"/*.bmp
+do
+  python3 "$TORCHCODEC_PATH/test/convert_image_to_tensor.py" "$bmp"
+  rm -f "$bmp"
+done
\ No newline at end of file
diff --git a/test/resources/var_fps_video.mp4 b/test/resources/var_fps_video.mp4
new file mode 100644
index 00000000..529b0407
Binary files /dev/null and b/test/resources/var_fps_video.mp4 differ
diff --git a/test/resources/var_fps_video.mp4.stream0.all_frames_info.json b/test/resources/var_fps_video.mp4.stream0.all_frames_info.json
new file mode 100644
index 00000000..502477a9
--- /dev/null
+++ b/test/resources/var_fps_video.mp4.stream0.all_frames_info.json
@@ -0,0 +1,1202 @@
+[
+  {
+    "pts_time": "0.000000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.033333",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.066667",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.100000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.133333",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.166667",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.200000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.233333",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.266667",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.300000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.333333",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.366667",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.400000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.433333",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.466667",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.500000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.533333",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.566667",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.600000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.633333",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.666667",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.700000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.733333",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.766667",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.800000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.833333",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.866667",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.900000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.933333",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "0.966667",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "1.000000",
+    "duration_time": "0.533333"
+  },
+  {
+    "pts_time": "1.533333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "1.600000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "1.633333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "1.700000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "1.733333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "1.800000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "1.833333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "1.900000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "1.933333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "2.000000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "2.033333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "2.100000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "2.133333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "2.200000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "2.233333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "2.300000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "2.333333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "2.400000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "2.433333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "2.500000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "2.533333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "2.600000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "2.633333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "2.700000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "2.733333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "2.800000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "2.833333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "2.900000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "2.933333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "3.000000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "3.033333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "3.100000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "3.133333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "3.200000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "3.233333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "3.300000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "3.333333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "3.400000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "3.433333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "3.500000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "3.533333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "3.600000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "3.633333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "3.700000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "3.733333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "3.800000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "3.833333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "3.900000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "3.933333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "4.000000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "4.033333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "4.100000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "4.133333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "4.200000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "4.233333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "4.300000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "4.333333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "4.400000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "4.433333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "4.500000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "4.533333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "4.600000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "4.633333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "4.700000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "4.733333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "4.800000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "4.833333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "4.900000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "4.933333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "5.000000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "5.033333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "5.100000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "5.133333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "5.200000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "5.233333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "5.300000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "5.333333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "5.400000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "5.433333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "5.500000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "5.533333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "5.600000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "5.633333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "5.700000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "5.733333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "5.800000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "5.833333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "5.900000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "5.933333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "6.000000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "6.033333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "6.100000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "6.133333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "6.200000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "6.233333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "6.300000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "6.333333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "6.400000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "6.433333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "6.500000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "6.533333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "6.600000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "6.633333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "6.700000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "6.733333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "6.800000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "6.833333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "6.900000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "6.933333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "7.000000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "7.033333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "7.100000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "7.133333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "7.200000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "7.233333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "7.300000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "7.333333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "7.400000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "7.433333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "7.500000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "7.533333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "7.600000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "7.633333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "7.700000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "7.733333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "7.800000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "7.833333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "7.900000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "7.933333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "8.000000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "8.033333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "8.100000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "8.133333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "8.200000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "8.233333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "8.300000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "8.333333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "8.400000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "8.433333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "8.500000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "8.533333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "8.600000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "8.633333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "8.700000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "8.733333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "8.800000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "8.833333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "8.900000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "8.933333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "9.000000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "9.033333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "9.100000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "9.133333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "9.200000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "9.233333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "9.300000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "9.333333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "9.400000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "9.433333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "9.500000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "9.533333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "9.600000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "9.633333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "9.700000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "9.733333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "9.800000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "9.833333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "9.900000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "9.933333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "10.000000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "10.033333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "10.100000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "10.133333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "10.200000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "10.233333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "10.300000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "10.333333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "10.400000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "10.433333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "10.500000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "10.533333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "10.600000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "10.633333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "10.700000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "10.733333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "10.800000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "10.833333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "10.900000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "10.933333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "11.000000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "11.033333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "11.100000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "11.133333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "11.200000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "11.233333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "11.300000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "11.333333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "11.400000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "11.433333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "11.500000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "11.533333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "11.600000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "11.633333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "11.700000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "11.733333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "11.800000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "11.833333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "11.900000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "11.933333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "12.000000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "12.033333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "12.100000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "12.133333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "12.200000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "12.233333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "12.300000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "12.333333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "12.400000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "12.433333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "12.500000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "12.533333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "12.600000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "12.633333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "12.700000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "12.733333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "12.800000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "12.833333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "12.900000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "12.933333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "13.000000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "13.033333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "13.100000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "13.133333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "13.200000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "13.233333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "13.300000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "13.333333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "13.400000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "13.433333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "13.500000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "13.533333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "13.600000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "13.633333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "13.700000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "13.733333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "13.800000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "13.833333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "13.900000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "13.933333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "14.000000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "14.033333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "14.100000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "14.133333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "14.200000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "14.233333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "14.300000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "14.333333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "14.400000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "14.433333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "14.500000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "14.533333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "14.600000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "14.633333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "14.700000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "14.733333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "14.800000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "14.833333",
+    "duration_time": "0.066667"
+  },
+  {
+    "pts_time": "14.900000",
+    "duration_time": "0.033333"
+  },
+  {
+    "pts_time": "14.933333",
+    "duration_time": "0.033333"
+  }
+]
diff --git a/test/resources/var_fps_video.mp4.stream0.frame000000.pt b/test/resources/var_fps_video.mp4.stream0.frame000000.pt
new file mode 100644
index 00000000..a7a834a0
Binary files /dev/null and b/test/resources/var_fps_video.mp4.stream0.frame000000.pt differ
diff --git a/test/resources/var_fps_video.mp4.stream0.frame000001.pt b/test/resources/var_fps_video.mp4.stream0.frame000001.pt
new file mode 100644
index 00000000..99336d4a
Binary files /dev/null and b/test/resources/var_fps_video.mp4.stream0.frame000001.pt differ
diff --git a/test/resources/var_fps_video.mp4.stream0.frame000002.pt b/test/resources/var_fps_video.mp4.stream0.frame000002.pt
new file mode 100644
index 00000000..301c260e
Binary files /dev/null and b/test/resources/var_fps_video.mp4.stream0.frame000002.pt differ
diff --git a/test/resources/var_fps_video.mp4.stream0.frame000003.pt b/test/resources/var_fps_video.mp4.stream0.frame000003.pt
new file mode 100644
index 00000000..7bcd549a
Binary files /dev/null and b/test/resources/var_fps_video.mp4.stream0.frame000003.pt differ
diff --git a/test/resources/var_fps_video.mp4.stream0.frame000004.pt b/test/resources/var_fps_video.mp4.stream0.frame000004.pt
new file mode 100644
index 00000000..e0649277
Binary files /dev/null and b/test/resources/var_fps_video.mp4.stream0.frame000004.pt differ
diff --git a/test/resources/var_fps_video.mp4.stream0.frame000005.pt b/test/resources/var_fps_video.mp4.stream0.frame000005.pt
new file mode 100644
index 00000000..1a647182
Binary files /dev/null and b/test/resources/var_fps_video.mp4.stream0.frame000005.pt differ
diff --git a/test/resources/var_fps_video.mp4.stream0.frame000010.pt b/test/resources/var_fps_video.mp4.stream0.frame000010.pt
new file mode 100644
index 00000000..c5fdf222
Binary files /dev/null and b/test/resources/var_fps_video.mp4.stream0.frame000010.pt differ
diff --git a/test/resources/var_fps_video.mp4.stream0.frame000015.pt b/test/resources/var_fps_video.mp4.stream0.frame000015.pt
new file mode 100644
index 00000000..50ed25ab
Binary files /dev/null and b/test/resources/var_fps_video.mp4.stream0.frame000015.pt differ
diff --git a/test/resources/var_fps_video.mp4.stream0.frame000020.pt b/test/resources/var_fps_video.mp4.stream0.frame000020.pt
new file mode 100644
index 00000000..75d1714b
Binary files /dev/null and b/test/resources/var_fps_video.mp4.stream0.frame000020.pt differ
diff --git a/test/resources/var_fps_video.mp4.stream0.frame000025.pt b/test/resources/var_fps_video.mp4.stream0.frame000025.pt
new file mode 100644
index 00000000..989f636e
Binary files /dev/null and b/test/resources/var_fps_video.mp4.stream0.frame000025.pt differ
diff --git a/test/resources/var_fps_video.mp4.stream0.frame000030.pt b/test/resources/var_fps_video.mp4.stream0.frame000030.pt
new file mode 100644
index 00000000..817609b1
Binary files /dev/null and b/test/resources/var_fps_video.mp4.stream0.frame000030.pt differ
diff --git a/test/resources/var_fps_video.mp4.stream0.frame000035.pt b/test/resources/var_fps_video.mp4.stream0.frame000035.pt
new file mode 100644
index 00000000..442c4b4a
Binary files /dev/null and b/test/resources/var_fps_video.mp4.stream0.frame000035.pt differ
diff --git a/test/resources/var_fps_video.mp4.stream0.frame000040.pt b/test/resources/var_fps_video.mp4.stream0.frame000040.pt
new file mode 100644
index 00000000..62acd5c4
Binary files /dev/null and b/test/resources/var_fps_video.mp4.stream0.frame000040.pt differ
diff --git a/test/resources/var_fps_video.mp4.stream0.frame000045.pt b/test/resources/var_fps_video.mp4.stream0.frame000045.pt
new file mode 100644
index 00000000..0e9a0cff
Binary files /dev/null and b/test/resources/var_fps_video.mp4.stream0.frame000045.pt differ
diff --git a/test/resources/var_fps_video.mp4.stream0.frame000050.pt b/test/resources/var_fps_video.mp4.stream0.frame000050.pt
new file mode 100644
index 00000000..cedb6d21
Binary files /dev/null and b/test/resources/var_fps_video.mp4.stream0.frame000050.pt differ
diff --git a/test/resources/var_fps_video.mp4.stream0.frame000055.pt b/test/resources/var_fps_video.mp4.stream0.frame000055.pt
new file mode 100644
index 00000000..a57ca9f6
Binary files /dev/null and b/test/resources/var_fps_video.mp4.stream0.frame000055.pt differ
diff --git a/test/resources/var_fps_video.mp4.stream0.frame000060.pt b/test/resources/var_fps_video.mp4.stream0.frame000060.pt
new file mode 100644
index 00000000..b0643afa
Binary files /dev/null and b/test/resources/var_fps_video.mp4.stream0.frame000060.pt differ
diff --git a/test/test_variable_fps_video.py b/test/test_variable_fps_video.py
new file mode 100644
index 00000000..1597fef4
--- /dev/null
+++ b/test/test_variable_fps_video.py
@@ -0,0 +1,204 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD-style license found in the
+# LICENSE file in the root directory of this source tree.
+
+import os
+import json
+import pathlib
+import pytest
+import numpy as np
+import torch
+
+from torchcodec._core import (
+    create_from_file,
+    add_video_stream,
+    get_next_frame,
+    get_frame_at_index,
+    get_frame_at_pts,
+    get_frames_in_range,
+    get_json_metadata,
+    seek_to_pts,
+)
+
+from torchcodec.decoders import VideoDecoder,VideoStreamMetadata
+from torchcodec import Frame, FrameBatch
+
+from .utils import (
+    assert_frames_equal,
+    cpu_and_cuda,
+    TestVideo,
+    TestVideoStreamInfo,
+    TestFrameInfo,
+    _get_file_path,
+    VAR_FPS_VIDEO,
+)
+
+class TestVariableFPSVideoDecoder:
+    def _check_video_exists(self):
+        try:
+            VAR_FPS_VIDEO.path
+        except FileNotFoundError:
+            pytest.skip("Variable FPS test video not found")
+
+    @pytest.mark.parametrize("device", cpu_and_cuda())
+    def test_basic_decoding(self, device):
+        self._check_video_exists()
+        
+        decoder = VideoDecoder(str(VAR_FPS_VIDEO.path))
+        
+        frame = decoder.get_frame_at(0)
+        assert isinstance(frame, Frame)
+        
+        metadata = decoder.metadata
+        assert isinstance(metadata, VideoStreamMetadata)
+        assert metadata.num_frames > 30
+
+    @pytest.mark.parametrize("device", cpu_and_cuda())
+    def test_exact_seeking_mode(self, device):
+        self._check_video_exists()
+        
+        decoder = VideoDecoder(str(VAR_FPS_VIDEO.path), seek_mode="exact")
+        
+        test_timestamps = [0.0, 0.5, 1.0, 1.5, 2.0]
+        for timestamp in test_timestamps:
+            if timestamp < decoder.metadata.duration_seconds:
+                frame_batch = decoder.get_frames_played_at(seconds=[timestamp])
+                assert isinstance(frame_batch, FrameBatch)
+                assert abs(frame_batch.pts_seconds[0] - timestamp) <= frame_batch.duration_seconds[0]
+
+    @pytest.mark.parametrize("device", cpu_and_cuda())
+    def test_approximate_seeking_mode_behavior(self, device):
+        """Test behavior in approximate seeking mode (may fail as expected)"""
+        self._check_video_exists()
+        
+        # Create two decoders: one with exact mode, one with approximate mode
+        decoder_exact = create_from_file(str(VAR_FPS_VIDEO.path), seek_mode="exact")
+        add_video_stream(decoder_exact, device=device)
+        
+        decoder_approx = create_from_file(str(VAR_FPS_VIDEO.path), seek_mode="approximate")
+        add_video_stream(decoder_approx, device=device)
+
+        metadata = get_json_metadata(decoder_exact)
+        metadata_dict = json.loads(metadata)
+        
+        # Compare seeking in both modes
+        test_pts = [0.0, 0.5, 1.0, 1.5, 2.0]
+        differences = []
+        
+        for pts in test_pts:
+            if pts < metadata_dict["durationSeconds"]:
+                frame_exact, pts_exact, _ = get_frame_at_pts(decoder_exact, pts)
+                
+                try:
+                    frame_approx, pts_approx, _ = get_frame_at_pts(decoder_approx, pts)
+                    
+                    differences.append({
+                        "seek_pts": pts,
+                        "exact_pts": pts_exact.item(),
+                        "approx_pts": pts_approx.item(),
+                        "frames_match": torch.allclose(frame_exact, frame_approx),
+                        "pts_difference": abs(pts_exact.item() - pts_approx.item()),
+                        "approximate_failed": False
+                    })
+                except Exception as e:
+                    differences.append({
+                        "seek_pts": pts,
+                        "exact_pts": pts_exact.item(),
+                        "error": str(e),
+                        "approximate_failed": True
+                    })
+        
+        # Print differences (useful for debugging)
+        for diff in differences:
+            if diff["approximate_failed"]:
+                print(f"Seeking to {diff['seek_pts']}s failed in approximate mode: {diff['error']}")
+            else:
+                print(f"Seeking to {diff['seek_pts']}s: exact={diff['exact_pts']}, "
+                      f"approx={diff['approx_pts']}, diff={diff['pts_difference']}, "
+                      f"frames {'match' if diff['frames_match'] else 'differ'}")
+        
+        # No assertion as approximate mode is expected to potentially fail
+
+    @pytest.mark.parametrize("device", cpu_and_cuda())
+    def test_frame_timing_pattern(self, device):
+        self._check_video_exists()
+        
+        decoder = create_from_file(str(VAR_FPS_VIDEO.path))
+        add_video_stream(decoder, device=device)
+        
+        frames_info = []
+        frame_index = 0
+        
+        seek_to_pts(decoder, 0.0)
+        
+        while True:
+            try:
+                frame, pts, duration = get_next_frame(decoder)
+                frames_info.append({
+                    "index": frame_index,
+                    "pts": pts.item(),
+                    "duration": duration.item()
+                })
+                frame_index += 1
+            except IndexError:
+                break
+        
+        assert len(frames_info) > 30, "Not enough frames to verify variable frame rate"        
+
+        intervals_before = [frames_info[i+1]["pts"] - frames_info[i]["pts"] 
+                           for i in range(min(30, len(frames_info)-1))]
+        
+        intervals_after = [frames_info[i+1]["pts"] - frames_info[i]["pts"] 
+                          for i in range(30, min(60, len(frames_info)-1))]
+        
+        if len(intervals_after) > 5:
+            avg_interval_before = sum(intervals_before) / len(intervals_before)
+            avg_interval_after = sum(intervals_after) / len(intervals_after)
+            
+            print(f"Average interval for first 30 frames: {avg_interval_before:.6f}s")
+            print(f"Average interval for subsequent frames: {avg_interval_after:.6f}s")
+            
+            expected_ratio = 0.5
+            actual_ratio = avg_interval_before / avg_interval_after
+            
+            # Allow for some error
+            assert abs(actual_ratio - expected_ratio) < 0.2, \
+                f"Interval ratio ({actual_ratio:.2f}) differs too much from expected ({expected_ratio})"
+
+    @pytest.mark.parametrize("device", cpu_and_cuda())
+    def test_sequential_decoding(self, device):
+        self._check_video_exists()
+        
+        decoder = create_from_file(str(VAR_FPS_VIDEO.path))
+        add_video_stream(decoder, device=device)
+        
+        seek_to_pts(decoder, 0.0)
+        
+        # Decode multiple frames and verify monotonically increasing timestamps
+        last_pts = -1.0
+        for _ in range(50):
+            try:
+                frame, pts, duration = get_next_frame(decoder)
+                current_pts = pts.item()
+                
+                assert current_pts > last_pts, \
+                    f"Frame timestamps not monotonically increasing: current={current_pts}, previous={last_pts}"
+                
+                last_pts = current_pts
+            except IndexError:
+                break
+
+    @pytest.mark.parametrize("device", cpu_and_cuda())
+    def test_frames_in_range(self, device):
+        self._check_video_exists()
+        
+        decoder = VideoDecoder(str(VAR_FPS_VIDEO.path))
+        
+        frame_batch = decoder.get_frames_in_range(0, 10)
+        assert isinstance(frame_batch, FrameBatch)
+        assert len(frame_batch) == 10
+        
+        timestamps = frame_batch.pts_seconds.tolist()
+        assert all(timestamps[i] < timestamps[i+1] for i in range(len(timestamps)-1))
diff --git a/test/utils.py b/test/utils.py
index e7ce12e5..3e81183e 100644
--- a/test/utils.py
+++ b/test/utils.py
@@ -561,3 +561,14 @@ def sample_format(self) -> str:
         },
     },
 )
+
+VAR_FPS_VIDEO = TestVideo(
+    filename="var_fps_video.mp4",
+    default_stream_index=0,
+    # This metadata is extracted manually.
+    #  $ ffprobe -v error -hide_banner -select_streams v:0 -show_frames -of json test/resources/av1_video.mkv > out.json
+    stream_infos={
+        0: TestVideoStreamInfo(width=320, height=240, num_color_channels=3),
+    },
+    frames={},
+)
\ No newline at end of file