[vlc-commits] [Git][videolan/vlc][3.0.x] 5 commits: demux: hls: add test for subrange continuity
Felix Paul Kühne (@fkuehne)
gitlab at videolan.org
Sun Jun 29 11:44:38 UTC 2025
Felix Paul Kühne pushed to branch 3.0.x at VideoLAN / VLC
Commits:
9e304223 by François Cartegnie at 2025-06-29T11:27:53+00:00
demux: hls: add test for subrange continuity
(cherry picked from commit 5503b393ec578aca23fb3cb237ade492ff5586d5)
- - - - -
eebc64c3 by François Cartegnie at 2025-06-29T11:27:53+00:00
demux: adaptive: add std::optional compatibility
(cherry picked from commit 3870be59cdf753c571ab3834d9c8a85547bc635e)
- - - - -
e4d11f20 by François Cartegnie at 2025-06-29T11:27:53+00:00
demux: adaptive: replace Unset with optional
(adapted from commit af4c229f325dd89c2f8bbb207533a548e667369a)
- - - - -
e7cf1c17 by François Cartegnie at 2025-06-29T11:27:53+00:00
demux: hls: fix byterange attribute comment
(cherry picked from commit e367a322a9f268c38a25924d2449af557dc6f563)
- - - - -
0ef5c129 by François Cartegnie at 2025-06-29T11:27:53+00:00
demux: hls: fix byterange offset propagation
refs #29179
(cherry picked from commit c52d819d60090ac41d78604e6455e3deaeffb736)
- - - - -
12 changed files:
- modules/demux/Makefile.am
- modules/demux/adaptive/logic/BufferingLogic.cpp
- modules/demux/adaptive/logic/BufferingLogic.hpp
- modules/demux/adaptive/playlist/BaseAdaptationSet.cpp
- modules/demux/adaptive/playlist/BaseAdaptationSet.h
- modules/demux/adaptive/playlist/CommonAttributesElements.h
- modules/demux/adaptive/test/playlist/M3U8.cpp
- + modules/demux/adaptive/tools/Compatibility.hpp
- modules/demux/adaptive/tools/Properties.hpp
- modules/demux/hls/playlist/Parser.cpp
- modules/demux/hls/playlist/Tags.cpp
- modules/demux/hls/playlist/Tags.hpp
Changes:
=====================================
modules/demux/Makefile.am
=====================================
@@ -383,6 +383,7 @@ libvlc_adaptive_la_SOURCES = \
demux/adaptive/Streams.cpp \
demux/adaptive/Streams.hpp \
demux/adaptive/Time.hpp \
+ demux/adaptive/tools/Compatibility.hpp \
demux/adaptive/tools/Conversions.hpp \
demux/adaptive/tools/Conversions.cpp \
demux/adaptive/tools/Debug.hpp \
=====================================
modules/demux/adaptive/logic/BufferingLogic.cpp
=====================================
@@ -388,7 +388,5 @@ vlc_tick_t DefaultBufferingLogic::getBufferingOffset(const BasePlaylist *p) cons
bool DefaultBufferingLogic::isLowLatency(const BasePlaylist *p) const
{
- if(userLowLatency.isSet())
- return userLowLatency.value();
- return p->isLowLatency();
+ return userLowLatency.value_or(p->isLowLatency());
}
=====================================
modules/demux/adaptive/logic/BufferingLogic.hpp
=====================================
@@ -22,7 +22,9 @@
#include <vector>
#include <vlc_common.h>
-#include "../tools/Properties.hpp"
+#include <vlc_mtime.h>
+
+#include "../tools/Compatibility.hpp"
namespace adaptive
{
@@ -60,7 +62,7 @@ namespace adaptive
vlc_tick_t userMinBuffering;
vlc_tick_t userMaxBuffering;
vlc_tick_t userLiveDelay;
- Undef<bool> userLowLatency;
+ optional<bool> userLowLatency;
};
class DefaultBufferingLogic : public AbstractBufferingLogic
=====================================
modules/demux/adaptive/playlist/BaseAdaptationSet.cpp
=====================================
@@ -112,12 +112,12 @@ void BaseAdaptationSet::setBitswitchAble(bool b)
bool BaseAdaptationSet::isSegmentAligned() const
{
- return !segmentAligned.isSet() || segmentAligned.value();
+ return segmentAligned.value_or(true);
}
bool BaseAdaptationSet::isBitSwitchable() const
{
- return bitswitchAble.isSet() && segmentAligned.value();
+ return bitswitchAble.has_value() && isSegmentAligned();
}
void BaseAdaptationSet::setRole(const Role &r)
=====================================
modules/demux/adaptive/playlist/BaseAdaptationSet.h
=====================================
@@ -68,8 +68,8 @@ namespace adaptive
Role role;
std::vector<BaseRepresentation *> representations;
std::string lang;
- Undef<bool> segmentAligned;
- Undef<bool> bitswitchAble;
+ optional<bool> segmentAligned;
+ optional<bool> bitswitchAble;
};
}
}
=====================================
modules/demux/adaptive/playlist/CommonAttributesElements.h
=====================================
@@ -24,6 +24,7 @@
#ifndef COMMONATTRIBUTESELEMENTS_H
#define COMMONATTRIBUTESELEMENTS_H
+#include "../tools/Compatibility.hpp"
#include "../tools/Properties.hpp"
#include <string>
=====================================
modules/demux/adaptive/test/playlist/M3U8.cpp
=====================================
@@ -543,5 +543,47 @@ int M3U8Playlist_test()
return 1;
}
+
+ /* Manifest 6 */
+ const char manifest6[] =
+ "#EXTM3U\n"
+ "#EXT-X-MEDIA-SEQUENCE:10\n"
+ "#EXTINF:1\n"
+ "#EXT-X-BYTERANGE:1000 at 0\n"
+ "foobar.ts\n"
+ "#EXT-X-BYTERANGE:4000 at 2000\n"
+ "foobar.ts\n"
+ "#EXT-X-BYTERANGE:500\n"
+ "foobar.ts\n"
+ "#EXT-X-BYTERANGE:1000 at 0\n"
+ "foobar.ts\n";
+
+ m3u = ParseM3U8(obj, manifest6, sizeof(manifest6));
+ try
+ {
+ Expect(m3u);
+ BaseRepresentation *rep = m3u->getFirstPeriod()->getAdaptationSets().front()->
+ getRepresentations().front();
+ Segment *seg = rep->getMediaSegment(10);
+ Expect(seg);
+ Expect(seg->getOffset() == 0);
+ seg = rep->getMediaSegment(11);
+ Expect(seg);
+ Expect(seg->getOffset() == 2000);
+ seg = rep->getMediaSegment(12);
+ Expect(seg);
+ Expect(seg->getOffset() == 6000);
+ seg = rep->getMediaSegment(13);
+ Expect(seg);
+ Expect(seg->getOffset() == 0);
+ delete m3u;
+ }
+ catch (...)
+ {
+ delete m3u;
+ return 1;
+ }
+
+
return 0;
}
=====================================
modules/demux/adaptive/tools/Compatibility.hpp
=====================================
@@ -0,0 +1,214 @@
+/*
+ * Compatibility.hpp
+ *****************************************************************************
+ * Copyright (C) 2025 - VideoLabs, VideoLAN and 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 COMPATIBILITY_HPP
+#define COMPATIBILITY_HPP
+
+/* Provide std::optional compatibility for builds with c++17 or
+ incomplete/bogus c++17 with MacOS <= 10.13 and iOS < 12 */
+
+#ifdef __APPLE__
+# include <TargetConditionals.h>
+# if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < 120000) || \
+ (TARGET_OS_MAC && __MAC_OS_X_VERSION_MIN_REQUIRED < 101400)
+# define IOS_INCOMPLETE_CPP17
+# endif
+#endif
+
+#if __cplusplus >= 201703L && !defined(IOS_INCOMPLETE_CPP17)
+# include <optional>
+#else
+# include <utility>
+# include <type_traits>
+# include <stdexcept>
+#endif
+
+namespace adaptive
+{
+
+#if __cplusplus >= 201703L && !defined(IOS_INCOMPLETE_CPP17)
+
+template <typename T>
+using optional = std::optional<T>;
+using nullopt_t = std::nullopt_t;
+constexpr auto nullopt = std::nullopt;
+using in_place_t = std::in_place_t;
+constexpr auto in_place = std::in_place;
+using bad_optional_access = std::bad_optional_access;
+#else
+
+struct nullopt_t {
+ explicit nullopt_t() = default;
+};
+constexpr nullopt_t nullopt{};
+
+struct in_place_t {
+ explicit in_place_t() = default;
+};
+constexpr in_place_t in_place{};
+
+class bad_optional_access : public std::exception {
+public:
+ const char* what() const noexcept override {
+ return "Bad optional access";
+ }
+};
+
+template <typename T>
+class optional
+{
+private:
+ alignas(T) unsigned char storage[sizeof(T)];
+ bool has_value_ = false;
+
+ T* ptr() noexcept
+ {
+ return reinterpret_cast<T*>(storage);
+ }
+ const T* ptr() const noexcept
+ {
+ return reinterpret_cast<const T*>(storage);
+ }
+
+ void destroy() noexcept(std::is_nothrow_destructible<T>::value)
+ {
+ if (has_value_)
+ {
+ ptr()->~T();
+ has_value_ = false;
+ }
+ }
+
+public:
+ optional() noexcept = default;
+
+ optional(nullopt_t) noexcept : optional() {}
+
+ optional(const T& value) : has_value_(true)
+ {
+ new (storage) T(value);
+ }
+ optional(T&& value) : has_value_(true)
+ {
+ new (storage) T(std::move(value));
+ }
+ optional(optional&& other) noexcept(std::is_nothrow_move_constructible<T>::value)
+ : has_value_(other.has_value_) {
+ if (has_value_) { new (storage) T(std::move(*other.ptr())); other.destroy(); }
+ }
+
+ ~optional() {destroy();}
+
+ optional& operator=(const optional& other)
+ {
+ if (this != &other)
+ {
+ destroy();
+ has_value_ = other.has_value_;
+ if (has_value_)
+ new (storage) T(*other.ptr());
+ }
+ return *this;
+ }
+
+ optional& operator=(optional&& other) noexcept(
+ std::is_nothrow_move_constructible<T>::value &&
+ std::is_nothrow_move_assignable<T>::value)
+ {
+ if (this != &other)
+ {
+ destroy();
+ has_value_ = other.has_value_;
+ if (has_value_)
+ {
+ new (storage) T(std::move(*other.ptr()));
+ other.destroy();
+ }
+ }
+ return *this;
+ }
+
+ optional& operator=(nullopt_t) noexcept
+ {
+ destroy();
+ return *this;
+ }
+
+ optional& operator=(const T& value)
+ {
+ destroy();
+ has_value_ = true;
+ new (storage) T(value);
+ return *this;
+ }
+ optional& operator=(T&& value)
+ {
+ destroy();
+ has_value_ = true;
+ new (storage) T(std::move(value));
+ return *this;
+ }
+
+ template <typename... Args>
+ void emplace(Args&&... args)
+ {
+ destroy();
+ has_value_ = true;
+ new (storage) T(std::forward<Args>(args)...);
+ }
+
+ explicit operator bool() const noexcept { return has_value_; }
+ bool has_value() const noexcept { return has_value_; }
+
+ T& value()
+ {
+ if (!has_value_) throw bad_optional_access{};
+ return *ptr();
+ }
+ const T& value() const
+ {
+ if (!has_value_) throw bad_optional_access{};
+ return *ptr();
+ }
+
+ T* operator->() { return ptr(); }
+ const T* operator->() const { return ptr(); }
+ T& operator*() { return *ptr(); }
+ const T& operator*() const { return *ptr(); }
+
+ template <typename U>
+ T value_or(U&& default_value) const& {
+ return has_value_ ? *ptr() : static_cast<T>(std::forward<U>(default_value));
+ }
+ template <typename U>
+ T value_or(U&& default_value) && {
+ return has_value_ ? std::move(*ptr()) : static_cast<T>(std::forward<U>(default_value));
+ }
+
+ void reset() noexcept
+ {
+ destroy();
+ }
+};
+
+#endif // #if __cplusplus < 201703L
+
+}
+
+#endif // COMPATIBILITY_HPP
=====================================
modules/demux/adaptive/tools/Properties.hpp
=====================================
@@ -39,24 +39,6 @@ template <typename T> class Property
T value;
};
-template <typename T> class Undef
-{
- public:
- Undef() { undef = true; }
-
- bool isSet() const
- {
- return !undef;
- }
-
- void operator =(const T &v) { val = v; undef = false; }
- const T& value() const { return val; }
-
- private:
- bool undef;
- T val;
-};
-
template <typename T> class Ratio
{
public:
=====================================
modules/demux/hls/playlist/Parser.cpp
=====================================
@@ -362,11 +362,11 @@ void M3U8Parser::parseSegments(vlc_object_t *, HLSRepresentation *rep, const std
if(ctx_byterange)
{
- std::pair<std::size_t,std::size_t> range = ctx_byterange->getValue().getByteRange();
- if(range.first == 0) /* first == size, second = offset */
+ ByteRange range = ctx_byterange->getValue().getByteRange();
+ if(!range.first.has_value()) /* first == offset, second = length */
range.first = prevbyterangeoffset;
- prevbyterangeoffset = range.first + range.second;
- segment->setByteRange(range.first, prevbyterangeoffset - 1);
+ prevbyterangeoffset = range.first.value() + range.second;
+ segment->setByteRange(range.first.value(), prevbyterangeoffset - 1);
ctx_byterange = nullptr;
}
segment->setDiscontinuitySequenceNumber(discontinuitySequence);
@@ -428,8 +428,8 @@ void M3U8Parser::parseSegments(vlc_object_t *, HLSRepresentation *rep, const std
const Attribute *byterangeAttr = keytag->getAttributeByName("BYTERANGE");
if(byterangeAttr)
{
- const std::pair<std::size_t,std::size_t> range = byterangeAttr->unescapeQuotes().getByteRange();
- initSegment->setByteRange(range.first, range.first + range.second - 1);
+ const ByteRange range = byterangeAttr->unescapeQuotes().getByteRange();
+ initSegment->setByteRange(range.first.value_or(0), range.first.value_or(0) + range.second - 1);
}
segmentList->initialisationSegment.Set(initSegment);
}
=====================================
modules/demux/hls/playlist/Tags.cpp
=====================================
@@ -72,10 +72,18 @@ std::vector<uint8_t> Attribute::hexSequence() const
return ret;
}
-std::pair<std::size_t,std::size_t> Attribute::getByteRange() const
+static inline std::istream& operator>>(std::istream& is, adaptive::optional<std::size_t>& data)
{
- std::size_t length = 0;
- std::size_t offset = 0;
+ size_t val;
+ is >> val;
+ data = val;
+ return is;
+}
+
+ByteRange Attribute::getByteRange() const
+{
+ std::size_t length;
+ adaptive::optional<std::size_t> offset;
std::istringstream is(value);
is.imbue(std::locale("C"));
@@ -90,7 +98,7 @@ std::pair<std::size_t,std::size_t> Attribute::getByteRange() const
}
}
- return std::make_pair(offset, length);
+ return ByteRange(std::move(offset), length);
}
std::pair<int, int> Attribute::getResolution() const
=====================================
modules/demux/hls/playlist/Tags.hpp
=====================================
@@ -20,6 +20,8 @@
#ifndef TAGS_HPP
#define TAGS_HPP
+#include "../../adaptive/tools/Compatibility.hpp"
+
#include <stdint.h>
#include <string>
@@ -32,6 +34,7 @@ namespace hls
namespace playlist
{
+ using ByteRange = std::pair<adaptive::optional<std::size_t>,std::size_t>;
class Attribute
{
@@ -43,7 +46,7 @@ namespace hls
std::string quotedString() const;
double floatingPoint() const;
std::vector<uint8_t> hexSequence() const;
- std::pair<std::size_t,std::size_t> getByteRange() const;
+ ByteRange getByteRange() const;
std::pair<int, int> getResolution() const;
std::string name;
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/0598db331e123aa38681380458970c7bfa76d84c...0ef5c1296bda493a733c270e7b0f501ee3a4ca5f
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/0598db331e123aa38681380458970c7bfa76d84c...0ef5c1296bda493a733c270e7b0f501ee3a4ca5f
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