[vlc-devel] [PATCH] Flaschen Taschen output: Support for large(r) video sizes

Johannes Lechner git at fudgy.de
Sat Apr 25 10:06:20 CEST 2020


This patches contains two modifications to make Flaschen Taschen support large(r) video sizes:
(1) Increase of UDP send buffer, allowing maximum-sized UDP packets to be sent
(2) Splitting a frame into multiple UDP packets in case one frame exceeds the maximum UDP packet size

The implemention for (2) draws heavily from the "official" UDPFlaschenTaschen::Send implemention:
https://github.com/hzeller/flaschen-taschen/blob/master/api/lib/udp-flaschen-taschen.cc
---
 modules/video_output/flaschen.c | 113 +++++++++++++++++++-------------
 1 file changed, 66 insertions(+), 47 deletions(-)

diff --git a/modules/video_output/flaschen.c b/modules/video_output/flaschen.c
index 00e1e66a34..b9f541dc30 100644
--- a/modules/video_output/flaschen.c
+++ b/modules/video_output/flaschen.c
@@ -134,8 +134,9 @@ static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
 
     /* Ignore any unexpected incoming packet */
     setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &(int){ 0 }, sizeof (int));
-
-
+    /* Increase send buffer size to allow queuing of several "full" UDP packets  */
+    setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &(int){ 16 * 65536 }, sizeof (int));
+        
     *fmtp = fmt;
 
     vd->prepare = NULL;
@@ -155,55 +156,73 @@ static void Close(vout_display_t *vd)
     free(sys);
 }
 
+/*
+ * Adaptation of UDPFlaschenTaschen::Send implemention
+ * (https://github.com/hzeller/flaschen-taschen/)
+ */
 static void Display(vout_display_t *vd, picture_t *picture)
 {
-#ifdef IOV_MAX
-    const long iovmax = IOV_MAX;
-#else
-    const long iovmax = sysconf(_SC_IOV_MAX);
-#endif
-    vout_display_sys_t *sys = vd->sys;
-    video_format_t *fmt = &picture->format;
-    int result;
-
-    char buffer[64];
-    int header_len = snprintf(buffer, sizeof(buffer), "P6\n%d %d\n255\n",
-                              fmt->i_width, fmt->i_height);
-    /* TODO: support offset_{x,y,z}? (#FT:...) */
-    /* Note the protocol doesn't include any picture order field. */
-    /* (maybe add as comment?) */
-
-    int iovcnt = 1 + fmt->i_height;
-    if (unlikely(iovcnt > iovmax))
-        return;
-
-    struct iovec iov[iovcnt];
-    iov[0].iov_base = buffer;
-    iov[0].iov_len = header_len;
-
-    uint8_t *src = picture->p->p_pixels;
-    for (int i = 1; i < iovcnt; i++)
+    video_format_t *format = &picture->format;
+    uint8_t *pixels = picture->p->p_pixels;
+
+    const int max_data_packet_length = 65507 - 64;  // Leave some space for the P6 header
+    const size_t row_size = format->i_width * 3;
+    const int max_send_height = max_data_packet_length / row_size;
+
+    int rows = format->i_height;
+    int row_offset = 0;
+    
+    while(rows)
     {
-        iov[i].iov_base = src;
-        iov[i].iov_len = fmt->i_width * 3;
-        src += picture->p->i_pitch;
+        // Send as many rows as can fit within one UDP packet
+        const int send_height = (rows < max_send_height) ? rows : max_send_height;
+        
+        char p6_header[64];
+        const int p6_header_len = snprintf(p6_header, sizeof(p6_header),
+                                           "P6\n%d %d\n#FT: %d %d %d\n255\n",
+                                           format->i_width, send_height,
+                                           0, row_offset, 0);
+        //msg_Dbg(vd, "p6_header: %s", p6_header`);
+        
+        const int p6_data_len = send_height * row_size;
+        
+        // Create and send UDP packet
+        {
+            struct iovec iov[2];
+            iov[0].iov_base = p6_header;
+            iov[0].iov_len = p6_header_len;
+            iov[1].iov_base = pixels;
+            iov[1].iov_len = p6_data_len;
+            
+            struct msghdr hdr = {
+                .msg_name = NULL,
+                .msg_namelen = 0,
+                .msg_iov = iov,
+                .msg_iovlen = 2,
+                .msg_control = NULL,
+                .msg_controllen = 0,
+                .msg_flags = 0 };
+
+            int result;
+            result = sendmsg(vd->sys->fd, &hdr, 0);
+            
+            if (result < 0) {
+                msg_Err(vd, "sendmsg: error %s in vout display flaschen, dropping remainder of frame", vlc_strerror_c(errno));
+                // dropping remainder of frame
+                break;
+            }
+            else if (result < (int)(p6_header_len + p6_data_len)) {
+                msg_Err(vd, "sendmsg only sent %d bytes in vout display flaschen, dropping remainder of frame", result);
+                // dropping remainder of frame
+                break;
+            }
+        }
+
+        pixels += p6_data_len;
+        
+        rows -= send_height;
+        row_offset += send_height;
     }
-
-    struct msghdr hdr = {
-        .msg_name = NULL,
-        .msg_namelen = 0,
-        .msg_iov = iov,
-        .msg_iovlen = iovcnt,
-        .msg_control = NULL,
-        .msg_controllen = 0,
-        .msg_flags = 0 };
-
-    result = sendmsg(sys->fd, &hdr, 0);
-    if (result < 0)
-        msg_Err(vd, "sendmsg: error %s in vout display flaschen", vlc_strerror_c(errno));
-    else if (result < (int)(header_len + fmt->i_width * fmt->i_height * 3))
-        msg_Err(vd, "sendmsg only sent %d bytes in vout display flaschen", result);
-        /* we might want to drop some frames? */
 }
 
 /**
-- 
2.24.2 (Apple Git-127)



More information about the vlc-devel mailing list