如何从 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 00:50:19  来源:igfitidea点击:

How to transmit live video from within a Java application?

javavideo-streamingxuggle

提问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 传输实时视频,但我还没有找到任何有关如何以编程方式执行此操作的文档。

  1. Does anyone know how to stream RTMP video programmatically from Xuggler?
  2. 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.
  1. 有谁知道如何从 Xuggler 以编程方式流式传输 RTMP 视频?
  2. 有没有人对我可以用来实现相同结果的其他库提出建议?我更喜欢通过 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();
    }
}