JMF笔记

(听说好像有个FMJ比JMF好用,但FMJ的资料很难找到,有FMJ相关资料的朋友能不能共享下,3Q~


好久就想学学JMF的多媒体编程了,断断续续试验了几个月,大概知道了怎么操作摄像头和麦克风来录像、拍照、录音,保存文件,和通过rtp进行视频和语音聊天。下面一些代码来自网上,或参考教程手册 Java Media Framework API Guide.pdf 总结出来的


播放本地多媒体文件或摄像头、麦克风的步骤基本是:得到MediaLocator,创建Player或Processor,然后就是了


首先得到数据源的媒体定位器(MediaLocator)
有点像文件的URL定位符,MediaLocator是多媒体数据源的定位符——不管是硬件设备或本地和网络上的多媒体,都用它定位。

得到文件的数据源的定位:
MediaLocator mediaLocator = new MediaLocator(new File("D:/aa.mov").toURL());
//一些常见的格式,如avi等好像不支持,是不是要用一些plug-in?

得到摄像头定位:
Vector videoList = CaptureDeviceManager.getDeviceList(new VideoFormat(null));
if(videoList.size()>0) {
	MediaLocator mediaLocator = ((CaptureDeviceInfo) videoList.get(0)).getLocator();
}

得到麦克风定位:
Vector audioList = CaptureDeviceManager.getDeviceList(new AudioFormat(null));
if(audioList .size()>0) {
	MediaLocator mediaLocator = ((CaptureDeviceInfo) videoList.get(0)).getLocator();
} 


创建Player

Player player = Manager.createPlayer(mediaLocator);
player.start();

player.start()的过程中经历了unrealized、realized、started等几个状态的变化。当player到realized状态时,可以的到它的可视化组件;started状态时开始输出数据流。为了看到可视化效果,比较完整的代码应该给它添加一个事件监听器处理事件:

Player player = Manager.createPlayer(mediaLocator);
player.addControllerListener(new ControllerListener() {	
	@Override
	public void controllerUpdate(ControllerEvent e) {
		Player player = (Player) e.getSourceController();
		if(e instanceof RealizeCompleteEvent) {
			if(player.getVisualComponent()!=null)
				frame.add(player.getVisualComponent());
			if(player.getControlPanelComponent()!=null)
				frame.add(player.getControlPanelComponent(),BorderLayout.SOUTH);
			frame.pack();
		}
	}
});
player.start();



摄像头拍照
player.start()了之后,用以下代码得到一帧图片

FrameGrabbingControl fgc = (FrameGrabbingControl) player.getControl("javax.media.control.FrameGrabbingControl");
Buffer buf = fgc.grabFrame();
BufferToImage b2i = new BufferToImage((VideoFormat)buf.getFormat());
Image img = b2i.createImage(buf);


创建DataSink保存录像录音文件

DataSink是数据流的去处,可以使本地文件或网络。

像创建Player一样创建一个Processor(Processor继承了Player,但Processor可以对输出数据流进行编码处理等),设置输出格式,然后创建一个DataSink指明数据要保存到哪,然后processor.start(),dataSink.open()就开始录制了。
下面一段代码用摄像机录制了10秒后保存文件,用注释的替换后是麦克风录制10秒,其中用到StateHelper类

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;

import javax.media.CaptureDeviceInfo;
import javax.media.CaptureDeviceManager;
import javax.media.DataSink;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoDataSinkException;
import javax.media.NoProcessorException;
import javax.media.NotRealizedError;
import javax.media.Processor;
import javax.media.format.VideoFormat;
import javax.media.protocol.FileTypeDescriptor;

public class Save2File {

	public static void main(String[] args) {
		CaptureDeviceInfo info = (CaptureDeviceInfo) CaptureDeviceManager.getDeviceList(new VideoFormat(null)).get(0);
//		CaptureDeviceInfo info = (CaptureDeviceInfo) CaptureDeviceManager.getDeviceList(new AudioFormat(null)).get(0);
		Processor p = null;
		try {
			p = Manager.createProcessor(info.getLocator());
		} catch (NoProcessorException | IOException e) {
			e.printStackTrace();
		}
		StateHelper sh = new StateHelper(p);
		sh.configure(5000);
		VideoFormat vf = new VideoFormat(VideoFormat.CINEPAK);
//		AudioFormat vf = new AudioFormat(AudioFormat.IMA4);
		p.getTrackControls()[0].setFormat(vf);
		p.getTrackControls()[0].setEnabled(true);
		p.setContentDescriptor(new FileTypeDescriptor(FileTypeDescriptor.QUICKTIME));
		sh.realize(5000);
		File file = new File("video.wav");
		try {
			file.createNewFile();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		DataSink sink = null;
		try {
			sink = Manager.createDataSink(p.getDataOutput(), new MediaLocator(file.toURL()));			
		} catch (NoDataSinkException | NotRealizedError | MalformedURLException e) {
			e.printStackTrace();
		}		
		try {
			p.start();
			sink.open();
			sink.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
		try {
			Thread.sleep(10000);//录制10秒
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		try {
			p.close();
			sink.stop();
			sink.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

可以用Manager.createMergingDataSource(...)把视频数据和音频数据合成,不过我试了下,总是报NoDataSinkException


用RTPManager进行rtp视频音频聊天

发送的步骤基本是:configure  processor,设置processor输出格式,realize  processor;然后创建一个RTPManager,设置本地和远程端的IP地址和端口,用RTPManager.createSendStream(...)把processor的输出数据流发送出去,然后processor.start()开始发送。

接收端也创建RTPManager,添加事件监听器,设置本机和远程端的地址和端口,检测到发送端来的数据后创建Player,把多媒体数据播放出来或保存。

代码http://www.oschina.net/code/snippet_189801_8717



 

你可能感兴趣的:(视频,JMF,语音,保存,RTP)