Xuggler로 스크린 레코딩 응용 프로그램을 만들고 있습니다. 기본적으로 Java 코드 괴짜의 Xuggler 자습서 코드를 실제 녹음을위한 실행 가능한 클래스에 캡슐화했습니다. 튜토리얼처럼 실행해야하지만, 실제로는 몇 가지 오류가 발생합니다. 코드 링크는 JavaCodeGeeks입니다. 이 코드 블록 전체에 대해 신용을 얻으려고하지는 않습니다.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)
나는 경우 isHeaderWritten()를 추가하여 그것을 해결하기 위해 노력 정지 방법 문 ,하지만 결코 전혀 호출되지 않습니다, 그래서 그것은 어딘가에 (또는 if 문 내에서) 있어야합니다. 내 코드의 어떤 줄이 오류를 던지는지 모르겠다. 왜냐하면이 두 가지 오류는 내 코드가 아닌 Xuggler를 가리킨다. 이것을 실행하면 mp4 파일이 생성되지만 크기는 0 바이트이므로 파일이 재생되지 않습니다. 이러한 오류가 무엇을 의미하는지 모르기 때문에 실제로 도움을받을 수 있습니다. 따라서 디버깅하기가 어렵습니다. 감사!
예고편 작성을 사용 중지하면 출력 파일은 어떻게됩니까? 그 내용은 여전히 0 바이트입니까? 그렇다면 실제로 오류를 발생시키는 트레일러를 작성하는 경우에도 인코딩에 문제가 있습니다. IStreamCoder의 너비와 높이가 개별 이미지의 너비와 높이와 다른 것으로 설정되어 있음을 알았습니다. 그것은 그것과 관련이있을 수 있습니다. – Luke
이 오류와 관련없는 부수적 인 메모입니다. 캡처 한 이미지에 버퍼를 사용하고 쓰기 위해 별도의 스레드를 사용하려고 할 것입니다. 정말 빠른 컴퓨터를 사용하지 않는 한 캡처, 변환 및 인코딩 작업은 정말 오래 걸릴 것입니다. 그리고 현재 코드가 그 시간 동안 새로운 이미지를 캡처하지 않기 때문에 프레임 속도가 다양 해지고 종종 사라집니다. 비디오 플레이어는 마음에 들지 않습니다. – Luke
죄송합니다. 어디에서 예고편을 사용할 수 없나요? IMediaWriter 또는 IContainer에 있습니까? 내 코드를 편집 했으므로 이제는 bounds.width와 height를 나누는 대신 사용합니다. –