如何从 Java 应用程序中传输实时视频?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3214422/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to transmit live video from within a Java application?
提问by Tansir1
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.
我正在尝试寻找流式传输 Java 应用程序中生成的实时视频的方法。应用程序需要对其自身进行截图并将其编码为视频流并发布该流。
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.
到目前为止,我一直在使用Xuggler(基于 FFMPEG 的 Java 库)将屏幕截图编码为视频文件。这很好用。Xuggler 声称能够通过 RTMP 传输实时视频,但我还没有找到任何有关如何以编程方式执行此操作的文档。
- 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.
- 有谁知道如何从 Xuggler 以编程方式流式传输 RTMP 视频?
- 有没有人对我可以用来实现相同结果的其他库提出建议?我更喜欢通过 RTP 以 MPEG2 格式流式传输视频。
I did find someone else asking a very similar question on the Xuggler forums herewith no response.
我没有找别人问一个非常类似的问题在Xuggler论坛这里没有响应。
I have looked into JMF and it is not an option for other reasons.
我已经研究过 JMF,但由于其他原因,它不是一个选项。
回答by Paul Gregtheitroade
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 [email protected] for the example). If the code doesn't show up here's pastebin for it: http://pastebin.com/sJHwj0nW
老实说,不要在 JMF 上浪费时间,您可以认为该产品已死。以下是使用 h.264 对 rtmp 流进行屏幕截图的方法(感谢 [email protected] 作为示例)。如果代码没有显示在这里是它的 pastebin: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();
}
}

