scrcpy: Recording stops intermittently.

Environment

  • OS: [Windows10]
  • scrcpy version: [1.16 and 1.17]
  • device model:Galaxy Note5
  • Android version: [7.0]

Describe the bug Recording stops intermittently.

Option used –serial udid –no-control –window-title window_title –record C:/Log/test.mp4 –max-size 800 –encoder OMX.google.h264.encoder

ERROR: Could not record packet
ERROR: Could not send packet to recorder
ERROR: Could not process frame
INFO: Finishing recording...
ERROR: Recording failed to C:/Log/test.mp4
WARN: Device disconnected

About this issue

Commits related to this issue

Most upvoted comments

Yes, there is a problem on the device, but as a workaround scrcpy could readjust pts when they are not increasing.

scrcpy -Vdebug --record file.mp4

How did you build the server?

Thank you very much for the dump.

The reason why it fails is that the PTS are not strictly increasing (and some muxers are more liberal than others, that’s why it fails with mp4 but works with mkv):

DEBUG: [  0] PTS=8985633, DTS=8985633   1067
DEBUG: [  0] PTS=8993271, DTS=8993271    611
DEBUG: [  0] PTS=9005650, DTS=9005650    534
DEBUG: [  0] PTS=9014650, DTS=9014650    529
DEBUG: [-22] PTS=9014630, DTS=9014630    529

I would like to know if this is a mistake from your device encoder, or something scrcpy does not handle correclty.

Could you please apply these changes on master, and build (both the client and server!), and retry. When it fails, I’m interested in the logs 😉

diff --git a/app/src/recorder.c b/app/src/recorder.c
index e31492c0..93610815 100644
--- a/app/src/recorder.c
+++ b/app/src/recorder.c
@@ -252,7 +252,9 @@ recorder_write(struct recorder *recorder, AVPacket *packet) {
     }
 
     recorder_rescale_packet(recorder, packet);
-    return av_write_frame(recorder->ctx, packet) >= 0;
+    int ret = av_write_frame(recorder->ctx, packet);
+    LOGI("[%3d] PTS=%ld, DTS=%ld %6d\n", ret, packet->pts, packet->dts, packet->size);
+    return ret >= 0;
 }
 
 static int
diff --git a/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java b/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java
index c7c104e4..d6b1b3a9 100644
--- a/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java
+++ b/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java
@@ -139,6 +139,8 @@ public class ScreenEncoder implements Device.RotationListener {
     private void writeFrameMeta(FileDescriptor fd, MediaCodec.BufferInfo bufferInfo, int packetSize) throws IOException {
         headerBuffer.clear();
 
+        Ln.i("bufferInfo: flags=" + bufferInfo.flags + "; pts=" + bufferInfo.presentationTimeUs + "; relpts=" + (bufferInfo.presentationTimeUs - ptsOrigin));
+
         long pts;
         if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
             pts = NO_PTS; // non-media data packet

Could you please apply these changes to dump the raw stream received from the device into /tmp/scrcpy.dump:

diff --git a/app/src/stream.c b/app/src/stream.c
index dd2dbd76..97705ece 100644
--- a/app/src/stream.c
+++ b/app/src/stream.c
@@ -35,9 +35,16 @@ stream_recv_packet(struct stream *stream, AVPacket *packet) {
     //
     // It is followed by <packet_size> bytes containing the packet/frame.
 
+    static FILE *dump = NULL;
+    if (!dump) {
+        dump = fopen("/tmp/scrcpy.dump", "w");
+        assert(dump);
+    }
+
     uint8_t header[HEADER_SIZE];
     ssize_t r = net_recv_all(stream->socket, header, HEADER_SIZE);
     if (r < HEADER_SIZE) {
+        fclose(dump);
         return false;
     }
 
@@ -48,17 +55,24 @@ stream_recv_packet(struct stream *stream, AVPacket *packet) {
 
     if (av_new_packet(packet, len)) {
         LOGE("Could not allocate packet");
+        fclose(dump);
         return false;
     }
 
     r = net_recv_all(stream->socket, packet->data, len);
     if (r < 0 || ((uint32_t) r) < len) {
         av_packet_unref(packet);
+        fclose(dump);
         return false;
     }
 
     packet->pts = pts != NO_PTS ? (int64_t) pts : AV_NOPTS_VALUE;
 
+    size_t w = fwrite(header, HEADER_SIZE, 1, dump);
+    assert(w == 1);
+    w = fwrite(packet->data, 1, len, dump);
+    assert(w == len);
+
     return true;
 }
 

Once you reproduce the error, post the dump. That way, I’ll be able to use the exact same input to see if I can reproduce if I record to mp4.

Did you checkout the branch and build this version? It seems it’s not the case.

I will try to reproduce the issue tomorrow with this branch.

Did you checkout the branch and build this version? It seems it’s not the case.