Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ int main(int argc, char* argv[])
## Requirements

- C++20 compiler (tested with MSVC 2022, GCC 14, Clang 18)
- C++23 for the test runner (`std::format`)

## Consumption

Expand Down
37 changes: 37 additions & 0 deletions include/mbmff/boxes/alis.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#pragma once
#include "box_view.hpp"

namespace mbmff {

struct alis_data {};

template <>
struct basic_box_view<mbmff::box_type::alis> : public mbmff::box_view_base {
constexpr static mbmff::box_properties properties = mbmff::box_properties::full_box;
constexpr static auto validate(mbmff::any_box_view box) noexcept -> mbmff::result<mbmff::any_box_view>;
constexpr auto value() const noexcept -> mbmff::alis_data;
};

inline constexpr auto mbmff::basic_box_view<mbmff::box_type::alis>::validate(mbmff::any_box_view box) noexcept
-> mbmff::result<mbmff::any_box_view>
{
if (box.payload.size() < 4) {
return mbmff::make_result<mbmff::any_box_view>(mbmff::error_code::need_more_data, 4);
}
box.fill_full_header(box.payload);
(void)box.payload.subspan(0);
return {box};
}

inline constexpr auto mbmff::basic_box_view<mbmff::box_type::alis>::value() const noexcept -> mbmff::alis_data
{
return {};
}

#ifdef MBMFF_ENABLE_CONSTEXPR_TEST
static_assert(
!mbmff::basic_box_view<mbmff::box_type::alis>::validate({mbmff::box_header{}, std::span<const std::byte>{}})
);
#endif

} // namespace mbmff
62 changes: 62 additions & 0 deletions include/mbmff/boxes/apcn.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#pragma once
#include "box_view.hpp"

namespace mbmff {

struct apcn_data {
std::uint16_t data_reference_index;
std::uint16_t width;
std::uint16_t height;
std::uint32_t horizresolution;
std::uint32_t vertresolution;
std::uint16_t frame_count;
std::span<const std::byte> compressorname;
std::uint16_t depth;
};

template <>
struct basic_box_view<mbmff::box_type::apcn> : public mbmff::box_view_base {
constexpr static mbmff::box_properties properties = mbmff::box_properties::container;
constexpr static auto validate(mbmff::any_box_view box) noexcept -> mbmff::result<mbmff::any_box_view>;
constexpr auto value() const noexcept -> mbmff::apcn_data;
};

inline constexpr auto mbmff::basic_box_view<mbmff::box_type::apcn>::validate(mbmff::any_box_view box) noexcept
-> mbmff::result<mbmff::any_box_view>
{
if (box.payload.size() < 78) {
return mbmff::make_result<mbmff::any_box_view>(mbmff::error_code::need_more_data, 78);
}
box.payload = box.payload.subspan(78);
return {box};
}

inline constexpr auto mbmff::basic_box_view<mbmff::box_type::apcn>::value() const noexcept -> mbmff::apcn_data
{
if (payload.empty() && payload.data() == nullptr) {
return {};
}
auto span = std::span<const std::byte>(payload.data() - 78, 78);
return {
mbmff::read_be<std::uint16_t>(span.subspan(6)),
mbmff::read_be<std::uint16_t>(span.subspan(24)),
mbmff::read_be<std::uint16_t>(span.subspan(26)),
mbmff::read_be<std::uint32_t>(span.subspan(28)),
mbmff::read_be<std::uint32_t>(span.subspan(32)),
mbmff::read_be<std::uint16_t>(span.subspan(40)),
span.subspan(42, 32),
mbmff::read_be<std::uint16_t>(span.subspan(74)),
};
}

#ifdef MBMFF_ENABLE_CONSTEXPR_TEST
static_assert(
!mbmff::basic_box_view<mbmff::box_type::apcn>::validate({mbmff::box_header{}, std::span<const std::byte>{}})
);

static_assert(static_cast<bool>(mbmff::basic_box_view<mbmff::box_type::apcn>::validate(
{mbmff::box_header{}, std::span<const std::byte>(std::array<std::byte, 78>{}.data(), 78)}
)));
#endif

} // namespace mbmff
16 changes: 8 additions & 8 deletions include/mbmff/boxes/av1C.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ struct av1C_data {
};

template <>
struct basic_box_view<box_type::av1C> : public box_view_base {
constexpr static box_properties properties = box_properties::none;
struct basic_box_view<mbmff::box_type::av1C> : public mbmff::box_view_base {
constexpr static mbmff::box_properties properties = mbmff::box_properties::none;
constexpr static auto validate(mbmff::any_box_view box) noexcept -> mbmff::result<mbmff::any_box_view>;
constexpr auto value() const noexcept -> mbmff::av1C_data;
};

inline constexpr auto basic_box_view<box_type::av1C>::validate(mbmff::any_box_view box) noexcept
inline constexpr auto mbmff::basic_box_view<mbmff::box_type::av1C>::validate(mbmff::any_box_view box) noexcept
-> mbmff::result<mbmff::any_box_view>
{
if (box.payload.size() < 4) {
Expand All @@ -37,7 +37,7 @@ inline constexpr auto basic_box_view<box_type::av1C>::validate(mbmff::any_box_vi
return {box};
}

constexpr auto basic_box_view<box_type::av1C>::value() const noexcept -> mbmff::av1C_data
constexpr auto mbmff::basic_box_view<mbmff::box_type::av1C>::value() const noexcept -> mbmff::av1C_data
{
av1C_data result{};
std::uint8_t read_byte = static_cast<std::uint8_t>(payload[0]);
Expand Down Expand Up @@ -70,14 +70,14 @@ constexpr auto basic_box_view<box_type::av1C>::value() const noexcept -> mbmff::

#ifdef MBMFF_ENABLE_CONSTEXPR_TEST
// validate must reject empty payload
static_assert(!mbmff::basic_box_view<box_type::av1C>::validate(
{mbmff::box_header{}, std::span<const std::byte>{}}));
static_assert(
!mbmff::basic_box_view<mbmff::box_type::av1C>::validate({mbmff::box_header{}, std::span<const std::byte>{}})
);

// validate must accept 4-byte payload
static_assert([] {
constexpr std::byte min_data[4]{};
auto r = mbmff::basic_box_view<box_type::av1C>::validate(
{mbmff::box_header{}, std::span(min_data)});
auto r = mbmff::basic_box_view<mbmff::box_type::av1C>::validate({mbmff::box_header{}, std::span(min_data)});
return static_cast<bool>(r);
}());
#endif
Expand Down
62 changes: 62 additions & 0 deletions include/mbmff/boxes/avc1.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#pragma once
#include "box_view.hpp"

namespace mbmff {

struct avc1_data {
std::uint16_t data_reference_index;
std::uint16_t width;
std::uint16_t height;
std::uint32_t horizresolution;
std::uint32_t vertresolution;
std::uint16_t frame_count;
std::span<const std::byte> compressorname;
std::uint16_t depth;
};

template <>
struct basic_box_view<mbmff::box_type::avc1> : public mbmff::box_view_base {
constexpr static mbmff::box_properties properties = mbmff::box_properties::container;
constexpr static auto validate(mbmff::any_box_view box) noexcept -> mbmff::result<mbmff::any_box_view>;
constexpr auto value() const noexcept -> mbmff::avc1_data;
};

inline constexpr auto basic_box_view<mbmff::box_type::avc1>::validate(mbmff::any_box_view box) noexcept
-> mbmff::result<mbmff::any_box_view>
{
if (box.payload.size() < 78) {
return mbmff::make_result<mbmff::any_box_view>(mbmff::error_code::need_more_data, 78);
}
box.payload = box.payload.subspan(78);
return {box};
}

inline constexpr auto basic_box_view<mbmff::box_type::avc1>::value() const noexcept -> mbmff::avc1_data
{
if (payload.empty() && payload.data() == nullptr) {
return {};
}
auto span = std::span<const std::byte>(payload.data() - 78, 78);
return {
mbmff::read_be<std::uint16_t>(span.subspan(6)),
mbmff::read_be<std::uint16_t>(span.subspan(24)),
mbmff::read_be<std::uint16_t>(span.subspan(26)),
mbmff::read_be<std::uint32_t>(span.subspan(28)),
mbmff::read_be<std::uint32_t>(span.subspan(32)),
mbmff::read_be<std::uint16_t>(span.subspan(40)),
span.subspan(42, 32),
mbmff::read_be<std::uint16_t>(span.subspan(74)),
};
}

#ifdef MBMFF_ENABLE_CONSTEXPR_TEST
static_assert(
!mbmff::basic_box_view<mbmff::box_type::avc1>::validate({mbmff::box_header{}, std::span<const std::byte>{}})
);

static_assert(static_cast<bool>(mbmff::basic_box_view<mbmff::box_type::avc1>::validate(
{mbmff::box_header{}, std::span<const std::byte>(std::array<std::byte, 78>{}.data(), 78)}
)));
#endif

} // namespace mbmff
75 changes: 75 additions & 0 deletions include/mbmff/boxes/avcC.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#pragma once
#include "box_view.hpp"

namespace mbmff {

struct avcC_data {
std::uint8_t configurationVersion = 0;
std::uint8_t AVCProfileIndication = 0;
std::uint8_t profile_compatibility = 0;
std::uint8_t AVCLevelIndication = 0;
std::uint8_t lengthSizeMinusOne = 0;
std::span<const std::byte> nalu_data{};
};

template <>
struct basic_box_view<mbmff::box_type::avcC> : public mbmff::box_view_base {
constexpr static mbmff::box_properties properties = mbmff::box_properties::none;
constexpr static auto validate(mbmff::any_box_view box) noexcept -> mbmff::result<mbmff::any_box_view>;
constexpr auto value() const noexcept -> mbmff::avcC_data;
};

inline constexpr auto mbmff::basic_box_view<mbmff::box_type::avcC>::validate(mbmff::any_box_view box) noexcept
-> mbmff::result<mbmff::any_box_view>
{
if (box.payload.size() < 6) {
return mbmff::make_result<mbmff::any_box_view>(mbmff::error_code::need_more_data, 6);
}
return {box};
}

constexpr auto mbmff::basic_box_view<mbmff::box_type::avcC>::value() const noexcept -> mbmff::avcC_data
{
avcC_data result{};
result.configurationVersion = static_cast<std::uint8_t>(payload[0]);
result.AVCProfileIndication = static_cast<std::uint8_t>(payload[1]);
result.profile_compatibility = static_cast<std::uint8_t>(payload[2]);
result.AVCLevelIndication = static_cast<std::uint8_t>(payload[3]);
result.lengthSizeMinusOne = static_cast<std::uint8_t>(payload[4]) & 0x03;
result.nalu_data = payload.subspan(6);
return result;
}

#ifdef MBMFF_ENABLE_CONSTEXPR_TEST
static_assert(
!mbmff::basic_box_view<mbmff::box_type::avcC>::validate({mbmff::box_header{}, std::span<const std::byte>{}})
);

static_assert([] {
constexpr std::byte min_data[6]{};
auto r = mbmff::basic_box_view<mbmff::box_type::avcC>::validate({mbmff::box_header{}, std::span(min_data)});
return static_cast<bool>(r);
}());

static_assert([] {
constexpr std::array<std::byte, 10> data{
std::byte{0x01},
std::byte{0x64},
std::byte{0x00},
std::byte{0x1e},
std::byte{0xff},
std::byte{0x01},
std::byte{0x00},
std::byte{0x04},
std::byte{0xbe},
std::byte{0xef},
};
mbmff::basic_box_view<mbmff::box_type::avcC> avcc;
avcc.payload = std::span(data);
auto v = avcc.value();
return v.configurationVersion == 1 && v.AVCProfileIndication == 100 && v.profile_compatibility == 0
&& v.AVCLevelIndication == 30 && v.lengthSizeMinusOne == 3 && v.nalu_data.size() == 4;
}());
#endif

} // namespace mbmff
Loading
Loading