Skip to content

Commit d18bdc1

Browse files
committed
1.6.4
1 parent 0520edd commit d18bdc1

12 files changed

Lines changed: 193 additions & 13 deletions

File tree

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ loader_version=0.16.14
1010
loom_version=1.10-SNAPSHOT
1111

1212
# Mod Properties
13-
mod_version=1.6.3
13+
mod_version=1.6.4
1414
maven_group=com.github.squi2rel.vp
1515
archives_base_name=VideoPlayer
1616

src/client/java/com/github/squi2rel/vp/CameraRenderer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ public static void renderWorld(Entity entity, Pool pool, Framebuffer framebuffer
2929
height = framebuffer.textureHeight;
3030
framebuffer.beginWrite(true);
3131
rendering = true;
32+
Entity oldEntity = client.getCameraEntity();
33+
client.setCameraEntity(entity);
3234
CameraRenderer.aspect = aspect;
3335
Camera c = client.gameRenderer.getCamera();
3436
camera.update(client.world, entity, false, false, client.getRenderTickCounter().getTickDelta(true));
@@ -52,6 +54,7 @@ public static void renderWorld(Entity entity, Pool pool, Framebuffer framebuffer
5254
((GameRendererAccessor) client.gameRenderer).setCamera(camera);
5355
client.worldRenderer.render(pool, client.getRenderTickCounter(), false, camera, client.gameRenderer, pos, proj);
5456
((GameRendererAccessor) client.gameRenderer).setCamera(c);
57+
client.setCameraEntity(oldEntity);
5558
renderSelf = false;
5659
rendering = false;
5760
client.gameRenderer.setRenderHand(true);

src/client/java/com/github/squi2rel/vp/ClientPacketHandler.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,12 @@ public static void handle(ByteBuf buf) {
174174
if (screen == null) return;
175175
ServerPacketHandler.readScale(buf, screen);
176176
}
177+
case AUTO_SYNC -> {
178+
long sysTime = System.currentTimeMillis();
179+
ClientVideoScreen screen = areas.get(readName(buf)).getScreen(readName(buf));
180+
if (screen == null) return;
181+
screen.autoSync((int) (sysTime - buf.readLong()), buf.readLong());
182+
}
177183
default -> LOGGER.warn("Unknown packet type: {}", type);
178184
}
179185
if (buf.readableBytes() > 0) {
@@ -297,4 +303,12 @@ public static void setCustomMeta(VideoScreen screen, String key, int value, bool
297303
public static void setScale(VideoScreen screen, boolean fill, float scaleX, float scaleY) {
298304
send(ServerPacketHandler.setScale(screen, fill, scaleX, scaleY));
299305
}
306+
307+
public static void autoSync(VideoScreen screen, long clientTime) {
308+
ByteBuf buf = create(AUTO_SYNC);
309+
writeString(buf, screen.area.name);
310+
writeString(buf, screen.name);
311+
buf.writeLong(clientTime);
312+
send(toByteArray(buf));
313+
}
300314
}

src/client/java/com/github/squi2rel/vp/VideoPlayerClient.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,14 @@ public void onInitializeClient() {
387387
ClientPacketHandler.setMeta(screen, PacketID.Action.FOV.ordinal(), s.getArgument("fov", Integer.class));
388388
return 1;
389389
})))
390+
.then(ClientCommandManager.literal("autoSync")
391+
.then(ClientCommandManager.argument("autoSync", BoolArgumentType.bool())
392+
.executes(s -> {
393+
ClientVideoScreen screen = getScreen(s);
394+
if (screen == null) return 0;
395+
ClientPacketHandler.setMeta(screen, PacketID.Action.AUTO_SYNC.ordinal(), s.getArgument("autoSync", Boolean.class) ? 1 : 0);
396+
return 1;
397+
})))
390398
.then(ClientCommandManager.literal("custom")
391399
.then(ClientCommandManager.literal("set")
392400
.then(ClientCommandManager.argument("key", StringArgumentType.string())
@@ -622,7 +630,7 @@ public static void update() {
622630
for (ClientVideoScreen screen : screens) {
623631
if (screen.isPostUpdate()) continue;
624632
screen.swapTexture();
625-
screen.updateTexture();
633+
screen.update();
626634
}
627635
profiler.swap("checkInteract");
628636
checkInteract();
@@ -640,7 +648,7 @@ public static void postUpdate() {
640648
profiler.push("updateFrame");
641649
for (ClientVideoScreen screen : screens) {
642650
if (!screen.isPostUpdate()) continue;
643-
screen.updateTexture();
651+
screen.update();
644652
}
645653
profiler.pop();
646654
profiler.pop();

src/client/java/com/github/squi2rel/vp/video/ClientVideoScreen.java

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
package com.github.squi2rel.vp.video;
22

3+
import com.github.squi2rel.vp.ClientPacketHandler;
34
import com.github.squi2rel.vp.VideoPlayerClient;
45
import com.github.squi2rel.vp.provider.VideoInfo;
56
import io.netty.buffer.ByteBuf;
7+
import net.minecraft.client.MinecraftClient;
68
import net.minecraft.client.render.VertexConsumerProvider;
79
import net.minecraft.client.util.math.MatrixStack;
10+
import net.minecraft.text.Text;
11+
import net.minecraft.util.Formatting;
812
import org.joml.Vector3f;
913

10-
import java.util.Objects;
14+
import java.util.*;
1115

1216
public class ClientVideoScreen extends VideoScreen {
1317
public IVideoPlayer player = null;
@@ -16,6 +20,14 @@ public class ClientVideoScreen extends VideoScreen {
1620
private long startTime = System.currentTimeMillis();
1721
public boolean interactable = true;
1822

23+
private long lastAutoSync;
24+
private int syncFrames;
25+
26+
private double srtt = -1;
27+
private double rttvar = -1;
28+
private static final double ALPHA = 0.125;
29+
private static final double BETA = 0.25;
30+
1931
public ClientVideoScreen(VideoArea area, String name, Vector3f v1, Vector3f v2, Vector3f v3, Vector3f v4, String source) {
2032
super(area, name, v1, v2, v3, v4, source);
2133
}
@@ -54,8 +66,16 @@ public void swapTexture() {
5466
if (player != null) player.swapTexture();
5567
}
5668

57-
public void updateTexture() {
69+
public void update() {
5870
if (player != null) player.updateTexture();
71+
72+
if (player instanceof VideoPlayer vp && !vp.isPaused()) {
73+
long syncTime = 150L * Math.max(syncFrames, 1);
74+
if (meta.getOrDefault("autoSync", 0) != 0 && System.currentTimeMillis() - lastAutoSync >= syncTime) {
75+
lastAutoSync = System.currentTimeMillis();
76+
ClientPacketHandler.autoSync(this, System.currentTimeMillis());
77+
}
78+
}
5979
}
6080

6181
public ClientVideoScreen getTrackingScreen() {
@@ -73,6 +93,7 @@ public void load() {
7393
}
7494

7595
public void play(VideoInfo info) {
96+
syncFrames = 0;
7697
if (source.isEmpty()) {
7798
IVideoPlayer old = player;
7899
player = VideoPlayers.from(info, this, player);
@@ -107,10 +128,75 @@ public long getStartTime() {
107128
}
108129

109130
public void setProgress(long progress) {
131+
syncFrames = 0;
110132
player.setProgress(progress);
111133
startTime = System.currentTimeMillis() - progress;
112134
}
113135

136+
public void autoSync(int clientDelay, long syncProgress) {
137+
if (srtt < 0) {
138+
srtt = clientDelay;
139+
rttvar = clientDelay / 2.0;
140+
} else {
141+
double delta = Math.abs(clientDelay - srtt);
142+
if (delta > 1000) return;
143+
rttvar = (1 - BETA) * rttvar + BETA * delta;
144+
srtt = (1 - ALPHA) * srtt + ALPHA * clientDelay;
145+
}
146+
147+
int rtt = (int) Math.round(srtt);
148+
syncProgress += rtt / 2;
149+
150+
if (player instanceof VideoPlayer vp && !vp.isPaused()) {
151+
if (syncProgress <= 0) return;
152+
long progress = vp.getProgress();
153+
if (progress <= 0) return;
154+
155+
long delta = syncProgress - progress;
156+
if (delta > -25 && delta <= 25) {
157+
syncFrames++;
158+
} else {
159+
syncFrames--;
160+
}
161+
syncFrames = Math.clamp(syncFrames, 0, 7);
162+
163+
if (syncFrames < 5) {
164+
if (delta > 10000) {
165+
if (vp.getRate() != 3f) vp.setRate(3f);
166+
} else if (delta > 5000) {
167+
if (vp.getRate() != 2f) vp.setRate(2f);
168+
} else if (delta > 3000) {
169+
if (vp.getRate() != 1.5f) vp.setRate(1.5f);
170+
} else if (delta > 1500) {
171+
if (vp.getRate() != 1.4f) vp.setRate(1.4f);
172+
} else if (delta > 500) {
173+
if (vp.getRate() != 1.3f) vp.setRate(1.3f);
174+
} else if (delta > 100) {
175+
if (vp.getRate() != 1.2f) vp.setRate(1.2f);
176+
} else if (delta > 25) {
177+
if (vp.getRate() != 1.1f) vp.setRate(1.1f);
178+
} else if (delta > -25) {
179+
if (vp.getRate() != 1f) vp.setRate(1f);
180+
} else if (delta > -1000) {
181+
if (vp.getRate() != 0.9f) vp.setRate(0.9f);
182+
} else if (delta > -5000) {
183+
if (vp.getRate() != 0.8f) vp.setRate(0.8f);
184+
} else if (delta > -10000) {
185+
vp.stop();
186+
MinecraftClient.getInstance().inGameHud.setOverlayMessage(Text.literal("提前太多,失去同步").formatted(Formatting.RED), false);
187+
}
188+
}
189+
190+
if (meta.getOrDefault("debug", 0) != 0) {
191+
MinecraftClient.getInstance().inGameHud.setOverlayMessage(Text.literal(
192+
"local: %s, server: %s, rtt: %s, delta: %s, sync: %s/7, rate: %.2f".formatted(
193+
progress, syncProgress, rtt, delta, syncFrames, vp.getRate()
194+
)
195+
).formatted(Formatting.GREEN), false);
196+
}
197+
}
198+
}
199+
114200
public void unload() {
115201
VideoPlayerClient.screens.remove(this);
116202
if (player != null) player.cleanup();

src/client/java/com/github/squi2rel/vp/video/VideoPlayer.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,14 @@ public void setTargetTime(long targetTime) {
153153
this.targetTime = targetTime;
154154
}
155155

156+
public void setRate(float rate) {
157+
decoder.setRate(rate);
158+
}
159+
160+
public float getRate() {
161+
return decoder.getRate();
162+
}
163+
156164
@Override
157165
public synchronized void cleanup() {
158166
initialized = false;

src/client/java/com/github/squi2rel/vp/video/VlcDecoder.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public class VlcDecoder {
2323
private final TextureRenderFormatCallback callback = new TextureRenderFormatCallback();
2424
private ByteBuffer buffer, glBuffer;
2525

26+
public long lastPlayTime;
27+
public long lastPlayUpdateTime;
28+
2629
private BiConsumer<Integer, Integer> sizeListener = (a, b) -> {};
2730
private Runnable playListener = () -> {}, finishListener = () -> {};
2831

@@ -60,12 +63,18 @@ public void finished(MediaPlayer mediaPlayer) {
6063
public void error(MediaPlayer mediaPlayer) {
6164
mediaPlayer.submit(() -> mediaPlayer.controls().stop());
6265
}
66+
67+
@Override
68+
public void timeChanged(MediaPlayer mediaPlayer, long newTime) {
69+
lastPlayTime = newTime;
70+
lastPlayUpdateTime = System.currentTimeMillis();
71+
}
6372
});
6473
}
6574

6675
public static void load() {
6776
VideoPlayerMain.LOGGER.info("loading library");
68-
factory = new MediaPlayerFactory();
77+
factory = new MediaPlayerFactory("--audio-filter=scaletempo");
6978
VideoPlayerMain.LOGGER.info("loaded library");
7079
}
7180

@@ -86,6 +95,7 @@ public void submit(Runnable r) {
8695
}
8796

8897
public void init(VideoInfo info) {
98+
lastPlayTime = 0;
8999
mediaPlayer.media().play(info.path().replace("rtspt://", "rtsp://"), info.params());
90100
}
91101

@@ -113,7 +123,7 @@ public void pause(boolean pause) {
113123
}
114124

115125
public boolean isPaused() {
116-
return mediaPlayer.status().isPlaying();
126+
return !mediaPlayer.status().isPlaying();
117127
}
118128

119129
public int getWidth() {
@@ -137,13 +147,21 @@ public void setProgress(long progress) {
137147
}
138148

139149
public long getProgress() {
140-
return mediaPlayer.status().time();
150+
return lastPlayTime == 0 ? 0 : System.currentTimeMillis() - lastPlayUpdateTime + lastPlayTime;
141151
}
142152

143153
public long getTotalProgress() {
144154
return mediaPlayer.status().length();
145155
}
146156

157+
public void setRate(float rate) {
158+
mediaPlayer.controls().setRate(rate);
159+
}
160+
161+
public float getRate() {
162+
return mediaPlayer.status().rate();
163+
}
164+
147165
private class TextureRenderFormatCallback implements RenderCallback {
148166
private static final ByteBuffer empty = BufferUtils.createByteBuffer(0);
149167

src/main/java/com/github/squi2rel/vp/DataHolder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@ public static void update() {
5252
ServerPacketHandler.sendTo(player, ServerPacketHandler.createScreen(area.screens));
5353
ServerPacketHandler.sendTo(player, ServerPacketHandler.loadArea(area));
5454
ServerPacketHandler.sendTo(player, ServerPacketHandler.updatePlaylist(area.screens));
55-
player.sendMessage(Text.literal("进入观影区 " + area.name).formatted(Formatting.DARK_AQUA));
55+
player.sendMessage(Text.literal("进入观影区 " + area.name).formatted(Formatting.DARK_AQUA), true);
5656
}
5757
} else {
5858
if (area.removePlayer(player.getUuid())) {
5959
ServerPacketHandler.sendTo(player, ServerPacketHandler.unloadArea(area));
6060
ServerPacketHandler.sendTo(player, ServerPacketHandler.removeArea(area));
61-
player.sendMessage(Text.literal("离开观影区 " + area.name).formatted(Formatting.DARK_AQUA));
61+
player.sendMessage(Text.literal("离开观影区 " + area.name).formatted(Formatting.DARK_AQUA), true);
6262
}
6363
}
6464
}

src/main/java/com/github/squi2rel/vp/network/PacketID.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@ public class PacketID {
2525
OPEN_MENU = 15,
2626
SET_META = 16,
2727
SET_CUSTOM_META = 17,
28-
SET_SCALE = 18;
28+
SET_SCALE = 18,
29+
AUTO_SYNC = 19;
2930

3031
public enum Action {
3132
MUTE("静音", i -> (i >>> 1) == 0, (v, i) -> v.meta.put("mute", i)),
3233
INTERACTABLE("可交互", i -> (i >>> 1) == 0, (v, i) -> v.meta.put("interactable", i)),
3334
ASPECT("宽高比", i -> Float.intBitsToFloat(i) >= 0.0625f && Float.intBitsToFloat(i) <= 16f, (v, i) -> v.meta.put("aspect", i)),
34-
FOV("视场角", i -> i > 0 && i < 180, (v, i) -> v.meta.put("fov", i));
35+
FOV("视场角", i -> i > 0 && i < 180, (v, i) -> v.meta.put("fov", i)),
36+
AUTO_SYNC("自动同步", i -> (i >>> 1) == 0, (v, i) -> v.meta.put("autoSync", i));
3537

3638
public static final Action[] VALUES = values();
3739

src/main/java/com/github/squi2rel/vp/network/ServerPacketHandler.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.github.squi2rel.vp.provider.PlayerProviderSource;
55
import com.github.squi2rel.vp.provider.VideoInfo;
66
import com.github.squi2rel.vp.provider.VideoProviders;
7+
import com.github.squi2rel.vp.video.IVideoListener;
78
import com.github.squi2rel.vp.video.VideoArea;
89
import com.github.squi2rel.vp.DataHolder;
910
import com.github.squi2rel.vp.video.VideoScreen;
@@ -224,6 +225,18 @@ public static void handle(ServerPlayerEntity player, ByteBuf buf) {
224225
area.forEachPlayer(p -> sendTo(pm.getPlayer(p), data));
225226
}
226227
}
228+
case AUTO_SYNC -> {
229+
VideoArea area = getArea(player, readName(buf));
230+
if (area == null) return;
231+
VideoScreen screen = area.getScreen(readName(buf));
232+
if (screen == null) return;
233+
long clientTime = buf.readLong();
234+
IVideoListener listener = screen.getListener();
235+
if (listener == null) return;
236+
long progress = listener.getProgress();
237+
if (progress <= 0) return;
238+
sendTo(player, autoSync(screen, clientTime, progress));
239+
}
227240
default -> player.networkHandler.disconnect(Text.of("Unknown packet type: " + type));
228241
}
229242
if (buf.readableBytes() > 0) {
@@ -459,4 +472,13 @@ public static byte[] setScale(VideoScreen screen, boolean fill, float scaleX, fl
459472
buf.writeFloat(scaleY);
460473
return toByteArray(buf);
461474
}
475+
476+
public static byte[] autoSync(VideoScreen screen, long clientTime, long progress) {
477+
ByteBuf buf = create(AUTO_SYNC);
478+
writeString(buf, screen.area.name);
479+
writeString(buf, screen.name);
480+
buf.writeLong(clientTime);
481+
buf.writeLong(progress);
482+
return toByteArray(buf);
483+
}
462484
}

0 commit comments

Comments
 (0)