Use RGB instead of ARGB for export and therefore speed up OpenGL to output conversion process
This commit is contained in:
@@ -4,7 +4,7 @@ import eu.crushedpixel.replaymod.gui.elements.GuiProgressBar;
|
|||||||
import eu.crushedpixel.replaymod.utils.BoundingUtils;
|
import eu.crushedpixel.replaymod.utils.BoundingUtils;
|
||||||
import eu.crushedpixel.replaymod.utils.DurationUtils;
|
import eu.crushedpixel.replaymod.utils.DurationUtils;
|
||||||
import eu.crushedpixel.replaymod.video.VideoRenderer;
|
import eu.crushedpixel.replaymod.video.VideoRenderer;
|
||||||
import eu.crushedpixel.replaymod.video.frame.ARGBFrame;
|
import eu.crushedpixel.replaymod.video.frame.RGBFrame;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.GuiButton;
|
import net.minecraft.client.gui.GuiButton;
|
||||||
import net.minecraft.client.gui.GuiScreen;
|
import net.minecraft.client.gui.GuiScreen;
|
||||||
@@ -234,7 +234,7 @@ public class GuiVideoRenderer extends GuiScreen {
|
|||||||
drawScaledCustomSizeModalRect(x, y, 0, 0, 1280, 720, actualWidth, actualHeight, 1280, 720);
|
drawScaledCustomSizeModalRect(x, y, 0, 0, 1280, 720, actualWidth, actualHeight, 1280, 720);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updatePreview(ARGBFrame frame) {
|
public void updatePreview(RGBFrame frame) {
|
||||||
if (previewCheckBox.isChecked() && previewTexture != null) {
|
if (previewCheckBox.isChecked() && previewTexture != null) {
|
||||||
ByteBuffer buffer = frame.getByteBuffer();
|
ByteBuffer buffer = frame.getByteBuffer();
|
||||||
buffer.mark();
|
buffer.mark();
|
||||||
|
|||||||
@@ -9,22 +9,22 @@ import net.minecraft.client.resources.I18n;
|
|||||||
public enum EncodingPreset implements GuiEntryListEntry {
|
public enum EncodingPreset implements GuiEntryListEntry {
|
||||||
|
|
||||||
MP4CUSTOM("replaymod.gui.rendersettings.presets.mp4.custom",
|
MP4CUSTOM("replaymod.gui.rendersettings.presets.mp4.custom",
|
||||||
"-f rawvideo -pix_fmt argb -s %WIDTH%x%HEIGHT% -r %FPS% -i - -an -c:v libx264 -b:v %BITRATE% -pix_fmt yuv420p %FILENAME%.mp4", "mp4"),
|
"-f rawvideo -pix_fmt rgb24 -s %WIDTH%x%HEIGHT% -r %FPS% -i - -an -c:v libx264 -b:v %BITRATE% -pix_fmt yuv420p %FILENAME%.mp4", "mp4"),
|
||||||
|
|
||||||
MP4HIGH("replaymod.gui.rendersettings.presets.mp4.high",
|
MP4HIGH("replaymod.gui.rendersettings.presets.mp4.high",
|
||||||
"-f rawvideo -pix_fmt argb -s %WIDTH%x%HEIGHT% -r %FPS% -i - -an -c:v libx264 -preset ultrafast -qp 1 -pix_fmt yuv420p %FILENAME%.mp4", "mp4"),
|
"-f rawvideo -pix_fmt rgb24 -s %WIDTH%x%HEIGHT% -r %FPS% -i - -an -c:v libx264 -preset ultrafast -qp 1 -pix_fmt yuv420p %FILENAME%.mp4", "mp4"),
|
||||||
|
|
||||||
MP4DEFAULT("replaymod.gui.rendersettings.presets.mp4.default",
|
MP4DEFAULT("replaymod.gui.rendersettings.presets.mp4.default",
|
||||||
"-f rawvideo -pix_fmt argb -s %WIDTH%x%HEIGHT% -r %FPS% -i - -an -c:v libx264 -preset ultrafast -pix_fmt yuv420p %FILENAME%.mp4", "mp4"),
|
"-f rawvideo -pix_fmt rgb24 -s %WIDTH%x%HEIGHT% -r %FPS% -i - -an -c:v libx264 -preset ultrafast -pix_fmt yuv420p %FILENAME%.mp4", "mp4"),
|
||||||
|
|
||||||
MP4POTATO("replaymod.gui.rendersettings.presets.mp4.potato",
|
MP4POTATO("replaymod.gui.rendersettings.presets.mp4.potato",
|
||||||
"-f rawvideo -pix_fmt argb -s %WIDTH%x%HEIGHT% -r %FPS% -i - -an -c:v libx264 -preset ultrafast -crf 51 -pix_fmt yuv420p %FILENAME%.mp4", "mp4"),
|
"-f rawvideo -pix_fmt rgb24 -s %WIDTH%x%HEIGHT% -r %FPS% -i - -an -c:v libx264 -preset ultrafast -crf 51 -pix_fmt yuv420p %FILENAME%.mp4", "mp4"),
|
||||||
|
|
||||||
WEBMCUSTOM("replaymod.gui.rendersettings.presets.webm.custom",
|
WEBMCUSTOM("replaymod.gui.rendersettings.presets.webm.custom",
|
||||||
"-f rawvideo -pix_fmt argb -s %WIDTH%x%HEIGHT% -r %FPS% -i - -an -c:v libvpx -b:v %BITRATE% %FILENAME%.webm", "webm"),
|
"-f rawvideo -pix_fmt rgb24 -s %WIDTH%x%HEIGHT% -r %FPS% -i - -an -c:v libvpx -b:v %BITRATE% %FILENAME%.webm", "webm"),
|
||||||
|
|
||||||
MKVLOSSLESS("replaymod.gui.rendersettings.presets.mkv.lossless",
|
MKVLOSSLESS("replaymod.gui.rendersettings.presets.mkv.lossless",
|
||||||
"-f rawvideo -pix_fmt argb -s %WIDTH%x%HEIGHT% -r %FPS% -i - -an -c:v libx264 -preset ultrafast -qp 0 %FILENAME%.mkv", "mkv");
|
"-f rawvideo -pix_fmt rgb24 -s %WIDTH%x%HEIGHT% -r %FPS% -i - -an -c:v libx264 -preset ultrafast -qp 0 %FILENAME%.mkv", "mkv");
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
|||||||
@@ -25,19 +25,14 @@ public class OpenGLUtils {
|
|||||||
public static void init() {
|
public static void init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void openGlBytesToARBG(ByteBuffer buffer, int bufferWidth, int xOffset, int yOffset, ByteBuffer to, int width) {
|
public static void openGlBytesToRBG(ByteBuffer buffer, int bufferWidth, int xOffset, int yOffset, ByteBuffer to, int width) {
|
||||||
byte[] pixel = new byte[4];
|
byte[] rowBuf = new byte[bufferWidth * 3];
|
||||||
pixel[0] = (byte) 0xff;
|
// Copy image flipped vertically to target buffer
|
||||||
int bufferSize = buffer.remaining() / 3;
|
int rows = buffer.remaining() / 3 / bufferWidth;
|
||||||
// Read the OpenGL image row by row from right to left (flipped horizontally)
|
for (int i = 0; i < rows; i++) {
|
||||||
for (int i = bufferSize - 1; i >= 0; i--) {
|
buffer.get(rowBuf);
|
||||||
// Coordinates in the final image
|
to.position(((yOffset + rows - i - 1) * width + xOffset) * 3);
|
||||||
int x = xOffset + bufferWidth - i % bufferWidth - 1; // X coord of OpenGL image has to be flipped first
|
to.put(rowBuf);
|
||||||
int y = yOffset + i / bufferWidth;
|
|
||||||
// Write to image (row by row, left to right)
|
|
||||||
buffer.get(pixel, 1, 3);
|
|
||||||
to.position((y * width + x) * 4);
|
|
||||||
to.put(pixel);
|
|
||||||
}
|
}
|
||||||
to.rewind();
|
to.rewind();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import eu.crushedpixel.replaymod.settings.RenderOptions;
|
|||||||
import eu.crushedpixel.replaymod.timer.EnchantmentTimer;
|
import eu.crushedpixel.replaymod.timer.EnchantmentTimer;
|
||||||
import eu.crushedpixel.replaymod.timer.ReplayTimer;
|
import eu.crushedpixel.replaymod.timer.ReplayTimer;
|
||||||
import eu.crushedpixel.replaymod.video.capturer.RenderInfo;
|
import eu.crushedpixel.replaymod.video.capturer.RenderInfo;
|
||||||
import eu.crushedpixel.replaymod.video.frame.ARGBFrame;
|
import eu.crushedpixel.replaymod.video.frame.RGBFrame;
|
||||||
import eu.crushedpixel.replaymod.video.rendering.Pipeline;
|
import eu.crushedpixel.replaymod.video.rendering.Pipeline;
|
||||||
import eu.crushedpixel.replaymod.video.rendering.Pipelines;
|
import eu.crushedpixel.replaymod.video.rendering.Pipelines;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
@@ -62,7 +62,7 @@ public class VideoRenderer implements RenderInfo {
|
|||||||
this.options = options;
|
this.options = options;
|
||||||
this.renderingPipeline = Pipelines.newPipeline(options.getMode(), this, new VideoWriter(options) {
|
this.renderingPipeline = Pipelines.newPipeline(options.getMode(), this, new VideoWriter(options) {
|
||||||
@Override
|
@Override
|
||||||
public void consume(ARGBFrame frame) {
|
public void consume(RGBFrame frame) {
|
||||||
gui.updatePreview(frame);
|
gui.updatePreview(frame);
|
||||||
super.consume(frame);
|
super.consume(frame);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import eu.crushedpixel.replaymod.settings.RenderOptions;
|
|||||||
import eu.crushedpixel.replaymod.utils.ByteBufferPool;
|
import eu.crushedpixel.replaymod.utils.ByteBufferPool;
|
||||||
import eu.crushedpixel.replaymod.utils.StreamPipe;
|
import eu.crushedpixel.replaymod.utils.StreamPipe;
|
||||||
import eu.crushedpixel.replaymod.utils.StringUtils;
|
import eu.crushedpixel.replaymod.utils.StringUtils;
|
||||||
import eu.crushedpixel.replaymod.video.frame.ARGBFrame;
|
import eu.crushedpixel.replaymod.video.frame.RGBFrame;
|
||||||
import eu.crushedpixel.replaymod.video.rendering.FrameConsumer;
|
import eu.crushedpixel.replaymod.video.rendering.FrameConsumer;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.crash.CrashReport;
|
import net.minecraft.crash.CrashReport;
|
||||||
@@ -24,7 +24,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
import static org.apache.commons.lang3.Validate.isTrue;
|
import static org.apache.commons.lang3.Validate.isTrue;
|
||||||
|
|
||||||
public class VideoWriter implements FrameConsumer<ARGBFrame> {
|
public class VideoWriter implements FrameConsumer<RGBFrame> {
|
||||||
|
|
||||||
private final RenderOptions options;
|
private final RenderOptions options;
|
||||||
private final Process process;
|
private final Process process;
|
||||||
@@ -84,7 +84,7 @@ public class VideoWriter implements FrameConsumer<ARGBFrame> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void consume(ARGBFrame frame) {
|
public void consume(RGBFrame frame) {
|
||||||
try {
|
try {
|
||||||
checkSize(frame.getSize());
|
checkSize(frame.getSize());
|
||||||
channel.write(frame.getByteBuffer());
|
channel.write(frame.getByteBuffer());
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import org.lwjgl.util.ReadableDimension;
|
|||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class ARGBFrame implements Frame {
|
public class RGBFrame implements Frame {
|
||||||
@Getter
|
@Getter
|
||||||
private final int frameId;
|
private final int frameId;
|
||||||
|
|
||||||
@@ -17,8 +17,8 @@ public class ARGBFrame implements Frame {
|
|||||||
@Getter
|
@Getter
|
||||||
private final ByteBuffer byteBuffer;
|
private final ByteBuffer byteBuffer;
|
||||||
|
|
||||||
public ARGBFrame(int frameId, ReadableDimension size, ByteBuffer byteBuffer) {
|
public RGBFrame(int frameId, ReadableDimension size, ByteBuffer byteBuffer) {
|
||||||
Validate.isTrue(size.getWidth() * size.getHeight() * 4 == byteBuffer.remaining(),
|
Validate.isTrue(size.getWidth() * size.getHeight() * 3 == byteBuffer.remaining(),
|
||||||
"Buffer size is %d (cap: %d) but should be %d",
|
"Buffer size is %d (cap: %d) but should be %d",
|
||||||
byteBuffer.remaining(), byteBuffer.capacity(), size.getWidth() * size.getHeight() * 4);
|
byteBuffer.remaining(), byteBuffer.capacity(), size.getWidth() * size.getHeight() * 4);
|
||||||
this.frameId = frameId;
|
this.frameId = frameId;
|
||||||
@@ -1,33 +1,33 @@
|
|||||||
package eu.crushedpixel.replaymod.video.processor;
|
package eu.crushedpixel.replaymod.video.processor;
|
||||||
|
|
||||||
import eu.crushedpixel.replaymod.utils.ByteBufferPool;
|
import eu.crushedpixel.replaymod.utils.ByteBufferPool;
|
||||||
import eu.crushedpixel.replaymod.video.frame.ARGBFrame;
|
|
||||||
import eu.crushedpixel.replaymod.video.frame.CubicOpenGlFrame;
|
import eu.crushedpixel.replaymod.video.frame.CubicOpenGlFrame;
|
||||||
|
import eu.crushedpixel.replaymod.video.frame.RGBFrame;
|
||||||
import org.lwjgl.util.Dimension;
|
import org.lwjgl.util.Dimension;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import static eu.crushedpixel.replaymod.utils.OpenGLUtils.openGlBytesToARBG;
|
import static eu.crushedpixel.replaymod.utils.OpenGLUtils.openGlBytesToRBG;
|
||||||
|
|
||||||
public class CubicToARGBProcessor extends AbstractFrameProcessor<CubicOpenGlFrame, ARGBFrame> {
|
public class CubicToRGBProcessor extends AbstractFrameProcessor<CubicOpenGlFrame, RGBFrame> {
|
||||||
@Override
|
@Override
|
||||||
public ARGBFrame process(CubicOpenGlFrame rawFrame) {
|
public RGBFrame process(CubicOpenGlFrame rawFrame) {
|
||||||
int size = rawFrame.getLeft().getSize().getWidth();
|
int size = rawFrame.getLeft().getSize().getWidth();
|
||||||
int width = size * 4;
|
int width = size * 4;
|
||||||
int height = size * 3;
|
int height = size * 3;
|
||||||
ByteBuffer result = ByteBufferPool.allocate(width * height * 4);
|
ByteBuffer result = ByteBufferPool.allocate(width * height * 3);
|
||||||
openGlBytesToARBG(rawFrame.getLeft().getByteBuffer(), size, 0, size, result, width);
|
openGlBytesToRBG(rawFrame.getLeft().getByteBuffer(), size, 0, size, result, width);
|
||||||
openGlBytesToARBG(rawFrame.getFront().getByteBuffer(), size, size, size, result, width);
|
openGlBytesToRBG(rawFrame.getFront().getByteBuffer(), size, size, size, result, width);
|
||||||
openGlBytesToARBG(rawFrame.getRight().getByteBuffer(), size, size * 2, size, result, width);
|
openGlBytesToRBG(rawFrame.getRight().getByteBuffer(), size, size * 2, size, result, width);
|
||||||
openGlBytesToARBG(rawFrame.getBack().getByteBuffer(), size, size * 3, size, result, width);
|
openGlBytesToRBG(rawFrame.getBack().getByteBuffer(), size, size * 3, size, result, width);
|
||||||
openGlBytesToARBG(rawFrame.getTop().getByteBuffer(), size, size, 0, result, width);
|
openGlBytesToRBG(rawFrame.getTop().getByteBuffer(), size, size, 0, result, width);
|
||||||
openGlBytesToARBG(rawFrame.getBottom().getByteBuffer(), size, size, size * 2, result, width);
|
openGlBytesToRBG(rawFrame.getBottom().getByteBuffer(), size, size, size * 2, result, width);
|
||||||
ByteBufferPool.release(rawFrame.getLeft().getByteBuffer());
|
ByteBufferPool.release(rawFrame.getLeft().getByteBuffer());
|
||||||
ByteBufferPool.release(rawFrame.getRight().getByteBuffer());
|
ByteBufferPool.release(rawFrame.getRight().getByteBuffer());
|
||||||
ByteBufferPool.release(rawFrame.getFront().getByteBuffer());
|
ByteBufferPool.release(rawFrame.getFront().getByteBuffer());
|
||||||
ByteBufferPool.release(rawFrame.getBack().getByteBuffer());
|
ByteBufferPool.release(rawFrame.getBack().getByteBuffer());
|
||||||
ByteBufferPool.release(rawFrame.getTop().getByteBuffer());
|
ByteBufferPool.release(rawFrame.getTop().getByteBuffer());
|
||||||
ByteBufferPool.release(rawFrame.getBottom().getByteBuffer());
|
ByteBufferPool.release(rawFrame.getBottom().getByteBuffer());
|
||||||
return new ARGBFrame(rawFrame.getFrameId(), new Dimension(width, height), result);
|
return new RGBFrame(rawFrame.getFrameId(), new Dimension(width, height), result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package eu.crushedpixel.replaymod.video.processor;
|
package eu.crushedpixel.replaymod.video.processor;
|
||||||
|
|
||||||
import eu.crushedpixel.replaymod.utils.ByteBufferPool;
|
import eu.crushedpixel.replaymod.utils.ByteBufferPool;
|
||||||
import eu.crushedpixel.replaymod.video.frame.ARGBFrame;
|
|
||||||
import eu.crushedpixel.replaymod.video.frame.CubicOpenGlFrame;
|
import eu.crushedpixel.replaymod.video.frame.CubicOpenGlFrame;
|
||||||
|
import eu.crushedpixel.replaymod.video.frame.RGBFrame;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.lwjgl.util.Dimension;
|
import org.lwjgl.util.Dimension;
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ import java.nio.ByteBuffer;
|
|||||||
|
|
||||||
import static java.lang.Math.PI;
|
import static java.lang.Math.PI;
|
||||||
|
|
||||||
public class EquirectangularToARGBProcessor extends AbstractFrameProcessor<CubicOpenGlFrame, ARGBFrame> {
|
public class EquirectangularToRGBProcessor extends AbstractFrameProcessor<CubicOpenGlFrame, RGBFrame> {
|
||||||
private static final byte IMAGE_BACK = 0;
|
private static final byte IMAGE_BACK = 0;
|
||||||
private static final byte IMAGE_FRONT = 1;
|
private static final byte IMAGE_FRONT = 1;
|
||||||
private static final byte IMAGE_LEFT = 2;
|
private static final byte IMAGE_LEFT = 2;
|
||||||
@@ -27,7 +27,7 @@ public class EquirectangularToARGBProcessor extends AbstractFrameProcessor<Cubic
|
|||||||
private final int[][] imageY;
|
private final int[][] imageY;
|
||||||
|
|
||||||
|
|
||||||
public EquirectangularToARGBProcessor(int frameSize) {
|
public EquirectangularToRGBProcessor(int frameSize) {
|
||||||
this.frameSize = frameSize;
|
this.frameSize = frameSize;
|
||||||
|
|
||||||
width = frameSize * 4;
|
width = frameSize * 4;
|
||||||
@@ -82,17 +82,16 @@ public class EquirectangularToARGBProcessor extends AbstractFrameProcessor<Cubic
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ARGBFrame process(CubicOpenGlFrame rawFrame) {
|
public RGBFrame process(CubicOpenGlFrame rawFrame) {
|
||||||
Validate.isTrue(rawFrame.getLeft().getSize().getWidth() == frameSize, "Frame size must be %d but was %d",
|
Validate.isTrue(rawFrame.getLeft().getSize().getWidth() == frameSize, "Frame size must be %d but was %d",
|
||||||
frameSize, rawFrame.getLeft().getSize().getWidth());
|
frameSize, rawFrame.getLeft().getSize().getWidth());
|
||||||
ByteBuffer result = ByteBufferPool.allocate(width * height * 4);
|
ByteBuffer result = ByteBufferPool.allocate(width * height * 3);
|
||||||
ByteBuffer[] images = {
|
ByteBuffer[] images = {
|
||||||
rawFrame.getBack().getByteBuffer(), rawFrame.getFront().getByteBuffer(),
|
rawFrame.getBack().getByteBuffer(), rawFrame.getFront().getByteBuffer(),
|
||||||
rawFrame.getLeft().getByteBuffer(), rawFrame.getRight().getByteBuffer(),
|
rawFrame.getLeft().getByteBuffer(), rawFrame.getRight().getByteBuffer(),
|
||||||
rawFrame.getTop().getByteBuffer(), rawFrame.getBottom().getByteBuffer()
|
rawFrame.getTop().getByteBuffer(), rawFrame.getBottom().getByteBuffer()
|
||||||
};
|
};
|
||||||
byte[] pixel = new byte[4];
|
byte[] pixel = new byte[3];
|
||||||
pixel[0] = (byte) 0xff;
|
|
||||||
byte[] image;
|
byte[] image;
|
||||||
int[] imageX, imageY;
|
int[] imageX, imageY;
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
@@ -102,7 +101,7 @@ public class EquirectangularToARGBProcessor extends AbstractFrameProcessor<Cubic
|
|||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
ByteBuffer source = images[image[x]];
|
ByteBuffer source = images[image[x]];
|
||||||
source.position((imageX[x] + imageY[x] * frameSize) * 3);
|
source.position((imageX[x] + imageY[x] * frameSize) * 3);
|
||||||
source.get(pixel, 1, 3);
|
source.get(pixel);
|
||||||
result.put(pixel);
|
result.put(pixel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,6 +113,6 @@ public class EquirectangularToARGBProcessor extends AbstractFrameProcessor<Cubic
|
|||||||
ByteBufferPool.release(rawFrame.getBack().getByteBuffer());
|
ByteBufferPool.release(rawFrame.getBack().getByteBuffer());
|
||||||
ByteBufferPool.release(rawFrame.getTop().getByteBuffer());
|
ByteBufferPool.release(rawFrame.getTop().getByteBuffer());
|
||||||
ByteBufferPool.release(rawFrame.getBottom().getByteBuffer());
|
ByteBufferPool.release(rawFrame.getBottom().getByteBuffer());
|
||||||
return new ARGBFrame(rawFrame.getFrameId(), new Dimension(width, height), result);
|
return new RGBFrame(rawFrame.getFrameId(), new Dimension(width, height), result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package eu.crushedpixel.replaymod.video.processor;
|
|
||||||
|
|
||||||
import eu.crushedpixel.replaymod.utils.ByteBufferPool;
|
|
||||||
import eu.crushedpixel.replaymod.video.frame.ARGBFrame;
|
|
||||||
import eu.crushedpixel.replaymod.video.frame.OpenGlFrame;
|
|
||||||
import org.lwjgl.util.ReadableDimension;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
import static eu.crushedpixel.replaymod.utils.OpenGLUtils.openGlBytesToARBG;
|
|
||||||
|
|
||||||
public class OpenGlToARGBProcessor extends AbstractFrameProcessor<OpenGlFrame, ARGBFrame> {
|
|
||||||
@Override
|
|
||||||
public ARGBFrame process(OpenGlFrame rawFrame) {
|
|
||||||
ReadableDimension size = rawFrame.getSize();
|
|
||||||
ByteBuffer buffer = rawFrame.getByteBuffer();
|
|
||||||
ByteBuffer argb = ByteBufferPool.allocate(size.getWidth() * size.getHeight() * 4);
|
|
||||||
openGlBytesToARBG(buffer, size.getWidth(), 0, 0, argb, size.getWidth());
|
|
||||||
ByteBufferPool.release(buffer);
|
|
||||||
return new ARGBFrame(rawFrame.getFrameId(), size, argb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package eu.crushedpixel.replaymod.video.processor;
|
||||||
|
|
||||||
|
import eu.crushedpixel.replaymod.video.frame.OpenGlFrame;
|
||||||
|
import eu.crushedpixel.replaymod.video.frame.RGBFrame;
|
||||||
|
import org.lwjgl.util.ReadableDimension;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class OpenGlToRGBProcessor extends AbstractFrameProcessor<OpenGlFrame, RGBFrame> {
|
||||||
|
|
||||||
|
private byte[] row, rowSwap;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RGBFrame process(OpenGlFrame rawFrame) {
|
||||||
|
// Flip whole image in place
|
||||||
|
|
||||||
|
ReadableDimension size = rawFrame.getSize();
|
||||||
|
int rowSize = size.getWidth() * 3;
|
||||||
|
if (row == null || row.length < rowSize) {
|
||||||
|
row = new byte[rowSize];
|
||||||
|
rowSwap = new byte[rowSize];
|
||||||
|
}
|
||||||
|
ByteBuffer buffer = rawFrame.getByteBuffer();
|
||||||
|
int rows = size.getHeight();
|
||||||
|
byte[] row = this.row;
|
||||||
|
byte[] rowSwap = this.rowSwap;
|
||||||
|
for (int i = 0; i < rows / 2; i++) {
|
||||||
|
int from = rowSize * i;
|
||||||
|
int to = rowSize * (rows - i - 1);
|
||||||
|
buffer.position(from);
|
||||||
|
buffer.get(row);
|
||||||
|
buffer.position(to);
|
||||||
|
buffer.get(rowSwap);
|
||||||
|
buffer.position(to);
|
||||||
|
buffer.put(row);
|
||||||
|
buffer.position(from);
|
||||||
|
buffer.put(rowSwap);
|
||||||
|
}
|
||||||
|
buffer.rewind();
|
||||||
|
return new RGBFrame(rawFrame.getFrameId(), size, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,27 +1,27 @@
|
|||||||
package eu.crushedpixel.replaymod.video.processor;
|
package eu.crushedpixel.replaymod.video.processor;
|
||||||
|
|
||||||
import eu.crushedpixel.replaymod.utils.ByteBufferPool;
|
import eu.crushedpixel.replaymod.utils.ByteBufferPool;
|
||||||
import eu.crushedpixel.replaymod.video.frame.ARGBFrame;
|
import eu.crushedpixel.replaymod.video.frame.RGBFrame;
|
||||||
import eu.crushedpixel.replaymod.video.frame.StereoscopicOpenGlFrame;
|
import eu.crushedpixel.replaymod.video.frame.StereoscopicOpenGlFrame;
|
||||||
import org.lwjgl.util.Dimension;
|
import org.lwjgl.util.Dimension;
|
||||||
import org.lwjgl.util.ReadableDimension;
|
import org.lwjgl.util.ReadableDimension;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import static eu.crushedpixel.replaymod.utils.OpenGLUtils.openGlBytesToARBG;
|
import static eu.crushedpixel.replaymod.utils.OpenGLUtils.openGlBytesToRBG;
|
||||||
|
|
||||||
public class StereoscopicToARGBProcessor extends AbstractFrameProcessor<StereoscopicOpenGlFrame, ARGBFrame> {
|
public class StereoscopicToRGBProcessor extends AbstractFrameProcessor<StereoscopicOpenGlFrame, RGBFrame> {
|
||||||
@Override
|
@Override
|
||||||
public ARGBFrame process(StereoscopicOpenGlFrame rawFrame) {
|
public RGBFrame process(StereoscopicOpenGlFrame rawFrame) {
|
||||||
ReadableDimension size = rawFrame.getLeft().getSize();
|
ReadableDimension size = rawFrame.getLeft().getSize();
|
||||||
int width = size.getWidth();
|
int width = size.getWidth();
|
||||||
ByteBuffer leftBuffer = rawFrame.getLeft().getByteBuffer();
|
ByteBuffer leftBuffer = rawFrame.getLeft().getByteBuffer();
|
||||||
ByteBuffer rightBuffer = rawFrame.getRight().getByteBuffer();
|
ByteBuffer rightBuffer = rawFrame.getRight().getByteBuffer();
|
||||||
ByteBuffer result = ByteBufferPool.allocate(width * 2 * size.getHeight() * 4);
|
ByteBuffer result = ByteBufferPool.allocate(width * 2 * size.getHeight() * 3);
|
||||||
openGlBytesToARBG(leftBuffer, width, 0, 0, result, width * 2);
|
openGlBytesToRBG(leftBuffer, width, 0, 0, result, width * 2);
|
||||||
openGlBytesToARBG(rightBuffer, width, size.getWidth(), 0, result, width * 2);
|
openGlBytesToRBG(rightBuffer, width, size.getWidth(), 0, result, width * 2);
|
||||||
ByteBufferPool.release(leftBuffer);
|
ByteBufferPool.release(leftBuffer);
|
||||||
ByteBufferPool.release(rightBuffer);
|
ByteBufferPool.release(rightBuffer);
|
||||||
return new ARGBFrame(rawFrame.getFrameId(), new Dimension(width * 2, size.getHeight()), result);
|
return new RGBFrame(rawFrame.getFrameId(), new Dimension(width * 2, size.getHeight()), result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,14 +6,14 @@ import eu.crushedpixel.replaymod.video.capturer.*;
|
|||||||
import eu.crushedpixel.replaymod.video.entity.CubicEntityRenderer;
|
import eu.crushedpixel.replaymod.video.entity.CubicEntityRenderer;
|
||||||
import eu.crushedpixel.replaymod.video.entity.CustomEntityRenderer;
|
import eu.crushedpixel.replaymod.video.entity.CustomEntityRenderer;
|
||||||
import eu.crushedpixel.replaymod.video.entity.StereoscopicEntityRenderer;
|
import eu.crushedpixel.replaymod.video.entity.StereoscopicEntityRenderer;
|
||||||
import eu.crushedpixel.replaymod.video.frame.ARGBFrame;
|
|
||||||
import eu.crushedpixel.replaymod.video.frame.CubicOpenGlFrame;
|
import eu.crushedpixel.replaymod.video.frame.CubicOpenGlFrame;
|
||||||
import eu.crushedpixel.replaymod.video.frame.OpenGlFrame;
|
import eu.crushedpixel.replaymod.video.frame.OpenGlFrame;
|
||||||
|
import eu.crushedpixel.replaymod.video.frame.RGBFrame;
|
||||||
import eu.crushedpixel.replaymod.video.frame.StereoscopicOpenGlFrame;
|
import eu.crushedpixel.replaymod.video.frame.StereoscopicOpenGlFrame;
|
||||||
import eu.crushedpixel.replaymod.video.processor.CubicToARGBProcessor;
|
import eu.crushedpixel.replaymod.video.processor.CubicToRGBProcessor;
|
||||||
import eu.crushedpixel.replaymod.video.processor.EquirectangularToARGBProcessor;
|
import eu.crushedpixel.replaymod.video.processor.EquirectangularToRGBProcessor;
|
||||||
import eu.crushedpixel.replaymod.video.processor.OpenGlToARGBProcessor;
|
import eu.crushedpixel.replaymod.video.processor.OpenGlToRGBProcessor;
|
||||||
import eu.crushedpixel.replaymod.video.processor.StereoscopicToARGBProcessor;
|
import eu.crushedpixel.replaymod.video.processor.StereoscopicToRGBProcessor;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
@@ -22,7 +22,7 @@ public class Pipelines {
|
|||||||
DEFAULT, STEREOSCOPIC, CUBIC, EQUIRECTANGULAR
|
DEFAULT, STEREOSCOPIC, CUBIC, EQUIRECTANGULAR
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pipeline newPipeline(Preset preset, RenderInfo renderInfo, FrameConsumer<ARGBFrame> consumer) {
|
public static Pipeline newPipeline(Preset preset, RenderInfo renderInfo, FrameConsumer<RGBFrame> consumer) {
|
||||||
switch (preset) {
|
switch (preset) {
|
||||||
case DEFAULT:
|
case DEFAULT:
|
||||||
return newDefaultPipeline(renderInfo, consumer);
|
return newDefaultPipeline(renderInfo, consumer);
|
||||||
@@ -36,7 +36,7 @@ public class Pipelines {
|
|||||||
throw new UnsupportedOperationException("Unknown preset: " + preset);
|
throw new UnsupportedOperationException("Unknown preset: " + preset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pipeline<OpenGlFrame, ARGBFrame> newDefaultPipeline(RenderInfo renderInfo, FrameConsumer<ARGBFrame> consumer) {
|
public static Pipeline<OpenGlFrame, RGBFrame> newDefaultPipeline(RenderInfo renderInfo, FrameConsumer<RGBFrame> consumer) {
|
||||||
RenderOptions options = renderInfo.getRenderOptions();
|
RenderOptions options = renderInfo.getRenderOptions();
|
||||||
FrameCapturer<OpenGlFrame> capturer;
|
FrameCapturer<OpenGlFrame> capturer;
|
||||||
if (PixelBufferObject.SUPPORTED) {
|
if (PixelBufferObject.SUPPORTED) {
|
||||||
@@ -44,32 +44,32 @@ public class Pipelines {
|
|||||||
} else {
|
} else {
|
||||||
capturer = new SimpleOpenGlFrameCapturer(new CustomEntityRenderer<CaptureData>(options), renderInfo);
|
capturer = new SimpleOpenGlFrameCapturer(new CustomEntityRenderer<CaptureData>(options), renderInfo);
|
||||||
}
|
}
|
||||||
return new Pipeline<OpenGlFrame, ARGBFrame>(capturer, new OpenGlToARGBProcessor(), consumer);
|
return new Pipeline<OpenGlFrame, RGBFrame>(capturer, new OpenGlToRGBProcessor(), consumer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pipeline<StereoscopicOpenGlFrame, ARGBFrame> newStereoscopicPipeline(RenderInfo renderInfo, FrameConsumer<ARGBFrame> consumer) {
|
public static Pipeline<StereoscopicOpenGlFrame, RGBFrame> newStereoscopicPipeline(RenderInfo renderInfo, FrameConsumer<RGBFrame> consumer) {
|
||||||
RenderOptions options = renderInfo.getRenderOptions();
|
RenderOptions options = renderInfo.getRenderOptions();
|
||||||
return new Pipeline<StereoscopicOpenGlFrame, ARGBFrame>(
|
return new Pipeline<StereoscopicOpenGlFrame, RGBFrame>(
|
||||||
new StereoscopicOpenGlFrameCapturer(new StereoscopicEntityRenderer(options), renderInfo),
|
new StereoscopicOpenGlFrameCapturer(new StereoscopicEntityRenderer(options), renderInfo),
|
||||||
new StereoscopicToARGBProcessor(),
|
new StereoscopicToRGBProcessor(),
|
||||||
consumer
|
consumer
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pipeline<CubicOpenGlFrame, ARGBFrame> newCubicPipeline(RenderInfo renderInfo, FrameConsumer<ARGBFrame> consumer) {
|
public static Pipeline<CubicOpenGlFrame, RGBFrame> newCubicPipeline(RenderInfo renderInfo, FrameConsumer<RGBFrame> consumer) {
|
||||||
RenderOptions options = renderInfo.getRenderOptions();
|
RenderOptions options = renderInfo.getRenderOptions();
|
||||||
return new Pipeline<CubicOpenGlFrame, ARGBFrame>(
|
return new Pipeline<CubicOpenGlFrame, RGBFrame>(
|
||||||
new CubicOpenGlFrameCapturer(new CubicEntityRenderer(options), renderInfo, options.getWidth() / 4),
|
new CubicOpenGlFrameCapturer(new CubicEntityRenderer(options), renderInfo, options.getWidth() / 4),
|
||||||
new CubicToARGBProcessor(),
|
new CubicToRGBProcessor(),
|
||||||
consumer
|
consumer
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pipeline<CubicOpenGlFrame, ARGBFrame> newEquirectangularPipeline(RenderInfo renderInfo, FrameConsumer<ARGBFrame> consumer) {
|
public static Pipeline<CubicOpenGlFrame, RGBFrame> newEquirectangularPipeline(RenderInfo renderInfo, FrameConsumer<RGBFrame> consumer) {
|
||||||
RenderOptions options = renderInfo.getRenderOptions();
|
RenderOptions options = renderInfo.getRenderOptions();
|
||||||
return new Pipeline<CubicOpenGlFrame, ARGBFrame>(
|
return new Pipeline<CubicOpenGlFrame, RGBFrame>(
|
||||||
new CubicOpenGlFrameCapturer(new CubicEntityRenderer(options), renderInfo, options.getWidth() / 4),
|
new CubicOpenGlFrameCapturer(new CubicEntityRenderer(options), renderInfo, options.getWidth() / 4),
|
||||||
new EquirectangularToARGBProcessor(options.getWidth() / 4),
|
new EquirectangularToRGBProcessor(options.getWidth() / 4),
|
||||||
consumer
|
consumer
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user