Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[camera] Provide a way to record a video in landscape when device orientation is locked to portrait #109381

Open
thao-vu-0106 opened this issue Aug 11, 2022 · 2 comments
Labels
c: new feature Nothing broken; request for a new capability c: proposal A detailed proposal for a change to Flutter p: camera The camera plugin P3 Issues that are less important to the Flutter project package flutter/packages repository. See also p: labels. team-ecosystem Owned by Ecosystem team triaged-ecosystem Triaged by Ecosystem team

Comments

@thao-vu-0106
Copy link

thao-vu-0106 commented Aug 11, 2022

Use case

i want to have more use case rotation in camera flutter.

Proposal

For example: Initially, device is in portrait mode . Then i rotate screen to horizontal (remember that the device rotation is set to locked) and record video. My expectation is the output video is in landscape mode but the actual result is that the video is still in portrait mode. For more detail you can see in the CameraX usecase rotation How to determine the target rotation example 1

Procedure:

  • When rotate camera with locked portrait mode:

(the status bar show that device is still in portrait mode)

  • Expectation output:

(The picture or video which is recorded should be in portrait mode).

In android, they have some function like Display.getRotation() to get this device, we can use it to change recordingRotation before record video.

@exaby73 exaby73 added the in triage Presently being triaged by the triage team label Aug 11, 2022
@exaby73
Copy link
Member

exaby73 commented Aug 11, 2022

Hello @tda-thaovd. I am not sure if this is a valid feature or something that should be implemented by another plugin and/or method channels. Anyways, I will label it for further insights from the team. Thank you for filing this request

@exaby73 exaby73 changed the title Usecase rotation in camera flutter for locked portrait mode [camera] Provide a way to record a video in landscape when device orientation is locked to portrait Aug 11, 2022
@exaby73 exaby73 added c: new feature Nothing broken; request for a new capability plugin p: camera The camera plugin c: proposal A detailed proposal for a change to Flutter and removed in triage Presently being triaged by the triage team labels Aug 11, 2022
@stuartmorgan stuartmorgan added the P3 Issues that are less important to the Flutter project label Aug 18, 2022
@thao-vu-0106
Copy link
Author

I did it after customize CameraPreview and listen rotation from my app. Hope this help some one try to do that.

import 'package:camera/camera.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

/// A widget showing a live camera preview.
class CustomCameraPreview extends StatelessWidget {
  /// Creates a preview widget for the given camera controller.
  const CustomCameraPreview(this.controller, {Key? key, this.child})
      : super(key: key);

  /// The controller for the camera that the preview is shown for.
  final CameraController controller;

  /// A widget to overlay on top of the camera preview
  final Widget? child;

  @override
  Widget build(BuildContext context) {
    return controller.value.isInitialized
        ? ValueListenableBuilder<CameraValue>(
            valueListenable: controller,
            builder: (BuildContext context, Object? value, Widget? child) {
              return AspectRatio(
                aspectRatio: (1 / controller.value.aspectRatio),
                child: Stack(
                  fit: StackFit.expand,
                  children: <Widget>[
                    _wrapInRotatedBox(child: controller.buildPreview()),
                    child ?? Container(),
                  ],
                ),
              );
            },
            child: child,
          )
        : Container();
  }

  Widget _wrapInRotatedBox({required Widget child}) {
    if (kIsWeb || defaultTargetPlatform != TargetPlatform.android) {
      return RotatedBox(quarterTurns: _getQuarterTurns(), child: child);
    }
    return child;
  }

  int _getQuarterTurns() {
    final Map<DeviceOrientation, int> turns = <DeviceOrientation, int>{
      DeviceOrientation.portraitUp: 0,
      DeviceOrientation.landscapeRight: 1,
      DeviceOrientation.portraitDown: 2,
      DeviceOrientation.landscapeLeft: 3,
    };
    return turns[_getApplicableOrientation()]!;
  }

  DeviceOrientation _getApplicableOrientation() {
    return controller.value.isRecordingVideo
        ? controller.value.recordingOrientation!
        : (controller.value.previewPauseOrientation ??
            controller.value.lockedCaptureOrientation ??
            controller.value.deviceOrientation);
  }
}
import android.view.OrientationEventListener
import android.view.Surface
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.EventChannel

class MainActivity : FlutterActivity() {
    private val rotationEventChannel = "app/rotation"
    private var eventSink: EventChannel.EventSink? = null

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        EventChannel(flutterEngine.dartExecutor.binaryMessenger, rotationEventChannel).setStreamHandler(object : EventChannel.StreamHandler {
            override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
                eventSink = events
                startListenRotation()
            }

            override fun onCancel(arguments: Any?) {
                stopListenRotation()
                eventSink = null
            }
        })
    }

    fun startListenRotation() {
        orientationEventListener.enable()
    }

    fun stopListenRotation() {
        orientationEventListener.disable()
    }

    private val orientationEventListener by lazy {
        object : OrientationEventListener(this) {
            override fun onOrientationChanged(orientation: Int) {
                val rotation = when (orientation) {
                    in 45 until 135 -> Surface.ROTATION_270
                    in 135 until 225 -> Surface.ROTATION_180
                    in 225 until 315 -> Surface.ROTATION_90
                    else -> Surface.ROTATION_0
                }
                eventSink?.success(rotation)
            }
        }
    }
}
@injectable
class RecordCameraController extends GetxController {
  static const rotationEventChannel =
      EventChannel('app/rotation');
  late Stream<DeviceOrientation> rotationStream;
  late StreamSubscription<DeviceOrientation> streamSubscription;
  DeviceOrientation? currentOrientation;

  DeviceOrientation intToOrientation(int orientation) {
    var deviceOrientation = DeviceOrientation.portraitUp;
    Log.d("$orientation");
    switch (orientation) {
      case 0:
        deviceOrientation = DeviceOrientation.portraitUp;
        break;
      case 1:
        deviceOrientation = DeviceOrientation.landscapeLeft;
        break;
      case 2:
        deviceOrientation = DeviceOrientation.portraitDown;
        break;
      case 3:
        deviceOrientation = DeviceOrientation.landscapeRight;
        break;
    }
    return deviceOrientation;
  }
}

In the widget which has customcamerapreview

  @override
  void initState() {
    recordCameraController.rotationStream = RecordCameraController
          .rotationEventChannel
          .receiveBroadcastStream()
          .distinct()
          .map((event) => recordCameraController.intToOrientation(event as int));
      recordCameraController.streamSubscription =
          recordCameraController.rotationStream.listen(
        (event) async {
          recordCameraController.currentOrientation = event;
          await cameraController?.lockCaptureOrientation(event);
        },
      );
super.initState();
}

@flutter-triage-bot flutter-triage-bot bot added the package flutter/packages repository. See also p: labels. label Jul 5, 2023
@Hixie Hixie removed the plugin label Jul 6, 2023
@flutter-triage-bot flutter-triage-bot bot added team-ecosystem Owned by Ecosystem team triaged-ecosystem Triaged by Ecosystem team labels Jul 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: new feature Nothing broken; request for a new capability c: proposal A detailed proposal for a change to Flutter p: camera The camera plugin P3 Issues that are less important to the Flutter project package flutter/packages repository. See also p: labels. team-ecosystem Owned by Ecosystem team triaged-ecosystem Triaged by Ecosystem team
Projects
None yet
Development

No branches or pull requests

4 participants