Extracting Frames from MPEG I
After a long time search for a pure Java implementation, I found one.
You can download the source from a SourceForge project called Viper.
There is a subproject called jmpeg.
You have to download the FULL version to get the source.
After that, it is VERY simple to use.
Call videoStream.seek(frameNumber) and then getImage().
Couldnt be simpler.
http://viper-toolkit.sourceforge.net/products/jmpeg/
It took me a little while to get it up and running (but im kind of dim)
so just ask if you have questions.
also, though you only need the 80 kb viper-jmpeg.jar file there is ONE
TOTALLY UNNECESSARY dependence on a single class from the viper-api which is 300 kb!
this is easy hack. just move the Rational class into the mpeg1/video folder and adjust both package declarations and rejar.
I dont know if this breaks a license or anything like that (i cant imagine how moving one class would) so if you use it for a legit project you may want to contact the writers.
here is a goofy little test class I wrote to learn my way around the program:
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import edu.umd.cfar.lamp.mpeg1.*;
public class VideoWatcher implements ActionListener{
public static void main(String[] args) {
new VideoWatcher();
}
public VideoWatcher(){
try{
defaultDir = "C:/";
File file = getFile();
mpgFile = new Mpeg1File(file);
vidStream = mpgFile.getVideoStream();
int frames = vidStream.getNumFrames();
long length = getVideoLengthInMillis(vidStream);
System.out.println("Frames: " + frames);
System.out.println("Length: " + length);
// MOVIE SCREEN
movieScreen = new JFrame();
movieScreen.setContentPane(new Painter());
//frame.setSize(frameImage.getWidth() + 100, frameImage.getHeight() + 100);
movieScreen.setSize(500, 500);
movieScreen.setLocationRelativeTo(null);
movieScreen.setVisible(true);
timer = new Timer(30, this);
timer.start();
///////////////
} catch(Exception e){
e.printStackTrace();
}
}
public void actionPerformed(ActionEvent e) {
if(e.getSource() == timer){
System.out.println("Timer Event");
nextFrame();
}
}
public File getFile(){
JFileChooser jfc = new JFileChooser();
jfc.setCurrentDirectory(new File(defaultDir));
int option = jfc.showOpenDialog(null);
if(option == jfc.APPROVE_OPTION){
return jfc.getSelectedFile();
}
return null;
}
public void nextFrame(){
try{
currentFrame ++;
System.out.println("Frame: " + currentFrame);
vidStream.seek(currentFrame);
frameImage = vidStream.getImage();
movieScreen.repaint();
} catch(Exception e){
timer.stop();
e.printStackTrace();
}
}
public void setFrame(int frameNumber){
try{
vidStream.seek(frameNumber);
frameImage = vidStream.getImage();
movieScreen.repaint();
} catch(Exception e){
e.printStackTrace();
}
}
public long getVideoLengthInMillis(Mpeg1VideoStream stream) {
try {
int nframes = stream.getNumFrames();
double fps = stream.getFrameRate();
return (long) ((1000*(long)nframes) / fps);
} catch(Exception e){
e.printStackTrace();
}
return 0;
}
// PAINTER
public class Painter extends JPanel{
public Painter(){}
public void paintComponent(Graphics gr){
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
if(frameImage != null){
g.drawImage(frameImage, 0, 0, null);
}
}
}
// PAINTER
Timer timer;
int currentFrame = 0;
Image frameImage = null;
JFrame movieScreen;
Mpeg1File mpgFile;
Mpeg1VideoStream vidStream;
String defaultDir = ".";
}
Dear andreyvk ,
I've read your post
http://forum.java.sun.com/thread.jspa?threadID=785134&tstart=165
about how to use a single RTP session for both media reception and trasmission (I'm referring to you RTPSocketAdapter modified version), but, at the moment, I'receive a BIND error.
I think that your post is an EXCELLENT solution. I'modified AVReceive3 and AVTransmit3 in order to accept all parameters (Local IP & Port, Remote IP & Port).
Can you please give me a simple scenario so I can understand what the mistake?
I'use AVTransmit3 and AVReceive3 from different prompts and if I run these 2 classes contemporarely both in 2 different PC (172.17.32.27 and 172.17.32.30) I can transmit the media (vfw://0 for example) using AVTransmit3 but I'can't receive nothing if I run also AVReceive3 in the same PC?
What's the problem? Furthermore, If I run first AVReceive3 from a MSDOS Prompt and subsequently I run AVTransmit3 from another prompt I see a BIND error (port already in use).
How can I use your modified RTPSocketAdapter in order to send and receive a single media from the same port (e.g. 7500).
I've used this scenario PC1: IP 172.17.32.30 Local Port 5000 and PC2:IP 172.17.32.27 LocalPort 10000
So in the PC1 I run:
AVTransmit3 vfw://0 <Local IP 172.17.32.30> <5000> <Remote IP 172.17.32.27> <10000>
AVReceive3 <Local IP 172.17.32.30/5000> <Remote IP 172.17.32.27/10000>
and in PC2:
AVTransmit3 vfw://0 <Local IP 172.17.32.27> <10000> <Remote IP 172.17.32.30> <5000>
AVReceive3 <Local IP 172.17.32.27/10000> <Remote IP 172.17.32.30/5000>
I'd like to use the same port 5000 (in PC1) and 10000 (in PC2) in order to transmit and receive rtp packets. How can i do that without receive a Bind Error? How can I receive packets (and playing these media if audio &/or video) from the same port used to send stream over the network?
How can I obtain a RTP Symmetric Transmission/Reception solution?
Please give me an hint. If you can't post this is my email: Siracg99@libero.it