fix #5 camera video preview with settling and diagnostics
iOS CI / Build and Test SwiftUI App (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build Unsigned iOS IPA (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build macOS ZIP (push) Canceled after 0s

- Wait until the picker movie's file size stops changing before
  staging it, so a movie whose final bytes are still being flushed is
  never copied truncated (which produced drafts without a thumbnail
  and unplayable previews).
- Log the whole camera video path (pickup size, staging result,
  analyze outcome, thumbnail decode) under the video-preview os_log
  category for fast on-device diagnosis.
- Cover the video analysis pipeline with a simulator test that
  generates an HEVC QuickTime movie and asserts duration plus JPEG
  thumbnail, and guard the diagnostics in Scripts/verify.sh.
This commit is contained in:
wt committed 2026-08-29 04:30:40 +07:00
1 parent 75fbcc5346
commit 496ee6f0f2
7 files changed
+137 -5

No files matched your search

@@ -1,4 +1,5 @@
import Foundation
import os
struct CapturedCameraMedia: Sendable {
let url: URL
@@ -121,7 +122,10 @@ struct SystemPhotoCameraView: UIViewControllerRepresentable {
/// races that cleanup and fails with an unreadable source. The move
/// is a same-volume rename and does not block the main thread.
private func prepareMovie(from sourceURL: URL) {
let logger = Logger(subsystem: "Luma", category: "video-preview")
do {
let sourceSize = (try? sourceURL.resourceValues(forKeys: [.fileSizeKey]).fileSize) ?? -1
logger.info("picker movie ready: source=\(sourceURL.lastPathComponent) size=\(sourceSize)")
let fileExtension = sourceURL.pathExtension.isEmpty
? "mov"
: sourceURL.pathExtension
@@ -130,13 +134,15 @@ struct SystemPhotoCameraView: UIViewControllerRepresentable {
let values = try destination.resourceValues(
forKeys: [.fileSizeKey, .isRegularFileKey]
)
guard values.isRegularFile == true,
(values.fileSize ?? 0) > 0 else {
let movedSize = values.fileSize ?? 0
logger.info("picker movie moved: size=\(movedSize) regular=\(values.isRegularFile == true)")
guard values.isRegularFile == true, movedSize > 0 else {
try? FileManager.default.removeItem(at: destination)
throw SystemCameraError.emptyMovie
}
onMedia(.success(CapturedCameraMedia(url: destination, kind: .video)))
} catch {
logger.error("picker movie preparation failed: \(error.localizedDescription)")
onMedia(.failure(error))
}
}