In my current flutter project i need to record video, modified it and then show to user.
The problem is that in the iOS (14.2) the recorded video/modified can not be shown by video player, unfortunately there is no error from iOS (tested on physical devices).
Libraries and versions:
video_player: 1.0.1
flick_video_player: ^0.1.1
camera: ^0.5.8+17
flutter_ffmpeg: ^0.3.0
The reason why i do not use newest version of camera is that it is bugged and for certain number of devices there is no way to show even the preview.
Code:
Camera initialization
Future<void> _initCamera() async {
final cameras = await availableCameras();
final camera = cameras.firstWhereOrNull(
(element) => element.lensDirection == CameraLensDirection.back,
);
_controller = CameraController(
camera,
resolutionTarget,
enableAudio: false,
);
await _controller.initialize();
await _controller.prepareForVideoRecording();
//Show the preview
setState(() {});
}
Recording video
Future<void> startVideoRecording() async {
_videoPath = await generatePath(PathExtension.mp4);
await _controller.startVideoRecording(_videoPath);
}
Future<String> stopVideoRecording() async{
await _controller.stopVideoRecording();
return _videoPath;
}
Showing recorded video
void _createFlickManager(File videoFile) {
final videoController = VideoPlayerController.file(videoFile);
_flickManager = FlickManager(
videoPlayerController: videoController,
);
}
Widget _buildVideoPreview(){
return FlickVideoPlayer(
flickManager: _flickManager,
flickVideoWithControls:
FlickVideoWithControls(controls: Container()),
);
}
Summary:
the camera preview is showing properly,
the recording video file has size and does not throw any exception,
black screen when trying to show video using FlickVideoPlayer or just VideoPlayer,
converted video to mp4/mov by ffmpeg still not working.
Apparently in iOS 14.2 there is problem with paths that contains spaces, as i used DateTime.now()
to generate unique file name and that was reason of the problem. Changing it to DateTime.now().millisecond solved it.
Related
The audio works in the background as long as my bundle id is "dev.suragch.flutterAudioServiceDemo" (not mine)
but if I change bunde id to my "com.ambee.new":
— background stops working.
What's going on? How to make it work with my bundleId "com.ambee.new"?
This is my main.dart:
import 'package:audio_service/audio_service.dart';
import 'package:get_it/get_it.dart';
import 'package:audioplayers/audioplayers.dart' as audioplayers;
void main() async {
await setupServiceLocator();
final _audioHandler = getIt<AudioHandler>();
_audioHandler.play();
}
GetIt getIt = GetIt.instance;
Future<void> setupServiceLocator() async {
// services
getIt.registerSingleton<AudioHandler>(await initAudioService());
}
Future<AudioHandler> initAudioService() async {
return await AudioService.init(
builder: () => MyAudioHandler(),
config: AudioServiceConfig(
androidNotificationChannelId: 'com.mycompany.myapp.audio',
androidNotificationChannelName: 'Audio Service Demo',
androidNotificationOngoing: true,
androidStopForegroundOnPause: true,
),
);
}
class MyAudioHandler extends BaseAudioHandler {
final _player = audioplayers.AudioPlayer();
MyAudioHandler() {
_player.setReleaseMode(audioplayers.ReleaseMode.LOOP);
}
#override
Future<void> play() => _player.play(
'https://firebasestorage.googleapis.com/v0/b/ambee-cloud.appspot.com/o/Sound%2Fshort.wav?alt=media&token=bd7cc97f-d3d8-490b-9aff-b92df304e145');
}
You can reproduce the issue yourself by going to ios -> Runner.xcworkspace from this repo. Test the background audio loop with a physical iPhone, not simulator.
When you test it with this bundle ID in Xcode:
dev.suragch.flutterAudioServiceDemo: once you block the physical iPhone, it keeps looping the audio in background
com.ambee.new: once you block the physical iPhone, it STOPS looping the audio in background
It's because you need to add the background audio capability to your new bundle ID. Without this being added, the app doesn't have permission to play audio in the background.
You can find the documentation here: https://developer.apple.com/documentation/avfoundation/media_playback_and_selection/creating_a_basic_video_player_ios_and_tvos/enabling_background_audio
I am using the native camera (iOS/Android) calling as following:
async function takePhoto() {
const photo = await ImagePicker.launchCameraAsync(cameraOptions);
if (photo.cancelled) {
return '';
}
return photo.uri;
}
Since upgraded from Expo 39 to 42 it is broken (see screenshots)
Portrait
Landscape
It seems to me, that it is beeing opened as Modal. I don't know where to change this.
Expected behaviour:
Display of camera in fullscreen as native camera under iOS
Update: 20210730: Meanwhile it has been opend as a bug/issue:
https://github.com/expo/expo/issues/13614
Any ideas, suggestions - especially in terms of a workaround?
Thanks a lot.
I've done a massive upgrade from EXPO SDK 37 to EXPO SDK 42. Had to change alot of things around camera, location and permissions.
I do not experience this behavior when using the following (I cannot see your import statements or your package versions but this is what I've implemented and experience no issue)
// Import statements...
import * as ImagePicker from 'expo-image-picker';
import * as FileSystem from 'expo-file-system';
import { Camera } from 'expo-camera';
// Code within Component
const takePicture = async () => {
// You MUST ask for permissions first.
const permissions = {
[Camera]: await Camera.requestPermissionsAsync()
};
// If denied let the user know its required.
if (permissions[Camera].status !== 'granted') {
return Promise.reject(new Error('Camera Permission Required'));
}
// Then let them launch the camera and perform any other task
await ImagePicker.launchCameraAsync({
allowsEditing: false
})
.then(({ uri }) => imageProcesser(uri))
.then(res => onImageAdded(res))
.catch((e) => console.log(e));
};
// These are my concerning package versions
"expo-camera": "^11.2.2"
"expo-file-system": "~11.1.3",
"expo-image-picker": "~10.2.2",
"expo": "^42.0.3"
I'm using qr_code_scanner to scan barcodes in my Flutter app and it works fine for Android, but when I try to scan for iOS a pop-up appears and looks like:
I'm using the descriptions Flutter code that looks like the following:
QRView(
key: qrKey,
onQRViewCreated: (controller) => {
controller.scannedDataStream.listen((code) async {
...
})
})
And in my Info.plist file I have the following fields:
<key>io.flutter.embedded_views_preview</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>Camera permission is required to scan QR codes.</string>
However even with these settings set, I can't seem to figure out how to have access to the camera. Thanks for any help.
Update
I followed #EvgeniyTrubilo suggestion and used permission_handler to request permission using the following code:
void getCameraPermission() async {
print(await Permission.camera.status); // prints PermissionStatus.granted
var status = await Permission.camera.status;
if (!status.isGranted) {
final result = await Permission.camera.request();
if (result.isGranted) {
setState(() {
canShowQRScanner = true;
});
} else {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text('Please enable camera to scan barcodes')));
Navigator.of(context).pop();
}
} else {
setState(() {
canShowQRScanner = true;
});
}
}
The first time this code was executed it successfully requested permission to access camera, and once permission was granted, the same error showed up. Sequential tries the print statement at the top of the above function said the Permission was granted??
Update 2x
Just realized you can mock the camera in an iOS simulator like you can on Android. I will try this on an actual device and update.
You can use permission_handler. With this, you could ask for camera permission before build QRView. Of course, you should build QRView after camera permission is enabled.
I'm not sure it would be right solution for your issue, but I think that would be an awesome improvement.
following the instructions from:
https://codingwithjoe.com/playing-audio-from-the-web-and-http/ (using his example and AudioProvider class)
I have been using:
audioplayer: ^0.8.1
audioplayer_web: ^0.7.1
to play audio from https link.
The problem it has some weird inconsistent effect.
- after playing few audio, it keeps on playing the same audio eventhough new url is loaded
- after playing few audio, the sound is weird like some part is cut with other audio.
What is a good audio player that accepts url link for flutter that can produce a consistent result ?
the provided audioplayer from your example works great and has good features. From what you are describing for me it seems like you're not closing the session when you play a sound. It seems like you are stacking the sounds which causes weird sounds.
You have to close the instance then. even though the article is outdated (march 2018) the audioplayer has developed further. check their offical guide here:
https://pub.dev/packages/audioplayer
This is version audioplayer 0.8.1 not 3.0 or something..
Example from docs:
Instantiate an AudioPlayer instance
//...
AudioPlayer audioPlugin = AudioPlayer();
//...
Player controls:
audioPlayer.play(url);
audioPlayer.pause();
audioPlayer.stop();
status and current position:
//...
_positionSubscription = audioPlayer.onAudioPositionChanged.listen(
(p) => setState(() => position = p)
);
_audioPlayerStateSubscription = audioPlayer.onPlayerStateChanged.listen((s) {
if (s == AudioPlayerState.PLAYING) {
setState(() => duration = audioPlayer.duration);
} else if (s == AudioPlayerState.STOPPED) {
onComplete();
setState(() {
position = duration;
});
}
}, onError: (msg) {
setState(() {
playerState = PlayerState.stopped;
duration = new Duration(seconds: 0);
position = new Duration(seconds: 0);
});
});
Like I said most of the audio plugins are running in singleton mode with instances. To provide getting weird effects you have to load the next song in the same instance, don't open another new instance, and you wont get any weird effects.
If you want to switch to a different audio player another great one which I used in an app project is the following:
https://pub.dev/packages/audio_manager#-readme-tab-
Hope it helps.
I followed this blog for taking photos from the gallery and camera. But the selected picture is showing in right rotated form when it comes to the UI in IOS. Problem only occurs when using the camera and I have no issues with the gallery. This feature is working fine in android and UWP.
Screenshot added below:
Code of Camera:
async void CameraClick()
{
try
{
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert("Camera", "No camera available.", "OK");
return;
}
_mediaFile = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
Directory = "Sample",
Name = "test.jpg",
AllowCropping = true
});
if (_mediaFile == null)
return;
profileImage.Source = ImageSource.FromStream(() =>
{
isPicture = true;
return _mediaFile.GetStream();
});
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Exception:>" + ex);
}
}
Device : IOS SE
Version of the media plugin: 3.1.1
Control I am using to display the image : Xam.plugins.Forms.Imagecircle 2.0.2(For android and UWP I am using 1.8.1)
Gallery pictures are working fine and the issue is only when taking pictures using the camera. No issues in android and UWP part.
Cause:
This is a common experience even outside of Xamarin. It is caused by iOS.
A UIImage has a property imageOrientation, which instructs the
UIImageView and other UIImage consumers to rotate the raw image data.
There's a good chance that this flag is being saved to the exif data
in the uploaded jpeg image, but the program you use to view it is not
honoring that flag.
Solution:
In the Issues part in jamesmontemagno/MediaPlugin in Github, there are several issues like the problem you meet. Seems using GetStreamWithImageRotatedForExternalStorage will fix this issue.
You can refer to:
https://github.com/jamesmontemagno/MediaPlugin/issues/333
In another way, you can rotate the image yourself.
Here are some links that might help you:
iOS Image Orientation has Strange Behavior
iOS UIImagePickerController result image orientation after upload
iOS: Image get rotated 90 degree after saved as PNG representation data
I faced this problem in the last few months on iOS.
The solution for this is add one more line in your code that is:- SaveMetaData = false,
async void CameraClick()
{
try
{
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert("Camera", "No camera available.", "OK");
return;
}
_mediaFile = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
Directory = "Sample",
Name = "test.jpg",
AllowCropping = true,
SaveMetaData = false
});
if (_mediaFile == null)
return;
profileImage.Source = ImageSource.FromStream(() =>
{
isPicture = true;
return _mediaFile.GetStream();
});
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Exception:>" + ex);
}
}