[vlc-commits] demux: add timestamps continuity helper

Francois Cartegnie git at videolan.org
Tue Oct 30 18:12:41 CET 2018


vlc/vlc-3.0 | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Tue Apr 24 18:18:50 2018 +0200| [b7b06f5dde85cad5f4b2a2e8ea8558e0823291a5] | committer: Francois Cartegnie

demux: add timestamps continuity helper

> http://git.videolan.org/gitweb.cgi/vlc/vlc-3.0.git/?a=commit;h=b7b06f5dde85cad5f4b2a2e8ea8558e0823291a5
---

 modules/demux/timestamps_filter.h | 301 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 301 insertions(+)

diff --git a/modules/demux/timestamps_filter.h b/modules/demux/timestamps_filter.h
new file mode 100644
index 0000000000..1b53a3213b
--- /dev/null
+++ b/modules/demux/timestamps_filter.h
@@ -0,0 +1,301 @@
+/*****************************************************************************
+ * timestamps_filter.h: Seamless timestamps helper
+ *****************************************************************************
+ * Copyright © 2018 VideoLabs, VideoLAN, VLC authors
+ *
+ * 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.
+ *****************************************************************************/
+#ifndef VLC_TIMESTAMPS_FILTER_H
+#define VLC_TIMESTAMPS_FILTER_H
+
+#include <vlc_common.h>
+#include <vlc_es_out.h>
+
+#include "moving_avg.h"
+
+//#define DEBUG_TIMESTAMPS_FILTER
+
+enum
+{
+    ES_OUT_TF_FILTER_GET_TIME = (ES_OUT_PRIVATE_START + 1),
+    ES_OUT_TF_FILTER_DISCONTINUITY,
+    ES_OUT_TF_FILTER_RESET,
+};
+
+struct timestamps_filter_s
+{
+    struct moving_average_s mva;
+    mtime_t sequence_offset;
+    mtime_t contiguous_last;
+    unsigned sequence;
+};
+
+struct tf_es_out_id_s
+{
+    es_out_id_t *id;
+    vlc_fourcc_t fourcc;
+    struct timestamps_filter_s tf;
+    mtime_t pcrdiff;
+    unsigned pcrpacket;
+    bool contiguous;
+};
+
+struct tf_es_out_sys_s
+{
+    es_out_t *original_es_out;
+    DECL_ARRAY(struct tf_es_out_id_s *) es_list;
+    struct timestamps_filter_s pcrtf;
+    bool b_discontinuity;
+};
+
+static void timestamps_filter_init(struct timestamps_filter_s *tf)
+{
+    mva_init(&tf->mva);
+    tf->sequence_offset = 0;
+    tf->contiguous_last = 0;
+    tf->sequence = -1;
+}
+
+static void timestamps_filter_push(const char *s, struct timestamps_filter_s *tf,
+                                   mtime_t i_dts, mtime_t i_length,
+                                   bool b_discontinuity, bool b_contiguous)
+{
+    if(i_dts == 0 && i_length == 0)
+        return;
+
+    struct mva_packet_s *prev = mva_getLastPacket(&tf->mva);
+    if (prev)
+    {
+        if(prev->dts == i_dts)
+            return; /* duplicate packet */
+
+        if(b_contiguous)
+        {
+            const int64_t i_maxdiff = tf->mva.i_packet > MVA_PACKETS ? mva_get(&tf->mva) * 2 : CLOCK_FREQ;
+            if(llabs(i_dts - prev->dts) > i_maxdiff || b_discontinuity) /* Desync */
+            {
+                prev->diff = mva_get(&tf->mva);
+                tf->sequence_offset = tf->contiguous_last - i_dts + prev->diff;
+#ifdef DEBUG_TIMESTAMPS_FILTER
+                printf("%4.4s found offset of %ld\n", s, (prev->dts - i_dts));
+#endif
+            }
+            else prev->diff = i_dts - prev->dts;
+        }
+
+#ifdef DEBUG_TIMESTAMPS_FILTER
+        mtime_t next = prev->dts + mva_get(&tf->mva);
+
+        printf("%4.4s expected %ld / %ld , prev %ld+%ld error %ld comp %ld\n",
+               s, next, i_dts, prev->dts, mva_get(&tf->mva),
+               b_contiguous ? llabs(i_dts - next): 0, i_dts + tf->sequence_offset);
+#else
+        VLC_UNUSED(s);
+#endif
+    }
+
+    tf->contiguous_last = i_dts + tf->sequence_offset;
+
+    mva_add(&tf->mva, i_dts, i_length);
+}
+
+static void timestamps_filter_es_out_Reset(struct tf_es_out_sys_s *out)
+{
+    for(int i=0; i<out->es_list.i_size; i++)
+    {
+        struct tf_es_out_id_s *cur = (struct tf_es_out_id_s *)out->es_list.p_elems[i];
+        timestamps_filter_init(&cur->tf);
+    }
+    timestamps_filter_init(&out->pcrtf);
+    out->b_discontinuity = false;
+}
+
+static int timestamps_filter_es_out_Control(es_out_t *out, int i_query, va_list va_list)
+{
+    struct tf_es_out_sys_s *p_sys = (struct tf_es_out_sys_s *) out->p_sys;
+    switch(i_query)
+    {
+        case ES_OUT_SET_PCR:
+        case ES_OUT_SET_GROUP_PCR:
+        {
+            int i_group;
+            if(i_query == ES_OUT_SET_GROUP_PCR)
+                i_group = va_arg(va_list, int);
+            else
+                i_group = 0;
+            int64_t pcr = va_arg(va_list, int64_t);
+
+            timestamps_filter_push("PCR ", &p_sys->pcrtf, pcr, 0, p_sys->b_discontinuity, true);
+
+            pcr += p_sys->pcrtf.sequence_offset;
+
+            if(i_query == ES_OUT_SET_GROUP_PCR)
+                return es_out_Control(p_sys->original_es_out, i_query, i_group, pcr);
+            else
+                return es_out_SetPCR(p_sys->original_es_out, pcr);
+        }
+            break;
+        case ES_OUT_RESET_PCR:
+        {
+            timestamps_filter_es_out_Reset(p_sys);
+            break;
+        }
+        /* Private controls, never forwarded */
+        case ES_OUT_TF_FILTER_GET_TIME:
+        {
+            *(va_arg(va_list, int64_t*)) = p_sys->pcrtf.contiguous_last;
+            return VLC_SUCCESS;
+        }
+        case ES_OUT_TF_FILTER_DISCONTINUITY:
+        {
+            p_sys->b_discontinuity = true;
+            return VLC_SUCCESS;
+        }
+        case ES_OUT_TF_FILTER_RESET:
+        {
+            timestamps_filter_es_out_Reset(p_sys);
+            return VLC_SUCCESS;
+        }
+        /* !Private controls */
+        default:
+            break;
+    }
+    return es_out_vaControl(p_sys->original_es_out, i_query, va_list);
+}
+
+static struct tf_es_out_id_s * timestamps_filter_es_out_getID(struct tf_es_out_sys_s *p_sys, es_out_id_t *id)
+{
+    for(int i=0; i<p_sys->es_list.i_size; i++)
+    {
+        struct tf_es_out_id_s *cur = (struct tf_es_out_id_s *)p_sys->es_list.p_elems[i];
+        if(cur->id != id)
+            continue;
+        return cur;
+    }
+    return NULL;
+}
+
+static int timestamps_filter_es_out_Send(es_out_t *out, es_out_id_t *id, block_t *p_block)
+{
+    struct tf_es_out_sys_s *p_sys = (struct tf_es_out_sys_s *) out->p_sys;
+    struct tf_es_out_id_s *cur = timestamps_filter_es_out_getID(p_sys, id);
+
+    timestamps_filter_push((char*)&cur->fourcc, &cur->tf,
+                            p_block->i_dts, p_block->i_length,
+                           p_sys->b_discontinuity, cur->contiguous);
+
+    /* Record diff with last PCR */
+    if(p_sys->pcrtf.mva.i_packet > 0 &&
+        p_sys->pcrtf.mva.i_packet != cur->pcrpacket)
+    {
+        cur->pcrpacket = p_sys->pcrtf.mva.i_packet;
+        cur->pcrdiff = mva_getLastDTS(&cur->tf.mva) - mva_getLastDTS(&p_sys->pcrtf.mva);
+
+        mtime_t i_offsetdiff = cur->tf.sequence_offset - p_sys->pcrtf.sequence_offset;
+        if(i_offsetdiff != 0)
+        {
+            cur->tf.sequence_offset -= i_offsetdiff;
+#ifdef DEBUG_TIMESTAMPS_FILTER
+            printf("PCR diff %ld %ld **********\n", cur->pcrdiff, i_offsetdiff);
+#endif
+        }
+    }
+
+    /* Fix timestamps */
+    if(p_block->i_dts)
+        p_block->i_dts += cur->tf.sequence_offset;
+    if(p_block->i_pts)
+        p_block->i_pts += cur->tf.sequence_offset;
+
+    return es_out_Send(p_sys->original_es_out, id, p_block);
+}
+
+static void timestamps_filter_es_out_Delete(es_out_t *out)
+{
+    struct tf_es_out_sys_s *p_sys = (struct tf_es_out_sys_s *) out->p_sys;
+    for(int i=0; i<p_sys->es_list.i_size; i++)
+        free(p_sys->es_list.p_elems[i]);
+    ARRAY_RESET(p_sys->es_list);
+    free(p_sys);
+    free(out);
+}
+
+static es_out_id_t *timestamps_filter_es_out_Add(es_out_t *out, const es_format_t *fmt)
+{
+    struct tf_es_out_sys_s *p_sys = (struct tf_es_out_sys_s *) out->p_sys;
+
+    struct tf_es_out_id_s *tf_es_sys = malloc(sizeof(*tf_es_sys));
+    if(!tf_es_sys)
+        return NULL;
+    timestamps_filter_init(&tf_es_sys->tf);
+    tf_es_sys->fourcc = fmt->i_codec;
+    tf_es_sys->pcrdiff = 0;
+    tf_es_sys->pcrpacket = -1;
+    tf_es_sys->contiguous = (fmt->i_cat == VIDEO_ES || fmt->i_cat == AUDIO_ES);
+
+    tf_es_sys->id = es_out_Add(p_sys->original_es_out, fmt);
+    if(!tf_es_sys->id)
+    {
+        free(tf_es_sys);
+        return NULL;
+    }
+
+    ARRAY_APPEND(p_sys->es_list, tf_es_sys);
+
+    return tf_es_sys->id;
+}
+
+static void timestamps_filter_es_out_Del(es_out_t *out, es_out_id_t *id)
+{
+    struct tf_es_out_sys_s *p_sys = (struct tf_es_out_sys_s *) out->p_sys;
+
+    es_out_Del(p_sys->original_es_out, id);
+
+    for(int i=0; i<p_sys->es_list.i_size; i++)
+    {
+        struct tf_es_out_id_s *cur = (struct tf_es_out_id_s *)p_sys->es_list.p_elems[i];
+        if(cur->id != id)
+            continue;
+        free(cur);
+        ARRAY_REMOVE(p_sys->es_list, i);
+        break;
+    }
+}
+
+static es_out_t * timestamps_filter_es_out_New(es_out_t *orig)
+{
+    es_out_t *p_out = malloc(sizeof(*p_out));
+    if(!p_out)
+        return NULL;
+    struct tf_es_out_sys_s *tf = malloc(sizeof(*tf));
+    if(!tf)
+    {
+        free(p_out);
+        return NULL;
+    }
+    tf->original_es_out = orig;
+    tf->b_discontinuity = false;
+    timestamps_filter_init(&tf->pcrtf);
+    ARRAY_INIT(tf->es_list);
+    p_out->p_sys = (es_out_sys_t *)tf;
+    p_out->pf_add = timestamps_filter_es_out_Add;
+    p_out->pf_send = timestamps_filter_es_out_Send;
+    p_out->pf_del = timestamps_filter_es_out_Del;
+    p_out->pf_control = timestamps_filter_es_out_Control;
+    p_out->pf_destroy = timestamps_filter_es_out_Delete;
+    return p_out;
+}
+
+#endif



More information about the vlc-commits mailing list