[vlc-commits] [Git][videolan/vlc][master] 3 commits: demux: adaptive: constify method

François Cartegnie (@fcartegnie) gitlab at videolan.org
Wed Jul 12 08:51:01 UTC 2023



François Cartegnie pushed to branch master at VideoLAN / VLC


Commits:
50af6c7a by Francois Cartegnie at 2023-07-12T08:08:42+00:00
demux: adaptive: constify method

- - - - -
e0a1df00 by Francois Cartegnie at 2023-07-12T08:08:42+00:00
demux: adaptive: add selection state getter

- - - - -
479e9f3f by Francois Cartegnie at 2023-07-12T08:08:42+00:00
test: adaptive: check es reuse and reselection

- - - - -


6 changed files:

- modules/demux/adaptive/plumbing/FakeESOut.cpp
- modules/demux/adaptive/plumbing/FakeESOut.hpp
- modules/demux/adaptive/plumbing/FakeESOutID.cpp
- modules/demux/adaptive/plumbing/FakeESOutID.hpp
- modules/demux/adaptive/test/plumbing/CommandsQueue.cpp
- modules/demux/adaptive/test/plumbing/FakeEsOut.cpp


Changes:

=====================================
modules/demux/adaptive/plumbing/FakeESOut.cpp
=====================================
@@ -283,7 +283,7 @@ void FakeESOut::createOrRecycleRealEsID( AbstractFakeESOutID *es_id_ )
                    Otherwise the es will select any other compatible track
                    and will end this in a activate/select loop when reactivating a track */
                 if( !b_select )
-                    es_out_Control( real_es_out, ES_OUT_GET_ES_STATE, cand->realESID(), &b_select );
+                    b_select = hasSelectedEs( cand );
             }
             else /* replace format instead of new ES */
             {
@@ -435,19 +435,25 @@ void FakeESOut::gc()
 
 bool FakeESOut::hasSelectedEs() const
 {
-    bool b_selected = false;
     std::list<FakeESOutID *> const * lists[2] = {&declared, &fakeesidlist};
     std::list<FakeESOutID *>::const_iterator it;
     for(int i=0; i<2; i++)
+        for( it=lists[i]->begin(); it!=lists[i]->end(); ++it )
+            if( hasSelectedEs( *it ) )
+                return true;
+    return false;
+}
+
+bool FakeESOut::hasSelectedEs(const AbstractFakeESOutID *id) const
+{
+    if( id->realESID() )
     {
-        for( it=lists[i]->begin(); it!=lists[i]->end() && !b_selected; ++it )
-        {
-            FakeESOutID *esID = *it;
-            if( esID->realESID() )
-                es_out_Control( real_es_out, ES_OUT_GET_ES_STATE, esID->realESID(), &b_selected );
-        }
+        bool b_selected;
+        return es_out_Control( real_es_out, ES_OUT_GET_ES_STATE,
+                               id->realESID(), &b_selected ) == VLC_SUCCESS
+               && b_selected;
     }
-    return b_selected;
+    return false;
 }
 
 bool FakeESOut::decodersDrained()


=====================================
modules/demux/adaptive/plumbing/FakeESOut.hpp
=====================================
@@ -89,6 +89,7 @@ namespace adaptive
             void resetTimestamps();
             size_t esCount() const;
             bool hasSelectedEs() const;
+            bool hasSelectedEs(const AbstractFakeESOutID *) const;
             bool decodersDrained();
             bool restarting() const;
             void setExtraInfoProvider( ExtraFMTInfoInterface * );


=====================================
modules/demux/adaptive/plumbing/FakeESOutID.cpp
=====================================
@@ -70,7 +70,7 @@ void FakeESOutID::release()
     fakeesout->recycle( this );
 }
 
-es_out_id_t * FakeESOutID::realESID()
+es_out_id_t * FakeESOutID::realESID() const
 {
     return p_real_es_id;
 }


=====================================
modules/demux/adaptive/plumbing/FakeESOutID.hpp
=====================================
@@ -38,7 +38,7 @@ namespace adaptive
     {
         public:
             virtual ~AbstractFakeESOutID() = default;
-            virtual es_out_id_t * realESID() = 0;
+            virtual es_out_id_t * realESID() const = 0;
             virtual void create() = 0;
             virtual void release() = 0;
             virtual void sendData(block_t *) = 0;
@@ -51,7 +51,7 @@ namespace adaptive
             FakeESOutID( FakeESOut *, const es_format_t * );
             virtual ~FakeESOutID();
             void setRealESID( es_out_id_t * );
-            virtual es_out_id_t * realESID() override;
+            virtual es_out_id_t * realESID() const override;
             const es_format_t *getFmt() const;
             virtual void create() override;
             virtual void release() override;


=====================================
modules/demux/adaptive/test/plumbing/CommandsQueue.cpp
=====================================
@@ -75,7 +75,7 @@ class TestEsOutID : public AbstractFakeESOutID
     public:
         TestEsOutID(TestEsOut *out) { this->out = out; }
         virtual ~TestEsOutID() {}
-        virtual es_out_id_t * realESID() override { return nullptr; }
+        virtual es_out_id_t * realESID() const override { return nullptr; }
         virtual void create() override {}
         virtual void release() override {}
         virtual void sendData(block_t *b) override


=====================================
modules/demux/adaptive/test/plumbing/FakeEsOut.cpp
=====================================
@@ -33,48 +33,104 @@
 #include <limits>
 #include <list>
 #include <algorithm>
+#include <cassert>
 
 using namespace adaptive;
 
 using OutputVal = std::pair<const AbstractFakeESOutID *, block_t *>;
+const Times drainTimes(SegmentTimes(),std::numeric_limits<vlc_tick_t>::max());
 
 #define DT(t) Times(SegmentTimes(), (t))
 
-struct context
+class DummyEsOut
 {
-    vlc_tick_t dts;
-    vlc_tick_t pts;
-    vlc_tick_t pcr;
+    public:
+        DummyEsOut();
+        ~DummyEsOut();
+
+        void reset();
+
+        static es_out_id_t *callback_add( es_out_t *, input_source_t *, const es_format_t * );
+        static int callback_send( es_out_t *, es_out_id_t *, block_t * );
+        static void callback_del( es_out_t *, es_out_id_t * );
+        static int callback_control( es_out_t *, input_source_t *, int, va_list );
+        static void callback_destroy( es_out_t * );
+
+        vlc_tick_t dts;
+        vlc_tick_t pts;
+        vlc_tick_t pcr;
+
+        class ES
+        {
+            public:
+                ES(const es_format_t *);
+                ~ES();
+                es_format_t fmt;
+                bool b_selected;
+        };
+
+        std::list<ES *> eslist;
 };
 
+DummyEsOut::DummyEsOut()
+{
+    reset();
+}
+
+DummyEsOut::~DummyEsOut()
+{
+
+}
+
+void DummyEsOut::reset()
+{
+    dts = VLC_TICK_INVALID;
+    pts = VLC_TICK_INVALID;
+    pcr = VLC_TICK_INVALID;
+    while(!eslist.empty())
+    {
+        delete eslist.front();
+        eslist.pop_front();
+    }
+}
+
 struct dropesout
 {
-    struct context *ctx;
+    DummyEsOut *dummyesout;
     es_out_t esout;
 };
 
-static es_out_id_t *dummy_callback_add(es_out_t *, input_source_t *, const es_format_t *)
+es_out_id_t *DummyEsOut::callback_add(es_out_t *out, input_source_t *, const es_format_t *fmt)
 {
-    return (es_out_id_t *) 0x01;
+    DummyEsOut *dummyesout = container_of(out, dropesout, esout)->dummyesout;
+    ES *es = new ES(fmt);
+    dummyesout->eslist.push_back(es);
+    return (es_out_id_t *) es;
 }
 
-static int dummy_callback_send(es_out_t *out, es_out_id_t *, block_t *b)
+int DummyEsOut::callback_send(es_out_t *out, es_out_id_t *, block_t *b)
 {
-    struct context *ctx = container_of(out, dropesout, esout)->ctx;
-    ctx->dts = b->i_dts;
-    ctx->pts = b->i_pts;
+    DummyEsOut *dummyesout = container_of(out, dropesout, esout)->dummyesout;
+    dummyesout->dts = b->i_dts;
+    dummyesout->pts = b->i_pts;
     block_Release(b);
     return VLC_SUCCESS;
 }
 
-static void dummy_callback_del(es_out_t *, es_out_id_t *)
+void DummyEsOut::callback_del(es_out_t *out, es_out_id_t *id)
 {
-
+    DummyEsOut *dummyesout = container_of(out, dropesout, esout)->dummyesout;
+    ES *es = (ES *) id;
+    auto it = std::find(dummyesout->eslist.begin(), dummyesout->eslist.end(), es);
+    assert(it != dummyesout->eslist.end());
+    if(it != dummyesout->eslist.end())
+        dummyesout->eslist.erase(it);
+    delete es;
 }
 
-static int dummy_callback_control(es_out_t *out, input_source_t *, int i_query, va_list args)
+int DummyEsOut::callback_control(es_out_t *out, input_source_t *, int i_query, va_list args)
 {
-    struct context *ctx = container_of(out, dropesout, esout)->ctx;
+    DummyEsOut *dummyesout = container_of(out, dropesout, esout)->dummyesout;
 
     switch( i_query )
     {
@@ -83,9 +139,40 @@ static int dummy_callback_control(es_out_t *out, input_source_t *, int i_query,
         {
             if( i_query == ES_OUT_SET_GROUP_PCR )
                 (void) va_arg( args, int );
-            ctx->pcr = va_arg( args, vlc_tick_t );
+            dummyesout->pcr = va_arg( args, vlc_tick_t );
             break;
         }
+        case ES_OUT_SET_ES:
+        {
+            ES *es = (ES *) va_arg( args, es_out_id_t * );
+            /* emulate reselection */
+            for( ES *e : dummyesout->eslist )
+            {
+                if( e->fmt.i_cat == es->fmt.i_cat )
+                    e->b_selected = (e == es);
+            }
+            return VLC_SUCCESS;
+        }
+        case ES_OUT_SET_ES_STATE:
+        {
+            /* emulate selection override */
+            ES *es = (ES *) va_arg( args, es_out_id_t * );
+            bool b = va_arg( args, int );
+            auto it = std::find(dummyesout->eslist.begin(), dummyesout->eslist.end(), es);
+            if(it == dummyesout->eslist.end())
+                return VLC_EGENERIC;
+            (*it)->b_selected = b;
+            return VLC_SUCCESS;
+        }
+        case ES_OUT_GET_ES_STATE:
+        {
+            ES *es = (ES *) va_arg( args, es_out_id_t * );
+            auto it = std::find(dummyesout->eslist.begin(), dummyesout->eslist.end(), es);
+            if(it == dummyesout->eslist.end())
+                return VLC_EGENERIC;
+            *va_arg( args, bool * ) = (*it)->b_selected;
+            return VLC_SUCCESS;
+        }
         default:
             return VLC_EGENERIC;
     }
@@ -93,21 +180,33 @@ static int dummy_callback_control(es_out_t *out, input_source_t *, int i_query,
     return VLC_SUCCESS;
 }
 
-static void dummy_callback_destroy(es_out_t *)
+void DummyEsOut::callback_destroy(es_out_t *)
 {
 
 }
 
 const struct es_out_callbacks dummycbs =
 {
-    .add = dummy_callback_add,
-    .send = dummy_callback_send,
-    .del = dummy_callback_del,
-    .control = dummy_callback_control,
-    .destroy = dummy_callback_destroy,
+    .add = DummyEsOut::callback_add,
+    .send = DummyEsOut::callback_send,
+    .del = DummyEsOut::callback_del,
+    .control = DummyEsOut::callback_control,
+    .destroy = DummyEsOut::callback_destroy,
     .priv_control = nullptr,
 };
 
+DummyEsOut::ES::ES(const es_format_t *src)
+{
+    b_selected = false;
+    es_format_Init(&fmt, src->i_cat, src->i_codec);
+    es_format_Copy(&fmt, src);
+}
+
+DummyEsOut::ES::~ES()
+{
+    es_format_Clean(&fmt);
+}
+
 static void enqueue(es_out_t *out, es_out_id_t *id, vlc_tick_t dts, vlc_tick_t pts)
 {
     block_t *b = block_Alloc(1);
@@ -125,7 +224,147 @@ static void enqueue(es_out_t *out, es_out_id_t *id, vlc_tick_t dts, vlc_tick_t p
 #define PCR(t) es_out_SetPCR(out, t)
 #define FROM_MPEGTS(x) (INT64_C(x) * 100 / 9)
 
-static int check2(es_out_t *out, struct context *, FakeESOut *fakees)
+static int check3(es_out_t *out, DummyEsOut *dummy, FakeESOut *fakees)
+{
+    es_format_t fmt;
+
+    /* few ES reusability checks */
+    try
+    {
+        es_format_Init(&fmt, AUDIO_ES, VLC_CODEC_MP4A);
+        FakeESOutID fakeid0(fakees, &fmt);
+        fmt.audio.i_rate = 48000;
+        FakeESOutID fakeid1(fakees, &fmt);
+        fmt.i_original_fourcc = 0xbeef;
+        FakeESOutID fakeid2(fakees, &fmt);
+        es_format_Clean(&fmt);
+        es_format_Init(&fmt, VIDEO_ES, VLC_CODEC_H264);
+        FakeESOutID fakeid3(fakees, &fmt);
+        Expect(fakeid0.isCompatible(&fakeid0) == false); // aac without rate
+        Expect(fakeid0.isCompatible(&fakeid1) == false); // aac rate/unknown mix
+        Expect(fakeid1.isCompatible(&fakeid1) == true);  // aac with same rate
+        Expect(fakeid0.isCompatible(&fakeid3) == false); // different codecs
+        Expect(fakeid1.isCompatible(&fakeid2) == false); // different original fourcc
+        Expect(fakeid2.isCompatible(&fakeid2) == true);  // same original fourcc
+        Expect(fakeid3.isCompatible(&fakeid3) == false);  // same video with extra codecs
+        es_format_Clean(&fmt);
+    } catch (...) {
+        return 1;
+    }
+
+    es_format_Init(&fmt, VIDEO_ES, VLC_CODEC_H264);
+    es_out_id_t *id = es_out_Add(out, &fmt);
+    try
+    {
+        Expect(id != nullptr);
+
+        /* single ES should be allocated */
+        Expect(dummy->eslist.size() == 0);
+        fakees->commandsQueue()->Commit();
+        fakees->commandsQueue()->Process(drainTimes);
+        Expect(dummy->eslist.size() == 1);
+        Expect(dummy->eslist.front()->fmt.i_codec == VLC_CODEC_H264);
+        dummy->eslist.front()->b_selected = true; /* fake selection */
+
+        /* subsequent ES should be allocated */
+        es_format_Clean(&fmt);
+        es_format_Init(&fmt, AUDIO_ES, VLC_CODEC_MP4A);
+        id = es_out_Add(out, &fmt);
+        fakees->commandsQueue()->Commit();
+        fakees->commandsQueue()->Process(drainTimes);
+        Expect(dummy->eslist.size() == 2);
+        Expect(dummy->eslist.front()->fmt.i_codec == VLC_CODEC_H264);
+        Expect(dummy->eslist.front()->b_selected == true);
+        Expect(dummy->eslist.back()->fmt.i_codec == VLC_CODEC_MP4A);
+
+        /* on restart / new segment, unused ES should be reclaimed */
+        fakees->recycleAll();
+        es_format_Clean(&fmt);
+        es_format_Init(&fmt, VIDEO_ES, VLC_CODEC_MPGV);
+        id = es_out_Add(out, &fmt);
+        fakees->commandsQueue()->Commit();
+        fakees->commandsQueue()->Process(drainTimes);
+        Expect(dummy->eslist.size() == 3);
+        fakees->gc();
+        Expect(dummy->eslist.size() == 1);
+        Expect(dummy->eslist.front()->fmt.i_codec == VLC_CODEC_MPGV);
+        Expect(dummy->eslist.front()->b_selected == true);
+
+        /* on restart / new segment, ES MUST be reused */
+        fakees->recycleAll();
+        Expect(dummy->eslist.size() == 1);
+        es_format_Clean(&fmt);
+        es_format_Init(&fmt, VIDEO_ES, VLC_CODEC_MPGV);
+        /* check ID signaling so we don't blame FakeEsOut */
+        {
+            FakeESOutID fakeid(fakees, &fmt);
+            Expect(fakeid.isCompatible(&fakeid));
+        }
+        id = es_out_Add(out, &fmt);
+        fakees->commandsQueue()->Commit();
+        fakees->commandsQueue()->Process(drainTimes);
+        Expect(dummy->eslist.size() == 1);
+        fakees->gc();
+        Expect(dummy->eslist.size() == 1);
+        Expect(dummy->eslist.front()->b_selected == true);
+
+        /* on restart / new segment, different codec, ES MUST NOT be reused */
+        fakees->recycleAll();
+        Expect(dummy->eslist.size() == 1);
+        es_format_Clean(&fmt);
+        es_format_Init(&fmt, VIDEO_ES, VLC_CODEC_H264);
+        id = es_out_Add(out, &fmt);
+        es_format_Clean(&fmt);
+        es_format_Init(&fmt, AUDIO_ES, VLC_CODEC_MP4A);
+        id = es_out_Add(out, &fmt);
+        fakees->commandsQueue()->Commit();
+        fakees->commandsQueue()->Process(drainTimes);
+        Expect(dummy->eslist.size() == 3);
+        fakees->gc();
+        Expect(dummy->eslist.size() == 2);
+        for( DummyEsOut::ES *e : dummy->eslist ) /* selection state must have been kept */
+            if( e->fmt.i_cat == VIDEO_ES )
+                Expect(e->b_selected == true);
+
+        /* on restart / new segment, incompatible codec parameters, ES MUST NOT be reused */
+        fakees->recycleAll();
+        Expect(dummy->eslist.size() == 2);
+        es_format_Clean(&fmt);
+        es_format_Init(&fmt, VIDEO_ES, VLC_CODEC_H264);
+        id = es_out_Add(out, &fmt);
+        /* check ID signaling so we don't blame FakeEsOut */
+        {
+            FakeESOutID fakeid(fakees, &fmt);
+            Expect(fakeid.isCompatible(&fakeid) == false);
+        }
+        es_format_Clean(&fmt);
+        es_format_Init(&fmt, AUDIO_ES, VLC_CODEC_MP4A);
+        id = es_out_Add(out, &fmt);
+        /* check ID signaling so we don't blame FakeEsOut */
+        {
+            FakeESOutID fakeid(fakees, &fmt);
+            Expect(fakeid.isCompatible(&fakeid) == false);
+        }
+        fakees->commandsQueue()->Commit();
+        fakees->commandsQueue()->Process(drainTimes);
+        Expect(dummy->eslist.size() == 4);
+        fakees->gc();
+        Expect(dummy->eslist.size() == 2);
+        for( DummyEsOut::ES *e : dummy->eslist ) /* selection state must have been kept */
+            if( e->fmt.i_cat == VIDEO_ES )
+                Expect(e->b_selected == true);
+
+    } catch (...) {
+        return 1;
+    }
+
+    es_format_Clean(&fmt);
+
+    return 0;
+}
+
+
+static int check2(es_out_t *out, DummyEsOut *, FakeESOut *fakees)
 {
     es_format_t fmt;
     es_format_Init(&fmt, VIDEO_ES, VLC_CODEC_H264);
@@ -208,7 +447,7 @@ static int check2(es_out_t *out, struct context *, FakeESOut *fakees)
     return 0;
 }
 
-static int check1(es_out_t *out, struct context *ctx, FakeESOut *fakees)
+static int check1(es_out_t *out, DummyEsOut *ctx, FakeESOut *fakees)
 {
     es_format_t fmt;
     es_format_Init(&fmt, VIDEO_ES, VLC_CODEC_H264);
@@ -216,6 +455,7 @@ static int check1(es_out_t *out, struct context *ctx, FakeESOut *fakees)
 
     /* ensure ES is created */
     const Times drainTimes(SegmentTimes(),std::numeric_limits<vlc_tick_t>::max());
+
     fakees->commandsQueue()->Commit();
     fakees->commandsQueue()->Process(drainTimes);
 
@@ -328,7 +568,7 @@ static int check1(es_out_t *out, struct context *ctx, FakeESOut *fakees)
     return 0;
 }
 
-static int check0(es_out_t *out, struct context *, FakeESOut *fakees)
+static int check0(es_out_t *out, DummyEsOut *, FakeESOut *fakees)
 {
     es_format_t fmt;
     es_format_Init(&fmt, VIDEO_ES, VLC_CODEC_H264);
@@ -374,21 +614,25 @@ static int check0(es_out_t *out, struct context *, FakeESOut *fakees)
 
 int FakeEsOut_test()
 {
-    struct context ctx = {VLC_TICK_INVALID,VLC_TICK_INVALID,VLC_TICK_INVALID};
-    struct dropesout dummy = { .ctx = &ctx, .esout = { .cbs = &dummycbs } };
-
-    int(* const tests[3])(es_out_t *, struct context *, FakeESOut *)
-            = { check0, check1, check2 };
-    for(size_t i=0; i<3; i++)
+    DummyEsOut dummyEsOut;
+    struct dropesout dummy = {
+            .dummyesout = &dummyEsOut,
+            .esout = { .cbs = &dummycbs }
+    };
+
+    int(* const tests[4])(es_out_t *, DummyEsOut *, FakeESOut *)
+            = { check0, check1, check2, check3 };
+    for(size_t i=0; i<4; i++)
     {
         CommandsFactory *factory = new CommandsFactory();
         CommandsQueue *queue = new CommandsQueue();
         FakeESOut *fakees = new FakeESOut(&dummy.esout, queue, factory);
         es_out_t *out = *fakees;
-        int ret = tests[i](out, &ctx, fakees);
+        int ret = tests[i](out, &dummyEsOut, fakees);
         delete fakees;
         if (ret)
             return ret;
+        dummyEsOut.reset();
     }
 
     return 0;



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/a0f1dc38fa722e210b7b0eb85124550f051c373a...479e9f3fcbce1ae0283004606e4f7a00e6195647

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


VideoLAN code repository instance


More information about the vlc-commits mailing list