Flutter - how do I get the duration of a picked video file on Web? - flutter-web

I've tried everything and failed to determine the duration of a picked video file on Flutter Web. All libraries on pub.dev need a 'File' and this is not available on the web.
I've not been able to get this from the metadata either.

What worked for me, though I am unhappy with the solution approach is:
Widget buildHiddenVideoPlayer(Key key) {
var _videoElement = html.VideoElement();
_videoElement.id = 'htmlHiddenVideoID';
_videoElement.autoplay = true;
_videoElement.muted = true;
_videoElement.loop = true;
_videoElement.controls = false;
_videoElement.defaultMuted = true;
if (fileData != null) {
_videoElement.src = xfile.path; // where xfile is the file picked as XFile
}
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
'htmlHiddenVideoID',
(int viewId) => _videoElement,
);
return HtmlElementView(
key: key,
viewType: 'htmlHiddenVideoID',
);
}
This widget is hidden in a 5 x 5 sized box behind a iFrame widget (in my implementation)
Then when I need the duration of a picked file:
VideoElement element = document.getElementById('htmlHiddenVideoID') as VideoElement;
setState(() {
element.src = pickedFile.path;
});
while (true) {
await Future.delayed(const Duration(milliseconds: 200), () {});
duration = element.duration;
if (!duration.isNaN) break; // duration is not returned immediately in many cases
}
element.pause(); // stops the hidden video from playing and consuming resources

Related

Reusing a function for buttons that work independently of each other?

I'm trying to create something with P5.js that resembles an audio looper—that is, you record a snippet of audio, it plays back to you as a loop, and then you can record other snippets of audio to play together to create a song.
I figured out how to record audio, play it back as a loop, and stop the loop, but I'm not sure the best way to repeat that function so that it can be used for buttons that function independently of each other and record separate audio files, as I would like to record multiple loops.
I'm still pretty new to P5.js, so there's probably a simple way to do this—any ideas help! In general, if you have any ideas on how to achieve this project as a whole (the audio looper) I'd love to hear them.
This is my code:
let mic, recorder, soundFile, button;
let state = 0;
function setup() {
createCanvas(windowWidth, windowHeight);
background(200);
mic = new p5.AudioIn();
mic.start();
recorder = new p5.SoundRecorder();
recorder.setInput(mic);
soundFile = new p5.SoundFile();
button = createButton("record");
button.size(200, 100);
button.style("font-family", "Bodoni");
button.style("font-size", "48px");
button.position(10, 10, 10);
button.mouseClicked(loopRecord);
}
// this is the looper
function loopRecord() {
if (state === 0 && mic.enabled) {
recorder.record(soundFile);
background(255, 0, 0);
state++;
} else if (state === 1) {
recorder.stop();
background(0, 255, 0);
state++;
} else if (state === 2) {
soundFile.loop();
state++;
} else if (state === 3) {
soundFile.stop();
state++;
} else if (state === 4) {
state === 0;
}
}
You should somehow structure your data so that each button has its own state (and other parameters that should not be global, but instead unique to each loop).
Here an example using an array of track objects:
https://editor.p5js.org/RemyDekor/sketches/gM75vBYmk
I'll copy the code here as well
let mic
// this array will be filled afterwards
let tracksArray = [];
function setup() {
createCanvas(400, 400);
background(200);
// we need only one mic (it is still global)
mic = new p5.AudioIn();
mic.start();
// we call a function that creates a custom "track" object and puts it in the tracksArray (which you could use for some other things, but is currently un-used)
createTrack();
// we create a button that call the same function when we click on it
const addTrackButton = createButton("add track");
addTrackButton.mouseClicked(createTrack)
addTrackButton.position(10, 10)
}
// We now use names (strings) instead of abstract numbers to set the state of the track
function handleTrackButtonClick(trackObject) {
if (trackObject.state === "idle" && mic.enabled) {
trackObject.recorder.record(trackObject.soundFile);
background(255, 0, 0);
trackObject.state = "recording";
console.dir(trackObject.button.elt.innerText = "[recording..]");
} else if (trackObject.state === "recording") {
trackObject.recorder.stop();
background(0, 255, 0);
trackObject.state = "stopped";
console.dir(trackObject.button.elt.innerText = "play");
} else if (trackObject.state === "stopped") {
trackObject.soundFile.loop();
trackObject.state = "playing";
console.dir(trackObject.button.elt.innerText = "[playing..] stop")
} else if (trackObject.state === "playing") {
trackObject.soundFile.stop();
trackObject.state = "stopped";
console.dir(trackObject.button.elt.innerText = "[stopped..] play")
}
}
function createTrack() {
const newButton = createButton("record");
newButton.style("font-family", "Bodoni");
newButton.style("font-size", "48px");
// we do not position this button anymore, and use the "flow" of the html document
newButton.style("display", "block");
// this is the "track" object we create, and we attach the previously global parameters/states on it
const newTrackObject = {
button: newButton,
state: "idle",
recorder: new p5.SoundRecorder(),
soundFile: new p5.SoundFile()
};
newButton.mouseClicked(function() {
handleTrackButtonClick(newTrackObject)
});
newTrackObject.recorder.setInput(mic);
tracksArray.push(newTrackObject);
}

how can i get the recorded file length in ionic?

I am using ionic cordova media plugin to record audio from the user's phone. Once recorded i get the file to play and everything is fine. I just want to get the duration of the file and when i play the recorded file i want to show the minutes::seconds of the file being played. How do i do that?
record_audio(){
this.file.startRecord();
this.recording = true;
/*
let record_opt: CaptureAudioOptions = { limit: 1 };
this.mediacapture.captureAudio(record_opt).then(
(data: MediaFile[]) => alert('audio recorded'),
(err: CaptureError)=> alert('cannot record')
);
*/
}
cancel_record(){
this.file.release();
this.show_record_div = false;
this.recordedfile_available = false;
}
stop_recording(){
this.file.stopRecord();
this.recording = false;
this.recordedfile_available = true;
//this.filelength = this.file.getDuration();
}
play_recorded(){
this.file.play();
}
stop_playing(){
this.file.stop();
}
try this.
let duration = this.file.getDuration();
console.log(duration);
// get current playback position
file.getCurrentPosition().then((position) => {
console.log(position);
});

Phaserjs, sprite overlap, not working

I am new to Phaserjs, trying to create basic drag-drop style game.
I have created the game and add arcade physics (this.game.physics.arcade.enable(this.orange_outline);)
Currently overlap happen as soon as the edges collide.
I want to detect that my code should trigger when 50% overlap happen. is it possible in phaserjs?
var GameState = {
init:function(){
this.physics.startSystem(Phaser.Physics.ARCADE);
},
create: function () {
this.background = this.game.add.sprite(0, 0, 'background');
this.overlapHappen = false;
this.orange_outline = this.game.add.sprite(459,199,'orange_outline');
this.orange_outline.frame = 2;
this.orange_outline.anchor.setTo(.5);
this.orange_outline.customParams = {myName:'orange_outline',questionImg:'orange'};
this.orange_inner = this.game.add.sprite(150,197,'orange_inner');
this.orange_inner.anchor.setTo(.5);
this.orange_inner.customParams = {myName:'orange_inner',questionImg:'orange',targetKey:this.orange_outline,targetImg:'orange_outline'};
this.orange_inner.frame = 1;
this.orange_inner.inputEnabled = true;
this.orange_inner.input.enableDrag();
this.orange_inner.input.pixelPerfectOver = true;
this.orange_inner.events.onDragStart.add(this.onDragStart,this);
// this.game.physics.enable(this.orange_inner,Phaser.Physics.ARCADE);
this.game.physics.arcade.enable(this.orange_inner);
this.game.physics.arcade.enable(this.orange_outline);
this.orange_inner.events.onDragStop.add(this.onDragStop,this);
},
update: function () {
//this.orange.animations.play('orange_one',1)
},
onDragStart:function(sprite,pointer){
//console.log(sprite.key + " dragged")
},
onDragStop:function(sprite,pointer){
var endSprite = sprite.customParams.targetKey;
//console.log(sprite.customParams);
this.stopDrag(sprite,endSprite)
},
stopDrag:function(currentSprite,endSprite){
if (!this.game.physics.arcade.overlap(currentSprite, endSprite, function() {
var currentSpriteTarget = currentSprite.customParams.targetImg;
var endSpriteName = endSprite.customParams.myName;
if(currentSpriteTarget === endSpriteName){
currentSprite.input.draggable = false;
currentSprite.position.copyFrom(endSprite.position);
currentSprite.anchor.setTo(endSprite.anchor.x, endSprite.anchor.y);
}
console.log(currentSpriteTarget,endSpriteName);
})) {
//currentSprite.position.copyFrom(currentSprite.originalPosition);
console.log('you')
}
}
}
In stopDrag() I am detecting overlap.
You can try to get the amount of horizontal and vertical overlap amount and check if it satisfies a certain threshold. This can be done in additional overlap function callback, that is called processCallback in documentation. As an example:
if (!this.game.physics.arcade.overlap(currentSprite, endSprite, function() {
//your callback !
},function() {
if (this.game.physics.arcade.getOverlapX(currentSprite, endSprite) > currentSprite.width / 2
&& this.game.physics.arcade.getOverlapY(currentSprite, endSprite) > currentSprite.height / 2) {
//Overlaping !
return true;
} else {
//as if no overlap occured
return false;
}
},this) {
//
}
Another way to do this (other than what Hamdi Douss offers) is to resize your body to only take up 50% of the area. This will automatically ensure that collisions/overlap don't occur unless the reduced bodies touch each other.
To view your current body, use Phaser's debug methods
this.game.debug.body(someSprite, 'rgba(255,0,0,0.5)');

ZXing.Net.Mobile Sample.WindowsUniversal Sample Not Scanning

Testing this to incorporate into Win 10 UWP app to scan 1D barcodes (format 39 & 128). I have updated latest through nuget 2.0.4.46. Referenced post at http://www.yortondotnet.com/2015/07/mobile-barcode-scanning-with-zxingnet.html regarding some options setting prior to scan() with no luck. The scanner (camera) opens but never recognizes a barcode scan successfully - or failure for that matter. It seems nothing is happening whatsoever. I have included straight, pertinent sample code with some options modifications for review. I have gotten Scandit API to work and was going to try Manateeworks but both are really costly and not an option. I am developing on Surface Pro 3 (Win 10) and that build will also be target machines when complete.
public sealed partial class MainPage : Page
{
UIElement customOverlayElement = null;
MobileBarcodeScanner scanner;
public MainPage()
{
this.InitializeComponent();
//Create a new instance of our scanner
scanner = new MobileBarcodeScanner(this.Dispatcher);
scanner.Dispatcher = this.Dispatcher;
}
private void buttonScanDefault_Click(object sender, RoutedEventArgs e)
{
//Tell our scanner to use the default overlay
scanner.UseCustomOverlay = false;
//We can customize the top and bottom text of our default overlay
scanner.TopText = "Hold camera up to barcode";
scanner.BottomText = "Camera will automatically scan barcode\r\n\r\nPress the 'Back' button to Cancel";
// GWS Set Options
var options = new MobileBarcodeScanningOptions();
options.PossibleFormats = new List<ZXing.BarcodeFormat>() {
ZXing.BarcodeFormat.CODE_39, ZXing.BarcodeFormat.CODE_128
};
options.AutoRotate = false;
options.TryHarder = false;
options.TryInverted = false;
//Start scanning
scanner.Scan(options).ContinueWith(t =>
{
if (t.Result != null)
HandleScanResult(t.Result);
});
}
private void buttonScanContinuously_Click(object sender, RoutedEventArgs e)
{
//Tell our scanner to use the default overlay
scanner.UseCustomOverlay = false;
//We can customize the top and bottom text of our default overlay
scanner.TopText = "Hold camera up to barcode";
scanner.BottomText = "Camera will automatically scan barcode\r\n\r\nPress the 'Back' button to Cancel";
// GWS Set Options
var options = new MobileBarcodeScanningOptions();
options.PossibleFormats = new List<ZXing.BarcodeFormat>() {
ZXing.BarcodeFormat.CODE_39, ZXing.BarcodeFormat.CODE_128
};
options.AutoRotate = false;
options.TryHarder = false;
options.TryInverted = false;
//Start scanning
scanner.ScanContinuously(options, async (result) =>
{
var msg = "Found Barcode: " + result.Text;
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
await MessageBox(msg);
});
});
}
async void HandleScanResult(ZXing.Result result)
{
string msg = "";
if (result != null && !string.IsNullOrEmpty(result.Text))
msg = "Found Barcode: " + result.Text;
else
msg = "Scanning Canceled!";
await MessageBox(msg);
}
}
Simon,
I have the exact same problem. I tested your code with the latest nuget 2.1.47, the problem still exists.
You need to download the latest from Github and add the following projects (or DLLs) to your project:
ZXing.Net (project: zxing.portable.csproj)
ZXing.Net.Mobile.Core
ZXing.Net.Mobile.WindowsUniversal
I have tested your code and it works fine. I hope this help.
Cheers,
Sam
I think that the problem in the hardware you are testing with. Surface Pro 3 (Win 10) does not have an auto focus camera. I've never succeed to scan with ZXing using my Surface Pro 3, while the same application is working fine with my other windows 10 device.

Unity 3D, WWW function works in the editor yet when I build to PC the audio files are not loading or playing

Yeh I know the function works fine in the editor but when I build to PC no luck in getting the audio imported. The Audio source and listener are loaded in another class at runtime. This works perfectly when running it in the editor but when i build the game to PC no luck when trying to play audio at runtime.
# void Start()
{
if (aSource == null && aListener == null)
{
//creating the audio sources for the music to play
//and audio listener in order to hear the music
aSource = gameObject.AddComponent<AudioSource>();
aListener = gameObject.AddComponent<AudioListener>();
toggleBrowser = false;
}
// Getting the component play Button
playButton = GameObject.FindGameObjectWithTag("PlayButton");
button = playButton.GetComponent<Button>();
}
public void toggleFileBroswer()
{
// Toggle the file browser window
toggleBrowser = !toggleBrowser;
}
public void OnGUI()
{
// File browser, cancel returns to menu and select chooses music file to load
if (toggleBrowser)
{
if (fb.draw())
{
if (fb.outputFile == null)
{
Application.LoadLevel("_WaveRider_Menu");
toggleBrowser = !toggleBrowser;
}
else
{
Debug.Log("Ouput File = \"" + fb.outputFile.ToString() + "\"");
// Taking the selected file and assigning it a string
userAudio = fb.outputFile.ToString();
//Starting the load process for the file
StartCoroutine(LoadFilePC(userAudio));
toggleBrowser = false;
startLoad = true;
}
}
}
}
void Update()
{
// Making the play button inactive untill the file has loaded
if (startLoad)
{
loadTime += Time.deltaTime;
}
if (loadTime >= 5)
{
button.interactable = true;
}
}
public void playTrack()
{
// Dont destroy these GameObjects as we load the next scene
Object.DontDestroyOnLoad(aSource);
Object.DontDestroyOnLoad(aListener);
//assigns the clip to the audio source and play it
aSource.clip = aClip;
aSource.Play();
Debug.Log("Playing track");
}
IEnumerator LoadFilePC(string filePath)
{
filePath = userAudio;
print("loading " + filePath);
//Loading the string file from the File browser
WWW www = new WWW("file:///" + filePath);
//create audio clip from the www
aClip = www.GetAudioClip(false);
while (!aClip.isReadyToPlay)
{
yield return www;
}
}
public void exit()
{
// Exit game, only works on built .exe not in the editor window
Application.Quit();
}
}

Resources