Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/367.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Xuggler“;“无法写入标题”;错误_Java_Screenshot_Screen Capture_Xuggler_Xuggle - Fatal编程技术网

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;

我正在用Xuggler制作一个屏幕录制应用程序。我基本上已经将Java代码极客的Xuggler教程代码封装到一个可运行的类中,用于实际录制。它应该像教程一样运行,但是我得到了一些(实际上是一大堆)错误。指向该代码的链接位于此处:。我不想把这整段代码都归功于我

以下是我到目前为止的情况:

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字节,并且该文件不会播放。我真的需要一些帮助,因为我甚至不知道这些错误是什么意思,所以很难调试它们。谢谢

我们可能会因为不遵守本网站的问答格式而遇到麻烦,所以我只列出一些你可以尝试的东西

  • 当您没有专门调用
    writeHeader()
    时,也会引发与标头相关的错误。您还将收到一个关于“缺少流”的错误。这表明Xugler缺少正确添加视频流和打开编写器所需的一些信息。因此,首先调试Java应用程序,找出导致错误的具体行

  • 另外,在编写之前,请尝试将每个输出帧渲染为
    JFrame
    。这将允许您验证要写入的
    缓冲区图像是否具有正确的内容

  • 您写入的文件是MP4,这将使Xuggler对所需的输出参数得出一些结论,但您最好不要依赖于此。请尝试自行设置像素格式比特率帧速率时基。这就是为什么建议您使用缓冲区:您将能够以特定的间隔写入帧,这将保证正确的帧速率。现在设置它的方式将导致可变帧速率,这是一些编解码器和容器不喜欢的。缓冲区的类型没有那么重要,您甚至可以使用
    ArrayList
    。但是,一些数据结构自然会比其他数据结构更有效

  • 有些编解码器和文件容器比其他的要宽容得多。所以也可以试试其他的编解码器,比如H.264。您也可以尝试更改文件容器,但MP4在Xugler中通常可以正常工作

  • 这与您当前的问题无关,因为这与输出文件为空无关。但是你应该注意你写帧的时间戳。第一个视频帧应该在时间戳0处,但由于您在相同的
    循环中捕获和编码,因此第一个帧将具有更高的时间戳。此外,当您暂停时,应用程序不会写入任何帧,但时间戳仍会增加。当你以后继续录制时,这会在你的视频中造成一个“洞”,一个没有任何视频数据的小时间窗口


当您禁用写入预告片时,输出文件的结果如何?它的内容仍然是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()
,允许您