-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Closed
flutter/engine
#33195Labels
engineflutter/engine related. See also e: labels.flutter/engine related. See also e: labels.found in release: 2.13Found to occur in 2.13Found to occur in 2.13has reproducible stepsThe issue has been confirmed reproducible and is ready to work onThe issue has been confirmed reproducible and is ready to work onp: cameraThe camera pluginThe camera pluginpackageflutter/packages repository. See also p: labels.flutter/packages repository. See also p: labels.platform-windowsBuilding on or for Windows specificallyBuilding on or for Windows specificallyr: fixedIssue is closed as already fixed in a newer versionIssue is closed as already fixed in a newer version
Description
Steps to Reproduce
Camera preview got broken recently (tested today with 2.13.0-0.0.pre.851).
- Add "camera_windows: any" under dependencies in pubspec.yaml
- Execute
flutter runon the code sample copied from https://pub.dev/packages/camera_windows/example
Expected results: Camera preview works
Actual results: Camera preview doesn't work and the following error messages are shown in console:
[ERROR:flutter/shell/platform/embedder/embedder_external_texture_gl.cc(95)] Could not create external texture->
[ERROR:flutter/shell/platform/embedder/embedder_external_texture_gl.cc(95)] Could not create external texture->
[ERROR:flutter/shell/platform/embedder/embedder_external_texture_gl.cc(95)] Could not create external texture->
Picture taking still works - it's just the preview rendering.
Code sample
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:camera_platform_interface/camera_platform_interface.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
/// Example app for Camera Windows plugin.
class MyApp extends StatefulWidget {
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _cameraInfo = 'Unknown';
List<CameraDescription> _cameras = <CameraDescription>[];
int _cameraIndex = 0;
int _cameraId = -1;
bool _initialized = false;
bool _recording = false;
bool _recordingTimed = false;
bool _recordAudio = true;
bool _previewPaused = false;
Size? _previewSize;
ResolutionPreset _resolutionPreset = ResolutionPreset.veryHigh;
StreamSubscription<CameraErrorEvent>? _errorStreamSubscription;
StreamSubscription<CameraClosingEvent>? _cameraClosingStreamSubscription;
@override
void initState() {
super.initState();
WidgetsFlutterBinding.ensureInitialized();
_fetchCameras();
}
@override
void dispose() {
_disposeCurrentCamera();
_errorStreamSubscription?.cancel();
_errorStreamSubscription = null;
_cameraClosingStreamSubscription?.cancel();
_cameraClosingStreamSubscription = null;
super.dispose();
}
/// Fetches list of available cameras from camera_windows plugin.
Future<void> _fetchCameras() async {
String cameraInfo;
List<CameraDescription> cameras = <CameraDescription>[];
int cameraIndex = 0;
try {
cameras = await CameraPlatform.instance.availableCameras();
if (cameras.isEmpty) {
cameraInfo = 'No available cameras';
} else {
cameraIndex = _cameraIndex % cameras.length;
cameraInfo = 'Found camera: ${cameras[cameraIndex].name}';
}
} on PlatformException catch (e) {
cameraInfo = 'Failed to get cameras: ${e.code}: ${e.message}';
}
if (mounted) {
setState(() {
_cameraIndex = cameraIndex;
_cameras = cameras;
_cameraInfo = cameraInfo;
});
}
}
/// Initializes the camera on the device.
Future<void> _initializeCamera() async {
assert(!_initialized);
if (_cameras.isEmpty) {
return;
}
int cameraId = -1;
try {
final int cameraIndex = _cameraIndex % _cameras.length;
final CameraDescription camera = _cameras[cameraIndex];
cameraId = await CameraPlatform.instance.createCamera(
camera,
_resolutionPreset,
enableAudio: _recordAudio,
);
_errorStreamSubscription?.cancel();
_errorStreamSubscription = CameraPlatform.instance
.onCameraError(cameraId)
.listen(_onCameraError);
_cameraClosingStreamSubscription?.cancel();
_cameraClosingStreamSubscription = CameraPlatform.instance
.onCameraClosing(cameraId)
.listen(_onCameraClosing);
final Future<CameraInitializedEvent> initialized =
CameraPlatform.instance.onCameraInitialized(cameraId).first;
await CameraPlatform.instance.initializeCamera(
cameraId,
imageFormatGroup: ImageFormatGroup.unknown,
);
final CameraInitializedEvent event = await initialized;
_previewSize = Size(
event.previewWidth,
event.previewHeight,
);
if (mounted) {
setState(() {
_initialized = true;
_cameraId = cameraId;
_cameraIndex = cameraIndex;
_cameraInfo = 'Capturing camera: ${camera.name}';
});
}
} on CameraException catch (e) {
try {
if (cameraId >= 0) {
await CameraPlatform.instance.dispose(cameraId);
}
} on CameraException catch (e) {
debugPrint('Failed to dispose camera: ${e.code}: ${e.description}');
}
// Reset state.
if (mounted) {
setState(() {
_initialized = false;
_cameraId = -1;
_cameraIndex = 0;
_previewSize = null;
_recording = false;
_recordingTimed = false;
_cameraInfo =
'Failed to initialize camera: ${e.code}: ${e.description}';
});
}
}
}
Future<void> _disposeCurrentCamera() async {
if (_cameraId >= 0 && _initialized) {
try {
await CameraPlatform.instance.dispose(_cameraId);
if (mounted) {
setState(() {
_initialized = false;
_cameraId = -1;
_previewSize = null;
_recording = false;
_recordingTimed = false;
_previewPaused = false;
_cameraInfo = 'Camera disposed';
});
}
} on CameraException catch (e) {
if (mounted) {
setState(() {
_cameraInfo =
'Failed to dispose camera: ${e.code}: ${e.description}';
});
}
}
}
}
Widget _buildPreview() {
return CameraPlatform.instance.buildPreview(_cameraId);
}
Future<void> _takePicture() async {
final XFile _file = await CameraPlatform.instance.takePicture(_cameraId);
_showInSnackBar('Picture captured to: ${_file.path}');
}
Future<void> _recordTimed(int seconds) async {
if (_initialized && _cameraId > 0 && !_recordingTimed) {
CameraPlatform.instance
.onVideoRecordedEvent(_cameraId)
.first
.then((VideoRecordedEvent event) async {
if (mounted) {
setState(() {
_recordingTimed = false;
});
_showInSnackBar('Video captured to: ${event.file.path}');
}
});
await CameraPlatform.instance.startVideoRecording(
_cameraId,
maxVideoDuration: Duration(seconds: seconds),
);
if (mounted) {
setState(() {
_recordingTimed = true;
});
}
}
}
Future<void> _toggleRecord() async {
if (_initialized && _cameraId > 0) {
if (_recordingTimed) {
/// Request to stop timed recording short.
await CameraPlatform.instance.stopVideoRecording(_cameraId);
} else {
if (!_recording) {
await CameraPlatform.instance.startVideoRecording(_cameraId);
} else {
final XFile _file =
await CameraPlatform.instance.stopVideoRecording(_cameraId);
_showInSnackBar('Video captured to: ${_file.path}');
}
if (mounted) {
setState(() {
_recording = !_recording;
});
}
}
}
}
Future<void> _togglePreview() async {
if (_initialized && _cameraId >= 0) {
if (!_previewPaused) {
await CameraPlatform.instance.pausePreview(_cameraId);
} else {
await CameraPlatform.instance.resumePreview(_cameraId);
}
if (mounted) {
setState(() {
_previewPaused = !_previewPaused;
});
}
}
}
Future<void> _switchCamera() async {
if (_cameras.isNotEmpty) {
// select next index;
_cameraIndex = (_cameraIndex + 1) % _cameras.length;
if (_initialized && _cameraId >= 0) {
await _disposeCurrentCamera();
await _fetchCameras();
if (_cameras.isNotEmpty) {
await _initializeCamera();
}
} else {
await _fetchCameras();
}
}
}
Future<void> _onResolutionChange(ResolutionPreset newValue) async {
setState(() {
_resolutionPreset = newValue;
});
if (_initialized && _cameraId >= 0) {
// Re-inits camera with new resolution preset.
await _disposeCurrentCamera();
await _initializeCamera();
}
}
Future<void> _onAudioChange(bool recordAudio) async {
setState(() {
_recordAudio = recordAudio;
});
if (_initialized && _cameraId >= 0) {
// Re-inits camera with new record audio setting.
await _disposeCurrentCamera();
await _initializeCamera();
}
}
void _onCameraError(CameraErrorEvent event) {
if (mounted) {
_scaffoldMessengerKey.currentState?.showSnackBar(
SnackBar(content: Text('Error: ${event.description}')));
// Dispose camera on camera error as it can not be used anymore.
_disposeCurrentCamera();
_fetchCameras();
}
}
void _onCameraClosing(CameraClosingEvent event) {
if (mounted) {
_showInSnackBar('Camera is closing');
}
}
void _showInSnackBar(String message) {
_scaffoldMessengerKey.currentState?.showSnackBar(SnackBar(
content: Text(message),
duration: const Duration(seconds: 1),
));
}
final GlobalKey<ScaffoldMessengerState> _scaffoldMessengerKey =
GlobalKey<ScaffoldMessengerState>();
@override
Widget build(BuildContext context) {
final List<DropdownMenuItem<ResolutionPreset>> resolutionItems =
ResolutionPreset.values
.map<DropdownMenuItem<ResolutionPreset>>((ResolutionPreset value) {
return DropdownMenuItem<ResolutionPreset>(
value: value,
child: Text(value.toString()),
);
}).toList();
return MaterialApp(
scaffoldMessengerKey: _scaffoldMessengerKey,
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: ListView(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(
vertical: 5,
horizontal: 10,
),
child: Text(_cameraInfo),
),
if (_cameras.isEmpty)
ElevatedButton(
onPressed: _fetchCameras,
child: const Text('Re-check available cameras'),
),
if (_cameras.isNotEmpty)
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DropdownButton<ResolutionPreset>(
value: _resolutionPreset,
onChanged: (ResolutionPreset? value) {
if (value != null) {
_onResolutionChange(value);
}
},
items: resolutionItems,
),
const SizedBox(width: 20),
const Text('Audio:'),
Switch(
value: _recordAudio,
onChanged: (bool state) => _onAudioChange(state)),
const SizedBox(width: 20),
ElevatedButton(
onPressed: _initialized
? _disposeCurrentCamera
: _initializeCamera,
child:
Text(_initialized ? 'Dispose camera' : 'Create camera'),
),
const SizedBox(width: 5),
ElevatedButton(
onPressed: _initialized ? _takePicture : null,
child: const Text('Take picture'),
),
const SizedBox(width: 5),
ElevatedButton(
onPressed: _initialized ? _togglePreview : null,
child: Text(
_previewPaused ? 'Resume preview' : 'Pause preview',
),
),
const SizedBox(width: 5),
ElevatedButton(
onPressed: _initialized ? _toggleRecord : null,
child: Text(
(_recording || _recordingTimed)
? 'Stop recording'
: 'Record Video',
),
),
const SizedBox(width: 5),
ElevatedButton(
onPressed: (_initialized && !_recording && !_recordingTimed)
? () => _recordTimed(5)
: null,
child: const Text(
'Record 5 seconds',
),
),
if (_cameras.length > 1) ...<Widget>[
const SizedBox(width: 5),
ElevatedButton(
onPressed: _switchCamera,
child: const Text(
'Switch camera',
),
),
]
],
),
const SizedBox(height: 5),
if (_initialized && _cameraId > 0 && _previewSize != null)
Padding(
padding: const EdgeInsets.symmetric(
vertical: 10,
),
child: Align(
alignment: Alignment.center,
child: Container(
constraints: const BoxConstraints(
maxHeight: 500,
),
child: AspectRatio(
aspectRatio: _previewSize!.width / _previewSize!.height,
child: _buildPreview(),
),
),
),
),
if (_previewSize != null)
Center(
child: Text(
'Preview size: ${_previewSize!.width.toStringAsFixed(0)}x${_previewSize!.height.toStringAsFixed(0)}',
),
),
],
),
),
);
}
}Logs
PS C:\Users\tgucio\Desktop\wrk\flutter\camera_test> flutter doctor -v
[√] Flutter (Channel master, 2.13.0-0.0.pre.851, on Microsoft Windows [Version 10.0.19044.1645], locale en-US)
• Flutter version 2.13.0-0.0.pre.851 at C:\flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 2dd20a5a64 (3 hours ago), 2022-05-02 09:29:08 -0400
• Engine revision 66430ae6c1
• Dart version 2.18.0 (build 2.18.0-76.0.dev)
• DevTools version 2.12.2
[X] Android toolchain - develop for Android devices
X Unable to locate Android SDK.
Install Android Studio from: https://developer.android.com/studio/index.html
On first launch it will assist you in installing the Android SDK components.
(or visit https://flutter.dev/docs/get-started/install/windows#android-setup for detailed instructions).
If the Android SDK has been installed to a custom location, please use
`flutter config --android-sdk` to update to that location.
[√] Chrome - develop for the web
• Chrome at C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
[√] Visual Studio - develop for Windows (Visual Studio Community 2019 16.11.13)
• Visual Studio at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community
• Visual Studio Community 2019 version 16.11.32413.511
• Windows 10 SDK version 10.0.19041.0
[!] Android Studio (not installed)
• Android Studio not found; download from https://developer.android.com/studio/index.html
(or visit https://flutter.dev/docs/get-started/install/windows#android-setup for detailed instructions).
[√] VS Code, 64-bit edition (version 1.66.2)
• VS Code at C:\Program Files\Microsoft VS Code
• Flutter extension version 3.40.0
[√] Connected device (3 available)
• Windows (desktop) • windows • windows-x64 • Microsoft Windows [Version 10.0.19044.1645]
• Chrome (web) • chrome • web-javascript • Google Chrome 101.0.4951.41
• Edge (web) • edge • web-javascript • Microsoft Edge 99.0.1150.46
[√] HTTP Host Availability
• All required HTTP hosts are available
! Doctor found issues in 2 categories.
mono0926
Metadata
Metadata
Assignees
Labels
engineflutter/engine related. See also e: labels.flutter/engine related. See also e: labels.found in release: 2.13Found to occur in 2.13Found to occur in 2.13has reproducible stepsThe issue has been confirmed reproducible and is ready to work onThe issue has been confirmed reproducible and is ready to work onp: cameraThe camera pluginThe camera pluginpackageflutter/packages repository. See also p: labels.flutter/packages repository. See also p: labels.platform-windowsBuilding on or for Windows specificallyBuilding on or for Windows specificallyr: fixedIssue is closed as already fixed in a newer versionIssue is closed as already fixed in a newer version