prevent fps rounding

This commit is contained in:
Kilian Boute
2026-08-06 17:46:38 +02:00
parent dbff9fbc8e
commit fea6d81246
5 changed files with 18 additions and 13 deletions

View File

@@ -62,7 +62,7 @@ func recordingUploadMetadata(name, deviceKey string, timestamp int64, mp4Video *
}
value := mp4Video.AverageFPS()
if value > 0 && value <= 240 && !math.IsInf(value, 0) && !math.IsNaN(value) {
metadata.FPS = int(math.Floor(value))
metadata.FPS = value
}
return metadata
}

View File

@@ -29,9 +29,13 @@ func TestQueueRecordingForUploadStoresFinalizedMetadata(t *testing.T) {
if err := json.Unmarshal(got, &stored); err != nil {
t.Fatalf("decode upload marker: %v", err)
}
if stored.FileName != "recording.mp4" || stored.DeviceKey != "device-key" || stored.Timestamp != 1785934709414 || stored.Duration != 20452 || stored.FPS != 29 {
expectedFPS := mp4Video.AverageFPS()
if stored.FileName != "recording.mp4" || stored.DeviceKey != "device-key" || stored.Timestamp != 1785934709414 || stored.Duration != 20452 || math.Abs(stored.FPS-expectedFPS) > 1e-9 {
t.Fatalf("upload marker = %+v", stored)
}
if stored.FPS == math.Floor(stored.FPS) {
t.Fatalf("upload marker FPS = %v, want fractional precision", stored.FPS)
}
}
func TestQueueRecordingForUploadKeepsUnknownFPSCompatible(t *testing.T) {
@@ -44,7 +48,7 @@ func TestQueueRecordingForUploadKeepsUnknownFPSCompatible(t *testing.T) {
metadata := models.RecordingUploadMetadata{FileName: "recording.mp4"}
if fps >= 1 && fps <= 240 && !math.IsNaN(fps) && !math.IsInf(fps, 0) {
metadata.FPS = int(math.Floor(fps))
metadata.FPS = fps
}
queueRecordingForUpload(configDirectory, metadata)

View File

@@ -28,10 +28,10 @@ func queuedRecordingFPS(fileName string) string {
marker := strings.TrimSpace(string(value))
if strings.HasPrefix(marker, "{") {
metadata, ok := decodeRecordingUploadMetadata(value)
if !ok || metadata.FPS <= 0 || metadata.FPS > 240 {
if !ok || metadata.FPS <= 0 || metadata.FPS > 240 || math.IsInf(metadata.FPS, 0) || math.IsNaN(metadata.FPS) {
return ""
}
return strconv.Itoa(metadata.FPS)
return strconv.FormatFloat(metadata.FPS, 'f', -1, 64)
}
// Compatibility with markers created before upload metadata used JSON.

View File

@@ -272,7 +272,7 @@ func TestUploadVaultResumable_HappyPath(t *testing.T) {
fileName := "1564859471_6-474162_oprit_577-283-727-375_1153_27.mp4"
payload := bytes.Repeat([]byte("x"), 4096)
withRecording(t, fileName, payload)
withQueuedRecordingFPS(t, fileName, `{"filename":"recording.mp4","device_key":"device-key","timestamp":1785934709414,"duration":20452,"fps":29}`)
withQueuedRecordingFPS(t, fileName, `{"filename":"recording.mp4","device_key":"device-key","timestamp":1785934709414,"duration":20452,"fps":29.97}`)
uploaded, responded, supported, _, err := uploadVaultResumable(testVault(ts.URL), "pk", "dev", fileName, "test", "primary")
if err != nil {
@@ -289,8 +289,8 @@ func TestUploadVaultResumable_HappyPath(t *testing.T) {
}
posts := srv.requestsForMethod(http.MethodPost)
metadata := decodeTusMetadata(posts[0].header.Get("Upload-Metadata"))
if got := metadata["fps"]; got != "29" {
t.Fatalf("POST metadata fps = %q, want %q", got, "29")
if got := metadata["fps"]; got != "29.97" {
t.Fatalf("POST metadata fps = %q, want %q", got, "29.97")
}
if got := metadata["duration"]; got != "20452" {
t.Fatalf("POST metadata duration = %q, want %q", got, "20452")
@@ -307,6 +307,7 @@ func TestQueuedRecordingFPSValidation(t *testing.T) {
want string
}{
{name: "json", fps: `{"fps":29}`, want: "29"},
{name: "json fractional", fps: `{"fps":17.35}`, want: "17.35"},
{name: "json with future field", fps: `{"fps":29,"codec":"h264"}`, want: "29"},
{name: "json without fps", fps: `{}`},
{name: "json invalid fps", fps: `{"fps":241}`},

View File

@@ -11,11 +11,11 @@ const RecordingUploadMetadataExtension = ".metadata"
// with a recording. New optional fields can be added without changing the queue
// mechanism or breaking older agents.
type RecordingUploadMetadata struct {
FileName string `json:"filename"`
DeviceKey string `json:"device_key"`
Timestamp int64 `json:"timestamp"` // Unix milliseconds.
Duration uint64 `json:"duration"` // Milliseconds.
FPS int `json:"fps,omitempty"`
FileName string `json:"filename"`
DeviceKey string `json:"device_key"`
Timestamp int64 `json:"timestamp"` // Unix milliseconds.
Duration uint64 `json:"duration"` // Milliseconds.
FPS float64 `json:"fps,omitempty"`
}
// RecordingUploadMetadataFileName returns the queue marker name associated