diff mbox

[FFmpeg-devel,1/1] avformat: Add alignment mode to Pro-MPEG

Message ID ASOTpR8PinEJrcb6Cv52MULAyfZTeGR7ihh9C_MeqBa69SdWDesIUMrmFZmDFE19HosG79eKe_ImGCQcT6S40wcSXElaiDMbcpwsUC1Pres=@protonmail.com
State New
Headers show

Commit Message

Andreas Håkon Jan. 13, 2017, 2:26 p.m. UTC
Hi,

The Pro-MPEG FEC module has troubles with some receivers.
This patch fixes this problem incorporating the option for selecting different alignment modes.

The problem is related to the alignment of the COLUMN FEC packets (aka. when send the packet).
Current block-alignment implies a delay of quasi-the-length of the matrix size.
Then several receivers discard the column fec packets when they start to receive DATA packets from the next matrix.

Three different modes are possible (only two implemented):

- Mode 0: No alignment. When a new row starts, and the column is complete, then send the COL FEC packet. This is the default behaviour for several devices. However, this mode is prone to errors when they happen in the last row; but it's still more compatible.

- Mode 1: COL alignment. This is the default and already implemented alignment. COL FEC packets are send equispaced when processing the next matrix. Implies more delay in the receiver and a double-size buffer.

- Mode 2: ROW alignment. This is unimplemented. After compute each column it's send the COL FEC packet. Very similar to mode 0.

Please, review the code. I do several tests with professional equipment. Results improves using mode 0 with some receivers.

A.H.
From ef52c6b87d38f790280ab1988287e71ef31ecdf7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andreas=20H=C3=A5kon?= <andreas.hakon@protonmail.com>
Date: Fri, 13 Jan 2017 15:09:07 +0100
Subject: [PATCH 1/1] avformat: Add alignment mode to Pro-MPEG

---
 doc/protocols.texi    |  3 +++
 libavformat/prompeg.c | 27 ++++++++++++++++++++++++---
 2 files changed, 27 insertions(+), 3 deletions(-)

Comments

Moritz Barsnick Jan. 13, 2017, 9:30 p.m. UTC | #1
On Fri, Jan 13, 2017 at 09:26:16 -0500, Andreas Håkon wrote:
>      { "d", "FEC D", OFFSET(d), AV_OPT_TYPE_INT, { .i64 =  5 }, 4, 20, .flags = E },
> +    { "align", "Alignment mode: 0=none; 1=COL (default); 2=ROW", OFFSET(align), AV_OPT_TYPE_INT, { .i64 =  1 }, 0, 2, .flags = E },

This usually calls for an enum. Something like (off the top of my
head):

enum AlignMode {
    ALIGN_MODE_NONE,
    ALIGN_MODE_COL,
    ALIGN_MODE_ROW,
};

    { "align", "alignment mode", OFFSET(align), AV_OPT_TYPE_INT, { .i64 = ALIGN_MODE_COL }, ALIGN_MODE_NONE, ALIGN_MODE_ROW, E, "align" },
        { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = ALIGN_MODE_NONE }, INT_MIN, INT_MAX, E, "align" },
        { "COL",  NULL, 0, AV_OPT_TYPE_CONST, { .i64 = ALIGN_MODE_COL  }, INT_MIN, INT_MAX, E, "align" },
        { "ROW",  NULL, 0, AV_OPT_TYPE_CONST, { .i64 = ALIGN_MODE_ROW  }, INT_MIN, INT_MAX, E, "align" },
[...]

(Or as option enums, call them "col" and "row" perhaps.)

> +        switch (s->align) {
> +        case 0:
case ALIGN_MODE_NONE:

> +        case 2:
case ALIGN_MODE_COL:

> +        // ROW block-aligned
> +        //   un-implemented!

If so, I think you should add a warning and tell the user that the code
is falling back to COL mode.

> +        case 1:
case ALIGN_MODE_ROW:
> +        default:
Can't be reached if you use the option system as above, add a warning
perhaps.

Moritz
diff mbox

Patch

diff --git a/doc/protocols.texi b/doc/protocols.texi
index e887b75..b9da67b 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -542,6 +542,9 @@  The number of columns (4-20, LxD <= 100)
 @item d=@var{n}
 The number of rows (4-20, LxD <= 100)
 
+@item align=@var{n}
+Alignment mode for column FEC packets (0=none, 1=COL (default), 2=ROW)
+
 @end table
 
 Example usage:
diff --git a/libavformat/prompeg.c b/libavformat/prompeg.c
index 9770a91..a040c43 100644
--- a/libavformat/prompeg.c
+++ b/libavformat/prompeg.c
@@ -105,6 +105,7 @@  typedef struct PrompegContext {
     PrompegFec **fec_arr, **fec_col_tmp, **fec_col, *fec_row;
     int ttl;
     uint8_t l, d;
+    uint8_t align;
     uint8_t *rtp_buf;
     uint16_t rtp_col_sn, rtp_row_sn;
     uint16_t length_recovery;
@@ -124,6 +125,7 @@  static const AVOption options[] = {
     { "ttl",   "Time to live (in milliseconds, multicast only)", OFFSET(ttl), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = E },
     { "l", "FEC L", OFFSET(l), AV_OPT_TYPE_INT, { .i64 =  5 }, 4, 20, .flags = E },
     { "d", "FEC D", OFFSET(d), AV_OPT_TYPE_INT, { .i64 =  5 }, 4, 20, .flags = E },
+    { "align", "Alignment mode: 0=none; 1=COL (default); 2=ROW", OFFSET(align), AV_OPT_TYPE_INT, { .i64 =  1 }, 0, 2, .flags = E },
     { NULL }
 };
 
@@ -430,9 +432,28 @@  static int prompeg_write(URLContext *h, const uint8_t *buf, int size) {
                 s->fec_col_tmp[col_idx]->bitstring, s->bitstring_size);
     }
 
-    // FEC (column) send block-aligned
-    if (!s->first && s->packet_idx % s->d == 0) {
-        col_out_idx = s->packet_idx / s->d;
+    // FEC (column) send
+    col_out_idx = -1;
+    if (!s->first) {
+        switch (s->align) {
+        case 0:
+        // non-aligned
+            if (s->packet_idx <= s->l)
+                col_out_idx = s->packet_idx - 1;
+            break;
+        case 2:
+        // ROW block-aligned
+        //   un-implemented!
+        case 1:
+        default:
+        // COL block-aligned 
+            if (s->packet_idx % s->d == 0)
+                col_out_idx = s->packet_idx / s->d;
+            break;
+        }
+
+    }
+    if (col_out_idx >= 0) {
         if ((ret = prompeg_write_fec(h, s->fec_col[col_out_idx], PROMPEG_FEC_COL)) < 0)
             goto end;
         written += ret;