diff --git a/ios/Classes/Camera/CameraInstance.swift b/ios/Classes/Camera/CameraInstance.swift index 673e852..70d1039 100644 --- a/ios/Classes/Camera/CameraInstance.swift +++ b/ios/Classes/Camera/CameraInstance.swift @@ -411,7 +411,15 @@ final class CameraInstance { } } - // Apply preview-output settings on the (new) connection. + // Apply preview-output orientation. Mirroring is deliberately + // NOT set here — the data output feeds both the preview + // texture and the recorder, so mirroring at the connection + // would land in the recorded MP4 too. Telegram avoids this + // by mirroring at the preview-LAYER level (CALayer transform + // in `CameraPreviewView.mirroring`). Our FlutterTexture + // equivalent is a `Transform.flip` in [CameraThumb] for the + // front camera — raw sensor feed at capture, mirror as a + // playback decision. if let videoConn = videoDataOutput?.connection(with: .video) { if videoConn.isVideoOrientationSupported { videoConn.videoOrientation = lockedOrientation?.avVideoOrientation @@ -419,7 +427,7 @@ final class CameraInstance { } if videoConn.isVideoMirroringSupported { videoConn.automaticallyAdjustsVideoMirroring = false - videoConn.isVideoMirrored = (device.position == .front) + videoConn.isVideoMirrored = false } } diff --git a/lib/src/camera/camera_preview.dart b/lib/src/camera/camera_preview.dart index 66b69d9..3252fdd 100644 --- a/lib/src/camera/camera_preview.dart +++ b/lib/src/camera/camera_preview.dart @@ -1,6 +1,6 @@ import 'package:flutter/widgets.dart'; -import 'camera.dart' show UxCameraController, UxCameraValue; +import 'camera.dart' show UxCameraController, UxCameraLens, UxCameraValue; /// Renders the live preview for [controller] into a [Texture]. Sizes /// itself to the parent — wrap in `AspectRatio` / `FittedBox` / `Hero` @@ -10,6 +10,11 @@ import 'camera.dart' show UxCameraController, UxCameraValue; /// transparent placeholder. The widget rebuilds on every /// `UxCameraValue` change, so once the native session starts /// producing frames the texture appears automatically. +/// +/// Front-camera preview is auto-mirrored here (the analog of +/// telegram-iOS's `CameraPreviewView.mirroring` property), so the +/// recorded MP4 + captured JPEG carry the raw sensor feed while the +/// on-screen preview still reads as a natural mirror to the user. class UxCameraPreview extends StatelessWidget { const UxCameraPreview({super.key, required this.controller}); @@ -19,10 +24,14 @@ class UxCameraPreview extends StatelessWidget { Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: controller, - builder: (context, _, __) { + builder: (context, value, _) { final id = controller.textureId; - if (id == null) return const SizedBox.expand(); - return Texture(textureId: id); + if (id == null) return SizedBox.expand(); + final mirror = value.description.lens == UxCameraLens.front; + final texture = Texture(textureId: id); + return mirror + ? Transform.flip(flipX: true, child: texture) + : texture; }, ); }