Pass video size as codec metadata

On initial connection, scrcpy sent some device metadata:
 - the device name (to be used as window title)
 - the initial video size (before any frame or even SPS/PPS)

But it is better to provide the initial video size as part as the video
stream, so that it can be demuxed and exposed via AVCodecContext to
sinks.

This avoids to pass an explicit "initial frame size" for the screen, the
recorder and the v4l2 sink.
This commit is contained in:
Romain Vimont
2023-03-11 09:21:49 +01:00
parent 3a72f3fb4d
commit 238ab872ba
17 changed files with 104 additions and 69 deletions

View File

@@ -101,7 +101,7 @@ public final class AudioEncoder implements AsyncProcessor {
}
private void outputThread(MediaCodec mediaCodec) throws IOException, InterruptedException {
streamer.writeHeader();
streamer.writeAudioHeader();
while (!Thread.currentThread().isInterrupted()) {
OutputTask task = outputTasks.take();

View File

@@ -26,7 +26,7 @@ public final class AudioRawRecorder implements AsyncProcessor {
try {
capture.start();
streamer.writeHeader();
streamer.writeAudioHeader();
while (!Thread.currentThread().isInterrupted()) {
buffer.position(0);
int r = capture.read(buffer, READ_SIZE, bufferInfo);

View File

@@ -122,18 +122,14 @@ public final class DesktopConnection implements Closeable {
}
}
public void sendDeviceMeta(String deviceName, int width, int height) throws IOException {
byte[] buffer = new byte[DEVICE_NAME_FIELD_LENGTH + 4];
public void sendDeviceMeta(String deviceName) throws IOException {
byte[] buffer = new byte[DEVICE_NAME_FIELD_LENGTH];
byte[] deviceNameBytes = deviceName.getBytes(StandardCharsets.UTF_8);
int len = StringUtils.getUtf8TruncationIndex(deviceNameBytes, DEVICE_NAME_FIELD_LENGTH - 1);
System.arraycopy(deviceNameBytes, 0, buffer, 0, len);
// byte[] are always 0-initialized in java, no need to set '\0' explicitly
buffer[DEVICE_NAME_FIELD_LENGTH] = (byte) (width >> 8);
buffer[DEVICE_NAME_FIELD_LENGTH + 1] = (byte) width;
buffer[DEVICE_NAME_FIELD_LENGTH + 2] = (byte) (height >> 8);
buffer[DEVICE_NAME_FIELD_LENGTH + 3] = (byte) height;
IO.writeFully(videoFd, buffer, 0, buffer.length);
}

View File

@@ -66,7 +66,7 @@ public class ScreenEncoder implements Device.RotationListener {
IBinder display = createDisplay();
device.setRotationListener(this);
streamer.writeHeader();
streamer.writeVideoHeader(device.getScreenInfo().getVideoSize());
boolean alive;
try {

View File

@@ -96,8 +96,7 @@ public final class Server {
try (DesktopConnection connection = DesktopConnection.open(scid, tunnelForward, audio, control, sendDummyByte)) {
if (options.getSendDeviceMeta()) {
Size videoSize = device.getScreenInfo().getVideoSize();
connection.sendDeviceMeta(Device.getDeviceName(), videoSize.getWidth(), videoSize.getHeight());
connection.sendDeviceMeta(Device.getDeviceName());
}
if (control) {

View File

@@ -30,8 +30,7 @@ public final class Streamer {
public Codec getCodec() {
return codec;
}
public void writeHeader() throws IOException {
public void writeAudioHeader() throws IOException {
if (sendCodecMeta) {
ByteBuffer buffer = ByteBuffer.allocate(4);
buffer.putInt(codec.getId());
@@ -40,6 +39,17 @@ public final class Streamer {
}
}
public void writeVideoHeader(Size videoSize) throws IOException {
if (sendCodecMeta) {
ByteBuffer buffer = ByteBuffer.allocate(12);
buffer.putInt(codec.getId());
buffer.putInt(videoSize.getWidth());
buffer.putInt(videoSize.getHeight());
buffer.flip();
IO.writeFully(fd, buffer);
}
}
public void writeDisableStream(boolean error) throws IOException {
// Writing a specific code as codec-id means that the device disables the stream
// code 0: it explicitly disables the stream (because it could not capture audio), scrcpy should continue mirroring video only