Java Xuggler“;“无法写入标题”;错误
我正在用Xuggler制作一个屏幕录制应用程序。我基本上已经将Java代码极客的Xuggler教程代码封装到一个可运行的类中,用于实际录制。它应该像教程一样运行,但是我得到了一些(实际上是一大堆)错误。指向该代码的链接位于此处:。我不想把这整段代码都归功于我 以下是我到目前为止的情况:Java Xuggler“;“无法写入标题”;错误,java,screenshot,screen-capture,xuggler,xuggle,Java,Screenshot,Screen Capture,Xuggler,Xuggle,我正在用Xuggler制作一个屏幕录制应用程序。我基本上已经将Java代码极客的Xuggler教程代码封装到一个可运行的类中,用于实际录制。它应该像教程一样运行,但是我得到了一些(实际上是一大堆)错误。指向该代码的链接位于此处:。我不想把这整段代码都归功于我 以下是我到目前为止的情况: import java.awt.AWTException; import java.awt.Dimension; import java.awt.Rectangle; import java.awt.Robot;
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.concurrent.TimeUnit;
import javax.swing.JOptionPane;
import src.dtf.gui.GUI;
import com.xuggle.mediatool.IMediaWriter;
import com.xuggle.mediatool.ToolFactory;
import com.xuggle.xuggler.ICodec;
public class ScreenRecorder implements Runnable {
//Booleans to run and to pause. (Pausing not implemented yet)
boolean running = true;
boolean paused = false;
//Some variables
private GUI gui;
private Toolkit tk;
private String path, name, outputFilename;
private int fps;
private long startTime;
private Rectangle recArea;
private Dimension bounds;
//Declare the MediaWriter
private IMediaWriter writer;
//Constructor
public ScreenRecorder(GUI gui) {
//Set the GUI to the one that I'm using (Another class
this.gui = gui;
//Initialize variables, based on previous user input.
tk = Toolkit.getDefaultToolkit();
path = gui.getPath();
name = JOptionPane.showInputDialog("Please enter a name for your video file:");
outputFilename = path + "\\" + name + ".mp4";
fps = gui.getFPS();
if (gui.fullscreenChecked()) {
recArea = new Rectangle(0, 0, tk.getScreenSize().width,
tk.getScreenSize().height);
} else {
recArea = gui.getArea();
}
bounds = new Dimension(recArea.width, recArea.height);
}
//Start method
public void start() {
gui.disableButtons();
gui.changeRecordButton(false);
running = true;
}
//Run method
public void run() {
//Initialize
init();
long lastTime = System.currentTimeMillis();
int updateTime = 1000 / fps;
startTime = System.nanoTime();
while (running) {
//Limit updates
if (System.currentTimeMillis() - lastTime >= updateTime) {
//Ensure the recording is not paused
if (!paused) {
//If the user has stopped, stop
if (!gui.isRecording()) {
stop();
}
//Take a screenshot and convert it
BufferedImage frame = takeScreenshot();
BufferedImage bgrScreen = convertImage(frame, BufferedImage.TYPE_3BYTE_BGR);
//Encode video
writer.encodeVideo(0, bgrScreen, System.nanoTime() - startTime, TimeUnit.NANOSECONDS);
System.out.println("Recording...");
} else if (paused) {
System.out.println("Paused...");
}
}
}
}
private void init() {
//Make sure the given directory exists
checkFile();
//Ensure there is not already a file of the same name
checkFilename();
//Make the writer
writer = ToolFactory.makeWriter(outputFilename);
writer.addVideoStream(0, 0, ICodec.ID.CODEC_ID_MPEG4, bounds.width, bounds.height);
}
//Method for checking if the directory exists
private void checkFile() {
if (!(new File(path).exists())) {
gui.resetPath();
JOptionPane.showMessageDialog(gui, "ERROR: File path does not exist!");
System.out.println("ERRR");
stop();
}
}
//Method for checking if the given filename exists
private void checkFilename() {
if (new File(path + "\\" + name + ".mp4").exists()) {
JOptionPane.showMessageDialog(gui, "ERROR: File already exists!!");
stop();
}
}
//Method for converting the BufferedImage (Thanks JavaCodeGeeks)
private BufferedImage convertImage(BufferedImage b, int targetType) {
BufferedImage image;
if (b.getType() == targetType) {
image = b;
} else {
image = new BufferedImage(b.getWidth(), b.getHeight(), targetType);
image.getGraphics().drawImage(b, 0, 0, null);
}
return image;
}
//Method for taking a screenshot
private BufferedImage takeScreenshot() {
try {
Robot r = new Robot();
return r.createScreenCapture(recArea);
} catch (AWTException e) {
e.printStackTrace();
return null;
}
}
//Stop method
public void stop() {
gui.enableButtons();
gui.changeRecordButton(true);
//Make sure the writer has been initialized. (Not an incorrect filename or anything)
if (writer != null) {
//Close the writer
writer.close();
}
//End thread
running = false;
}
}
下面是抛出的错误:
17:46:48.076 [Thread-2] ERROR org.ffmpeg - [mp4 @ 000000000028F660] no streams
17:46:48.123 [Thread-2] ERROR com.xuggle.xuggler - Error: could not write header for container (../../../../../../../csrc/com/xuggle/xuggler/Container.cpp:827)
我试图通过在stop方法中添加ISHEADERWRITED()if语句来修复它,但这根本不会被调用,因此它必须在其他地方(或在该if语句中)。我不知道我的代码的哪一行抛出了错误,因为它只给出了这两个错误,它们指向Xuggler,而不是我的代码。当我执行此操作时,它会创建一个mp4文件,但其大小为0字节,并且该文件不会播放。我真的需要一些帮助,因为我甚至不知道这些错误是什么意思,所以很难调试它们。谢谢 我们可能会因为不遵守本网站的问答格式而遇到麻烦,所以我只列出一些你可以尝试的东西
- 当您没有专门调用
时,也会引发与标头相关的错误。您还将收到一个关于“缺少流”的错误。这表明Xugler缺少正确添加视频流和打开编写器所需的一些信息。因此,首先调试Java应用程序,找出导致错误的具体行writeHeader()
- 另外,在编写之前,请尝试将每个输出帧渲染为
。这将允许您验证要写入的JFrame
缓冲区图像是否具有正确的内容
- 您写入的文件是MP4,这将使Xuggler对所需的输出参数得出一些结论,但您最好不要依赖于此。请尝试自行设置像素格式、比特率、帧速率和时基。这就是为什么建议您使用缓冲区:您将能够以特定的间隔写入帧,这将保证正确的帧速率。现在设置它的方式将导致可变帧速率,这是一些编解码器和容器不喜欢的。缓冲区的类型没有那么重要,您甚至可以使用
。但是,一些数据结构自然会比其他数据结构更有效ArrayList
- 有些编解码器和文件容器比其他的要宽容得多。所以也可以试试其他的编解码器,比如H.264。您也可以尝试更改文件容器,但MP4在Xugler中通常可以正常工作
- 这与您当前的问题无关,因为这与输出文件为空无关。但是你应该注意你写帧的时间戳。第一个视频帧应该在时间戳0处,但由于您在相同的
循环中捕获和编码,因此第一个帧将具有更高的时间戳。此外,当您暂停时,应用程序不会写入任何帧,但时间戳仍会增加。当你以后继续录制时,这会在你的视频中造成一个“洞”,一个没有任何视频数据的小时间窗口
IStreamCoder
的宽度和高度设置为不同于单个图像的宽度和高度。这可能与此有关。只是一个旁注,与此错误无关:您可能希望为捕获的图像使用缓冲区,并使用单独的线程来写入它们。除非你在一台速度非常快的计算机上,否则捕获、转换和编码都会花费很长时间。由于您当前的代码在此期间不会捕获任何新图像,帧速率会发生变化,并且经常会下降,这是视频播放器不喜欢的。很抱歉,但是我在哪里禁用预告片?是用IMediaWriter还是IContainer?我已经编辑了我的代码,现在我只使用bounds.width和height,而不是分割它们。我完全支持性能增强。不过我有一个问题,三条线会不会太多?因为现在我正在为GUI运行一个线程,然后这个类是第二个线程。我的错误是,我的意思是编写没有头的文件。您可以使用任意多的线程,但是您必须采取一些措施来管理CPU和内存的使用。如果所有线程都是while(true)的变体,则只需耗尽CPU,直到内存耗尽。相反,在你的while
-循环中包含如下内容:if(inBuffer.size()>0&&exputfer.size()<20){\\code}else{Thread.sleep(100);}
Hmm。我已经将图像绘制到一个帧中,它似乎正在工作。我将编解码器切换到H264,现在出现以下错误:ERROR org.ffmpeg-[libx264@0000000000 10db10]高度不能除以2(394x293)
和“错误:无法打开编解码器”。我自己不知道如何输入这些信息。你能给我指一些关于我应该如何在Xuggler做这些事情的研究吗?据我所见,Xugler上的文档非常糟糕,而且大多数情况下都无法加载到我的计算机上。你说得很对,文档非常糟糕。尝试和错误是唯一的出路,除了用谷歌搜索你的错误信息。“高度不能被2整除”的错误很容易解决:将你的高度设为294,而不是293,这样它就可以被2整除:)IMediaWriter有一个底层的IStream
和一个底层的IStreamCoder
。有一些函数,如getStreamCoder()
,允许您