Воспроизведение мультимедиа Flutter — аудио/видео
Привет всем разработчикам флаттера
В вашей повседневной разработке вы можете столкнуться с проблемой воспроизведения мультимедиа, как воспроизвести удаленное видео или аудио, любые проблемы с воспроизведением,
Здесь мы увидим, как играть Video
а также Audio
файл из Интернета, Активы и Локальные.
В этом демо я буду использовать три плагина.
video_player
audioplayers
file_picker
Итак, используя эти три плагина, мы собираемся создать демонстрационный проект для MediaPlayBack.
Давайте начнем,
Зависимости
Добавьте следующие зависимости в pubspec.yaml
video_player: ^0.10.2+1
file_picker: ^1.4.0
audioplayers: ^0.13.2
Сначала мы видим, как воспроизводить видео, затем переходим к аудио.
видео
Вот как продвигаться с видео
Разрешение
Предупреждение: видеопроигрыватель не работает на симуляторах iOS. Во время разработки/тестирования необходимо использовать устройство iOS.
Добавьте следующую запись в файл Info.plist, расположенный в папке
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Добавьте ниже разрешение в iOS для file_picker
<key>NSAppleMusicUsageDescription</key>
<string>Explain why your app uses music</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Explain why your app uses photo library</string>
Убедитесь, что в вашем файле манифеста Android, расположенном в
<uses-permission android:name="android.permission.INTERNET"/>
Поддерживаемые форматы
В iOS вспомогательным проигрывателем является AVPlayer. Поддерживаемые форматы различаются в зависимости от версии iOS. Класс AVURLAsset имеет audiovisualTypes, которые вы можете запрашивать для поддерживаемых форматов av.
На Android вспомогательным проигрывателем является ExoPlayer, список поддерживаемых форматов см. здесь.
Видео из Интернета
Объявите в своем коде переменную, которая VideoPlayerController
этот мы собираемся использовать с ним VideoPlayer
VideoPlayerController _videoPlayerController = VideoPlayerController.network(
"https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_2mb.mp4",);
Теперь, чтобы инициализировать контроллер, вызовите это в initState
@override
void initState() {
super.initState();
_videoPlayerController
..initialize().then((_) {
setState(() {});
});
_videoPlayerController..addListener(() {
setState(() {
});
});
}
Теперь, чтобы визуализировать Player, нам нужно добавить код пользовательского интерфейса.
_videoPlayerController.value.initialized
? AspectRatio(
aspectRatio: _videoPlayerController.value.aspectRatio,
child: VideoPlayer(_videoPlayerController),
)
: Container(),
В приведенном выше коде мы сделали следующее. После инициализации проигрывателя мы показываем VideoPlayer
но мы используем AspectRatio
тот используется для автоматического изменения размера видео по высоте и ширине
По умолчанию VideoPlayer не предоставляет элементы управления для использования, которые нам нужны для разработки и обработки их самостоятельно.
Center(
child: IconButton(
icon: Icon(
_videoPlayerController.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
onPressed: () {
_videoPlayerController.value.isPlaying ? _videoPlayerController.pause() : _videoPlayerController.play();
setState(() {
});
},
),
)
здесь в приведенном выше коде _videoPlayerController.play()
начнется воспроизведение видео _videoPlayerController.pause()
поставит плеер на паузу
@override
void dispose() {
_videoPlayerController.removeListener(() {});
_videoPlayerController.dispose();
super.dispose();
}
Вот полный код для воспроизведения видео из Интернета
import 'package:video_player/video_player.dart';
import 'package:flutter/material.dart';
class VideoNetwork extends StatefulWidget {
@override
_VideoNetworkState createState() => _VideoNetworkState();
}
class _VideoNetworkState extends State<VideoNetwork> {
VideoPlayerController _videoPlayerController = VideoPlayerController.network(
"https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_2mb.mp4",);
@override
void initState() {
super.initState();
_videoPlayerController
..initialize().then((_) {
_videoPlayerController.setLooping(true);
setState(() {});
});
_videoPlayerController..addListener(() {
setState(() {
});
});
}
@override
void dispose() {
_videoPlayerController.removeListener(() {});
_videoPlayerController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Video From Network"),
),
body: Center(
child: Column(
children: <Widget>[
_videoPlayerController.value.initialized
? AspectRatio(
aspectRatio: _videoPlayerController.value.aspectRatio,
child: VideoPlayer(_videoPlayerController),
)
: Container(),
Center(
child: IconButton(
icon: Icon(
_videoPlayerController.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
onPressed: () {
_videoPlayerController.value.isPlaying ? _videoPlayerController.pause() : _videoPlayerController.play();
setState(() {
});
},
),
)
],
),
),
);
}
}
Видео из активов
Единственное существенное различие между воспроизведением видео из интернета и активами — это VideoPlayerController
часть
VideoPlayerController _videoPlayerController = VideoPlayerController.asset(
"assets/video.mp4",);
Для воспроизведения видео из активов вместо VideoPlayerController.network
мы используем VideoPlayerController.asset
а в остальном все работает как указано выше
Видео из файла
Единственным существенным отличием между воспроизведением видео из Интернета и локального является VideoPlayerController
часть
VideoPlayerController _videoPlayerController = VideoPlayerController.file(videoFile);
Для воспроизведения видео с Local вместо VideoPlayerController.network
мы используем VideoPlayerController.file
а в остальном все работает как указано выше
Итак, чтобы получить файл, мы будем использовать file_picker
плагин
Выберите видеофайл
_pickVideoFileFrom(context) async {
File videoFile = await FilePicker.getFile(type: FileType.VIDEO);
if (videoFile == null) {
print("Video Picked is null");
}
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return VideoFile(
file: videoFile,
);
}));
}
Приведенный выше код работает, чтобы выбрать файл из локального хранилища и передать файл на новую страницу, где будет воспроизводиться видео.
File videoFile = await FilePicker.getFile(type: FileType.VIDEO);
этот код указывает, какой тип файла я должен получить. Для видео мы использовали FileType.VIDEO
и для аудио мы будем использовать FileType.AUDIO
окончательный, но важный dispose
@override
void dispose() {
_videoPlayerController.removeListener(() {});
_videoPlayerController.dispose();
super.dispose();
}
Аудио
Начнем с аудио
AudioPlayer для удаленных файлов
Инициализировать аудиоплеер
AudioPlayer audioPlayer = AudioPlayer();
чтобы начать воспроизведение удаленного вызова файла
await audioPlayer.play(
"https://file-examples.com/wp-content/uploads/2017/11/file_example_MP3_2MG.mp3");
приостановить или возобновить
audioPlayer.pause();
await audioPlayer.resume();
Примечание. Этот плагин не предоставляет никакого пользовательского интерфейса для вашего плеера, нам нужно создать пользовательский интерфейс самостоятельно.
Чтобы прослушать состояние игрока, нам нужно прослушать onPlayerStateChanged
audioPlayer.onPlayerStateChanged.listen((AudioPlayerState state) {
print("$state");
});
Чтобы прослушать обновления продолжительности проигрывателя, нам нужно прослушать onPlayerStateChanged
audioPlayer.onAudioPositionChanged.listen((Duration p) async {
print('Current position: $p');
});
Чтобы получить длину песни, используйте audioPlayer.getDuration()
await audioPlayer.getDuration();
окончательный, но важный dispose
@override
void dispose() async {
await audioPlayer.release();
await audioPlayer.dispose();
super.dispose();
}
Вот полный код AudioPlayer — Воспроизведение из Интернета
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
class AudioNetwork extends StatefulWidget {
@override
_AudioNetworkState createState() => _AudioNetworkState();
}
class _AudioNetworkState extends State<AudioNetwork> {
AudioPlayer audioPlayer = AudioPlayer();
bool isPlaying = false;
bool isStarted = false;
Duration duration;
int time;
String timeLeft = "";
double progress = 0.0;
startPlaying() async {
if (!isStarted) {
await audioPlayer.play(
"https://file-examples.com/wp-content/uploads/2017/11/file_example_MP3_2MG.mp3");
isStarted = true;
} else
await audioPlayer.resume();
}
getTimeLeft() {
if (duration == null) {
setState(() {
timeLeft = "Time Left 0s";
});
} else {
setState(() {
timeLeft = "Time Left ${duration.inSeconds}s";
});
}
}
getProgress() {
if (time == null || duration == null) {
setState(() {
progress = 0.0;
});
} else {
setState(() {
progress = time / (duration.inMilliseconds);
});
}
}
@override
void initState() {
super.initState();
audioPlayer.onAudioPositionChanged.listen((Duration p) async {
print('Current position: $p');
time = await audioPlayer.getDuration();
duration = p;
if (duration == null) {
timeLeft = "Time Left 0s/0s";
} else {
timeLeft = "Time Left ${duration.inSeconds}s/${time / 1000}s";
}
if (time == null || duration == null) {
progress = 0.0;
} else {
progress = (duration.inMilliseconds) / time;
}
print(progress);
setState(() {});
});
audioPlayer.onPlayerStateChanged.listen((AudioPlayerState state) {
print("$state");
if (state == AudioPlayerState.PLAYING) {
setState(() {
isPlaying = true;
});
} else {
if (mounted) {
setState(() {
isPlaying = false;
});
}
}
});
}
@override
void dispose() async {
await audioPlayer.release();
await audioPlayer.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Audio Player"),
),
body: Container(
padding: const EdgeInsets.all(16.0),
child: Center(
child: Column(
children: <Widget>[
LinearProgressIndicator(
value: progress,
),
SizedBox(
height: 16.0,
),
Text(timeLeft),
SizedBox(
height: 16.0,
),
Center(
child: IconButton(
icon: Icon(
isPlaying ? Icons.pause : Icons.play_arrow,
),
onPressed: () {
isPlaying ? audioPlayer.pause() : startPlaying();
setState(() {});
},
),
)
],
),
),
),
);
}
}
AudioPlayer для локальных файлов
Основное отличие от воспроизведения удаленных файлов и локальных файлов заключается только в том, как мы начинаем воспроизведение, в то время, когда мы вызываем play
нам нужно передать еще один параметр с именем isLoacal
воспроизвести локальный файл
Прежде всего нам нужно выбрать файл и отправить его на страницу AudioPlayer, где он будет воспроизводиться.
_pickAudioFileFrom(context) async {
File audioFile = await FilePicker.getFile(type: FileType.AUDIO);
if (audioFile == null) {
print("Audio Picked is null");
}
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return AudioLocal(
file: audioFile,
);
}));
}
Воспроизведение аудиофайла
await audioPlayer.play(audioFile.path, isLocal: true);
окончательный, но важный dispose
@override
void dispose() async {
await audioPlayer.release();
await audioPlayer.dispose();
super.dispose();
}
Я предоставлю ссылку на github внизу
AudioPlayer для активов
Воспроизведение аудиофайла из ресурсов отличается от других режимов
Инициализировать аудиоплеер
static AudioPlayer audioPlayer = AudioPlayer();
AudioCache audioPlayerCache = AudioCache(
fixedPlayer: audioPlayer
);
чтобы начать воспроизведение удаленного вызова файла
await audioPlayerCache.play("audio.mp3");
Остальные все такие же, как и в других режимах
окончательный, но важный dispose
@override
void dispose() async {
await audioPlayer.release();
await audioPlayer.dispose();
super.dispose();
}
Вот полный код AudioPlayer — Воспроизведение из активов
import 'package:audioplayers/audio_cache.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
class AudioAssets extends StatefulWidget {
@override
_AudioAssetsState createState() => _AudioAssetsState();
}
class _AudioAssetsState extends State<AudioAssets> {
static AudioPlayer audioPlayer = AudioPlayer();
AudioCache audioPlayerCache = AudioCache(
fixedPlayer: audioPlayer
);
bool isPlaying = false;
bool isStarted = false;
Duration duration;
int time;
String timeLeft = "";
double progress = 0.0;
startPlaying() async{
if(!isStarted) {
await audioPlayerCache.play(
"audio.mp3");
isStarted = true;
}
else await audioPlayer.resume();
}
getTimeLeft() {
if(duration == null) {
setState(() {
timeLeft = "Time Left 0s";
});
} else {
setState(() {
timeLeft = "Time Left ${duration.inSeconds}s";
});
}
}
getProgress() {
if(time == null || duration == null) {
setState(() {
progress = 0.0;
});
} else {
setState(() {
progress = time / (duration.inMilliseconds);
});
}
}
@override
void initState() {
super.initState();
audioPlayer.onAudioPositionChanged.listen((Duration p) async {
print('Current position: $p');
time = await audioPlayer.getDuration();
duration = p;
if(duration == null) {
timeLeft = "Time Left 0s/0s";
} else {
timeLeft = "Time Left ${duration.inSeconds}s/${time/1000}s";
}
if(time == null || duration == null) {
progress = 0.0;
} else {
progress = (duration.inMilliseconds)/ time ;
}
print(progress);
setState(() {
});
});
audioPlayer.onPlayerStateChanged.listen((AudioPlayerState state) {
print("$state");
if (state == AudioPlayerState.PLAYING) {
setState(() {
isPlaying = true;
});
} else {
if(mounted) {
setState(() {
isPlaying = false;
});
}
}
});
}
@override
void dispose() async {
await audioPlayer.release();
await audioPlayer.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Audio Player"),
),
body: Container(
padding: const EdgeInsets.all(16.0),
child: Center(
child: Column(
children: <Widget>[
LinearProgressIndicator(
value: progress,
),
SizedBox(
height: 16.0,
),
Text(timeLeft),
SizedBox(
height: 16.0,
),
Center(
child: IconButton(
icon: Icon(
isPlaying ? Icons.pause : Icons.play_arrow,
),
onPressed: () {
isPlaying ? audioPlayer.pause() : startPlaying();
setState(() {});
},
),
)
],
),
),
),
);
}
}