diff --git a/camera-ui-homekit/src/camera/accessory.ts b/camera-ui-homekit/src/camera/accessory.ts index f365ded3..308cc4d5 100644 --- a/camera-ui-homekit/src/camera/accessory.ts +++ b/camera-ui-homekit/src/camera/accessory.ts @@ -415,6 +415,19 @@ export class CameraAccessory extends Subscribed { this.recordingDelegate?.refreshPrebuffer(); }, }, + { + type: 'boolean', + key: 'forceVideoTranscodingForRecording', + title: 'Force Video Transcoding for HKSV', + description: 'Re-encode video for HomeKit Secure Video so its negotiated resolution, frame rate, and bitrate limits are applied.', + group: 'Advanced', + defaultValue: false, + store: true, + onSet: async (state: boolean) => { + this.cameraLogger.log('Force video transcoding for HKSV:', state); + this.recordingDelegate?.refreshPrebuffer(); + }, + }, ]); } diff --git a/camera-ui-homekit/src/camera/recordingSession.ts b/camera-ui-homekit/src/camera/recordingSession.ts index 3bd93264..fcc82ad0 100644 --- a/camera-ui-homekit/src/camera/recordingSession.ts +++ b/camera-ui-homekit/src/camera/recordingSession.ts @@ -236,7 +236,11 @@ export class RecordingSession extends EventEmitter { ]; await session.startStream({ - supportedVideoCodecs: ['h264'], + // An empty supported-codec list deliberately makes node-av transcode the + // input to H.264. This is useful for cameras whose already-compatible + // H.264 stream exceeds the resolution, frame-rate, or bitrate negotiated + // by HomeKit: stream-copy mode cannot apply those encoder constraints. + supportedVideoCodecs: this.cameraAccessory.cameraStorage.values.forceVideoTranscodingForRecording ? [] : ['h264'], supportedAudioCodecs: ['aac'], boxMode: true, fragDuration: (this.configuration?.mediaContainerConfiguration?.fragmentLength ?? 4000) * 1000, diff --git a/camera-ui-homekit/src/types.ts b/camera-ui-homekit/src/types.ts index f151ff9f..ca7d8053 100644 --- a/camera-ui-homekit/src/types.ts +++ b/camera-ui-homekit/src/types.ts @@ -13,6 +13,7 @@ export interface CameraStorageValues { republishId: string; useHardwareAcceleration: boolean; useHardwareAccelerationForRecording: boolean; + forceVideoTranscodingForRecording: boolean; adaptiveStreamSource: boolean; advertiser: string; }