My project is using Processing core jar and the GSVideo library on a OSX 10.8.5 using Eclipse.
I cannot get GSVideo jump(int frame) or jump(float time) to actually redraw the next frames. The image displayed toggles back and forth between frames when I repeatedly press the RIGHT to advance the frame in the example program below. Because the example below works with *.mov, but not *.mpg video I want to ask if there are any known problems with gstreamer advancing frames in MPEG2 video. Or perhaps something's up with either java-gstreamer or GSVideo?
I'm working with video in MPEG2 format.. And there is no problem just to play and pause the MPEG2. It just seems that movie.jump(frameNum or time) functions are not working. I've started looking for an example of frame stepping using playbin2's seek method.
Here is info about the video I'm trying to jump.
stream 0: type: CODEC_TYPE_VIDEO; codec: CODEC_ID_MPEG2VIDEO; duration: 7717710; start time: 433367; timebase: 1/90000; coder tb: 1001/60000;
width: 1920; height: 1080; format: YUV420P; frame-rate: 29.97;
The example code.
import processing.core.*;
import codeanticode.gsvideo.*;
public class FramesTest extends PApplet {
GSPlayer player;
GSMovie movie;
int newFrame = 0;
PFont font;
public void setup() {
size(320, 240);
background(0);
//movie = new GSMovie(this, "station.mov"); // sample works
movie = new GSMovie(this, "myMovie.mpg"); // mpg does not
movie.play();
movie.goToBeginning();
movie.pause();
textSize(24);
}
public void movieEvent(GSMovie movie) {
System.out.println("movie"+ movie.frame());
movie.read();
}
public void draw() {
image(movie, 0, 0, width, height);
fill(240, 20, 30);
text(movie.frame() + " / " + (movie.length() - 1), 10, 30);
}
public void keyPressed() {
if (movie.isSeeking()) return;
if (key == CODED) {
if (keyCode == LEFT) {
if (0 < newFrame) newFrame--;
} else if (keyCode == RIGHT) {
if (newFrame < movie.length() - 1) newFrame++;
}
}
movie.play();
movie.jump(newFrame);
movie.pause();
if (movie.available()){
System.out.println(movie.frame());
movie.read();
}
System.out.println(newFrame);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
PApplet.main(new String[] { FramesTest.class.getName() }); //
}
}
The example code was pulled from here...
http://gsvideo.sourceforge.net/examples/Movie/Frames/Frames.pde
I've searched the internet for a few days and this attempted contact with this forum as well...
https://sourceforge.net/projects/gsvideo/forums
This post seems similar but my problem is not playing (that's fine). I cannot jump to a specific frame.... GStreamer: Play mpeg2
Many thanks to the SO community for any help I might receive.
Update:
To work around the MPEG2 compression issue (described by v.k. below) I am trying to create a gstreamer pipeline to do on-the-fly transcoding to mp4 using either GSVideo Pipeline or with java-gstreamer. The command below works in Ubuntu.
gst-launch-0.10 filesrc location=myMpeg2Video.mpg ! mpegdemux name=demux demux.video_00 ! ffdec_mpeg2video ! queue ! x264enc ! ffdec_h264 ! xvimagesink
But the following GSVideo Pipeline displays an empty gray window :(
pipeline = new GSPipeline(this, "filesrc location=file:/path/movie.mpg ! mpegdemux name=demux demux.video_00 ! ffdec_mpeg2video");
pipeline.play();
as v.k. pointed out, seeking is in general not accurate.
One important thing to note is that development on gsvideo has basically stopped. The main elements of it were ported to the built-in video library in Processing 2.0. I did some work in built-in video to try to improve seeking, and the example Frames in Libraries|video|Movie shows how (to try) to jump to specific frames by indicating a time value. Maybe this helps in your case?
Also if you find a more accurate way of doing seeking as you suggest in your last post, I could include that in video library.
Related
Using Forge 1.8.9 in Eclipse (Mars.1 Release (4.5.1)) in local development environment.
The goal is to set a player's location to a predetermined xyz every time they join (or re-join) a world. So if they quit the game, but then come back to the world, they will start in the same location as determined by the code below instead of wherever they left off. Basically, it will work like a lobby, where players start in the same place each time.
The code works using the chat component (e.g. the chat message appears upon joining the game) but I've commented it out, for now. The player simply appears wherever they left off after having left the game from last time around.
Questions are:
1. is the PlayerLoggedInEvent the best event to use, or is there a better event?
2. is setLocationAndAngles the best to use, or should a different set location type event (or move) better?
Thanks in advance. Lots of experience with LAMP stack, but Java and mods are a new interest (obvs). Code is below.
import net.minecraftforge.client.event.RenderPlayerEvent;
//import net.minecraft.util.ChatComponentText;
//import net.minecraft.util.EnumChatFormatting;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent;
//import cpw.mods.fml.common.eventhandler.SubscribeEvent;
public class JoinGameLocation {
#SubscribeEvent
public void SpawningLocation(PlayerLoggedInEvent event){
event.player.setLocationAndAngles(145, 72, 145, 0, 0);
//-----This works when uncommented
//event.player
//.addChatMessage(
// new ChatComponentText(
// EnumChatFormatting.RED + "You joined the game"));
//event.world.setWorldTime(0);
int ticks = 0;
double good_x = 145;
double good_y = 72;
double good_z = 145;
event.player.setLocationAndAngles(good_x, good_y, good_z, 0, 0);
}
}
Use the entity join world and the clone event
#SubscribeEvent
public void onClonePlayer(PlayerEvent.Clone event) {
}
#SubscribeEvent
public void onEntityJoinWorld(EntityJoinWorldEvent event) {
if (event.entity != null && event.entity instanceof EntityPlayer && !event.entity.worldObj.isRemote) {
}
}
The clone event is triggered upon tp, dimension change, etc...
The join world obviously when the world is joined. I suggest you play around with these.
I have built a mouse emulator for a severely disabled person, which has a series of buttons arranged in a + pattern, with the center button being a 'click'. The inputs are read into an Arduino Micro, which then connects through USB to the computer. A processing script, using the Arduino library, responds to these changes by moving the mouse, using the Robot class. I exported an application, for both 32-bit and 64-bit windows, but found that the .exe files were problematic, and instead opted for .bat files using the embedded Java.
This all works perfectly on my computer (Microsoft Surface, Windows 8, 64-bit). But on the client's computer (Windows 7, 32-bit), the results are erratic. Each time I load the program, I get a different result. For example, sometimes up, down, and click work. Sometimes only up and click work. And so forth. The click usually seems to work, but the directions are less reliable, with vertical working more often than horizontal.
I have verified that nothing is wrong with the board. I tried putting in a debug statement which ran println() each time a movement's "if" statement was tripped - I only got printing from directions that worked on that particular run.
I see a number of potential sources for this problem: the differences between 32-bit and 64-bit Windows, possible issues with the Robot class, USB performance issues (though I've tried multiple ports on the client's laptop), etc. The client's laptop has generally poor performance (for example, if I click "Control Panel", it may be a full minute before Control Panel opens), so that may also be related.
Does anyone have other insights on this?
EDIT: As requested, here's a minimal version of the Processing code. The Arduino is just running Firmata:
import processing.serial.*;
import cc.arduino.*;
import java.awt.*;
import java.awt.event.*;
Arduino arduino;
Robot r;
final int upPin=8;
final int downPin=12;
final int leftPin=10;
final int rightPin=11;
final int buttonPin=9;
final int SPEED=8;
boolean arduinoConnected;
int prevButton=Arduino.LOW;
void setup() {
arduinoConnected = (Arduino.list().length>0);
if (arduinoConnected) {
arduino = new Arduino(this, Arduino.list()[Arduino.list().length-1], 57600);
arduino.pinMode(buttonPin, Arduino.INPUT);
arduino.pinMode(upPin, Arduino.INPUT);
arduino.pinMode(downPin, Arduino.INPUT);
arduino.pinMode(leftPin, Arduino.INPUT);
arduino.pinMode(rightPin, Arduino.INPUT);
}
try {
r = new Robot();
}
catch (Exception e) {
e.printStackTrace();
}
}
void draw() {
arduinoConnected = (Arduino.list().length>0);
if (arduinoConnected && arduino==null) setup();
if (arduinoConnected) {
if (arduino.digitalRead(upPin)==Arduino.HIGH) moveMouse(0,0-SPEED);
if (arduino.digitalRead(downPin)==Arduino.HIGH) moveMouse(0,SPEED);
if (arduino.digitalRead(leftPin)==Arduino.HIGH) moveMouse(0-SPEED,0);
if (arduino.digitalRead(rightPin)==Arduino.HIGH) moveMouse(SPEED,0);
int button=arduino.digitalRead(buttonPin);
if (button==Arduino.LOW && prevButton==Arduino.HIGH) clickMouse(InputEvent.BUTTON1_DOWN_MASK);
prevButton=button;
}
}
void moveMouse(int x, int y) {
PointerInfo pinfo = MouseInfo.getPointerInfo();
Point p = pinfo.getLocation();
r.mouseMove((int)p.getX()+x, (int)p.getY()+y);
}
void clickMouse(int whichType) {
r.mousePress(whichType);
r.mouseRelease(whichType);
r.waitForIdle();
}
I’m starting to work on a music/metronome application in Java and I’m running into some problems with the timing and speed.
For testing purposes I’m trying to play two sine wave tones at the same time at regular intervals, but instead they play in sync for a few beats and then slightly out of sync for a few beats and then back in sync again for a few beats.
From researching good metronome programming, I found that Thread.sleep() is horrible for timing, so I completely avoided that and went with checking System.nanoTime() to determine when the sounds should play.
I’m using AudioSystem’s SourceDataLine for my audio player and I’m using a thread for each tone that constantly polls System.nanoTime() in order to determine when the sound should play. I create a new SourceDataLine and delete the previous one each time a sound plays, because the volume fluctuates if I leave the line open and keep playing sounds on the same line. I create the player before polling nanoTime() so that the player is already created and all it has to do is play the sound when it is time.
In theory this seemed like a good method for getting each sound to play on time, but it’s not working correctly. I’m not sure if the timing problems are from running different threads or if it has to do with deleting and recreating the SourceDataLine or if it’s in playing sounds or what exactly...
At the moment this is just a simple test in Java, but my goal is to create my app on mobile devices (Android, iOS, Windows Phone, etc)...however my current method isn’t even keeping perfect time on a PC, so I’m worried that certain mobile devices with limited resources will have even more timing problems. I will also be adding more sounds to it to create more complex rhythms, so it needs to be able to handle multiple sounds going simultaneously without sounds lagging.
Another problem I’m having is that the max tempo is controlled by the length of the tone since the tones don’t overlap each other. I tried adding additional threads so that every tone that played would get its own thread...but that really screwed up the timing, so I took it out. I would like to have a way to overlap the previous sound to allow for much higher tempos.
Any help getting these timing and speed issues straightened out would be greatly appreciated!
Thanks.
SoundTest.java:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.io.*;
import javax.sound.sampled.*;
public class SoundTest implements ActionListener {
static SoundTest soundTest;
// ENABLE/DISABLE SOUNDS
boolean playSound1 = true;
boolean playSound2 = true;
JFrame mainFrame;
JPanel mainContent;
JPanel center;
JButton buttonPlay;
int sampleRate = 44100;
long startTime;
SourceDataLine line = null;
int tickLength;
boolean playing = false;
SoundElement sound01;
SoundElement sound02;
public static void main (String[] args) {
soundTest = new SoundTest();
SwingUtilities.invokeLater(new Runnable() { public void run() {
soundTest.gui_CreateAndShow();
}});
}
public void gui_CreateAndShow() {
gui_FrameAndContentPanel();
gui_AddContent();
}
public void gui_FrameAndContentPanel() {
mainContent = new JPanel();
mainContent.setLayout(new BorderLayout());
mainContent.setPreferredSize(new Dimension(500,500));
mainContent.setOpaque(true);
mainFrame = new JFrame("Sound Test");
mainFrame.setContentPane(mainContent);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.pack();
mainFrame.setVisible(true);
}
public void gui_AddContent() {
JPanel center = new JPanel();
center.setOpaque(true);
buttonPlay = new JButton("PLAY / STOP");
buttonPlay.setActionCommand("play");
buttonPlay.addActionListener(this);
buttonPlay.setPreferredSize(new Dimension(200, 50));
center.add(buttonPlay);
mainContent.add(center, BorderLayout.CENTER);
}
public void actionPerformed(ActionEvent e) {
if (!playing) {
playing = true;
if (playSound1)
sound01 = new SoundElement(this, 800, 1);
if (playSound2)
sound02 = new SoundElement(this, 1200, 1);
startTime = System.nanoTime();
if (playSound1)
new Thread(sound01).start();
if (playSound2)
new Thread(sound02).start();
}
else {
playing = false;
}
}
}
SoundElement.java
import java.io.*;
import javax.sound.sampled.*;
public class SoundElement implements Runnable {
SoundTest soundTest;
// TEMPO CHANGE
// 750000000=80bpm | 300000000=200bpm | 200000000=300bpm
long nsDelay = 750000000;
int clickLength = 4100;
byte[] audioFile;
double clickFrequency;
double subdivision;
SourceDataLine line = null;
long audioFilePlay;
public SoundElement(SoundTest soundTestIn, double clickFrequencyIn, double subdivisionIn){
soundTest = soundTestIn;
clickFrequency = clickFrequencyIn;
subdivision = subdivisionIn;
generateAudioFile();
}
public void generateAudioFile(){
audioFile = new byte[clickLength * 2];
double temp;
short maxSample;
int p=0;
for (int i = 0; i < audioFile.length;){
temp = Math.sin(2 * Math.PI * p++ / (soundTest.sampleRate/clickFrequency));
maxSample = (short) (temp * Short.MAX_VALUE);
audioFile[i++] = (byte) (maxSample & 0x00ff);
audioFile[i++] = (byte) ((maxSample & 0xff00) >>> 8);
}
}
public void run() {
createPlayer();
audioFilePlay = soundTest.startTime + nsDelay;
while (soundTest.playing){
if (System.nanoTime() >= audioFilePlay){
play();
destroyPlayer();
createPlayer();
audioFilePlay += nsDelay;
}
}
try { destroyPlayer(); } catch (Exception e) { }
}
public void createPlayer(){
AudioFormat af = new AudioFormat(soundTest.sampleRate, 16, 1, true, false);
try {
line = AudioSystem.getSourceDataLine(af);
line.open(af);
line.start();
}
catch (Exception ex) { ex.printStackTrace(); }
}
public void play(){
line.write(audioFile, 0, audioFile.length);
}
public void destroyPlayer(){
line.drain();
line.close();
}
}
This sort of thing is difficult to get right. What you have to realise is that in order to even play a sound, it has to be loaded into an audio driver (and possibly a sound card). This takes time, and you have to account for that. There are basically two options for you:
Rather than counting down a delay between every beat, count down a delay from the start, when the metronome activates. As an example, say for instance that you want a beat every second. Because of the ~20ms delay, in your old method you'd get beats at 20ms, 1040, 2060, 3080, etc... If you count down from the start and place beats at 1000, 2000, 3000, etc. then they will play at 20ms, 1020, 2020, 3020, etc... There will still be some variance since the dalay itself varies a bit, but there should be about 1000ms between beats and it will not go out of sync (or at least, the problem will not get worse over time and likely can't be heard).
The better option, and the one that most of such programs use, is to generate larger pieces of music. Buffer for instance 20 seconds ahead and play that. The timing should be perfect during those 20 seconds. When those 20 seconds are almost over you must generate some new sound. If you can find out how to do this, you should append the new waveform to the old and have it play continuously. Otherwise, just generate a new 20 second soundbit and accept the delay between them.
Now as for your problem with the sounds not being able to overlap... I'm no expert and I don't really know an answer, but this I do know: Something has to mix the sounds if you need them to overlap. Either you can do that yourself in software by combining the waveform bytes (I think it's an addition in some logarithmic space), or you need to send the different overlapping sounds to different 'channels', in which case the audio driver or sound card does it for you. I don't know how this works in Java though, or I forgot, but I learned this through trial-and-error and working with .mod files.
I'm trying to create a loop using Java Swing Timer to constantly cycle through a set of images (i1, i2, i3....in where n is total number of images).
Each of the images is exactly the same size and must be displayed on a Label (say, l1).
There must be a delay of ten seconds between each image being displayed.
Any idea how I can go about this without using the Java TumbleItem applet> It's seems much too complicated for a simple implementation such as mine. (Displaying special deals posters on an online storefront application for school).
I am open to this being achieved in any other way.
Help would be greatly appreciated. Thanks in advance!
I'm trying to create a loop using Java Swing Timer to constantly cycle through a set of images
When you use a Timer you don't use a loop. When the Timer fires you just change the image. So somewhere you would need to keep a List of the images to display and an index of the currently displayed image.
Any idea how I can go about this without using the Java TumbleItem applet> It's seems much too complicated for a simple implementation such as mine
How is it complicated? It displays a series of images, which is close to what you want.
Yes, there is some extra code that loads the images and doesn't start the animation until all the images are loaded. So you could easily simplify the code by not worry about that. Also, there is code that does animation from from left-to-right and then right-to-left. You also don't need that part of the code. Also, there is code that configures the animation speed. Again you can hard code that.
So if you start with that example and then simplify the code you will have a simple solution. Give it a try and then post your code when you encounter a problem.
This is very simple. Use a timer like this:
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
//codehere
}
}, 0, delayInMillis)
Use can use an integer to specify in image.
public int image = 1;
in the run() function, use this to switch between the image
if(image = 1) {
image = 2;
} else if(image = 2) {
image = 3;
} if(image = 3) {
image = 0;
}
Now, wherever you are drawing your images, use this:
if(image == 1) {
//draw first image
} else if(image == 2) {
//draw second image
} else if(image == 3) {
//draw third image
}
I am working on an OpenCV project that relies on finger detection. Currently I have an OpenCVFrameGrabber that grabs a frame and places it in an IplImage. I then draw that image onto my GUI.
This all works, but the image that is drawn seems to be in black and white even though I have a color camera. There are noticeable vertical lines in the image and when there is some color, it seems to be split into components along these lines.
Does anyone know of a way to get the original webcam image?
I recently started playing with JavaCV and I'm always trying to avoid this new classes and stick with the "original" OpenCV methods.
I suggest you try the following code and make sure that the most simple capture procedure works:
public static void main(String[] args)
{
CvCapture capture = cvCreateCameraCapture(0);
if (capture == null)
{
System.out.println("!!! Failed cvCreateCameraCapture");
return;
}
cvNamedWindow("camera_demo");
IplImage grabbed_image = null;
while (true)
{
grabbed_image = cvQueryFrame(capture);
if (grabbed_image == null)
{
System.out.println("!!! Failed cvQueryFrame");
break;
}
cvShowImage("camera_demo", grabbed_image);
int key = cvWaitKey(33);
if (key == 27)
{
break;
}
}
cvReleaseCapture(capture);
}
If this works, your problem might be related to OpenCVFrameGrabber. If it doesn't, you might want to experiment your code with another camera.