Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,31 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.io.File;

import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.EventChannel.EventSink;
import io.flutter.plugin.common.EventChannel.StreamHandler;

class FlutterVideoView implements PlatformView, MethodChannel.MethodCallHandler, MediaPlayer.EventListener {
class FlutterVideoView implements PlatformView, MethodChannel.MethodCallHandler,StreamHandler, MediaPlayer.EventListener {
private final MethodChannel channel;
private final EventChannel eventChannel;
private final Context context;

private MediaPlayer mediaPlayer;
private TextureView textureView;
private String url;
private String subtitle;
private Boolean isLocal;
private int duration;
private int position;
private EventSink events;
private Boolean isPlaying;
private float rate;
private IVLCVout vout;
private MethodChannel.Result result;
private boolean replyAlreadySubmitted = false;
Expand All @@ -43,7 +55,9 @@ public FlutterVideoView(Context context, BinaryMessenger messenger, int id) {
SurfaceTexture texture = new SurfaceTexture(false);
textureView.setSurfaceTexture(texture);
channel = new MethodChannel(messenger, "flutter_video_plugin/getVideoView_" + id);
eventChannel = new EventChannel(messenger, "flutter_video_plugin/event_"+id);
channel.setMethodCallHandler(this);
eventChannel.setStreamHandler(this);
}

@Override
Expand All @@ -57,6 +71,16 @@ public void dispose() {
vout.detachViews();
}

@Override
public void onListen(Object arguments, EventSink events) {
this.events = events;
}

@Override
public void onCancel(Object arguments) {
this.events=null;
}


@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
Expand All @@ -67,14 +91,23 @@ public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
textureView = new TextureView(context);
}
url = methodCall.argument("url");
isLocal = methodCall.argument("isLocal");
subtitle = methodCall.argument("subtitle");

ArrayList<String> options = new ArrayList<>();
options.add("--no-drop-late-frames");
options.add("--no-skip-frames");
options.add("--rtsp-tcp");

LibVLC libVLC = new LibVLC(context, options);
Media media = new Media(libVLC, Uri.parse(Uri.decode(url)));
Media media = null;
if (isLocal)
media = new Media(libVLC, Uri.fromFile(new File(url)));
else {
options.add("--rtsp-tcp");
media = new Media(libVLC, Uri.parse(Uri.decode(url)));
}
media.setHWDecoderEnabled(true, true);

mediaPlayer = new MediaPlayer(libVLC);
mediaPlayer.setVideoTrackEnabled(true);
vout = mediaPlayer.getVLCVout();
Expand All @@ -84,6 +117,9 @@ public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {

vout.attachViews();
mediaPlayer.setMedia(media);
if (!subtitle.isEmpty())
mediaPlayer.addSlave(Media.Slave.Type.Subtitle, subtitle, true);

mediaPlayer.setEventListener(this);
mediaPlayer.play();
break;
Expand Down Expand Up @@ -112,6 +148,39 @@ public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
mediaPlayer.play();
}
break;
case "pause":
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
break;
case "play":
if (!mediaPlayer.isPlaying()) {
mediaPlayer.play();
}
break;
case "isPlaying":
result.success(mediaPlayer.isPlaying());
break;
case "setRate":
rate = methodCall.argument("rate");
mediaPlayer.setRate(rate);
break;
case "getRate":
rate = mediaPlayer.getRate();
result.success(rate);
break;
case "getDuration":
duration = (int)mediaPlayer.getLength();
result.success(duration);
break;
case "getPosition":
position = (int)mediaPlayer.getTime();
result.success(position);
break;
case "addSubtitle":
subtitle = methodCall.argument("subtitle");
mediaPlayer.addSlave(Media.Slave.Type.Subtitle, subtitle, true);
break;
}
}

Expand All @@ -120,6 +189,21 @@ public void onEvent(MediaPlayer.Event event) {
Map<String, String> resultMap = new HashMap<>();

switch (event.type) {
case MediaPlayer.Event.EndReached:
if (this.events!=null){
resultMap.put("status", "end");
resultMap.put("value", "");
events.success(resultMap);
}
break;
case MediaPlayer.Event.PositionChanged:
if (this.events!=null){
float pos = event.getPositionChanged();
resultMap.put("status", "pos");
resultMap.put("value", Float.toString(pos));
events.success(resultMap);
}
break;
case MediaPlayer.Event.Vout:
String aspectRatio;
int height = 0;
Expand Down
6 changes: 5 additions & 1 deletion lib/vlc_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ class VlcPlayer extends StatefulWidget {
final int defaultHeight;
final int defaultWidth;
final String url;
final bool isLocal;
final String subtitle;
final Widget placeholder;
final VlcPlayerController controller;

Expand All @@ -17,6 +19,8 @@ class VlcPlayer extends StatefulWidget {
@required this.defaultHeight,
@required this.defaultWidth,
@required this.url,
this.isLocal=false,
this.subtitle='',
@required this.controller,
this.placeholder,
});
Expand Down Expand Up @@ -71,7 +75,7 @@ class _VlcPlayerState extends State<VlcPlayer> {
_controller.initView(id);
if (_controller.hasClients) {
String aspectRatioString = await _controller.setStreamUrl(
widget.url, widget.defaultHeight, widget.defaultWidth);
widget.url, widget.isLocal, widget.subtitle, widget.defaultHeight, widget.defaultWidth);
setState(() {
readyToShow = true;
});
Expand Down
66 changes: 61 additions & 5 deletions lib/vlc_player_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,43 @@ import 'dart:io';
import 'dart:typed_data';
import 'package:cryptoutils/cryptoutils.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';

typedef StatusChanged<T> = void Function(String status, T value);

class VlcPlayerController {
MethodChannel _channel;
EventChannel _eventChannel;

StatusChanged<dynamic> onStatusChanged;

bool hasClients = false;

VlcPlayerController({
Key key,
this.onStatusChanged=null
});

initView(int id) {
_channel = MethodChannel("flutter_video_plugin/getVideoView_$id");
_eventChannel = EventChannel("flutter_video_plugin/event_$id");
_eventChannel.receiveBroadcastStream().listen((dynamic event)
{
if (onStatusChanged!=null){

String status=event['status'];
onStatusChanged(status, event['value']);
}
}
);

hasClients = true;
}

Future<String> setStreamUrl(
String url, int defaultHeight, int defaultWidth) async {
var result = await _channel.invokeMethod("playVideo", {
'url': url,
});
Future<String> setStreamUrl(String url, bool isLocal, String subtitle,
int defaultHeight, int defaultWidth) async {
var result = await _channel.invokeMethod(
"playVideo", {'url': url, 'isLocal': isLocal, 'subtitle': subtitle});
return result['aspectRatio'];
}

Expand All @@ -27,6 +49,40 @@ class VlcPlayerController {
return imageBytes;
}

Future<void> play() async {
var result = await _channel.invokeMethod("play");
}

Future<void> pause() async {
var result = await _channel.invokeMethod("pause");
}

Future<bool> isPlaying() async {
var result = await _channel.invokeMethod("isPlaying");
return result;
}

Future<int> getDuration() async {
var result = await _channel.invokeMethod("getDuration");
return result;
}

Future<int> getPosition() async {
var result = await _channel.invokeMethod("getPosition");
return result;
}

Future<void> setRate(double rate) async {
var result = await _channel.invokeMethod("setRate", {
'rate': rate,
});
}

Future<double> getRate() async {
var result = await _channel.invokeMethod("getRate");
return result;
}

void dispose() {
if (Platform.isIOS) {
_channel.invokeMethod("dispose");
Expand Down