Skip to content

Commit

Permalink
Send frame meta only if recording is enabled
Browse files Browse the repository at this point in the history
The client needs the PTS for each frame only if recording is enabled.
Otherwise, the PTS are not necessary, and the protocol is more
straighforward.
  • Loading branch information
rom1v committed Nov 11, 2018
1 parent 22bf0c1 commit 345f885
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 30 deletions.
13 changes: 11 additions & 2 deletions app/src/decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

#define HEADER_SIZE 12

static int read_packet(void *opaque, uint8_t *buf, int buf_size) {
static int read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) {
struct decoder *decoder = opaque;
struct receiver_state *state = &decoder->receiver_state;

Expand Down Expand Up @@ -69,6 +69,11 @@ static int read_packet(void *opaque, uint8_t *buf, int buf_size) {
return ret;
}

static int read_raw_packet(void *opaque, uint8_t *buf, int buf_size) {
struct decoder *decoder = opaque;
return net_recv(decoder->video_socket, buf, buf_size);
}

// set the decoded frame as ready for rendering, and notify
static void push_frame(struct decoder *decoder) {
SDL_bool previous_frame_consumed = frames_offer_decoded_frame(decoder->frames);
Expand Down Expand Up @@ -123,7 +128,11 @@ static int run_decoder(void *data) {
// initialize the receiver state
decoder->receiver_state.remaining = 0;

AVIOContext *avio_ctx = avio_alloc_context(buffer, BUFSIZE, 0, decoder, read_packet, NULL, NULL);
// if recording is enabled, a "header" is sent between raw packets
int (*read_packet)(void *, uint8_t *, int) =
decoder->recorder ? read_packet_with_meta : read_raw_packet;
AVIOContext *avio_ctx = avio_alloc_context(buffer, BUFSIZE, 0, decoder,
read_packet, NULL, NULL);
if (!avio_ctx) {
LOGC("Could not allocate avio context");
// avformat_open_input takes ownership of 'buffer'
Expand Down
4 changes: 3 additions & 1 deletion app/src/scrcpy.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,10 @@ static void wait_show_touches(process_t process) {
}

SDL_bool scrcpy(const struct scrcpy_options *options) {
SDL_bool send_frame_meta = !!options->record_filename;
if (!server_start(&server, options->serial, options->port,
options->max_size, options->bit_rate, options->crop)) {
options->max_size, options->bit_rate, options->crop,
send_frame_meta)) {
return SDL_FALSE;
}

Expand Down
17 changes: 11 additions & 6 deletions app/src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ static SDL_bool disable_tunnel(struct server *server) {

static process_t execute_server(const char *serial,
Uint16 max_size, Uint32 bit_rate,
const char *crop, SDL_bool tunnel_forward) {
SDL_bool tunnel_forward, const char *crop,
SDL_bool send_frame_meta) {
char max_size_string[6];
char bit_rate_string[11];
sprintf(max_size_string, "%"PRIu16, max_size);
Expand All @@ -92,7 +93,8 @@ static process_t execute_server(const char *serial,
max_size_string,
bit_rate_string,
tunnel_forward ? "true" : "false",
crop ? crop : "",
crop ? crop : "''",
send_frame_meta ? "true" : "false",
};
return adb_execute(serial, cmd, sizeof(cmd) / sizeof(cmd[0]));
}
Expand Down Expand Up @@ -148,8 +150,9 @@ void server_init(struct server *server) {
*server = (struct server) SERVER_INITIALIZER;
}

SDL_bool server_start(struct server *server, const char *serial, Uint16 local_port,
Uint16 max_size, Uint32 bit_rate, const char *crop) {
SDL_bool server_start(struct server *server, const char *serial,
Uint16 local_port, Uint16 max_size, Uint32 bit_rate,
const char *crop, SDL_bool send_frame_meta) {
server->local_port = local_port;

if (serial) {
Expand Down Expand Up @@ -190,8 +193,10 @@ SDL_bool server_start(struct server *server, const char *serial, Uint16 local_po
}

// server will connect to our server socket
server->process = execute_server(serial, max_size, bit_rate, crop,
server->tunnel_forward);
server->process = execute_server(serial, max_size, bit_rate,
server->tunnel_forward, crop,
send_frame_meta);

if (server->process == PROCESS_NONE) {
if (!server->tunnel_forward) {
close_socket(&server->server_socket);
Expand Down
7 changes: 5 additions & 2 deletions app/src/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ struct server {
Uint16 local_port;
SDL_bool tunnel_enabled;
SDL_bool tunnel_forward; // use "adb forward" instead of "adb reverse"
SDL_bool send_frame_meta; // request frame PTS to be able to record properly
SDL_bool server_copied_to_device;
};

Expand All @@ -23,15 +24,17 @@ struct server {
.local_port = 0, \
.tunnel_enabled = SDL_FALSE, \
.tunnel_forward = SDL_FALSE, \
.send_frame_meta = SDL_FALSE, \
.server_copied_to_device = SDL_FALSE, \
}

// init default values
void server_init(struct server *server);

// push, enable tunnel et start the server
SDL_bool server_start(struct server *server, const char *serial, Uint16 local_port,
Uint16 max_size, Uint32 bit_rate, const char *crop);
SDL_bool server_start(struct server *server, const char *serial,
Uint16 local_port, Uint16 max_size, Uint32 bit_rate,
const char *crop, SDL_bool send_frame_meta);

// block until the communication with the server is established
socket_t server_connect_to(struct server *server);
Expand Down
9 changes: 9 additions & 0 deletions server/src/main/java/com/genymobile/scrcpy/Options.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public class Options {
private int bitRate;
private boolean tunnelForward;
private Rect crop;
private boolean sendFrameMeta; // send PTS so that the client may record properly

public int getMaxSize() {
return maxSize;
Expand Down Expand Up @@ -39,4 +40,12 @@ public Rect getCrop() {
public void setCrop(Rect crop) {
this.crop = crop;
}

public boolean getSendFrameMeta() {
return sendFrameMeta;
}

public void setSendFrameMeta(boolean sendFrameMeta) {
this.sendFrameMeta = sendFrameMeta;
}
}
47 changes: 29 additions & 18 deletions server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,23 @@ public class ScreenEncoder implements Device.RotationListener {
private static final int MICROSECONDS_IN_ONE_SECOND = 1_000_000;

private final AtomicBoolean rotationChanged = new AtomicBoolean();
private final ByteBuffer headerBuffer = ByteBuffer.allocate(12);

private int bitRate;
private int frameRate;
private int iFrameInterval;
private boolean sendFrameMeta;
private long ptsOrigin;

public ScreenEncoder(int bitRate, int frameRate, int iFrameInterval) {
public ScreenEncoder(boolean sendFrameMeta, int bitRate, int frameRate, int iFrameInterval) {
this.sendFrameMeta = sendFrameMeta;
this.bitRate = bitRate;
this.frameRate = frameRate;
this.iFrameInterval = iFrameInterval;
}

public ScreenEncoder(int bitRate) {
this(bitRate, DEFAULT_FRAME_RATE, DEFAULT_I_FRAME_INTERVAL);
public ScreenEncoder(boolean sendFrameMeta, int bitRate) {
this(sendFrameMeta, bitRate, DEFAULT_FRAME_RATE, DEFAULT_I_FRAME_INTERVAL);
}

@Override
Expand Down Expand Up @@ -82,7 +85,7 @@ public void streamScreen(Device device, FileDescriptor fd) throws IOException {
private boolean encode(MediaCodec codec, FileDescriptor fd) throws IOException {
boolean eof = false;
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
ByteBuffer bBuffer = ByteBuffer.allocate(12);


while (!consumeRotationChange() && !eof) {
int outputBufferId = codec.dequeueOutputBuffer(bufferInfo, -1);
Expand All @@ -94,22 +97,11 @@ private boolean encode(MediaCodec codec, FileDescriptor fd) throws IOException {
}
if (outputBufferId >= 0) {
ByteBuffer codecBuffer = codec.getOutputBuffer(outputBufferId);
bBuffer.clear();

long pts;
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
pts = 0; // non-media data packet
} else {
if (ptsOrigin == 0) {
ptsOrigin = bufferInfo.presentationTimeUs;
}
pts = bufferInfo.presentationTimeUs - ptsOrigin;

if (sendFrameMeta) {
writeFrameMeta(fd, bufferInfo, codecBuffer.remaining());
}

bBuffer.putLong(pts);
bBuffer.putInt(codecBuffer.remaining());
bBuffer.flip();
IO.writeFully(fd, bBuffer);
IO.writeFully(fd, codecBuffer);
}
} finally {
Expand All @@ -122,6 +114,25 @@ private boolean encode(MediaCodec codec, FileDescriptor fd) throws IOException {
return !eof;
}

private void writeFrameMeta(FileDescriptor fd, MediaCodec.BufferInfo bufferInfo, int packetSize) throws IOException {
headerBuffer.clear();

long pts;
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
pts = 0; // non-media data packet
} else {
if (ptsOrigin == 0) {
ptsOrigin = bufferInfo.presentationTimeUs;
}
pts = bufferInfo.presentationTimeUs - ptsOrigin;
}

headerBuffer.putLong(pts);
headerBuffer.putInt(packetSize);
headerBuffer.flip();
IO.writeFully(fd, headerBuffer);
}

private static MediaCodec createCodec() throws IOException {
return MediaCodec.createEncoderByType("video/avc");
}
Expand Down
9 changes: 8 additions & 1 deletion server/src/main/java/com/genymobile/scrcpy/Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import android.graphics.Rect;

import java.io.IOException;
import java.util.Arrays;

public final class Server {

Expand All @@ -14,7 +15,7 @@ private static void scrcpy(Options options) throws IOException {
final Device device = new Device(options);
boolean tunnelForward = options.isTunnelForward();
try (DesktopConnection connection = DesktopConnection.open(device, tunnelForward)) {
ScreenEncoder screenEncoder = new ScreenEncoder(options.getBitRate());
ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate());

// asynchronous
startEventController(device, connection);
Expand Down Expand Up @@ -71,6 +72,12 @@ private static Options createOptions(String... args) {
Rect crop = parseCrop(args[3]);
options.setCrop(crop);

if (args.length < 5) {
return options;
}
boolean sendFrameMeta = Boolean.parseBoolean(args[4]);
options.setSendFrameMeta(sendFrameMeta);

return options;
}

Expand Down

0 comments on commit 345f885

Please sign in to comment.