I'm trying to do a simple think: when a button is pressed i load a video using the processing video library, each button is associated with a different video, for example button 1 with video 1, button 2 with video 2, and so on. The code works but every time I call a video, also the same i have already load, rewriting the gloabal variable the consume of CPU grows, reaching the 40% after the thrid loading, after 7 video the consume of CPU is near the 100%. An extraction of the code:
import processing.video.*;
Movie movie;
void setup() {
size(1280, 720, P3D);
background(0);
}
void draw() {
//image(movie, 0, 0, width, height);
if (but1_1==1) {
println("video 1");
movie = new Movie(this, "1.mp4"));
movie.loop();
movie.volume(0);
}
if (but1_2==1) {
println("video 2");
movie = new Movie(this, "2.mp4"));
movie.loop();
movie.volume(0);
}
if (but1_3==1) {
println("video 3");
movie = new Movie(this, "3.mp4"));
movie.loop();
movie.volume(0);
}
}
As you can see, it should not be any reason in based on which the CPU consume grows: the instantiated object movie is always rewritten every time a new video (or the same) is loaded. Any suggestions?
You are loading the movies in loop, which means they don't stop. So the more buttons you press, the more videos are processed at the same time. On every button press, you should stop the movie-playing-process of the old movie first, before you start a new one.
Related
How to delay loading the scene to play the sound?
I'm trying to delay loading a scene so I can play the sound, but the sound stops in the middle or doesn't exist at all and the scene changes immediately
Here is my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class MeinMenu : MonoBehaviour
{
static AudioSource audioScr;
public void NewGame()
{
SoundManagerScript.PlaySound("clik");
DontDestroyOnLoad(audioScr.gameObject);
SceneManager.LoadScene("level 1");
}
public void LoadGame()
{
SceneManager.LoadScene(PlayerPrefs.GetInt("SavedScene"));
}
}
Happens when the scene loads faster than the sound can finish playing.
When a scene loads by default, it destroys all objects on the previous scene, which includes your audio source.
One way is to mark your audio-source with DontDestroyOnLoad
// Somewhere after your audio source have loaded...
DontDestroyOnLoad(yourAudioSource.gameObject);
Note that this means you are likely to end up with a singular instance of Audio Source, as this audio source (or the game-object attached to it, to be exact) will only be destroyed manually via script.
The other is to just do a coroutine that does nothing until the audio source have finished playing:
IEnumerator LoadSceneWithSoundCoroutine()
{
yourAudioSource.Play();
// Denies loading while audio source is playing.
while (yourAudioSource.isPlaying)
{
yield return null;
}
SceneManager.LoadScene("Your scene")
}
// ...
StartCoroutine(LoadSceneWithSoundCoroutine());
I am trying to achieve smooth animation using Xamarin SkiaSharp. The core issue is the the time between calling canvasView.InvalidateSurface(); and hitting the mathod OnCanvasViewPaintSurface to do the redraw can vary from 3 to 30 ms which gives a somewhat jerky appearance when you are moving an object across the screen. I have tried to mitigate this by adding a dead loop in the draw code, which helps some but is not a great solution. I do not understand why the time varies so much, and I do not see any way around this. You cannot put a sleep in the draw code. How do games achieve smooth animation? My code follows
async Task DoAnimationLoop()
{
while (DoAnimation)
{
AccumulatedTime = StopWatch1.ElapsedMilliseconds;
await Task.Delay(TimeSpan.FromMilliseconds(5));
if (AccumulatedTime > 50)
{
StopWatch1.Restart();
MoveItems();
SKCanvasView canvasView = Content as SKCanvasView;
TotalBounds = new Size(canvasView.Width,
canvasView.Height);
canvasView.InvalidateSurface();
}
}
}
private void OnCanvasViewPaintSurface(object sender,
SKPaintSurfaceEventArgs e)
{
AccumulatedTime = StopWatch1.ElapsedMilliseconds;
while (AccumulatedTime < 30)
{
AccumulatedTime = StopWatch1.ElapsedMilliseconds;
}
e.Surface.Canvas.Clear();
e.Surface.Canvas.DrawBitmap(Background, 0, 0);
foreach(Item item in AllItems)
{
e.Surface.Canvas.DrawBitmap(item.CurrentBitmap,
item.CurrentPositionX, item.CurrentPositionY);
}
}
For future readers:
From experience, I get the smoothest animations with SkiaSharp by creating SkiaSharp SKCanvasViews that have Bindable properties that can be incremented with Xamarin.Forms.Animate. Animate handles all the timing and sleeping code based on variables you configure it with. As you want a loop, you can set the repeat delegate to return true when calling Animate.Commit( ... repeat: () => true ...)
Here is a method example that animates a progress bar "filling" to 100 percent (without looping), by incrementing the ProgressBar's PercentageFilled Property. Note the timing settings you can configure: Refresh rate = 11ms (equates to "90 fps": 1000ms/90 = 11.11), timeToAnimate is the length of time the animation should take to complete in ms, and you can choose from several easing functions.
private void AnimateProgressBar()
{
double startPercentage = 0; //start at 0 percent
double endPercentage = 1; //fill to 100 percent (Forms.Animate will evenly increment
//between 0 and 1 , and in this case the ProgressBar's OnPaintSurface method knows how to draw based
//on the given decimal i.e. if PercentageFilled is .5 it will draw the bar to
//50 percent of its possible max length)
uint timeToAnimate = 1000;
Xamarin.Forms.Animation animation = new Animation(v => _ProgressBar.PercentageFilled = (float)v, startPercentage, endPercentage, easing: Easing.CubicOut);
animation.Commit(_ProgressBar, "FillPercentage", length: timeToAnimate, finished: (l, c) => animation = null, rate: 11);
}
When the PercentageFilled Property is changed it triggers InvalidateSurface by placing a call to InvalidateSurface() within the OnPropertyChanged method. To do this override OnPropertyChanged like so in your SKCanvasView derived class:
class ProgressBar: SKCanvasView
{
//...
public BindableProperty PercentageFilledProperty =
BindableProperty.Create(nameof(PercentageFilled), typeof(float), typeof(ProgressBar), 0f);
public float PercentageFilled
{
get { return (float)GetValue(PercentageFilledProperty ); }
set { SetValue(PercentageFilledProperty , value); }
}
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
InvalidateSurface();
}
protected override void OnPaintSurface(SKPaintSurfaceEventArgs args)
{
//Draws progress bar based on the PercentageFilled filled property
}
//....
}
In the question's code it appears that a lot of items are being moved (MoveItems();) in sequence and this technique of drawing items one by one moving might be the cause of jitter? But MoveItems appears to be the place where you might want to use Forms.Animate that is you could Create a Forms.Animation with MoveItems() as the Callback. Look into the microsoft documentation for "Custom Animations in Xamarin.Forms" for more info on how to animate with callbacks.
Also check out "The basics to create custom Xamarin.Forms controls using SkiaSharp" by Konrad Müller on Medium which contains this helpful paragraph which might be useful to consider if you are making a game:
The basic SkiaSharp.Views.Forms provides two views you can use as a
base for your controls: SKCanvasView and SKGLView. The CanvasView uses
the CPU accelerated backend while the GLView uses OpenGL and therefore
the GPU. You might intuitively think that using the GPU for graphics
operations is always the better choice but in fact, OpenGL has a high
overhead when creating the GL context. The CanvasView simply allocates
the memory it needs and as long as enough CPU power is available, it
can render without problems. In theory, the CanvasView should be
better suited for less demanding renderings and GlView better for
complex renderings but the power of modern smartphones makes these
differences mostly unnoticable. I would recommend to simply stick to
the CanvasView and switch to the GlView if the rendering gets to
complex and you notice performance problems.
I'm using a remote url for a PImage. It's a jpg from a cam. I'm grabbing it and sending it to a image() every sec. Switching to a new cam every 10 secs. Every hour or so, the script crashes due to a 502 error, since the image was not successfully downloaded.
I'm attempting to setup a script that looks at the image using requestImage(), does a quick error check, and skips draw of that image if it returns a 0 or -1. Which should be simple enough. But...
How can you send a constantly updating url to requestImage() if its parameters refuse to accept anything other than a static single filename in a string and it lives in setup() / pre-process?
Anyone run into this issue before? Or am I missing something?
Here is the code. Note: cams are not active at the moment, so there are placeholders in the array...;
Thanks for looking!
PImage webImg;
PImage testImg;
int timer;
String[] camlist = {
"random_url_with_JPG_here",
"random_url_with_JPG_here",
"random_url_with_JPG_here"
};
//find length of array
int camListLength = int(random(camlist.length));
void setup() {
testImg = requestImage(webImg, "jpg");
noCursor();
fullScreen();
background(0);
}
void draw() {
if (millis() - timer >= 10000) {
camLoad();
timer = millis();
} else {
displayWebImage();
}
}
void camLoad() {
//find length of array
camListLength = int(random(camlist.length));
}
void displayWebImage() {
// load random cam url into 'webImg'
webImg = loadImage(camlist[camListLength], "jpg");
// test load
println(testImg.width);
if (testImg.width == 0) {
println("Not Loaded");
} else if (testImg.width == -1) {
println("random error");
} else {
// display 'webImage'
image(webImg, 0, 0, 800, 480);
// cache cleanup
g.removeCache(webImg);
delay(1000);
// frame count
println(frameCount+" "+g.getCache(webImg));
}
}
It's true that for 95% of people, it's a very bad idea to create images in the draw() function. Most programs should load all of the images at the beginning, in the setup() function.
But if you're loading images that you don't know ahead of time, then nothing is stopping you from creating images in the draw() function. You can absolutely call requestImage() from inside the draw() function.
But note that the requestImage() function runs in the background, so your code keeps executing while the image is requested. From the reference:
This function loads images on a separate thread so that your sketch doesn't freeze while images load during setup(). While the image is loading, its width and height will be 0. If an error occurs while loading the image, its width and height will be set to -1.
This means that the image won't be loaded until a couple second later, so you can't use your image variable right away. You're fixing this using a call to delay(), but you're probably better off just using the loadImage() function instead. From the reference:
If the file is not available or an error occurs, null will be returned and an error message will be printed to the console. The error message does not halt the program, however the null value may cause a NullPointerException if your code does not check whether the value returned is null.
...
Depending on the type of error, a PImage object may still be returned, but the width and height of the image will be set to -1. This happens if bad image data is returned or cannot be decoded properly. Sometimes this happens with image URLs that produce a 403 error or that redirect to a password prompt, because loadImage() will attempt to interpret the HTML as image data.
That function does not run in the background, so the code only continues after the image is fully loaded.
I would like to modify a Timeline while it is running, for example in response to a mouse-click I want to change the target value of the animation. I have tried several methods to do this including (in a mouse clicked handler) :
Pausing the animation by calling pause() on the Timeline, clearing the KeyFrames ObservableList, adding a new KeyFrame and calling play() on the Timeline.
Creating a new KeyFrame with a Cue-name, adding the new frame to the Observable list and calling jumpTo(cueName) on the Timeline.
Some example code is:
String cueName = String.valueOf(System.currentTimeMillis());
KeyValue kv = new KeyValue(myObject.rotateProperty(), -90 + 180.0 * Math.random(), new CustomInterpolator());
KeyFrame kf = new KeyFrame(Duration.seconds(10), cueName, kv);
startupTimeline.getKeyFrames().add(kf);
startupTimeline.jumpTo(cueName);
startupTimeline.play();
Neither of these appear to work, the animation just stops.
Should I be able to modify the KeyFrame list of an existing Timeline or do I need to create a new Timeline if I want to change an animation while it is executing?
To the best of my knowledge, a Timeline can't be changed in that manner once it has started playing. The issue is that you might change the total cycle duration, which would confuse all the interpolation computations.
You probably need an AnimationTimer for this. AnimationTimer has an abstract handle(long timestamp) method which takes a time stamp (in nano-seconds), and is invoked every time the scene graph is rendered. So you can do something like:
AnimationTimer animation = new AnimationTimer() {
private long startTime = -1;
#Override
public void handle(long timestamp) {
if (startTime == -1) {
startTime = timestamp ;
}
long totalElapsedNanoseconds = timestamp - startTime ;
// update UI based on elapsed time...
}
}
The handle() method is invoked on the JavaFX Application Thread, so it is safe to update the UI, and to reference any variables that are only changed on the same thread.
I try to implement kind of a Videostream that relays on simple JPEG Files.
On my server, a JPEG is being created cyclically by an external Camera.
And I just want to include this Picture in my GWT Application.
My first idea to reload the Picture by a Timer was very simple but not so good: The client opens a connection for each reload-cycle, and the Picture flickers (at least in Firefox).
How could I solve these problems? I was thinking about something like "Web-Sockets", but I don't really know how to do.
I want to avoid a single connection for each reload. My idea was to have something like an open connection that just provides a new Picture as often as the Client asks for.
And how could I avoid the flickering when swapping the Picture?
Any ideas are welcome!
Regards, VanDahlen
A solution to avoid flickering is to have two images absolutely positioned in the same location. A timer would load one or other alternatively in each frame. Set a load handler to each image, so that it changes the z-index when the image is loaded and it restarts the timer.
Adding an extra parameter to the image url, makes the browser ask the server each time to bypass its cache.
If the time between frames is small, normally the browser will re-use the same connection if keep-alive is correctly configured in your server. It normally is enabled with a typical value of 5-15 seconds which you could increase, so if your .jpg images are updated with this periodicity, you don't have to worry and look for a better solution.
I propose a UI solution based on these ideas. But it will work as well if you use a websocket/comet mechanism giving you the last .jpg file in base64 format (just change the url by the value returned).
GWT code:
public void onModuleLoad() {
final Image i1 = new Image();
i1.setWidth("400px");
final Image i2 = new Image();
i2.setWidth("400px");
AbsolutePanel panel = new AbsolutePanel();
panel.add(i1, 0, 0);
panel.add(i2, 0, 0);
panel.setSize("600px", "400px");
RootPanel.get().add(panel);
// You could change this by base64 data if you use comet/websockets
String url = "my_image_url.jpg?";
final Timer loadNext = new Timer() {
boolean b;
int c;
public void run() {
// the counter parameter forces to load the next frame instead of using cache
if (b = !b) {
i1.setUrl(url + c++);
} else {
i2.setUrl(url + c++);
}
}
};
i1.addLoadHandler(new LoadHandler() {
public void onLoad(LoadEvent event) {
i1.getElement().getStyle().setZIndex(1);
i2.getElement().getStyle().setZIndex(0);
loadNext.schedule(1000);
}
});
i2.addLoadHandler(new LoadHandler() {
public void onLoad(LoadEvent event) {
i1.getElement().getStyle().setZIndex(0);
i2.getElement().getStyle().setZIndex(1);
loadNext.schedule(1000);
}
});
loadNext.schedule(1000);
}
If you want to use gwtquery, the code is obviously smaller:
// You could change this by base64 data if you use comet/websockets
final String url = "my_image_url.jpg?";
final GQuery images = $("<img/><img/>").appendTo(document);
images.css($$("position: fixed, top: 10px, left: 600px, width: 400px"));
final Timer timer = new Timer() {
int c;
public void run() {
images.eq(c%2).attr("src", url + c++);
}
};
images.bind("load", new Function(){
public void f() {
$(this).css($$("z-index: 1")).siblings("img").css($$("z-index: 0"));
timer.schedule(1000);
}
});
timer.schedule(1000);