java视频传输,如何从Java应用程序中传输实时视频?

I'm trying to find ways to stream a live video generated in a Java application. The application needs to take screenshots of itself and encode these into a video stream and publish the stream.

So far I have been using Xuggler (a Java library on top of FFMPEG) to encode the screenshots into a video file. This works great. Xuggler claims to be able to transmit live video via RTMP but I have not found any documentation on how to do this programmatically.

Does anyone know how to stream RTMP video programmatically from Xuggler?

Does anyone have a suggestion on other libraries I could use to achieve the same results? I'd prefer to stream the video in MPEG2 over RTP.

I did find someone else asking a very similar question on the Xuggler forums here with no response.

I have looked into JMF and it is not an option for other reasons.

解决方案

Honestly don't waste your time with JMF, you can consider that offering dead. Here is how you would do screen shotting to an rtmp stream using h.264 (thanks to tyreus@gmail.com for the example). If the code doesn't show up here's pastebin for it: http://pastebin.com/sJHwj0nW

import com.xuggle.xuggler.Configuration;

import com.xuggle.xuggler.ICodec;

import com.xuggle.xuggler.IContainer;

import com.xuggle.xuggler.IContainerFormat;

import com.xuggle.xuggler.IPacket;

import com.xuggle.xuggler.IPixelFormat;

import com.xuggle.xuggler.IRational;

import com.xuggle.xuggler.IStream;

import com.xuggle.xuggler.IStreamCoder;

import com.xuggle.xuggler.IVideoPicture;

import com.xuggle.xuggler.video.ConverterFactory;

import com.xuggle.xuggler.video.IConverter;

import java.awt.AWTException;

import java.awt.Rectangle;

import java.awt.Robot;

import java.awt.image.BufferedImage;

import java.io.IOException;

import java.io.InputStream;

import java.util.Properties;

public class XugglerRtmpReferenceImpl {

private static String url = "rtmp://your.test.server/screen/";

private static String fileName = "test/teststream";

private static int framesToEncode = 60;

private static int x = 0;

private static int y = 0;

private static int height = 480;

private static int width = 640;

public static void main(String[] args) {

IContainer container = IContainer.make();

IContainerFormat containerFormat_live = IContainerFormat.make();

containerFormat_live.setOutputFormat("flv", url + fileName, null);

container.setInputBufferLength(0);

int retVal = container.open(url + fileName, IContainer.Type.WRITE, containerFormat_live);

if (retVal < 0) {

System.err.println("Could not open output container for live stream");

System.exit(1);

}

IStream stream = container.addNewStream(0);

IStreamCoder coder = stream.getStreamCoder();

ICodec codec = ICodec.findEncodingCodec(ICodec.ID.CODEC_ID_H264);

coder.setNumPicturesInGroupOfPictures(5);

coder.setCodec(codec);

coder.setBitRate(200000);

coder.setPixelType(IPixelFormat.Type.YUV420P);

coder.setHeight(height);

coder.setWidth(width);

System.out.println("[ENCODER] video size is " + width + "x" + height);

coder.setFlag(IStreamCoder.Flags.FLAG_QSCALE, true);

coder.setGlobalQuality(0);

IRational frameRate = IRational.make(5, 1);

coder.setFrameRate(frameRate);

coder.setTimeBase(IRational.make(frameRate.getDenominator(), frameRate.getNumerator()));

Properties props = new Properties();

InputStream is = XugglerRtmpReferenceImpl.class.getResourceAsStream("/libx264-normal.ffpreset");

try {

props.load(is);

} catch (IOException e) {

System.err.println("You need the libx264-normal.ffpreset file from the Xuggle distribution in your classpath.");

System.exit(1);

}

Configuration.configure(props, coder);

coder.open();

container.writeHeader();

long firstTimeStamp = System.currentTimeMillis();

long lastTimeStamp = -1;

int i = 0;

try {

Robot robot = new Robot();

while (i < framesToEncode) {

//long iterationStartTime = System.currentTimeMillis();

long now = System.currentTimeMillis();

//grab the screenshot

BufferedImage image = robot.createScreenCapture(new Rectangle(x, y, width, height));

//convert it for Xuggler

BufferedImage currentScreenshot = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR);

currentScreenshot.getGraphics().drawImage(image, 0, 0, null);

//start the encoding process

IPacket packet = IPacket.make();

IConverter converter = ConverterFactory.createConverter(currentScreenshot, IPixelFormat.Type.YUV420P);

long timeStamp = (now - firstTimeStamp) * 1000;

IVideoPicture outFrame = converter.toPicture(currentScreenshot, timeStamp);

if (i == 0) {

//make first frame keyframe

outFrame.setKeyFrame(true);

}

outFrame.setQuality(0);

coder.encodeVideo(packet, outFrame, 0);

outFrame.delete();

if (packet.isComplete()) {

container.writePacket(packet);

System.out.println("[ENCODER] writing packet of size " + packet.getSize() + " for elapsed time " + ((timeStamp - lastTimeStamp) / 1000));

lastTimeStamp = timeStamp;

}

System.out.println("[ENCODER] encoded image " + i + " in " + (System.currentTimeMillis() - now));

i++;

try {

Thread.sleep(Math.max((long) (1000 / frameRate.getDouble()) - (System.currentTimeMillis() - now), 0));

} catch (InterruptedException e) {

e.printStackTrace();

}

}

} catch (AWTException e) {

e.printStackTrace();

}

container.writeTrailer();

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值