[vlc-commits] [Git][videolan/vlc][master] 18 commits: rtp: do not overflow PTS (fixes #26258)

Rémi Denis-Courmont (@Courmisch) gitlab at videolan.org
Tue Nov 30 20:35:02 UTC 2021



Rémi Denis-Courmont pushed to branch master at VideoLAN / VLC


Commits:
841c1522 by Rémi Denis-Courmont at 2021-11-30T19:01:24+00:00
rtp: do not overflow PTS (fixes #26258)

VLC does not handle negative timestamps so far. So the initial NTP
reference timestamp should be positive enough that the extrapolated
PTS will not end up negative when the RTP packet timestamp is lower
than the reference RTP timestamp. In that case the PTS is lower than
the NTP reference.

While 2^62 was a very safe value in that respect, it lead to integer
overflows in the clock and in time base conversion code. To avoid this,
we pick a default NTP reference value equal to the closest power of two
of the NTP time of this changeset: 2^52 is in 2042 CE, 2^51 in 1971 CE.

- - - - -
ffb55802 by Rémi Denis-Courmont at 2021-11-30T19:01:24+00:00
mpegaudio: split frame header parsing code

This moves the function to a header for reuse.
No functional changes.

- - - - -
53f36454 by Rémi Denis-Courmont at 2021-11-30T19:01:24+00:00
mpegaudio: use restrict qualifier

- - - - -
1f86c0ab by Rémi Denis-Courmont at 2021-11-30T19:01:24+00:00
mpegaudio: shrink table storage type

All values are between 0 and 65535 here, so they fit in unsigned short.

- - - - -
ed3db4c9 by Rémi Denis-Courmont at 2021-11-30T19:01:24+00:00
mpegaudio: invert condition to simplify

Invert the checks for (in)valid frame headers to bail out early,
reindent and remove logically dead code.

- - - - -
b39b392e by Rémi Denis-Courmont at 2021-11-30T19:01:24+00:00
rtp: do not assume all packets have a PTS

- - - - -
b18db613 by Rémi Denis-Courmont at 2021-11-30T19:01:24+00:00
rtp/mpa: packetize properly

RTP audio/MPA format is mostly but not quite packetised.
Do the strictly needful in the payload format handler.

- - - - -
49d67910 by Rémi Denis-Courmont at 2021-11-30T22:00:34+02:00
rtp: add pktinfo to convey the M bit

The M bit is part of the common RTP header, but handling is entirely
dependent on the payload format, so we have to pass it somehow.

The pktinfo structure will probably need to be extended to also convey
data from extension headers, e.g. picture orientation or (AV-1) decoding
dependency data.

- - - - -
aa12089e by Rémi Denis-Courmont at 2021-11-30T22:00:37+02:00
rtp: treat M bit as audio discontinuity

PCM and MPEG Audio have the M bit set at the start of a "talk spurt".
That is IETF AVT speak for audio after a gap of silence, so flag a
discontinuity.

- - - - -
fabe46b1 by Rémi Denis-Courmont at 2021-11-30T22:00:37+02:00
rtp: improve PT documentation

- - - - -
30d50a4e by Rémi Denis-Courmont at 2021-11-30T22:00:37+02:00
rtp/mpeg12: add basic support for video/MPV

- - - - -
2db75e08 by Rémi Denis-Courmont at 2021-11-30T22:00:37+02:00
rtp: remove hard-coded video/MPV parser

- - - - -
250b296c by Rémi Denis-Courmont at 2021-11-30T22:00:37+02:00
rtp/mpeg12: add video/MP2T format

- - - - -
8dd5c1f2 by Rémi Denis-Courmont at 2021-11-30T22:00:37+02:00
rtp: remove hard-coded video/MP2T parser

- - - - -
ded65db4 by Rémi Denis-Courmont at 2021-11-30T22:00:37+02:00
rtp/mpeg12: add video/MP1S and video/MP2P formats

- - - - -
76b3ad36 by Rémi Denis-Courmont at 2021-11-30T22:00:37+02:00
rtp/mpeg12: limit queue size

To avoid resource exhaustion DoS, make sure that the queue size cannot
grow infinitely with accumulated fragments of a singke packet.

- - - - -
de2518b1 by Rémi Denis-Courmont at 2021-11-30T22:00:37+02:00
display: remove unnecessary #include

- - - - -
2ddcadde by Rémi Denis-Courmont at 2021-11-30T22:00:37+02:00
window: split generic and vout-specific code

- - - - -


16 changed files:

- modules/access/rtp/mpeg12.c
- modules/access/rtp/pcm.c
- modules/access/rtp/rtp.c
- modules/access/rtp/rtp.h
- modules/access/rtp/rtpfmt.c
- modules/access/rtp/session.c
- modules/access/rtp/xiph.c
- modules/packetizer/Makefile.am
- modules/packetizer/mpegaudio.c
- + modules/packetizer/mpegaudio.h
- src/Makefile.am
- src/video_output/display.c
- src/video_output/video_output.c
- + src/video_output/video_window.c
- src/video_output/window.h → src/video_output/video_window.h
- src/video_output/window.c


Changes:

=====================================
modules/access/rtp/mpeg12.c
=====================================
@@ -34,8 +34,14 @@
 #include <vlc_strings.h>
 
 #include "rtp.h"
+#include "../../packetizer/mpegaudio.h"
 
+#define MAX_PACKET_SIZE (1u << 18)
+
+/* audio/MPA: MPEG-1/2 Audio layer I/II/III ES */
 struct rtp_mpa {
+    block_t *frags;
+    block_t **frag_end;
     size_t offset;
     struct vlc_rtp_es *es;
 };
@@ -46,14 +52,32 @@ static void *rtp_mpa_init(struct vlc_rtp_pt *pt)
     if (unlikely(sys == NULL))
         return NULL;
 
+    sys->frags = NULL;
+    sys->frag_end = &sys->frags;
+    sys->offset = 0;
+
     es_format_t fmt;
 
     es_format_Init(&fmt, AUDIO_ES, VLC_CODEC_MPGA);
-    fmt.b_packetized = false;
     sys->es = vlc_rtp_pt_request_es(pt, &fmt);
     return sys;
 }
 
+static void rtp_mpa_send(struct rtp_mpa *sys)
+{
+    block_t *frags = sys->frags;
+    block_t *frame = block_ChainGather(frags);
+
+    if (likely(frame != NULL))
+        vlc_rtp_es_send(sys->es, frame);
+    else
+        block_ChainRelease(frags);
+
+    sys->frags = NULL;
+    sys->frag_end = &sys->frags;
+    sys->offset = 0;
+}
+
 static void rtp_mpa_destroy(struct vlc_rtp_pt *pt, void *data)
 {
     struct rtp_mpa *sys = data;
@@ -61,12 +85,15 @@ static void rtp_mpa_destroy(struct vlc_rtp_pt *pt, void *data)
     if (unlikely(sys == NULL))
         return;
 
+    if (sys->frags != NULL)
+        rtp_mpa_send(sys);
     vlc_rtp_es_destroy(sys->es);
     free(sys);
     (void) pt;
 }
 
-static void rtp_mpa_decode(struct vlc_rtp_pt *pt, void *data, block_t *block)
+static void rtp_mpa_decode(struct vlc_rtp_pt *pt, void *data, block_t *block,
+                           const struct vlc_rtp_pktinfo *restrict info)
 {
     struct vlc_logger *log = pt->opaque;
     struct rtp_mpa *sys = data;
@@ -84,19 +111,82 @@ static void rtp_mpa_decode(struct vlc_rtp_pt *pt, void *data, block_t *block)
     block->p_buffer += 4;
     block->i_buffer -= 4;
 
-    if (offset != 0 && offset != sys->offset) {
+    if (offset < sys->offset)
+        rtp_mpa_send(sys); /* New frame started: send pending frame if any */
+
+    if (offset != sys->offset) {
         /* Discontinuous offset, probably packet loss. */
         vlc_warning(log, "offset discontinuity: expected %zu, got %"PRIuFAST16,
                     sys->offset, offset);
-        block->i_flags |= BLOCK_FLAG_DISCONTINUITY | BLOCK_FLAG_CORRUPTED;
+        block->i_flags |= BLOCK_FLAG_CORRUPTED;
     }
 
+    if (block->i_buffer == 0)
+        goto drop;
+
+    if (info->m)
+        block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
+
+    *sys->frag_end = block;
+    sys->frag_end = &block->p_next;
     sys->offset = offset + block->i_buffer;
-    /* This payload format does not flag the last fragment of a frame,
-     * so the MPGA header must be parsed to figure out the frame size and end
-     * (without introducing a one-packet delay).
-     * We let the packetiser handle it rather than duplicate the logic. */
-    vlc_rtp_es_send(sys->es, block);
+    block = sys->frags;
+
+    /* Extract full MPEG Audio frames */
+    for (;;) {
+        uint32_t header;
+
+        if (block_ChainExtract(block, &header, 4) < 4)
+           break;
+
+        /* This RTP payload format does atypically not flag end-of-frames, so
+         * we have to parse the MPEG Audio frame header to find out. */
+        unsigned chans, conf, mode, srate, brate, samples, maxsize, layer;
+        int frame_size = SyncInfo(ntoh32(header), &chans, &conf, &mode, &srate,
+                                  &brate, &samples, &maxsize, &layer);
+        /* If the frame size is unknown due to free bit rate, then we can only
+         * sense the completion of the frame when the next frame starts. */
+        if (frame_size <= 0) {
+            if (sys->offset >= MAX_PACKET_SIZE) {
+                vlc_warning(log, "oversized packet (%zu bytes)", sys->offset);
+                rtp_mpa_send(sys);
+            }
+            break;
+        }
+
+        if ((size_t)frame_size == sys->offset) {
+            rtp_mpa_send(sys);
+            break;
+        }
+
+        /* If the frame size is larger than the current offset, then we need to
+         * wait for the next fragment. */
+        if ((size_t)frame_size > sys->offset)
+            break;
+
+        if (offset != 0) {
+            vlc_warning(log, "invalid frame fragmentation");
+            block->i_flags |= BLOCK_FLAG_CORRUPTED;
+            break;
+        }
+
+        /* The RTP packet contains multiple small frames. */
+        block_t *frame = block_Alloc(frame_size);
+        if (likely(frame != NULL)) {
+            assert(block->p_next == NULL); /* Only one block to copy from */
+            memcpy(frame->p_buffer, block->p_buffer, frame_size);
+            frame->i_flags = block->i_flags;
+            frame->i_pts = block->i_pts;
+            vlc_rtp_es_send(sys->es, frame);
+
+            block->i_flags = 0;
+        } else
+            block->i_flags = BLOCK_FLAG_DISCONTINUITY;
+
+        block->p_buffer += frame_size;
+        block->i_buffer -= frame_size;
+        block->i_pts = VLC_TICK_INVALID;
+    }
     return;
 
 drop:
@@ -107,13 +197,207 @@ static const struct vlc_rtp_pt_operations rtp_mpa_ops = {
     NULL, rtp_mpa_init, rtp_mpa_destroy, rtp_mpa_decode,
 };
 
+/* video/MPV: MPEG-1/2 Video ES */
+struct rtp_mpv {
+    block_t *frags;
+    block_t **frag_end;
+    size_t size;
+    struct vlc_rtp_es *es;
+};
+
+static void *rtp_mpv_init(struct vlc_rtp_pt *pt)
+{
+    struct rtp_mpv *sys = malloc(sizeof (*sys));
+    if (unlikely(sys == NULL))
+        return NULL;
+
+    sys->frags = NULL;
+    sys->frag_end = &sys->frags;
+    sys->size = 0;
+
+    es_format_t fmt;
+
+    es_format_Init(&fmt, VIDEO_ES, VLC_CODEC_MPGV);
+    sys->es = vlc_rtp_pt_request_es(pt, &fmt);
+    return sys;
+}
+
+static void rtp_mpv_send(struct rtp_mpv *sys)
+{
+    block_t *frags = sys->frags;
+    block_t *frame = block_ChainGather(frags);
+
+    if (likely(frame != NULL))
+        vlc_rtp_es_send(sys->es, frame);
+    else
+        block_ChainRelease(frags);
+
+    sys->frags = NULL;
+    sys->frag_end = &sys->frags;
+    sys->size = 0;
+}
+
+static void rtp_mpv_destroy(struct vlc_rtp_pt *pt, void *data)
+{
+    struct rtp_mpv *sys = data;
+
+    if (unlikely(sys == NULL))
+        return;
+
+    if (sys->frags != NULL)
+        rtp_mpv_send(sys);
+    vlc_rtp_es_destroy(sys->es);
+    free(sys);
+    (void) pt;
+}
+
+/* RFC2250 §3.4 */
+#define MPV_TWO_BIT  0x04000000u
+#define MPV_TR_MASK  0x03ff0000u
+#define MPV_AN_BIT   0x00008000u
+#define MPV_N_BIT    0x00004000u
+#define MPV_S_BIT    0x00002000u
+#define MPV_BS_BIT   0x00001000u
+#define MPV_ES_BIT   0x00000800u
+#define MPV_PT_MASK  0x00000700u
+#define MPV_FBV_BIT  0x00000080u
+#define MPV_FBC_MASK 0x00000070u
+#define MPV_FFV_BIT  0x00000008u
+#define MPV_FFC_MASK 0x00000007u
+
+static const unsigned short pic_types[8] = {
+    BLOCK_FLAG_CORRUPTED /* forbidden */, BLOCK_FLAG_TYPE_I,
+    BLOCK_FLAG_TYPE_P, BLOCK_FLAG_TYPE_B,
+    BLOCK_FLAG_TYPE_I /* actually DC */, 0, 0, 0
+};
+
+#define EXTRACT(x,mask) (((x) & (mask)) >> vlc_ctz(mask))
+
+static void rtp_mpv_decode(struct vlc_rtp_pt *pt, void *data, block_t *block,
+                           const struct vlc_rtp_pktinfo *restrict info)
+{
+    struct vlc_logger *log = pt->opaque;
+    struct rtp_mpv *sys = data;
+
+    if (unlikely(sys == NULL))
+        goto drop;
+    if (block->i_buffer < 4) {
+        vlc_warning(log, "malformatted packet (%zu bytes)", block->i_buffer);
+        goto drop;
+    }
+
+    uint_fast32_t header = GetDWBE(block->p_buffer);
+    size_t hlen = 4;
+
+    if (header & MPV_TWO_BIT) {
+        if (block->i_buffer < 8) {
+            vlc_warning(log, "malformatted packet (%zu bytes)",
+                        block->i_buffer);
+            goto drop;
+        }
+
+        /* TODO: extract frame structure from header extension */
+        hlen += 4;
+    }
+    block->p_buffer += hlen;
+    block->i_buffer -= hlen;
+
+#if 0 /* We could set this flag, but it would not be used for anything */
+    if (header & MPV_S_BIT)
+        block->i_flags |= BLOCK_FLAG_HEADER;
+#endif
+
+    block->i_flags |= pic_types[EXTRACT(header, MPV_PT_MASK)];
+    *sys->frag_end = block;
+    sys->frag_end = &block->p_next;
+    sys->size += block->i_buffer;
+
+    if (sys->size >= MAX_PACKET_SIZE) {
+        vlc_warning(log, "oversized packet (%zu bytes)", sys->size);
+        rtp_mpv_send(sys); /* refuse to queue arbitrarily large packet */
+    }
+    else
+    if (info->m)
+        rtp_mpv_send(sys);
+
+    return;
+
+drop:
+    block_Release(block);
+}
+
+static const struct vlc_rtp_pt_operations rtp_mpv_ops = {
+    NULL, rtp_mpv_init, rtp_mpv_destroy, rtp_mpv_decode,
+};
+
+/* video/MP1S, video/MP2P: MPEG-1/2 system streams */
+static void *rtp_mp2p_init(struct vlc_rtp_pt *pt)
+{
+    return vlc_rtp_pt_request_mux(pt, "ps");
+}
+
+static void rtp_mp2p_destroy(struct vlc_rtp_pt *pt, void *data)
+{
+    vlc_rtp_es_destroy(data);
+    (void) pt;
+}
+
+static void rtp_mp2p_decode(struct vlc_rtp_pt *pt, void *data, block_t *block,
+                            const struct vlc_rtp_pktinfo *restrict info)
+{
+    if (info->m) /* TODO: avoid stream/chained-demux to preserve flags */
+        block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
+
+    vlc_rtp_es_send(data, block);
+    (void) pt;
+}
+
+static const struct vlc_rtp_pt_operations rtp_mp2p_ops = {
+    NULL, rtp_mp2p_init, rtp_mp2p_destroy, rtp_mp2p_decode,
+};
+
+/* video/MP2T: MPEG-2 Transport Stream */
+static void *rtp_mp2t_init(struct vlc_rtp_pt *pt)
+{
+    return vlc_rtp_pt_request_mux(pt, "ts");
+}
+
+static void rtp_mp2t_destroy(struct vlc_rtp_pt *pt, void *data)
+{
+    vlc_rtp_es_destroy(data);
+    (void) pt;
+}
+
+static void rtp_mp2t_decode(struct vlc_rtp_pt *pt, void *data, block_t *block,
+                            const struct vlc_rtp_pktinfo *restrict info)
+{
+    if (info->m) /* TODO: avoid stream/chained-demux to preserve flags */
+        block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
+
+    block->i_buffer -= block->i_buffer % 188;
+    vlc_rtp_es_send(data, block);
+    (void) pt;
+}
+
+static const struct vlc_rtp_pt_operations rtp_mp2t_ops = {
+    NULL, rtp_mp2t_init, rtp_mp2t_destroy, rtp_mp2t_decode,
+};
+
+
 static int rtp_mpeg12_open(vlc_object_t *obj, struct vlc_rtp_pt *pt,
                         const struct vlc_sdp_pt *desc)
 {
     pt->opaque = vlc_object_logger(obj);
 
-    if (vlc_ascii_strcasecmp(desc->name, "MPA") == 0) /* RFC2250 */
+    if (vlc_ascii_strcasecmp(desc->name, "MPA") == 0) /* RFC2250 §3.2 */
         pt->ops = &rtp_mpa_ops;
+    else if (vlc_ascii_strcasecmp(desc->name, "MPV") == 0) /* RFC2250 §3.1 */
+        pt->ops = &rtp_mpv_ops;
+    else if (vlc_ascii_strcasecmp(desc->name, "MP1S") == 0
+          || vlc_ascii_strcasecmp(desc->name, "MP2P") == 0) /* RFC2250 §2 */
+        pt->ops = &rtp_mp2p_ops;
+    else if (vlc_ascii_strcasecmp(desc->name, "MP2T") == 0) /* RFC2250 §2 */
+        pt->ops = &rtp_mp2t_ops;
     else
         return VLC_ENOTSUP;
 
@@ -126,5 +410,6 @@ vlc_module_begin()
     set_category(CAT_INPUT)
     set_subcategory(SUBCAT_INPUT_DEMUX)
     set_rtp_parser_callback(rtp_mpeg12_open)
-    add_shortcut("audio/MPA")
+    add_shortcut("audio/MPA", "video/MPV", "video/MP1S", "video/MP2P",
+                 "video/MP2T")
 vlc_module_end()


=====================================
modules/access/rtp/pcm.c
=====================================
@@ -90,7 +90,8 @@ static void rtp_pcm_reorder(void *restrict out, const void *restrict in,
     }
 }
 
-static void rtp_pcm_decode(struct vlc_rtp_pt *pt, void *data, block_t *block)
+static void rtp_pcm_decode(struct vlc_rtp_pt *pt, void *data, block_t *block,
+                           const struct vlc_rtp_pktinfo *restrict info)
 {
     struct rtp_pcm *sys = pt->opaque;
     struct vlc_rtp_es *es = data;
@@ -100,6 +101,9 @@ static void rtp_pcm_decode(struct vlc_rtp_pt *pt, void *data, block_t *block)
     block->i_buffer = ((frames * frame_bits) + 7) / 8;
     block->i_dts = VLC_TICK_INVALID;
 
+    if (info->m)
+        block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
+
     if (sys->channel_reorder) {
         block_t *reordered = block_Alloc(block->i_buffer);
 


=====================================
modules/access/rtp/rtp.c
=====================================
@@ -77,7 +77,8 @@ static void vlc_rtp_es_id_send(struct vlc_rtp_es *es, block_t *block)
 
     /* TODO: Don't set PCR here. Breaks multiple sources (in a session)
      * and more importantly eventually multiple sessions. */
-    es_out_SetPCR(ei->out, block->i_pts);
+    if (block->i_pts != VLC_TICK_INVALID)
+        es_out_SetPCR(ei->out, block->i_pts);
     es_out_Send(ei->out, ei->id, block);
 }
 


=====================================
modules/access/rtp/rtp.h
=====================================
@@ -36,15 +36,28 @@ struct vlc_demux_chained_t;
 struct vlc_sdp_media;
 
 /**
- * \defgroup rtp_pt RTP payload format
+ * \defgroup rtp_pt RTP payload formats
+ *
+ * RTP is a somewhat simplistic protocol to carry multiplexed and timestamped
+ * data over an unreliable network. It cannot be used as is: depending on the
+ * concrete type and subtype of data, a format must be selected which
+ * specifically defines how the data is carried as the payload of RTP packets.
+ * This format is known as an RTP payload format.
+ *
+ * A given RTP session (\ref rtp_session_t) can use up to 128 different payload
+ * types (\ref vlc_rtp_pt).
+ * Each payload type is identified by a 7-bit value and designates a
+ * payload format and an associated set of format-dependent parameters
+ * specified by a payload type mapping (\ref vlc_sdp_pt).
+ *
  * @{
  */
 
 /**
  * Payload type mapping.
  *
- * This structure represents a mapping for an RTP payload format
- * extracted from an \ref sdp description.
+ * This structure represents an RTP payload type mapping for an RTP payload
+ * format extracted from an \ref sdp description.
  */
 struct vlc_sdp_pt {
     const struct vlc_sdp_media *media; /**< Containant SDP media description */
@@ -55,42 +68,53 @@ struct vlc_sdp_pt {
 };
 
 /**
- * RTP payload format operations.
+ * RTP packet infos.
+ *
+ * This structure conveys infos extracted from the header of an RTP packet
+ * to payload format parsers.
+ */
+struct vlc_rtp_pktinfo {
+    bool m; /**< M bit from the RTP header */
+};
+
+/**
+ * RTP payload type operations.
  *
- * This structures contains the callbacks provided by an RTP payload format.
+ * This structures contains the callbacks provided by an RTP payload type
+ * (\ref vlc_rtp_pt).
  */
 struct vlc_rtp_pt_operations {
     /**
-     * Releases the payload format.
+     * Releases the payload type.
      *
      * This optional callback releases any resources associated with the
      * payload format, such as copies of the payload format parameters.
      *
-     * \param pt RTP payload format that is being released
+     * \param pt RTP payload type that is being released
      */
     void (*release)(struct vlc_rtp_pt *pt);
 
     /**
-     * Starts using a payload format.
+     * Starts using a payload type.
      *
      * This required callback initialises per-source resources for the payload
-     * format, such as an elementary stream output.
+     * type, such as an elementary stream output.
      *
-     * \note There may be multiple RTP sources using the same payload format
+     * \note There may be multiple RTP sources using the same payload type
      * concurrently within single given RTP session. This callback is invoked
      * for each source.
      *
-     * \param pt RTP payload format being taken into use
+     * \param pt RTP payload type being taken into use
      * \return a data pointer for decode() and destroy() callbacks
      */
     void *(*init)(struct vlc_rtp_pt *pt);
 
     /**
-     * Stops using a payload format.
+     * Stops using a payload type.
      *
      * This optional callback deinitialises per-source resources.
      *
-     * \param pt RTP payload format to relinquish
+     * \param pt RTP payload type to relinquish
      * \param data data pointer returned by init()
      */
     void (*destroy)(struct vlc_rtp_pt *pt, void *data);
@@ -98,32 +122,46 @@ struct vlc_rtp_pt_operations {
     /**
      * Processes a data payload.
      *
-     * \param pt RTP payload format of the payload
+     * \param pt RTP payload type of the payload
      * \param data data pointer returned by init()
      * \param block payload of a received RTP packet
+     * \param info RTP packet header infos
      */
-    void (*decode)(struct vlc_rtp_pt *pt, void *data, block_t *block);
+    void (*decode)(struct vlc_rtp_pt *pt, void *data, block_t *block,
+                   const struct vlc_rtp_pktinfo *restrict info);
 };
 
 struct vlc_rtp_pt_owner;
 struct vlc_rtp_es;
 
+/**
+ * RTP payload type owner operations.
+ *
+ * This structures contains the callbacks provided by an RTP payload type owner
+ * (\ref vlc_rtp_pt_owner).
+ */
 struct vlc_rtp_pt_owner_operations {
     struct vlc_rtp_es *(*request_es)(struct vlc_rtp_pt *pt,
                                      const es_format_t *restrict fmt);
     struct vlc_rtp_es *(*request_mux)(struct vlc_rtp_pt *pt, const char *name);
 };
 
+/**
+ * RTP payload type owner.
+ *
+ * This structure embedded in \ref vlc_rtp_pt conveys the callbacks provided by
+ * the owner of a payload type.
+ */
 struct vlc_rtp_pt_owner {
-    const struct vlc_rtp_pt_owner_operations *ops;
-    void *data;
+    const struct vlc_rtp_pt_owner_operations *ops; /**< Owner callbacks */
+    void *data; /**< Owner private data */
 };
 
 /**
- * RTP payload format.
+ * RTP payload type.
  *
  * This structures represents a payload format within an RTP session
- * (\ref vlc_rtp_session_t).
+ * (\ref rtp_session_t).
  */
 struct vlc_rtp_pt
 {
@@ -137,19 +175,22 @@ struct vlc_rtp_pt
 
 /**
  * Destroys a payload type parameter set.
+ *
+ * This function destroys a payload type.
+ * It can only be called when the payload type has no active sources.
  */
 void vlc_rtp_pt_release(struct vlc_rtp_pt *pt);
 
 /**
- * Instantiates a payload type from a set of parameters.
+ * Binds a payload type to a source.
  *
  * A given SDP media can have multiple alternative payload types, each with
  * their set of parameters. The RTP session can then have multiple concurrent
- * RTP sources (SSRC). This function creates an instance of a given payload
- * type for use by an unique RTP source.
+ * RTP sources (SSRC). This function starts an association of a given payload
+ * type with an unique RTP source.
  *
- * @param pt RTP payload type to instantiate
- * @return private data for the instance
+ * @param pt RTP payload type to associate with a source
+ * @return private data for the type-source association
  */
 static inline void *vlc_rtp_pt_begin(struct vlc_rtp_pt *pt)
 {
@@ -158,12 +199,13 @@ static inline void *vlc_rtp_pt_begin(struct vlc_rtp_pt *pt)
 }
 
 /**
- * Deinstantiates a payload type.
+ * Unbinds a payload type from a source.
  *
- * This destroys an instance of a payload type created by vlc_rtp_pt_begin().
+ * This removes an association between a payload type and a source created by
+ * vlc_rtp_pt_begin().
  *
- * @param pt RTP payload type to deinstantiate
- * @param data instance private data as returned by vlc_rtp_pt_begin()
+ * @param pt RTP payload type to deassociate
+ * @param data private data as returned by vlc_rtp_pt_begin()
  */
 static inline void vlc_rtp_pt_end(struct vlc_rtp_pt *pt, void *data)
 {
@@ -172,18 +214,30 @@ static inline void vlc_rtp_pt_end(struct vlc_rtp_pt *pt, void *data)
 }
 
 /**
- * Processes an payload packet.
+ * Processes a payload packet.
  *
- * This passes a data payload of an RTP packet to the instance of the
- * payload type specified in the packet (PT and SSRC fields).
+ * This passes a data payload from an RTP packet for processing to the payload
+ * type bound to the source of the packet. The payload type is determined from
+ * the RTP header PT field and the source from the SSRC field.
  */
-static inline void vlc_rtp_pt_decode(struct vlc_rtp_pt *pt,
-                                     void *data, block_t *pkt)
+static inline
+void vlc_rtp_pt_decode(struct vlc_rtp_pt *pt, void *data, block_t *pkt,
+                       const struct vlc_rtp_pktinfo *restrict info)
 {
     assert(pt->ops->decode != NULL);
-    pt->ops->decode(pt, data, pkt);
+    pt->ops->decode(pt, data, pkt, info);
 }
 
+/**
+ * Starts an elementary stream (ES).
+ *
+ * This function is used by an active RTP payload type to create an
+ * elementary (audio, video or subtitle) stream to process encoded data
+ * extracted from an RTP source.
+ *
+ * A given payload type normally maintains one such elementary stream per
+ * active type-source association (\ref vlc_rtp_pt_begin).
+ */
 static inline
 struct vlc_rtp_es *vlc_rtp_pt_request_es(struct vlc_rtp_pt *pt,
                                          const es_format_t *restrict fmt)
@@ -191,6 +245,13 @@ struct vlc_rtp_es *vlc_rtp_pt_request_es(struct vlc_rtp_pt *pt,
     return pt->owner.ops->request_es(pt, fmt);
 }
 
+/**
+ * Starts a complete multiplex.
+ *
+ * This function creates a complete multiplexed multimedia stream to process
+ * data extracted from RTP packets. This should be avoided as much as possible
+ * as RTP is designed to carry raw elementary streams.
+ */
 static inline
 struct vlc_rtp_es *vlc_rtp_pt_request_mux(struct vlc_rtp_pt *pt,
                                           const char *name)
@@ -199,15 +260,28 @@ struct vlc_rtp_es *vlc_rtp_pt_request_mux(struct vlc_rtp_pt *pt,
 }
 
 /**
- * RTP elementary output stream operations.
+ * RTP abstract output stream operations.
+ *
+ * This structures contains the callbacks provided by an RTP ES
+ * (\ref vlc_rtp_pt).
  */
 struct vlc_rtp_es_operations {
+    /**
+     * Destroys the corresponding \ref vlc_rtp_es.
+     *
+     * Use vlc_rtp_es_destroy() instead.
+     */
     void (*destroy)(struct vlc_rtp_es *es);
+    /**
+     * Passes data for processing to a \ref vlc_rtp_es.
+     *
+     * Use vlc_rtp_es_send() instead.
+     */
     void (*send)(struct vlc_rtp_es *es, block_t *block);
 };
 
 /**
- * RTP elementary output stream.
+ * RTP abstract output stream.
  *
  * This structure represents a data sink for an active instance of a payload
  * format, typically an output elementary stream (ES) \ref es_out_id_t.
@@ -240,7 +314,7 @@ static inline void vlc_rtp_es_send(struct vlc_rtp_es *es, block_t *block)
 }
 
 /**
- * A dummy output that discards data.
+ * A (pointer to a) dummy output that discards data.
  */
 extern struct vlc_rtp_es *const vlc_rtp_es_dummy;
 
@@ -258,6 +332,9 @@ extern struct vlc_rtp_es *const vlc_rtp_es_dummy;
 typedef int (*vlc_rtp_parser_cb)(vlc_object_t *obj, struct vlc_rtp_pt *pt,
                                  const struct vlc_sdp_pt *desc);
 
+/**
+ * Helper to set the RTP payload format parser module capability and callback.
+ */
 #define set_rtp_parser_callback(cb) \
     { \
         vlc_rtp_parser_cb cb__ = (cb); (void) cb__; \


=====================================
modules/access/rtp/rtpfmt.c
=====================================
@@ -44,9 +44,10 @@ static void codec_destroy(struct vlc_rtp_pt *pt, void *data)
 }
 
 /* Send a packet to ES */
-static void codec_decode(struct vlc_rtp_pt *pt, void *data, block_t *block)
+static void codec_decode(struct vlc_rtp_pt *pt, void *data, block_t *block,
+                         const struct vlc_rtp_pktinfo *restrict info)
 {
-    (void) pt;
+    (void) pt; (void) info;
     block->i_dts = VLC_TICK_INVALID;
     vlc_rtp_es_send(data, block);
 }
@@ -89,69 +90,19 @@ static const struct vlc_rtp_pt_operations rtp_audio_qcelp = {
     NULL, qcelp_init, codec_destroy, codec_decode,
 };
 
-/* PT=32
- * MPV: MPEG Video (RFC2250, §3.5)
- */
-static void *mpv_init(struct vlc_rtp_pt *pt)
-{
-    es_format_t fmt;
-
-    es_format_Init (&fmt, VIDEO_ES, VLC_CODEC_MPGV);
-    fmt.b_packetized = false;
-    return vlc_rtp_pt_request_es(pt, &fmt);
-}
-
-static void mpv_decode(struct vlc_rtp_pt *pt, void *data, block_t *block)
-{
-    if (block->i_buffer < 4)
-    {
-        block_Release (block);
-        return;
-    }
-
-    block->i_buffer -= 4; /* 32-bits RTP/MPV header */
-    block->p_buffer += 4;
-    block->i_dts = VLC_TICK_INVALID;
-#if 0
-    if (block->p_buffer[-3] & 0x4)
-    {
-        /* MPEG2 Video extension header */
-        /* TODO: shouldn't we skip this too ? */
-    }
-#endif
-    vlc_rtp_es_send(data, block);
-    (void) pt;
-}
-
-static const struct vlc_rtp_pt_operations rtp_video_mpv = {
-    NULL, mpv_init, codec_destroy, mpv_decode,
-};
-
-/* PT=33
- * MP2: MPEG TS (RFC2250, §2)
- */
-static void *ts_init(struct vlc_rtp_pt *pt)
-{
-    return vlc_rtp_pt_request_mux(pt, "ts");
-}
-
-static const struct vlc_rtp_pt_operations rtp_av_ts = {
-    NULL, ts_init, codec_destroy, codec_decode,
-};
-
 /* Not using SDP, we need to guess the payload format used */
 /* see http://www.iana.org/assignments/rtp-parameters */
 void rtp_autodetect(vlc_object_t *obj, rtp_session_t *session,
                     const struct vlc_rtp_pt_owner *restrict owner)
 {
     char type[] = "audio", proto[] = "RTP/AVP";
-    char format[] = "0 3 8 10 11 12 14 33";
+    char format[] = "0 3 8 10 11 12 14";
     struct vlc_sdp_media media = {
         .type = type, .port_count = 1, .proto = proto, .format = format };
 
     vlc_rtp_add_media_types(obj, session, &media, owner);
     strcpy(type, "video");
-    strcpy(format, "32");
+    strcpy(format, "32 33");
     vlc_rtp_add_media_types(obj, session, &media, owner);
 }
 
@@ -187,14 +138,8 @@ static struct vlc_rtp_pt *vlc_rtp_pt_create(vlc_object_t *obj,
             pt->ops = &rtp_audio_gsm;
         else if (strcmp(desc->name, "QCELP") == 0)
             pt->ops = &rtp_audio_qcelp;
-    } else if (strcmp(desc->media->type, "video") == 0) {
-        if (strcmp(desc->name, "MPV") == 0)
-            pt->ops = &rtp_video_mpv;
     }
 
-    if (strcmp(desc->name, "MP2T") == 0)
-        pt->ops = &rtp_av_ts;
-
     if (pt->ops == NULL) {
         msg_Err(obj, "unsupported media type %s/%s", desc->media->type,
                 desc->name);


=====================================
modules/access/rtp/session.c
=====================================
@@ -144,7 +144,7 @@ rtp_source_create (demux_t *demux, const rtp_session_t *session,
     source->ssrc = ssrc;
     source->jitter = 0;
     source->ref_rtp = 0;
-    source->ref_ntp = UINT64_C (1) << 62;
+    source->ref_ntp = UINT64_C (1) << 51;
     source->max_seq = source->bad_seq = init_seq;
     source->last_seq = init_seq - 1;
     source->blocks = NULL;
@@ -507,10 +507,15 @@ rtp_decode (demux_t *demux, const rtp_session_t *session, rtp_source_t *src)
     if (block->i_buffer < skip)
         goto drop;
 
+    struct vlc_rtp_pktinfo pktinfo = {
+        .m = block->p_buffer[1] >> 7,
+        /* TODO: extension headers (e.g. AV-1 deps) */
+    };
+
     block->p_buffer += skip;
     block->i_buffer -= skip;
 
-    vlc_rtp_pt_decode(pt, src->pt.opaque, block);
+    vlc_rtp_pt_decode(pt, src->pt.opaque, block, &pktinfo);
     return;
 
 drop:


=====================================
modules/access/rtp/xiph.c
=====================================
@@ -127,7 +127,8 @@ static ssize_t xiph_header (void **pextra, const uint8_t *buf, size_t len)
     return extra_size;
 }
 
-static void xiph_decode(struct vlc_rtp_pt *pt, void *data, block_t *block)
+static void xiph_decode(struct vlc_rtp_pt *pt, void *data, block_t *block,
+                        const struct vlc_rtp_pktinfo *restrict info)
 {
     struct rtp_xiph_source *self = data;
     struct rtp_xiph *sys = pt->opaque;
@@ -262,6 +263,7 @@ static void xiph_decode(struct vlc_rtp_pt *pt, void *data, block_t *block)
         pkts--;
     }
 
+    (void) info;
 drop:
     block_Release (block);
 }


=====================================
modules/packetizer/Makefile.am
=====================================
@@ -13,7 +13,8 @@ libpacketizer_mpeg4video_plugin_la_SOURCES = packetizer/mpeg4video.c \
 libpacketizer_mjpeg_plugin_la_SOURCES = packetizer/mjpeg.c
 libpacketizer_mpeg4audio_plugin_la_SOURCES = packetizer/mpeg4audio.c \
                                              packetizer/mpeg4audio.h
-libpacketizer_mpegaudio_plugin_la_SOURCES = packetizer/mpegaudio.c
+libpacketizer_mpegaudio_plugin_la_SOURCES = \
+	packetizer/mpegaudio.c packetizer/mpegaudio.h
 libpacketizer_h264_plugin_la_SOURCES = \
 	packetizer/h264_nal.c packetizer/h264_nal.h \
 	packetizer/h264_slice.c packetizer/h264_slice.h \


=====================================
modules/packetizer/mpegaudio.c
=====================================
@@ -40,6 +40,7 @@
 #include <vlc_block_helper.h>
 
 #include "packetizer_helper.h"
+#include "mpegaudio.h"
 
 /*****************************************************************************
  * decoder_sys_t : decoder descriptor
@@ -145,136 +146,6 @@ static uint8_t *GetOutBuffer( decoder_t *p_dec, block_t **pp_out_buffer )
     return p_block->p_buffer;
 }
 
-/*****************************************************************************
- * SyncInfo: parse MPEG audio sync info
- *****************************************************************************/
-static int SyncInfo( uint32_t i_header, unsigned int * pi_channels,
-                     unsigned int * pi_channels_conf,
-                     unsigned int * pi_chan_mode,
-                     unsigned int * pi_sample_rate, unsigned int * pi_bit_rate,
-                     unsigned int * pi_frame_length,
-                     unsigned int * pi_max_frame_size, unsigned int * pi_layer)
-{
-    static const int ppi_bitrate[2][3][16] =
-    {
-        {
-            /* v1 l1 */
-            { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384,
-              416, 448, 0},
-            /* v1 l2 */
-            { 0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256,
-              320, 384, 0},
-            /* v1 l3 */
-            { 0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224,
-              256, 320, 0}
-        },
-
-        {
-            /* v2 l1 */
-            { 0, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192,
-              224, 256, 0},
-            /* v2 l2 */
-            { 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128,
-              144, 160, 0},
-            /* v2 l3 */
-            { 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128,
-              144, 160, 0}
-        }
-    };
-
-    static const int ppi_samplerate[2][4] = /* version 1 then 2 */
-    {
-        { 44100, 48000, 32000, 0 },
-        { 22050, 24000, 16000, 0 }
-    };
-
-    int i_version, i_mode, i_emphasis;
-    bool b_padding, b_mpeg_2_5;
-    int i_frame_size = 0;
-    int i_bitrate_index, i_samplerate_index;
-    int i_max_bit_rate;
-
-    b_mpeg_2_5  = 1 - ((i_header & 0x100000) >> 20);
-    i_version   = 1 - ((i_header & 0x80000) >> 19);
-    *pi_layer   = 4 - ((i_header & 0x60000) >> 17);
-    //bool b_crc = !((i_header >> 16) & 0x01);
-    i_bitrate_index = (i_header & 0xf000) >> 12;
-    i_samplerate_index = (i_header & 0xc00) >> 10;
-    b_padding   = (i_header & 0x200) >> 9;
-    /* Extension */
-    i_mode      = (i_header & 0xc0) >> 6;
-    /* Modeext, copyright & original */
-    i_emphasis  = i_header & 0x3;
-    *pi_chan_mode = 0;
-
-    if( *pi_layer != 4 &&
-        i_bitrate_index < 0x0f &&
-        i_samplerate_index != 0x03 &&
-        i_emphasis != 0x02 )
-    {
-        switch ( i_mode )
-        {
-        case 2: /* dual-mono */
-            *pi_chan_mode = AOUT_CHANMODE_DUALMONO;
-            /* fall through */
-        case 0: /* stereo */
-        case 1: /* joint stereo */
-            *pi_channels = 2;
-            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
-            break;
-        case 3: /* mono */
-            *pi_channels = 1;
-            *pi_channels_conf = AOUT_CHAN_CENTER;
-            break;
-        }
-        *pi_bit_rate = ppi_bitrate[i_version][*pi_layer-1][i_bitrate_index];
-        i_max_bit_rate = ppi_bitrate[i_version][*pi_layer-1][14];
-        *pi_sample_rate = ppi_samplerate[i_version][i_samplerate_index];
-
-        if ( b_mpeg_2_5 )
-        {
-            *pi_sample_rate >>= 1;
-        }
-
-        switch( *pi_layer )
-        {
-        case 1:
-            i_frame_size = ( 12000 * *pi_bit_rate / *pi_sample_rate +
-                           b_padding ) * 4;
-            *pi_max_frame_size = ( 12000 * i_max_bit_rate /
-                                 *pi_sample_rate + 1 ) * 4;
-            *pi_frame_length = 384;
-            break;
-
-        case 2:
-            i_frame_size = 144000 * *pi_bit_rate / *pi_sample_rate + b_padding;
-            *pi_max_frame_size = 144000 * i_max_bit_rate / *pi_sample_rate + 1;
-            *pi_frame_length = 1152;
-            break;
-
-        case 3:
-            i_frame_size = ( i_version ? 72000 : 144000 ) *
-                           *pi_bit_rate / *pi_sample_rate + b_padding;
-            *pi_max_frame_size = ( i_version ? 72000 : 144000 ) *
-                                 i_max_bit_rate / *pi_sample_rate + 1;
-            *pi_frame_length = i_version ? 576 : 1152;
-            break;
-
-        default:
-            break;
-        }
-
-        /* Free bitrate mode can support higher bitrates */
-        if( !*pi_bit_rate ) *pi_max_frame_size *= 2;
-    }
-    else
-    {
-        return -1;
-    }
-
-    return i_frame_size;
-}
-
 /****************************************************************************
  * DecodeBlock: the whole thing
  ****************************************************************************


=====================================
modules/packetizer/mpegaudio.h
=====================================
@@ -0,0 +1,152 @@
+/*****************************************************************************
+ * mpegaudio.h:
+ *****************************************************************************
+ * Copyright (C) 2001-2016 VLC authors and VideoLAN
+ *
+ * Authors: Laurent Aimar <fenrir at via.ecp.fr>
+ *          Eric Petit <titer at videolan.org>
+ *          Christophe Massiot <massiot at via.ecp.fr>
+ *          Gildas Bazin <gbazin at videolan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/*****************************************************************************
+ * SyncInfo: parse MPEG audio sync info
+ *****************************************************************************/
+static int SyncInfo(uint32_t i_header, unsigned int *restrict pi_channels,
+                    unsigned int *restrict pi_channels_conf,
+                    unsigned int *restrict pi_chan_mode,
+                    unsigned int *restrict pi_sample_rate,
+                    unsigned int *restrict pi_bit_rate,
+                    unsigned int *restrict pi_frame_length,
+                    unsigned int *restrict pi_max_frame_size,
+                    unsigned int *restrict pi_layer)
+{
+    static const unsigned short ppi_bitrate[2][3][16] =
+    {
+        {
+            /* v1 l1 */
+            { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384,
+              416, 448, 0},
+            /* v1 l2 */
+            { 0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256,
+              320, 384, 0},
+            /* v1 l3 */
+            { 0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224,
+              256, 320, 0}
+        },
+
+        {
+            /* v2 l1 */
+            { 0, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192,
+              224, 256, 0},
+            /* v2 l2 */
+            { 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128,
+              144, 160, 0},
+            /* v2 l3 */
+            { 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128,
+              144, 160, 0}
+        }
+    };
+
+    static const unsigned short ppi_samplerate[2][4] = /* version 1 then 2 */
+    {
+        { 44100, 48000, 32000, 0 },
+        { 22050, 24000, 16000, 0 }
+    };
+
+    int i_frame_size;
+
+    bool b_mpeg_2_5 = 1 - ((i_header & 0x100000) >> 20);
+    int i_version = 1 - ((i_header & 0x80000) >> 19);
+    *pi_layer   = 4 - ((i_header & 0x60000) >> 17);
+    //bool b_crc = !((i_header >> 16) & 0x01);
+    int i_bitrate_index = (i_header & 0xf000) >> 12;
+    int i_samplerate_index = (i_header & 0xc00) >> 10;
+    bool b_padding = (i_header & 0x200) >> 9;
+    /* Extension */
+    int i_mode = (i_header & 0xc0) >> 6;
+    /* Modeext, copyright & original */
+    int i_emphasis = i_header & 0x3;
+
+    *pi_chan_mode = 0;
+
+    if (*pi_layer == 4
+     || i_bitrate_index == 0x0f
+     || i_samplerate_index == 0x03
+     || i_emphasis == 0x02)
+        return -1;
+
+    switch (i_mode)
+    {
+        case 2: /* dual-mono */
+            *pi_chan_mode = AOUT_CHANMODE_DUALMONO;
+            /* fall through */
+        case 0: /* stereo */
+        case 1: /* joint stereo */
+            *pi_channels = 2;
+            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
+            break;
+        case 3: /* mono */
+            *pi_channels = 1;
+            *pi_channels_conf = AOUT_CHAN_CENTER;
+            break;
+    }
+
+    int i_max_bit_rate = ppi_bitrate[i_version][*pi_layer-1][14];
+    *pi_bit_rate = ppi_bitrate[i_version][*pi_layer-1][i_bitrate_index];
+    *pi_sample_rate = ppi_samplerate[i_version][i_samplerate_index];
+
+    if (b_mpeg_2_5)
+        *pi_sample_rate /= 2;
+
+    switch (*pi_layer)
+    {
+        case 1:
+            i_frame_size = (12000 * *pi_bit_rate / *pi_sample_rate +
+                            b_padding) * 4;
+            *pi_max_frame_size = (12000 * i_max_bit_rate /
+                                  *pi_sample_rate + 1) * 4;
+            *pi_frame_length = 384;
+            break;
+
+        case 2:
+            i_frame_size = 144000 * *pi_bit_rate / *pi_sample_rate + b_padding;
+            *pi_max_frame_size = 144000 * i_max_bit_rate / *pi_sample_rate + 1;
+            *pi_frame_length = 1152;
+            break;
+
+        case 3:
+            i_frame_size = (i_version ? 72000 : 144000) *
+                            *pi_bit_rate / *pi_sample_rate + b_padding;
+            *pi_max_frame_size = (i_version ? 72000 : 144000) *
+                                  i_max_bit_rate / *pi_sample_rate + 1;
+            *pi_frame_length = i_version ? 576 : 1152;
+            break;
+
+        default:
+            vlc_assert_unreachable();
+    }
+
+    /* Free bitrate mode can support higher bitrates */
+    if (*pi_bit_rate == 0)
+        *pi_max_frame_size *= 2;
+
+    return i_frame_size;
+}


=====================================
src/Makefile.am
=====================================
@@ -329,8 +329,9 @@ libvlccore_la_SOURCES = \
 	video_output/vout_subpictures.c \
 	video_output/vout_spuregion_helper.h \
 	video_output/vout_wrapper.h \
+	video_output/video_window.c \
+	video_output/video_window.h \
 	video_output/window.c \
-	video_output/window.h \
 	video_output/opengl.c \
 	video_output/vout_intf.c \
 	video_output/vout_internal.h \


=====================================
src/video_output/display.c
=====================================
@@ -41,7 +41,6 @@
 #include <libvlc.h>
 
 #include "display.h"
-#include "window.h"
 #include "vout_internal.h"
 
 /*****************************************************************************


=====================================
src/video_output/video_output.c
=====================================
@@ -55,7 +55,7 @@
 #include "vout_internal.h"
 #include "display.h"
 #include "snapshot.h"
-#include "window.h"
+#include "video_window.h"
 #include "../misc/variables.h"
 #include "../clock/clock.h"
 #include "statistic.h"


=====================================
src/video_output/video_window.c
=====================================
@@ -0,0 +1,242 @@
+/*****************************************************************************
+ * video_window.c: vout-specific window management
+ *****************************************************************************
+ * Copyright © 2014-2021 Rémi Denis-Courmont
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <assert.h>
+#include <stdlib.h>
+
+#include <vlc_common.h>
+#include <vlc_vout_window.h>
+#include <vlc_vout.h>
+#include <vlc_vout_display.h>
+#include "video_window.h"
+#include "vout_internal.h"
+
+#define DOUBLE_CLICK_TIME VLC_TICK_FROM_MS(300)
+
+struct vout_window_ack_data {
+    vout_window_t *window;
+    vout_window_ack_cb callback;
+    unsigned width;
+    unsigned height;
+    void *opaque;
+};
+
+static void vout_window_Ack(void *data)
+{
+    struct vout_window_ack_data *cb_data = data;
+
+    if (cb_data->callback != NULL)
+        cb_data->callback(cb_data->window, cb_data->width, cb_data->height,
+                          cb_data->opaque);
+}
+
+typedef struct vout_display_window
+{
+    vout_thread_t *vout;
+    vlc_mouse_t mouse;
+    vlc_tick_t last_left_press;
+} vout_display_window_t;
+
+static void vout_display_window_ResizeNotify(vout_window_t *window,
+                                             unsigned width, unsigned height,
+                                             vout_window_ack_cb cb,
+                                             void *opaque)
+{
+    vout_display_window_t *state = window->owner.sys;
+    vout_thread_t *vout = state->vout;
+    struct vout_window_ack_data data = { window, cb, width, height, opaque };
+
+    msg_Dbg(window, "resized to %ux%u", width, height);
+    vout_ChangeDisplaySize(vout, width, height, vout_window_Ack, &data);
+}
+
+static void vout_display_window_CloseNotify(vout_window_t *window)
+{
+    /* TODO: Nowhere to dispatch to currently.
+     * Needs callback to ES output to deselect ES? */
+    msg_Err(window, "window closed");
+}
+
+static void vout_display_window_StateNotify(vout_window_t *window,
+                                            unsigned window_state)
+{
+    vout_display_window_t *state = window->owner.sys;
+    vout_thread_t *vout = state->vout;
+
+    static const char states[][8] = {
+        [VOUT_WINDOW_STATE_NORMAL] = "normal",
+        [VOUT_WINDOW_STATE_ABOVE] = "above",
+        [VOUT_WINDOW_STATE_BELOW] = "below",
+    };
+
+    assert(window_state < ARRAY_SIZE(states));
+    msg_Dbg(window, "window state changed: %s", states[window_state]);
+    var_SetInteger(vout, "window-state", window_state);
+}
+
+static void vout_display_window_FullscreenNotify(vout_window_t *window,
+                                                 const char *id)
+{
+    vout_display_window_t *state = window->owner.sys;
+    vout_thread_t *vout = state->vout;
+
+    msg_Dbg(window, (id != NULL) ? "window set to fullscreen on %s"
+                                 : "window set to fullscreen", id);
+    var_SetString(vout, "window-fullscreen-output",
+                  (id != NULL) ? id : "");
+    var_SetBool(vout, "window-fullscreen", true);
+}
+
+static void vout_display_window_WindowingNotify(vout_window_t *window)
+{
+    vout_display_window_t *state = window->owner.sys;
+    vout_thread_t *vout = state->vout;
+
+    msg_Dbg(window, "window set windowed");
+    var_SetBool(vout, "window-fullscreen", false);
+}
+
+static void vout_display_window_MouseEvent(vout_window_t *window,
+                                           const vout_window_mouse_event_t *ev)
+{
+    vout_display_window_t *state = window->owner.sys;
+    vout_thread_t *vout = state->vout;
+    vlc_mouse_t *m = &state->mouse;
+
+    m->b_double_click = false;
+
+    switch (ev->type)
+    {
+        case VOUT_WINDOW_MOUSE_MOVED:
+            vlc_mouse_SetPosition(m, ev->x, ev->y);
+            state->last_left_press = INT64_MIN;
+            break;
+
+        case VOUT_WINDOW_MOUSE_PRESSED:
+            if (!window->info.has_double_click
+             && ev->button_mask == MOUSE_BUTTON_LEFT
+             && !vlc_mouse_IsLeftPressed(m))
+            {
+                const vlc_tick_t now = vlc_tick_now();
+
+                if (state->last_left_press != INT64_MIN
+                 && now - state->last_left_press < DOUBLE_CLICK_TIME)
+                {
+                    m->b_double_click = true;
+                    state->last_left_press = INT64_MIN;
+                }
+                else
+                    state->last_left_press = now;
+            }
+
+            vlc_mouse_SetPressed(m, ev->button_mask);
+            break;
+
+        case VOUT_WINDOW_MOUSE_RELEASED:
+            vlc_mouse_SetReleased(m, ev->button_mask);
+            break;
+
+        case VOUT_WINDOW_MOUSE_DOUBLE_CLICK:
+            assert(window->info.has_double_click);
+            m->b_double_click = true;
+            break;
+
+        default:
+            vlc_assert_unreachable();
+    }
+
+    vout_MouseState(vout, m);
+}
+
+static void vout_display_window_KeyboardEvent(vout_window_t *window,
+                                              unsigned key)
+{
+    var_SetInteger(vlc_object_instance(window), "key-pressed", key);
+}
+
+static void vout_display_window_OutputEvent(vout_window_t *window,
+                                            const char *name, const char *desc)
+{
+    if (desc != NULL)
+        msg_Dbg(window, "fullscreen output %s (%s) added", name, desc);
+    else
+        msg_Dbg(window, "fullscreen output %s removed", name);
+}
+
+static const struct vout_window_callbacks vout_display_window_cbs = {
+    .resized = vout_display_window_ResizeNotify,
+    .closed = vout_display_window_CloseNotify,
+    .state_changed = vout_display_window_StateNotify,
+    .fullscreened = vout_display_window_FullscreenNotify,
+    .windowed = vout_display_window_WindowingNotify,
+    .mouse_event = vout_display_window_MouseEvent,
+    .keyboard_event = vout_display_window_KeyboardEvent,
+    .output_event = vout_display_window_OutputEvent,
+};
+
+/**
+ * Creates a video window, initially without any attached display.
+ */
+vout_window_t *vout_display_window_New(vout_thread_t *vout)
+{
+    vout_display_window_t *state = malloc(sizeof (*state));
+    if (state == NULL)
+        return NULL;
+
+    vlc_mouse_Init(&state->mouse);
+    state->last_left_press = INT64_MIN;
+    state->vout = vout;
+
+    char *modlist = var_InheritString(vout, "window");
+    vout_window_owner_t owner = {
+        .cbs = &vout_display_window_cbs,
+        .sys = state,
+    };
+    vout_window_t *window;
+
+    var_Create(vout, "window-state", VLC_VAR_INTEGER);
+    var_Create(vout, "window-fullscreen", VLC_VAR_BOOL);
+    var_Create(vout, "window-fullscreen-output", VLC_VAR_STRING);
+
+    window = vout_window_New((vlc_object_t *)vout, modlist, &owner);
+    free(modlist);
+    if (window == NULL)
+        free(state);
+    return window;
+}
+
+/**
+ * Destroys a video window.
+ * \note The window must be detached.
+ */
+void vout_display_window_Delete(vout_window_t *window)
+{
+    vout_display_window_t *state = window->owner.sys;
+    vout_thread_t *vout = state->vout;
+
+    vout_window_Delete(window);
+    var_Destroy(vout, "window-fullscreen-output");
+    var_Destroy(vout, "window-fullscreen");
+    var_Destroy(vout, "window-state");
+    free(state);
+}


=====================================
src/video_output/window.h → src/video_output/video_window.h
=====================================
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * window.h: window management for VLC video output
+ * video_window.h: window management for VLC video output
  *****************************************************************************
  * Copyright © 2014 Rémi Denis-Courmont
  *


=====================================
src/video_output/window.c
=====================================
@@ -1,7 +1,8 @@
 /*****************************************************************************
- * window.c: "vout window" management
+ * window.c: generic window management
  *****************************************************************************
  * Copyright (C) 2009 Laurent Aimar
+ * Copyright © 2009-2021 Rémi Denis-Courmont
  *
  * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
  *
@@ -197,219 +198,3 @@ void vout_window_ReportFullscreen(vout_window_t *window, const char *id)
     if (window->owner.cbs->fullscreened != NULL)
         window->owner.cbs->fullscreened(window, id);
 }
-
-struct vout_window_ack_data {
-    vout_window_t *window;
-    vout_window_ack_cb callback;
-    unsigned width;
-    unsigned height;
-    void *opaque;
-};
-
-static void vout_window_Ack(void *data)
-{
-    struct vout_window_ack_data *cb_data = data;
-
-    if (cb_data->callback != NULL)
-        cb_data->callback(cb_data->window, cb_data->width, cb_data->height,
-                          cb_data->opaque);
-}
-
-/* Video output display integration */
-#include <vlc_vout.h>
-#include <vlc_vout_display.h>
-#include "window.h"
-#include "vout_internal.h"
-
-#define DOUBLE_CLICK_TIME VLC_TICK_FROM_MS(300)
-
-typedef struct vout_display_window
-{
-    vout_thread_t *vout;
-    vlc_mouse_t mouse;
-    vlc_tick_t last_left_press;
-} vout_display_window_t;
-
-static void vout_display_window_ResizeNotify(vout_window_t *window,
-                                             unsigned width, unsigned height,
-                                             vout_window_ack_cb cb,
-                                             void *opaque)
-{
-    vout_display_window_t *state = window->owner.sys;
-    vout_thread_t *vout = state->vout;
-    struct vout_window_ack_data data = { window, cb, width, height, opaque };
-
-    msg_Dbg(window, "resized to %ux%u", width, height);
-    vout_ChangeDisplaySize(vout, width, height, vout_window_Ack, &data);
-}
-
-static void vout_display_window_CloseNotify(vout_window_t *window)
-{
-    /* TODO: Nowhere to dispatch to currently.
-     * Needs callback to ES output to deselect ES? */
-    msg_Err(window, "window closed");
-}
-
-static void vout_display_window_StateNotify(vout_window_t *window,
-                                            unsigned window_state)
-{
-    vout_display_window_t *state = window->owner.sys;
-    vout_thread_t *vout = state->vout;
-
-    static const char states[][8] = {
-        [VOUT_WINDOW_STATE_NORMAL] = "normal",
-        [VOUT_WINDOW_STATE_ABOVE] = "above",
-        [VOUT_WINDOW_STATE_BELOW] = "below",
-    };
-
-    assert(window_state < ARRAY_SIZE(states));
-    msg_Dbg(window, "window state changed: %s", states[window_state]);
-    var_SetInteger(vout, "window-state", window_state);
-}
-
-static void vout_display_window_FullscreenNotify(vout_window_t *window,
-                                                 const char *id)
-{
-    vout_display_window_t *state = window->owner.sys;
-    vout_thread_t *vout = state->vout;
-
-    msg_Dbg(window, (id != NULL) ? "window set to fullscreen on %s"
-                                 : "window set to fullscreen", id);
-    var_SetString(vout, "window-fullscreen-output",
-                  (id != NULL) ? id : "");
-    var_SetBool(vout, "window-fullscreen", true);
-}
-
-static void vout_display_window_WindowingNotify(vout_window_t *window)
-{
-    vout_display_window_t *state = window->owner.sys;
-    vout_thread_t *vout = state->vout;
-
-    msg_Dbg(window, "window set windowed");
-    var_SetBool(vout, "window-fullscreen", false);
-}
-
-static void vout_display_window_MouseEvent(vout_window_t *window,
-                                           const vout_window_mouse_event_t *ev)
-{
-    vout_display_window_t *state = window->owner.sys;
-    vout_thread_t *vout = state->vout;
-    vlc_mouse_t *m = &state->mouse;
-
-    m->b_double_click = false;
-
-    switch (ev->type)
-    {
-        case VOUT_WINDOW_MOUSE_MOVED:
-            vlc_mouse_SetPosition(m, ev->x, ev->y);
-            state->last_left_press = INT64_MIN;
-            break;
-
-        case VOUT_WINDOW_MOUSE_PRESSED:
-            if (!window->info.has_double_click
-             && ev->button_mask == MOUSE_BUTTON_LEFT
-             && !vlc_mouse_IsLeftPressed(m))
-            {
-                const vlc_tick_t now = vlc_tick_now();
-
-                if (state->last_left_press != INT64_MIN
-                 && now - state->last_left_press < DOUBLE_CLICK_TIME)
-                {
-                    m->b_double_click = true;
-                    state->last_left_press = INT64_MIN;
-                }
-                else
-                    state->last_left_press = now;
-            }
-
-            vlc_mouse_SetPressed(m, ev->button_mask);
-            break;
-
-        case VOUT_WINDOW_MOUSE_RELEASED:
-            vlc_mouse_SetReleased(m, ev->button_mask);
-            break;
-
-        case VOUT_WINDOW_MOUSE_DOUBLE_CLICK:
-            assert(window->info.has_double_click);
-            m->b_double_click = true;
-            break;
-
-        default:
-            vlc_assert_unreachable();
-    }
-
-    vout_MouseState(vout, m);
-}
-
-static void vout_display_window_KeyboardEvent(vout_window_t *window,
-                                              unsigned key)
-{
-    var_SetInteger(vlc_object_instance(window), "key-pressed", key);
-}
-
-static void vout_display_window_OutputEvent(vout_window_t *window,
-                                            const char *name, const char *desc)
-{
-    if (desc != NULL)
-        msg_Dbg(window, "fullscreen output %s (%s) added", name, desc);
-    else
-        msg_Dbg(window, "fullscreen output %s removed", name);
-}
-
-static const struct vout_window_callbacks vout_display_window_cbs = {
-    .resized = vout_display_window_ResizeNotify,
-    .closed = vout_display_window_CloseNotify,
-    .state_changed = vout_display_window_StateNotify,
-    .fullscreened = vout_display_window_FullscreenNotify,
-    .windowed = vout_display_window_WindowingNotify,
-    .mouse_event = vout_display_window_MouseEvent,
-    .keyboard_event = vout_display_window_KeyboardEvent,
-    .output_event = vout_display_window_OutputEvent,
-};
-
-/**
- * Creates a video window, initially without any attached display.
- */
-vout_window_t *vout_display_window_New(vout_thread_t *vout)
-{
-    vout_display_window_t *state = malloc(sizeof (*state));
-    if (state == NULL)
-        return NULL;
-
-    vlc_mouse_Init(&state->mouse);
-    state->last_left_press = INT64_MIN;
-    state->vout = vout;
-
-    char *modlist = var_InheritString(vout, "window");
-    vout_window_owner_t owner = {
-        .cbs = &vout_display_window_cbs,
-        .sys = state,
-    };
-    vout_window_t *window;
-
-    var_Create(vout, "window-state", VLC_VAR_INTEGER);
-    var_Create(vout, "window-fullscreen", VLC_VAR_BOOL);
-    var_Create(vout, "window-fullscreen-output", VLC_VAR_STRING);
-
-    window = vout_window_New((vlc_object_t *)vout, modlist, &owner);
-    free(modlist);
-    if (window == NULL)
-        free(state);
-    return window;
-}
-
-/**
- * Destroys a video window.
- * \note The window must be detached.
- */
-void vout_display_window_Delete(vout_window_t *window)
-{
-    vout_display_window_t *state = window->owner.sys;
-    vout_thread_t *vout = state->vout;
-
-    vout_window_Delete(window);
-    var_Destroy(vout, "window-fullscreen-output");
-    var_Destroy(vout, "window-fullscreen");
-    var_Destroy(vout, "window-state");
-    free(state);
-}



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/c8c78f75e7117498f1552f22c4ba53a229f50997...2ddcadde698efaab7986912cba514d81c2ecb6b6

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/c8c78f75e7117498f1552f22c4ba53a229f50997...2ddcadde698efaab7986912cba514d81c2ecb6b6
You're receiving this email because of your account on code.videolan.org.




More information about the vlc-commits mailing list