VideoPlayerController.networkUrl(Uri.parse('http://172.30.1.60:8080/video'))
안드로이드에서 http 를 통해 동영상 받아오는 코드
안드로이드
android/app/src/main/AndroidManifest.xml
경로에
<uses-permission android:name="android.permission.INTERNET" />
<!-- 네트워크 상태 확인 권한 (선택 사항) -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
권한 추가.
또 기본적으로 안드로이드는 https 와 통신하도록 설정되어있으므로 http 를 받아오는 것이 불가능하지만, 이걸 가능하도록 해주는 설정 추가해야한다.
<application
android:networkSecurityConfig="@xml/network_security_config"
android:usesCleartextTraffic="true">
이 두 줄의 권한을 추가해준다.
추가로
android/app/src/main/res
경로에 xml 폴더를 추가한 뒤 특정 도메인에 대한 접근 허용 파일을 추가해야 한다.
파일 이름
허용을 추가할 도메인을 파일에 작성해줌
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">172.30.1.60</domain>
</domain-config>
</network-security-config>
이러면 해당 도메인에 대한 http 접근이 허용된다.
기본적으로 video player 의
ExoPlayer 가 처리할 수 있는 것들은
MP4, HLS, DASH 파일이 있음.
이 것을 확인하기 위해 http 가 제공하는 도메인의 형식을 확인 해야 한다.
도메인의 형식을 확인하려면 http 의 헤더안의 content-type 을 확인해보면 되는데,
Future<void> getStreamInfo() async {
final response = await http.head(Uri.parse('http://172.30.1.60:8080/video'));
print('Content-Type: ${response.headers['content-type']}');
}
이 코드를 통해 확인할 수 있다.
응답 헤더에는 Content-Type이 포함되어 있으며, 이를 통해 스트림의 MIME 유형을 알 수 있다.
Content-Type
이런식으로 되어있어야 받기가 가능.
// / Stateful widget to fetch and then display video content.
class VideoApp extends StatefulWidget {
const VideoApp({super.key});
@override
_VideoAppState createState() => _VideoAppState();
}
class _VideoAppState extends State<VideoApp> {
late VideoPlayerController _controller;
Future<void> getStreamInfo() async {
final response = await http.head(Uri.parse('http://172.30.1.60:8080/video'));
print('Content-Type: ${response.headers['content-type']}');
}
@override
void initState() {
super.initState();
getStreamInfo();
_controller = VideoPlayerController.networkUrl(
Uri.parse('http://172.30.1.60:8080/video'))
..initialize().then((_) {
_controller.setLooping(true);
_controller.play();
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: _controller.value.isInitialized
? AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
)
: Container(),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_controller.value.isPlaying
? _controller.pause()
: _controller.play();
});
},
child: Icon(
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
사용 예시
Content-Type: multipart/x-mixed-replace
을 스트리밍 처리할 수 있는 라이브러리.
dependencies: flutter: sdk: flutter flutter_mjpeg: ^2.0.4
최신 버전이 2.0.4
이거 사용하려면 http 최신버전을 사용하지 못하는 듯 하다.
http: ^0.13.6
글쓰는 날짜 기준
1.0.0 이상을 사용하지 못하는 듯. 충돌이 발생함
class MjpegStreamScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('MJPEG Stream'),
),
body: Center(
child: Mjpeg(
stream: 'http://172.23.248.9:8080/video',
isLive: true,
),
),
);
}
}
간단하게 사용 가능.
권한도 필요 없는 듯 하다